Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of OmniWheels by
lwip_raw.c
00001 /** 00002 * @file 00003 * Implementation of raw protocol PCBs for low-level handling of 00004 * different types of protocols besides (or overriding) those 00005 * already available in lwIP.\n 00006 * See also @ref raw_raw 00007 * 00008 * @defgroup raw_raw RAW 00009 * @ingroup callbackstyle_api 00010 * Implementation of raw protocol PCBs for low-level handling of 00011 * different types of protocols besides (or overriding) those 00012 * already available in lwIP.\n 00013 * @see @ref raw_api 00014 */ 00015 00016 /* 00017 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 00018 * All rights reserved. 00019 * 00020 * Redistribution and use in source and binary forms, with or without modification, 00021 * are permitted provided that the following conditions are met: 00022 * 00023 * 1. Redistributions of source code must retain the above copyright notice, 00024 * this list of conditions and the following disclaimer. 00025 * 2. Redistributions in binary form must reproduce the above copyright notice, 00026 * this list of conditions and the following disclaimer in the documentation 00027 * and/or other materials provided with the distribution. 00028 * 3. The name of the author may not be used to endorse or promote products 00029 * derived from this software without specific prior written permission. 00030 * 00031 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00032 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00033 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00034 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00035 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00036 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00037 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00038 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00039 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00040 * OF SUCH DAMAGE. 00041 * 00042 * This file is part of the lwIP TCP/IP stack. 00043 * 00044 * Author: Adam Dunkels <adam@sics.se> 00045 * 00046 */ 00047 00048 #include "lwip/opt.h" 00049 00050 #if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ 00051 00052 #include "lwip/def.h" 00053 #include "lwip/memp.h" 00054 #include "lwip/ip_addr.h" 00055 #include "lwip/netif.h" 00056 #include "lwip/raw.h" 00057 #include "lwip/stats.h" 00058 #include "lwip/ip6.h" 00059 #include "lwip/ip6_addr.h" 00060 #include "lwip/inet_chksum.h" 00061 00062 #include <string.h> 00063 00064 /** The list of RAW PCBs */ 00065 static struct raw_pcb *raw_pcbs; 00066 00067 static u8_t 00068 raw_input_match(struct raw_pcb *pcb, u8_t broadcast) 00069 { 00070 LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */ 00071 00072 #if LWIP_IPV4 && LWIP_IPV6 00073 /* Dual-stack: PCBs listening to any IP type also listen to any IP address */ 00074 if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { 00075 #if IP_SOF_BROADCAST_RECV 00076 if ((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) { 00077 return 0; 00078 } 00079 #endif /* IP_SOF_BROADCAST_RECV */ 00080 return 1; 00081 } 00082 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 00083 00084 /* Only need to check PCB if incoming IP version matches PCB IP version */ 00085 if (IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) { 00086 #if LWIP_IPV4 00087 /* Special case: IPv4 broadcast: receive all broadcasts 00088 * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */ 00089 if (broadcast != 0) { 00090 #if IP_SOF_BROADCAST_RECV 00091 if (ip_get_option(pcb, SOF_BROADCAST)) 00092 #endif /* IP_SOF_BROADCAST_RECV */ 00093 { 00094 if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip))) { 00095 return 1; 00096 } 00097 } 00098 } else 00099 #endif /* LWIP_IPV4 */ 00100 /* Handle IPv4 and IPv6: catch all or exact match */ 00101 if (ip_addr_isany(&pcb->local_ip) || 00102 ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) { 00103 return 1; 00104 } 00105 } 00106 00107 return 0; 00108 } 00109 00110 /** 00111 * Determine if in incoming IP packet is covered by a RAW PCB 00112 * and if so, pass it to a user-provided receive callback function. 00113 * 00114 * Given an incoming IP datagram (as a chain of pbufs) this function 00115 * finds a corresponding RAW PCB and calls the corresponding receive 00116 * callback function. 00117 * 00118 * @param p pbuf to be demultiplexed to a RAW PCB. 00119 * @param inp network interface on which the datagram was received. 00120 * @return - 1 if the packet has been eaten by a RAW PCB receive 00121 * callback function. The caller MAY NOT not reference the 00122 * packet any longer, and MAY NOT call pbuf_free(). 00123 * @return - 0 if packet is not eaten (pbuf is still referenced by the 00124 * caller). 00125 * 00126 */ 00127 u8_t 00128 raw_input(struct pbuf *p, struct netif *inp) 00129 { 00130 struct raw_pcb *pcb, *prev; 00131 s16_t proto; 00132 u8_t eaten = 0; 00133 u8_t broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif()); 00134 00135 LWIP_UNUSED_ARG(inp); 00136 00137 #if LWIP_IPV6 00138 #if LWIP_IPV4 00139 if (IP_HDR_GET_VERSION(p->payload) == 6) 00140 #endif /* LWIP_IPV4 */ 00141 { 00142 struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload; 00143 proto = IP6H_NEXTH(ip6hdr); 00144 } 00145 #if LWIP_IPV4 00146 else 00147 #endif /* LWIP_IPV4 */ 00148 #endif /* LWIP_IPV6 */ 00149 #if LWIP_IPV4 00150 { 00151 proto = IPH_PROTO((struct ip_hdr *)p->payload); 00152 } 00153 #endif /* LWIP_IPV4 */ 00154 00155 prev = NULL; 00156 pcb = raw_pcbs; 00157 /* loop through all raw pcbs until the packet is eaten by one */ 00158 /* this allows multiple pcbs to match against the packet by design */ 00159 while ((eaten == 0) && (pcb != NULL)) { 00160 if ((pcb->protocol == proto) && raw_input_match(pcb, broadcast)) { 00161 /* receive callback function available? */ 00162 if (pcb->recv != NULL) { 00163 #ifndef LWIP_NOASSERT 00164 void* old_payload = p->payload; 00165 #endif 00166 /* the receive callback function did not eat the packet? */ 00167 eaten = pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()); 00168 if (eaten != 0) { 00169 /* receive function ate the packet */ 00170 p = NULL; 00171 eaten = 1; 00172 if (prev != NULL) { 00173 /* move the pcb to the front of raw_pcbs so that is 00174 found faster next time */ 00175 prev->next = pcb->next; 00176 pcb->next = raw_pcbs; 00177 raw_pcbs = pcb; 00178 } 00179 } else { 00180 /* sanity-check that the receive callback did not alter the pbuf */ 00181 LWIP_ASSERT("raw pcb recv callback altered pbuf payload pointer without eating packet", 00182 p->payload == old_payload); 00183 } 00184 } 00185 /* no receive callback function was set for this raw PCB */ 00186 } 00187 /* drop the packet */ 00188 prev = pcb; 00189 pcb = pcb->next; 00190 } 00191 return eaten; 00192 } 00193 00194 /** 00195 * @ingroup raw_raw 00196 * Bind a RAW PCB. 00197 * 00198 * @param pcb RAW PCB to be bound with a local address ipaddr. 00199 * @param ipaddr local IP address to bind with. Use IP4_ADDR_ANY to 00200 * bind to all local interfaces. 00201 * 00202 * @return lwIP error code. 00203 * - ERR_OK. Successful. No error occurred. 00204 * - ERR_USE. The specified IP address is already bound to by 00205 * another RAW PCB. 00206 * 00207 * @see raw_disconnect() 00208 */ 00209 err_t 00210 raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr) 00211 { 00212 if ((pcb == NULL) || (ipaddr == NULL)) { 00213 return ERR_VAL; 00214 } 00215 ip_addr_set_ipaddr(&pcb->local_ip, ipaddr); 00216 return ERR_OK; 00217 } 00218 00219 /** 00220 * @ingroup raw_raw 00221 * Connect an RAW PCB. This function is required by upper layers 00222 * of lwip. Using the raw api you could use raw_sendto() instead 00223 * 00224 * This will associate the RAW PCB with the remote address. 00225 * 00226 * @param pcb RAW PCB to be connected with remote address ipaddr and port. 00227 * @param ipaddr remote IP address to connect with. 00228 * 00229 * @return lwIP error code 00230 * 00231 * @see raw_disconnect() and raw_sendto() 00232 */ 00233 err_t 00234 raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr) 00235 { 00236 if ((pcb == NULL) || (ipaddr == NULL)) { 00237 return ERR_VAL; 00238 } 00239 ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr); 00240 return ERR_OK; 00241 } 00242 00243 /** 00244 * @ingroup raw_raw 00245 * Set the callback function for received packets that match the 00246 * raw PCB's protocol and binding. 00247 * 00248 * The callback function MUST either 00249 * - eat the packet by calling pbuf_free() and returning non-zero. The 00250 * packet will not be passed to other raw PCBs or other protocol layers. 00251 * - not free the packet, and return zero. The packet will be matched 00252 * against further PCBs and/or forwarded to another protocol layers. 00253 */ 00254 void 00255 raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) 00256 { 00257 /* remember recv() callback and user data */ 00258 pcb->recv = recv; 00259 pcb->recv_arg = recv_arg; 00260 } 00261 00262 /** 00263 * @ingroup raw_raw 00264 * Send the raw IP packet to the given address. Note that actually you cannot 00265 * modify the IP headers (this is inconsistent with the receive callback where 00266 * you actually get the IP headers), you can only specify the IP payload here. 00267 * It requires some more changes in lwIP. (there will be a raw_send() function 00268 * then.) 00269 * 00270 * @param pcb the raw pcb which to send 00271 * @param p the IP payload to send 00272 * @param ipaddr the destination address of the IP packet 00273 * 00274 */ 00275 err_t 00276 raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) 00277 { 00278 err_t err; 00279 struct netif *netif; 00280 const ip_addr_t *src_ip; 00281 struct pbuf *q; /* q will be sent down the stack */ 00282 s16_t header_size; 00283 00284 if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) { 00285 return ERR_VAL; 00286 } 00287 00288 LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); 00289 00290 header_size = ( 00291 #if LWIP_IPV4 && LWIP_IPV6 00292 IP_IS_V6(ipaddr) ? IP6_HLEN : IP_HLEN); 00293 #elif LWIP_IPV4 00294 IP_HLEN); 00295 #else 00296 IP6_HLEN); 00297 #endif 00298 00299 /* not enough space to add an IP header to first pbuf in given p chain? */ 00300 if (pbuf_header(p, header_size)) { 00301 /* allocate header in new pbuf */ 00302 q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); 00303 /* new header pbuf could not be allocated? */ 00304 if (q == NULL) { 00305 LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n")); 00306 return ERR_MEM; 00307 } 00308 if (p->tot_len != 0) { 00309 /* chain header q in front of given pbuf p */ 00310 pbuf_chain(q, p); 00311 } 00312 /* { first pbuf q points to header pbuf } */ 00313 LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); 00314 } else { 00315 /* first pbuf q equals given pbuf */ 00316 q = p; 00317 if (pbuf_header(q, -header_size)) { 00318 LWIP_ASSERT("Can't restore header we just removed!", 0); 00319 return ERR_MEM; 00320 } 00321 } 00322 00323 if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) { 00324 /* Don't call ip_route() with IP_ANY_TYPE */ 00325 netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(ipaddr)), ipaddr); 00326 } else { 00327 netif = ip_route(&pcb->local_ip, ipaddr); 00328 } 00329 00330 if (netif == NULL) { 00331 LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to ")); 00332 ip_addr_debug_print(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ipaddr); 00333 /* free any temporary header pbuf allocated by pbuf_header() */ 00334 if (q != p) { 00335 pbuf_free(q); 00336 } 00337 return ERR_RTE; 00338 } 00339 00340 #if IP_SOF_BROADCAST 00341 if (IP_IS_V4(ipaddr)) 00342 { 00343 /* broadcast filter? */ 00344 if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) { 00345 LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); 00346 /* free any temporary header pbuf allocated by pbuf_header() */ 00347 if (q != p) { 00348 pbuf_free(q); 00349 } 00350 return ERR_VAL; 00351 } 00352 } 00353 #endif /* IP_SOF_BROADCAST */ 00354 00355 if (ip_addr_isany(&pcb->local_ip)) { 00356 /* use outgoing network interface IP address as source address */ 00357 src_ip = ip_netif_get_local_ip(netif, ipaddr); 00358 #if LWIP_IPV6 00359 if (src_ip == NULL) { 00360 if (q != p) { 00361 pbuf_free(q); 00362 } 00363 return ERR_RTE; 00364 } 00365 #endif /* LWIP_IPV6 */ 00366 } else { 00367 /* use RAW PCB local IP address as source address */ 00368 src_ip = &pcb->local_ip; 00369 } 00370 00371 #if LWIP_IPV6 00372 /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542, 00373 compute the checksum and update the checksum in the payload. */ 00374 if (IP_IS_V6(ipaddr) && pcb->chksum_reqd) { 00375 u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ip_2_ip6(src_ip), ip_2_ip6(ipaddr)); 00376 LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2)); 00377 SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t)); 00378 } 00379 #endif 00380 00381 NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); 00382 err = ip_output_if(q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); 00383 NETIF_SET_HWADDRHINT(netif, NULL); 00384 00385 /* did we chain a header earlier? */ 00386 if (q != p) { 00387 /* free the header */ 00388 pbuf_free(q); 00389 } 00390 return err; 00391 } 00392 00393 /** 00394 * @ingroup raw_raw 00395 * Send the raw IP packet to the address given by raw_connect() 00396 * 00397 * @param pcb the raw pcb which to send 00398 * @param p the IP payload to send 00399 * 00400 */ 00401 err_t 00402 raw_send(struct raw_pcb *pcb, struct pbuf *p) 00403 { 00404 return raw_sendto(pcb, p, &pcb->remote_ip); 00405 } 00406 00407 /** 00408 * @ingroup raw_raw 00409 * Remove an RAW PCB. 00410 * 00411 * @param pcb RAW PCB to be removed. The PCB is removed from the list of 00412 * RAW PCB's and the data structure is freed from memory. 00413 * 00414 * @see raw_new() 00415 */ 00416 void 00417 raw_remove(struct raw_pcb *pcb) 00418 { 00419 struct raw_pcb *pcb2; 00420 /* pcb to be removed is first in list? */ 00421 if (raw_pcbs == pcb) { 00422 /* make list start at 2nd pcb */ 00423 raw_pcbs = raw_pcbs->next; 00424 /* pcb not 1st in list */ 00425 } else { 00426 for (pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { 00427 /* find pcb in raw_pcbs list */ 00428 if (pcb2->next != NULL && pcb2->next == pcb) { 00429 /* remove pcb from list */ 00430 pcb2->next = pcb->next; 00431 break; 00432 } 00433 } 00434 } 00435 memp_free(MEMP_RAW_PCB, pcb); 00436 } 00437 00438 /** 00439 * @ingroup raw_raw 00440 * Create a RAW PCB. 00441 * 00442 * @return The RAW PCB which was created. NULL if the PCB data structure 00443 * could not be allocated. 00444 * 00445 * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP) 00446 * 00447 * @see raw_remove() 00448 */ 00449 struct raw_pcb * 00450 raw_new(u8_t proto) 00451 { 00452 struct raw_pcb *pcb; 00453 00454 LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n")); 00455 00456 pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB); 00457 /* could allocate RAW PCB? */ 00458 if (pcb != NULL) { 00459 /* initialize PCB to all zeroes */ 00460 memset(pcb, 0, sizeof(struct raw_pcb)); 00461 pcb->protocol = proto; 00462 pcb->ttl = RAW_TTL; 00463 pcb->next = raw_pcbs; 00464 raw_pcbs = pcb; 00465 } 00466 return pcb; 00467 } 00468 00469 /** 00470 * @ingroup raw_raw 00471 * Create a RAW PCB for specific IP type. 00472 * 00473 * @return The RAW PCB which was created. NULL if the PCB data structure 00474 * could not be allocated. 00475 * 00476 * @param type IP address type, see @ref lwip_ip_addr_type definitions. 00477 * If you want to listen to IPv4 and IPv6 (dual-stack) packets, 00478 * supply @ref IPADDR_TYPE_ANY as argument and bind to @ref IP_ANY_TYPE. 00479 * @param proto the protocol number (next header) of the IPv6 packet payload 00480 * (e.g. IP6_NEXTH_ICMP6) 00481 * 00482 * @see raw_remove() 00483 */ 00484 struct raw_pcb * 00485 raw_new_ip_type(u8_t type, u8_t proto) 00486 { 00487 struct raw_pcb *pcb; 00488 pcb = raw_new(proto); 00489 #if LWIP_IPV4 && LWIP_IPV6 00490 if (pcb != NULL) { 00491 IP_SET_TYPE_VAL(pcb->local_ip, type); 00492 IP_SET_TYPE_VAL(pcb->remote_ip, type); 00493 } 00494 #else /* LWIP_IPV4 && LWIP_IPV6 */ 00495 LWIP_UNUSED_ARG(type); 00496 #endif /* LWIP_IPV4 && LWIP_IPV6 */ 00497 return pcb; 00498 } 00499 00500 /** This function is called from netif.c when address is changed 00501 * 00502 * @param old_addr IP address of the netif before change 00503 * @param new_addr IP address of the netif after change 00504 */ 00505 void raw_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr) 00506 { 00507 struct raw_pcb* rpcb; 00508 00509 if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) { 00510 for (rpcb = raw_pcbs; rpcb != NULL; rpcb = rpcb->next) { 00511 /* PCB bound to current local interface address? */ 00512 if (ip_addr_cmp(&rpcb->local_ip, old_addr)) { 00513 /* The PCB is bound to the old ipaddr and 00514 * is set to bound to the new one instead */ 00515 ip_addr_copy(rpcb->local_ip, *new_addr); 00516 } 00517 } 00518 } 00519 } 00520 00521 #endif /* LWIP_RAW */
Generated on Fri Jul 22 2022 04:53:53 by
1.7.2
