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