The Pedigree Project  0.1
raw.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
35 /*
36  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
37  * All rights reserved.
38  *
39  * Redistribution and use in source and binary forms, with or without modification,
40  * are permitted provided that the following conditions are met:
41  *
42  * 1. Redistributions of source code must retain the above copyright notice,
43  * this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright notice,
45  * this list of conditions and the following disclaimer in the documentation
46  * and/or other materials provided with the distribution.
47  * 3. The name of the author may not be used to endorse or promote products
48  * derived from this software without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
51  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
52  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
53  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
54  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
55  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
56  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
57  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
58  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
59  * OF SUCH DAMAGE.
60  *
61  * This file is part of the lwIP TCP/IP stack.
62  *
63  * Author: Adam Dunkels <adam@sics.se>
64  *
65  */
66 
67 #include "lwip/opt.h"
68 
69 #if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
70 
71 #include "lwip/def.h"
72 #include "lwip/memp.h"
73 #include "lwip/ip_addr.h"
74 #include "lwip/netif.h"
75 #include "lwip/raw.h"
76 #include "lwip/stats.h"
77 #include "lwip/ip6.h"
78 #include "lwip/ip6_addr.h"
79 #include "lwip/inet_chksum.h"
80 
81 #include <string.h>
82 
84 static struct raw_pcb *raw_pcbs;
85 
86 static u8_t
87 raw_input_match(struct raw_pcb *pcb, u8_t broadcast)
88 {
89  LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */
90 
91 #if LWIP_IPV4 && LWIP_IPV6
92  /* Dual-stack: PCBs listening to any IP type also listen to any IP address */
93  if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
94 #if IP_SOF_BROADCAST_RECV
95  if ((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) {
96  return 0;
97  }
98 #endif /* IP_SOF_BROADCAST_RECV */
99  return 1;
100  }
101 #endif /* LWIP_IPV4 && LWIP_IPV6 */
102 
103  /* Only need to check PCB if incoming IP version matches PCB IP version */
104  if (IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ip_current_dest_addr())) {
105 #if LWIP_IPV4
106  /* Special case: IPv4 broadcast: receive all broadcasts
107  * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */
108  if (broadcast != 0) {
109 #if IP_SOF_BROADCAST_RECV
110  if (ip_get_option(pcb, SOF_BROADCAST))
111 #endif /* IP_SOF_BROADCAST_RECV */
112  {
113  if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip))) {
114  return 1;
115  }
116  }
117  } else
118 #endif /* LWIP_IPV4 */
119  /* Handle IPv4 and IPv6: catch all or exact match */
120  if (ip_addr_isany(&pcb->local_ip) ||
121  ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) {
122  return 1;
123  }
124  }
125 
126  return 0;
127 }
128 
146 u8_t
147 raw_input(struct pbuf *p, struct netif *inp)
148 {
149  struct raw_pcb *pcb, *prev;
150  s16_t proto;
151  u8_t eaten = 0;
152  u8_t broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), ip_current_netif());
153 
154  LWIP_UNUSED_ARG(inp);
155 
156 #if LWIP_IPV6
157 #if LWIP_IPV4
158  if (IP_HDR_GET_VERSION(p->payload) == 6)
159 #endif /* LWIP_IPV4 */
160  {
161  struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload;
162  proto = IP6H_NEXTH(ip6hdr);
163  }
164 #if LWIP_IPV4
165  else
166 #endif /* LWIP_IPV4 */
167 #endif /* LWIP_IPV6 */
168 #if LWIP_IPV4
169  {
170  proto = IPH_PROTO((struct ip_hdr *)p->payload);
171  }
172 #endif /* LWIP_IPV4 */
173 
174  prev = NULL;
175  pcb = raw_pcbs;
176  /* loop through all raw pcbs until the packet is eaten by one */
177  /* this allows multiple pcbs to match against the packet by design */
178  while ((eaten == 0) && (pcb != NULL)) {
179  if ((pcb->protocol == proto) && raw_input_match(pcb, broadcast)) {
180  /* receive callback function available? */
181  if (pcb->recv != NULL) {
182 #ifndef LWIP_NOASSERT
183  void* old_payload = p->payload;
184 #endif
185  /* the receive callback function did not eat the packet? */
186  eaten = pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr());
187  if (eaten != 0) {
188  /* receive function ate the packet */
189  p = NULL;
190  eaten = 1;
191  if (prev != NULL) {
192  /* move the pcb to the front of raw_pcbs so that is
193  found faster next time */
194  prev->next = pcb->next;
195  pcb->next = raw_pcbs;
196  raw_pcbs = pcb;
197  }
198  } else {
199  /* sanity-check that the receive callback did not alter the pbuf */
200  LWIP_ASSERT("raw pcb recv callback altered pbuf payload pointer without eating packet",
201  p->payload == old_payload);
202  }
203  }
204  /* no receive callback function was set for this raw PCB */
205  }
206  /* drop the packet */
207  prev = pcb;
208  pcb = pcb->next;
209  }
210  return eaten;
211 }
212 
228 err_t
229 raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
230 {
231  if ((pcb == NULL) || (ipaddr == NULL)) {
232  return ERR_VAL;
233  }
234  ip_addr_set_ipaddr(&pcb->local_ip, ipaddr);
235  return ERR_OK;
236 }
237 
252 err_t
253 raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
254 {
255  if ((pcb == NULL) || (ipaddr == NULL)) {
256  return ERR_VAL;
257  }
258  ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr);
259  return ERR_OK;
260 }
261 
273 void
274 raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
275 {
276  /* remember recv() callback and user data */
277  pcb->recv = recv;
278  pcb->recv_arg = recv_arg;
279 }
280 
294 err_t
295 raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr)
296 {
297  err_t err;
298  struct netif *netif;
299  const ip_addr_t *src_ip;
300  struct pbuf *q; /* q will be sent down the stack */
301  s16_t header_size;
302 
303  if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
304  return ERR_VAL;
305  }
306 
307  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
308 
309  header_size = (
310 #if LWIP_IPV4 && LWIP_IPV6
311  IP_IS_V6(ipaddr) ? IP6_HLEN : IP_HLEN);
312 #elif LWIP_IPV4
313  IP_HLEN);
314 #else
315  IP6_HLEN);
316 #endif
317 
318  /* not enough space to add an IP header to first pbuf in given p chain? */
319  if (pbuf_header(p, header_size)) {
320  /* allocate header in new pbuf */
321  q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
322  /* new header pbuf could not be allocated? */
323  if (q == NULL) {
324  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
325  return ERR_MEM;
326  }
327  if (p->tot_len != 0) {
328  /* chain header q in front of given pbuf p */
329  pbuf_chain(q, p);
330  }
331  /* { first pbuf q points to header pbuf } */
332  LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
333  } else {
334  /* first pbuf q equals given pbuf */
335  q = p;
336  if (pbuf_header(q, -header_size)) {
337  LWIP_ASSERT("Can't restore header we just removed!", 0);
338  return ERR_MEM;
339  }
340  }
341 
342  if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
343  /* Don't call ip_route() with IP_ANY_TYPE */
344  netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(ipaddr)), ipaddr);
345  } else {
346  netif = ip_route(&pcb->local_ip, ipaddr);
347  }
348 
349  if (netif == NULL) {
350  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to "));
351  ip_addr_debug_print(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ipaddr);
352  /* free any temporary header pbuf allocated by pbuf_header() */
353  if (q != p) {
354  pbuf_free(q);
355  }
356  return ERR_RTE;
357  }
358 
359 #if IP_SOF_BROADCAST
360  if (IP_IS_V4(ipaddr))
361  {
362  /* broadcast filter? */
363  if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) {
364  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
365  /* free any temporary header pbuf allocated by pbuf_header() */
366  if (q != p) {
367  pbuf_free(q);
368  }
369  return ERR_VAL;
370  }
371  }
372 #endif /* IP_SOF_BROADCAST */
373 
374  if (ip_addr_isany(&pcb->local_ip)) {
375  /* use outgoing network interface IP address as source address */
376  src_ip = ip_netif_get_local_ip(netif, ipaddr);
377 #if LWIP_IPV6
378  if (src_ip == NULL) {
379  if (q != p) {
380  pbuf_free(q);
381  }
382  return ERR_RTE;
383  }
384 #endif /* LWIP_IPV6 */
385  } else {
386  /* use RAW PCB local IP address as source address */
387  src_ip = &pcb->local_ip;
388  }
389 
390 #if LWIP_IPV6
391  /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542,
392  compute the checksum and update the checksum in the payload. */
393  if (IP_IS_V6(ipaddr) && pcb->chksum_reqd) {
394  u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ip_2_ip6(src_ip), ip_2_ip6(ipaddr));
395  LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2));
396  SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t));
397  }
398 #endif
399 
400  NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
401  err = ip_output_if(q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
402  NETIF_SET_HWADDRHINT(netif, NULL);
403 
404  /* did we chain a header earlier? */
405  if (q != p) {
406  /* free the header */
407  pbuf_free(q);
408  }
409  return err;
410 }
411 
420 err_t
421 raw_send(struct raw_pcb *pcb, struct pbuf *p)
422 {
423  return raw_sendto(pcb, p, &pcb->remote_ip);
424 }
425 
435 void
436 raw_remove(struct raw_pcb *pcb)
437 {
438  struct raw_pcb *pcb2;
439  /* pcb to be removed is first in list? */
440  if (raw_pcbs == pcb) {
441  /* make list start at 2nd pcb */
442  raw_pcbs = raw_pcbs->next;
443  /* pcb not 1st in list */
444  } else {
445  for (pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
446  /* find pcb in raw_pcbs list */
447  if (pcb2->next != NULL && pcb2->next == pcb) {
448  /* remove pcb from list */
449  pcb2->next = pcb->next;
450  break;
451  }
452  }
453  }
454  memp_free(MEMP_RAW_PCB, pcb);
455 }
456 
468 struct raw_pcb *
469 raw_new(u8_t proto)
470 {
471  struct raw_pcb *pcb;
472 
473  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
474 
475  pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB);
476  /* could allocate RAW PCB? */
477  if (pcb != NULL) {
478  /* initialize PCB to all zeroes */
479  memset(pcb, 0, sizeof(struct raw_pcb));
480  pcb->protocol = proto;
481  pcb->ttl = RAW_TTL;
482  pcb->next = raw_pcbs;
483  raw_pcbs = pcb;
484  }
485  return pcb;
486 }
487 
503 struct raw_pcb *
504 raw_new_ip_type(u8_t type, u8_t proto)
505 {
506  struct raw_pcb *pcb;
507  pcb = raw_new(proto);
508 #if LWIP_IPV4 && LWIP_IPV6
509  if (pcb != NULL) {
510  IP_SET_TYPE_VAL(pcb->local_ip, type);
511  IP_SET_TYPE_VAL(pcb->remote_ip, type);
512  }
513 #else /* LWIP_IPV4 && LWIP_IPV6 */
514  LWIP_UNUSED_ARG(type);
515 #endif /* LWIP_IPV4 && LWIP_IPV6 */
516  return pcb;
517 }
518 
524 void raw_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr)
525 {
526  struct raw_pcb* rpcb;
527 
528  if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) {
529  for (rpcb = raw_pcbs; rpcb != NULL; rpcb = rpcb->next) {
530  /* PCB bound to current local interface address? */
531  if (ip_addr_cmp(&rpcb->local_ip, old_addr)) {
532  /* The PCB is bound to the old ipaddr and
533  * is set to bound to the new one instead */
534  ip_addr_copy(rpcb->local_ip, *new_addr);
535  }
536  }
537  }
538 }
539 
540 #endif /* LWIP_RAW */
u16_t tot_len
Definition: pbuf.h:175
u16_t len
Definition: pbuf.h:178
#define RAW_DEBUG
Definition: opt.h:2727
#define ip_current_src_addr()
Definition: ip.h:229
u8_t pbuf_header(struct pbuf *p, s16_t header_size_increment)
Definition: pbuf.c:684
#define ip_current_netif()
Definition: ip.h:152
void memp_free(memp_t type, void *mem)
Definition: memp.c:488
#define ip_current_dest_addr()
Definition: ip.h:231
Definition: err.h:84
void pbuf_chain(struct pbuf *h, struct pbuf *t)
Definition: pbuf.c:901
Definition: pbuf.h:161
Definition: netif.h:244
s8_t err_t
Definition: err.h:76
#define LWIP_DEBUGF(debug, message)
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:267
Definition: pbuf.h:127
Definition: err.h:94
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:327
#define RAW_TTL
Definition: opt.h:837
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:734
Definition: err.h:82
void * payload
Definition: pbuf.h:166
Definition: pbuf.h:99
Definition: err.h:90
void * memp_malloc(memp_t type)
Definition: memp.c:404
#define ip_get_option(pcb, opt)
Definition: ip.h:234
#define IP_HDR_GET_VERSION(ptr)
Definition: prot/ip.h:68