raw.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. /**
  2. * @file
  3. * Implementation of raw protocol PCBs for low-level handling of
  4. * different types of protocols besides (or overriding) those
  5. * already available in lwIP.
  6. *
  7. */
  8. /*
  9. * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or without modification,
  13. * are permitted provided that the following conditions are met:
  14. *
  15. * 1. Redistributions of source code must retain the above copyright notice,
  16. * this list of conditions and the following disclaimer.
  17. * 2. Redistributions in binary form must reproduce the above copyright notice,
  18. * this list of conditions and the following disclaimer in the documentation
  19. * and/or other materials provided with the distribution.
  20. * 3. The name of the author may not be used to endorse or promote products
  21. * derived from this software without specific prior written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  24. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  25. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
  26. * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  27. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  28. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  31. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  32. * OF SUCH DAMAGE.
  33. *
  34. * This file is part of the lwIP TCP/IP stack.
  35. *
  36. * Author: Adam Dunkels <adam@sics.se>
  37. *
  38. */
  39. #include "lwip/opt.h"
  40. #if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
  41. #include "lwip/def.h"
  42. #include "lwip/memp.h"
  43. #include "lwip/ip_addr.h"
  44. #include "lwip/netif.h"
  45. #include "lwip/raw.h"
  46. #include "lwip/stats.h"
  47. #include "lwip/ip6.h"
  48. #include "lwip/ip6_addr.h"
  49. #include "lwip/inet_chksum.h"
  50. #include <string.h>
  51. /** The list of RAW PCBs */
  52. static struct raw_pcb *raw_pcbs;
  53. static u8_t
  54. raw_input_match(struct raw_pcb *pcb, u8_t broadcast)
  55. {
  56. LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */
  57. /* Dual-stack: PCBs listening to any IP type also listen to any IP address */
  58. if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
  59. #if LWIP_IPV4 && IP_SOF_BROADCAST_RECV
  60. if((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) {
  61. return 0;
  62. }
  63. #endif /* LWIP_IPV4 && IP_SOF_BROADCAST_RECV */
  64. return 1;
  65. }
  66. /* Only need to check PCB if incoming IP version matches PCB IP version */
  67. if(IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) {
  68. #if LWIP_IPV4
  69. /* Special case: IPv4 broadcast: receive all broadcasts
  70. * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */
  71. if(broadcast != 0) {
  72. #if IP_SOF_BROADCAST_RECV
  73. if(ip_get_option(pcb, SOF_BROADCAST))
  74. #endif /* IP_SOF_BROADCAST_RECV */
  75. {
  76. if(ip4_addr_isany(ip_2_ip4(&pcb->local_ip))) {
  77. return 1;
  78. }
  79. }
  80. } else
  81. #endif /* LWIP_IPV4 */
  82. /* Handle IPv4 and IPv6: catch all or exact match */
  83. if(ip_addr_isany(&pcb->local_ip) ||
  84. ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) {
  85. return 1;
  86. }
  87. }
  88. return 0;
  89. }
  90. /**
  91. * Determine if in incoming IP packet is covered by a RAW PCB
  92. * and if so, pass it to a user-provided receive callback function.
  93. *
  94. * Given an incoming IP datagram (as a chain of pbufs) this function
  95. * finds a corresponding RAW PCB and calls the corresponding receive
  96. * callback function.
  97. *
  98. * @param p pbuf to be demultiplexed to a RAW PCB.
  99. * @param inp network interface on which the datagram was received.
  100. * @return - 1 if the packet has been eaten by a RAW PCB receive
  101. * callback function. The caller MAY NOT not reference the
  102. * packet any longer, and MAY NOT call pbuf_free().
  103. * @return - 0 if packet is not eaten (pbuf is still referenced by the
  104. * caller).
  105. *
  106. */
  107. u8_t
  108. raw_input(struct pbuf *p, struct netif *inp)
  109. {
  110. struct raw_pcb *pcb, *prev;
  111. s16_t proto;
  112. u8_t eaten = 0;
  113. u8_t broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif());
  114. LWIP_UNUSED_ARG(inp);
  115. #if LWIP_IPV6
  116. #if LWIP_IPV4
  117. if (IP_HDR_GET_VERSION(p->payload) == 6)
  118. #endif /* LWIP_IPV4 */
  119. {
  120. struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload;
  121. proto = IP6H_NEXTH(ip6hdr);
  122. }
  123. #if LWIP_IPV4
  124. else
  125. #endif /* LWIP_IPV4 */
  126. #endif /* LWIP_IPV6 */
  127. #if LWIP_IPV4
  128. {
  129. proto = IPH_PROTO((struct ip_hdr *)p->payload);
  130. }
  131. #endif /* LWIP_IPV4 */
  132. prev = NULL;
  133. pcb = raw_pcbs;
  134. /* loop through all raw pcbs until the packet is eaten by one */
  135. /* this allows multiple pcbs to match against the packet by design */
  136. while ((eaten == 0) && (pcb != NULL)) {
  137. if ((pcb->protocol == proto) && raw_input_match(pcb, broadcast)) {
  138. /* receive callback function available? */
  139. if (pcb->recv != NULL) {
  140. #ifndef LWIP_NOASSERT
  141. void* old_payload = p->payload;
  142. #endif
  143. /* the receive callback function did not eat the packet? */
  144. eaten = pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr());
  145. if (eaten != 0) {
  146. /* receive function ate the packet */
  147. p = NULL;
  148. eaten = 1;
  149. if (prev != NULL) {
  150. /* move the pcb to the front of raw_pcbs so that is
  151. found faster next time */
  152. prev->next = pcb->next;
  153. pcb->next = raw_pcbs;
  154. raw_pcbs = pcb;
  155. }
  156. } else {
  157. /* sanity-check that the receive callback did not alter the pbuf */
  158. LWIP_ASSERT("raw pcb recv callback altered pbuf payload pointer without eating packet",
  159. p->payload == old_payload);
  160. }
  161. }
  162. /* no receive callback function was set for this raw PCB */
  163. }
  164. /* drop the packet */
  165. prev = pcb;
  166. pcb = pcb->next;
  167. }
  168. return eaten;
  169. }
  170. /**
  171. * Bind a RAW PCB.
  172. *
  173. * @param pcb RAW PCB to be bound with a local address ipaddr.
  174. * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
  175. * bind to all local interfaces.
  176. *
  177. * @return lwIP error code.
  178. * - ERR_OK. Successful. No error occurred.
  179. * - ERR_USE. The specified IP address is already bound to by
  180. * another RAW PCB.
  181. *
  182. * @see raw_disconnect()
  183. */
  184. err_t
  185. raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
  186. {
  187. if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
  188. return ERR_VAL;
  189. }
  190. ip_addr_set_ipaddr(&pcb->local_ip, ipaddr);
  191. return ERR_OK;
  192. }
  193. /**
  194. * Connect an RAW PCB. This function is required by upper layers
  195. * of lwip. Using the raw api you could use raw_sendto() instead
  196. *
  197. * This will associate the RAW PCB with the remote address.
  198. *
  199. * @param pcb RAW PCB to be connected with remote address ipaddr and port.
  200. * @param ipaddr remote IP address to connect with.
  201. *
  202. * @return lwIP error code
  203. *
  204. * @see raw_disconnect() and raw_sendto()
  205. */
  206. err_t
  207. raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
  208. {
  209. if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)) {
  210. return ERR_VAL;
  211. }
  212. ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr);
  213. return ERR_OK;
  214. }
  215. /**
  216. * Set the callback function for received packets that match the
  217. * raw PCB's protocol and binding.
  218. *
  219. * The callback function MUST either
  220. * - eat the packet by calling pbuf_free() and returning non-zero. The
  221. * packet will not be passed to other raw PCBs or other protocol layers.
  222. * - not free the packet, and return zero. The packet will be matched
  223. * against further PCBs and/or forwarded to another protocol layers.
  224. *
  225. * @return non-zero if the packet was free()d, zero if the packet remains
  226. * available for others.
  227. */
  228. void
  229. raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
  230. {
  231. /* remember recv() callback and user data */
  232. pcb->recv = recv;
  233. pcb->recv_arg = recv_arg;
  234. }
  235. /**
  236. * Send the raw IP packet to the given address. Note that actually you cannot
  237. * modify the IP headers (this is inconsistent with the receive callback where
  238. * you actually get the IP headers), you can only specify the IP payload here.
  239. * It requires some more changes in lwIP. (there will be a raw_send() function
  240. * then.)
  241. *
  242. * @param pcb the raw pcb which to send
  243. * @param p the IP payload to send
  244. * @param ipaddr the destination address of the IP packet
  245. *
  246. */
  247. err_t
  248. raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr)
  249. {
  250. err_t err;
  251. struct netif *netif;
  252. const ip_addr_t *src_ip;
  253. struct pbuf *q; /* q will be sent down the stack */
  254. s16_t header_size;
  255. const ip_addr_t *dst_ip = ipaddr;
  256. if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
  257. return ERR_VAL;
  258. }
  259. LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
  260. header_size = (
  261. #if LWIP_IPV4 && LWIP_IPV6
  262. IP_IS_V6(ipaddr) ? IP6_HLEN : IP_HLEN);
  263. #elif LWIP_IPV4
  264. IP_HLEN);
  265. #else
  266. IP6_HLEN);
  267. #endif
  268. /* not enough space to add an IP header to first pbuf in given p chain? */
  269. if (pbuf_header(p, header_size)) {
  270. /* allocate header in new pbuf */
  271. q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
  272. /* new header pbuf could not be allocated? */
  273. if (q == NULL) {
  274. LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
  275. return ERR_MEM;
  276. }
  277. if (p->tot_len != 0) {
  278. /* chain header q in front of given pbuf p */
  279. pbuf_chain(q, p);
  280. }
  281. /* { first pbuf q points to header pbuf } */
  282. LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
  283. } else {
  284. /* first pbuf q equals given pbuf */
  285. q = p;
  286. if (pbuf_header(q, -header_size)) {
  287. LWIP_ASSERT("Can't restore header we just removed!", 0);
  288. return ERR_MEM;
  289. }
  290. }
  291. netif = ip_route(&pcb->local_ip, dst_ip);
  292. if (netif == NULL) {
  293. LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to "));
  294. ip_addr_debug_print(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip);
  295. /* free any temporary header pbuf allocated by pbuf_header() */
  296. if (q != p) {
  297. pbuf_free(q);
  298. }
  299. return ERR_RTE;
  300. }
  301. #if IP_SOF_BROADCAST
  302. if (!IP_IS_V6(ipaddr))
  303. {
  304. /* broadcast filter? */
  305. if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) {
  306. LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
  307. /* free any temporary header pbuf allocated by pbuf_header() */
  308. if (q != p) {
  309. pbuf_free(q);
  310. }
  311. return ERR_VAL;
  312. }
  313. }
  314. #endif /* IP_SOF_BROADCAST */
  315. if (ip_addr_isany(&pcb->local_ip)) {
  316. /* use outgoing network interface IP address as source address */
  317. src_ip = ip_netif_get_local_ip(netif, dst_ip);
  318. #if LWIP_IPV6
  319. if (src_ip == NULL) {
  320. if (q != p) {
  321. pbuf_free(q);
  322. }
  323. return ERR_RTE;
  324. }
  325. #endif /* LWIP_IPV6 */
  326. } else {
  327. /* use RAW PCB local IP address as source address */
  328. src_ip = &pcb->local_ip;
  329. }
  330. #if LWIP_IPV6
  331. /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542,
  332. compute the checksum and update the checksum in the payload. */
  333. if (IP_IS_V6(dst_ip) && pcb->chksum_reqd) {
  334. u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ip_2_ip6(src_ip), ip_2_ip6(dst_ip));
  335. LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2));
  336. SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t));
  337. }
  338. #endif
  339. NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
  340. err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, pcb->protocol, netif);
  341. NETIF_SET_HWADDRHINT(netif, NULL);
  342. /* did we chain a header earlier? */
  343. if (q != p) {
  344. /* free the header */
  345. pbuf_free(q);
  346. }
  347. return err;
  348. }
  349. /**
  350. * Send the raw IP packet to the address given by raw_connect()
  351. *
  352. * @param pcb the raw pcb which to send
  353. * @param p the IP payload to send
  354. *
  355. */
  356. err_t
  357. raw_send(struct raw_pcb *pcb, struct pbuf *p)
  358. {
  359. return raw_sendto(pcb, p, &pcb->remote_ip);
  360. }
  361. /**
  362. * Remove an RAW PCB.
  363. *
  364. * @param pcb RAW PCB to be removed. The PCB is removed from the list of
  365. * RAW PCB's and the data structure is freed from memory.
  366. *
  367. * @see raw_new()
  368. */
  369. void
  370. raw_remove(struct raw_pcb *pcb)
  371. {
  372. struct raw_pcb *pcb2;
  373. /* pcb to be removed is first in list? */
  374. if (raw_pcbs == pcb) {
  375. /* make list start at 2nd pcb */
  376. raw_pcbs = raw_pcbs->next;
  377. /* pcb not 1st in list */
  378. } else {
  379. for (pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
  380. /* find pcb in raw_pcbs list */
  381. if (pcb2->next != NULL && pcb2->next == pcb) {
  382. /* remove pcb from list */
  383. pcb2->next = pcb->next;
  384. break;
  385. }
  386. }
  387. }
  388. memp_free(MEMP_RAW_PCB, pcb);
  389. }
  390. /**
  391. * Create a RAW PCB.
  392. *
  393. * @return The RAW PCB which was created. NULL if the PCB data structure
  394. * could not be allocated.
  395. *
  396. * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)
  397. *
  398. * @see raw_remove()
  399. */
  400. struct raw_pcb *
  401. raw_new(u8_t proto)
  402. {
  403. struct raw_pcb *pcb;
  404. LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
  405. pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB);
  406. /* could allocate RAW PCB? */
  407. if (pcb != NULL) {
  408. /* initialize PCB to all zeroes */
  409. memset(pcb, 0, sizeof(struct raw_pcb));
  410. pcb->protocol = proto;
  411. pcb->ttl = RAW_TTL;
  412. pcb->next = raw_pcbs;
  413. raw_pcbs = pcb;
  414. }
  415. return pcb;
  416. }
  417. /**
  418. * Create a RAW PCB for IPv6.
  419. *
  420. * @return The RAW PCB which was created. NULL if the PCB data structure
  421. * could not be allocated.
  422. *
  423. * @param type IP address type, see IPADDR_TYPE_XX definitions.
  424. * @param proto the protocol number (next header) of the IPv6 packet payload
  425. * (e.g. IP6_NEXTH_ICMP6)
  426. *
  427. * @see raw_remove()
  428. */
  429. struct raw_pcb *
  430. raw_new_ip_type(u8_t type, u8_t proto)
  431. {
  432. struct raw_pcb *pcb;
  433. pcb = raw_new(proto);
  434. #if LWIP_IPV4 && LWIP_IPV6
  435. if(pcb != NULL) {
  436. IP_SET_TYPE_VAL(pcb->local_ip, type);
  437. IP_SET_TYPE_VAL(pcb->remote_ip, type);
  438. }
  439. #else /* LWIP_IPV4 && LWIP_IPV6 */
  440. LWIP_UNUSED_ARG(type);
  441. #endif /* LWIP_IPV4 && LWIP_IPV6 */
  442. return pcb;
  443. }
  444. #endif /* LWIP_RAW */