UbixOS  2.0
raw.c
Go to the documentation of this file.
1 
16 /*
17  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
18  * All rights reserved.
19  *
20  * Redistribution and use in source and binary forms, with or without modification,
21  * are permitted provided that the following conditions are met:
22  *
23  * 1. Redistributions of source code must retain the above copyright notice,
24  * this list of conditions and the following disclaimer.
25  * 2. Redistributions in binary form must reproduce the above copyright notice,
26  * this list of conditions and the following disclaimer in the documentation
27  * and/or other materials provided with the distribution.
28  * 3. The name of the author may not be used to endorse or promote products
29  * derived from this software without specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
32  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
33  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
34  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
35  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
36  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
39  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
40  * OF SUCH DAMAGE.
41  *
42  * This file is part of the lwIP TCP/IP stack.
43  *
44  * Author: Adam Dunkels <adam@sics.se>
45  *
46  */
47 
48 #include "net/opt.h"
49 
50 #if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
51 
52 #include "net/def.h"
53 #include "net/memp.h"
54 #include "net/ip_addr.h"
55 #include "net/netif.h"
56 #include "net/raw.h"
57 #include "net/stats.h"
58 #include "net/ip6.h"
59 #include "net/ip6_addr.h"
60 #include "net/inet_chksum.h"
61 
62 #include <string.h>
63 
65 static struct raw_pcb *raw_pcbs;
66 
67 static u8_t
68 raw_input_match(struct raw_pcb *pcb, u8_t broadcast)
69 {
70  LWIP_UNUSED_ARG(broadcast); /* in IPv6 only case */
71 
72 #if LWIP_IPV4 && LWIP_IPV6
73  /* Dual-stack: PCBs listening to any IP type also listen to any IP address */
74  if (IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
75 #if IP_SOF_BROADCAST_RECV
76  if ((broadcast != 0) && !ip_get_option(pcb, SOF_BROADCAST)) {
77  return 0;
78  }
79 #endif /* IP_SOF_BROADCAST_RECV */
80  return 1;
81  }
82 #endif /* LWIP_IPV4 && LWIP_IPV6 */
83 
84  /* Only need to check PCB if incoming IP version matches PCB IP version */
86 #if LWIP_IPV4
87  /* Special case: IPv4 broadcast: receive all broadcasts
88  * Note: broadcast variable can only be 1 if it is an IPv4 broadcast */
89  if (broadcast != 0) {
90 #if IP_SOF_BROADCAST_RECV
91  if (ip_get_option(pcb, SOF_BROADCAST))
92 #endif /* IP_SOF_BROADCAST_RECV */
93  {
94  if (ip4_addr_isany(ip_2_ip4(&pcb->local_ip))) {
95  return 1;
96  }
97  }
98  } else
99 #endif /* LWIP_IPV4 */
100  /* Handle IPv4 and IPv6: catch all or exact match */
101  if (ip_addr_isany(&pcb->local_ip) ||
102  ip_addr_cmp(&pcb->local_ip, ip_current_dest_addr())) {
103  return 1;
104  }
105  }
106 
107  return 0;
108 }
109 
127 u8_t
128 raw_input(struct pbuf *p, struct netif *inp)
129 {
130  struct raw_pcb *pcb, *prev;
131  s16_t proto;
132  u8_t eaten = 0;
134 
135  LWIP_UNUSED_ARG(inp);
136 
137 #if LWIP_IPV6
138 #if LWIP_IPV4
139  if (IP_HDR_GET_VERSION(p->payload) == 6)
140 #endif /* LWIP_IPV4 */
141  {
142  struct ip6_hdr *ip6hdr = (struct ip6_hdr *)p->payload;
143  proto = IP6H_NEXTH(ip6hdr);
144  }
145 #if LWIP_IPV4
146  else
147 #endif /* LWIP_IPV4 */
148 #endif /* LWIP_IPV6 */
149 #if LWIP_IPV4
150  {
151  proto = IPH_PROTO((struct ip_hdr *)p->payload);
152  }
153 #endif /* LWIP_IPV4 */
154 
155  prev = NULL;
156  pcb = raw_pcbs;
157  /* loop through all raw pcbs until the packet is eaten by one */
158  /* this allows multiple pcbs to match against the packet by design */
159  while ((eaten == 0) && (pcb != NULL)) {
160  if ((pcb->protocol == proto) && raw_input_match(pcb, broadcast)) {
161  /* receive callback function available? */
162  if (pcb->recv != NULL) {
163 #ifndef LWIP_NOASSERT
164  void* old_payload = p->payload;
165 #endif
166  /* the receive callback function did not eat the packet? */
167  eaten = pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr());
168  if (eaten != 0) {
169  /* receive function ate the packet */
170  p = NULL;
171  eaten = 1;
172  if (prev != NULL) {
173  /* move the pcb to the front of raw_pcbs so that is
174  found faster next time */
175  prev->next = pcb->next;
176  pcb->next = raw_pcbs;
177  raw_pcbs = pcb;
178  }
179  } else {
180  /* sanity-check that the receive callback did not alter the pbuf */
181  LWIP_ASSERT("raw pcb recv callback altered pbuf payload pointer without eating packet",
182  p->payload == old_payload);
183  }
184  }
185  /* no receive callback function was set for this raw PCB */
186  }
187  /* drop the packet */
188  prev = pcb;
189  pcb = pcb->next;
190  }
191  return eaten;
192 }
193 
209 err_t
210 raw_bind(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
211 {
212  if ((pcb == NULL) || (ipaddr == NULL)) {
213  return ERR_VAL;
214  }
215  ip_addr_set_ipaddr(&pcb->local_ip, ipaddr);
216  return ERR_OK;
217 }
218 
233 err_t
234 raw_connect(struct raw_pcb *pcb, const ip_addr_t *ipaddr)
235 {
236  if ((pcb == NULL) || (ipaddr == NULL)) {
237  return ERR_VAL;
238  }
239  ip_addr_set_ipaddr(&pcb->remote_ip, ipaddr);
240  return ERR_OK;
241 }
242 
254 void
255 raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
256 {
257  /* remember recv() callback and user data */
258  pcb->recv = recv;
259  pcb->recv_arg = recv_arg;
260 }
261 
275 err_t
276 raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr)
277 {
278  err_t err;
279  struct netif *netif;
280  const ip_addr_t *src_ip;
281  struct pbuf *q; /* q will be sent down the stack */
282  s16_t header_size;
283 
284  if ((pcb == NULL) || (ipaddr == NULL) || !IP_ADDR_PCB_VERSION_MATCH(pcb, ipaddr)) {
285  return ERR_VAL;
286  }
287 
288  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
289 
290  header_size = (
291 #if LWIP_IPV4 && LWIP_IPV6
292  IP_IS_V6(ipaddr) ? IP6_HLEN : IP_HLEN);
293 #elif LWIP_IPV4
294  IP_HLEN);
295 #else
296  IP6_HLEN);
297 #endif
298 
299  /* not enough space to add an IP header to first pbuf in given p chain? */
300  if (pbuf_header(p, header_size)) {
301  /* allocate header in new pbuf */
302  q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
303  /* new header pbuf could not be allocated? */
304  if (q == NULL) {
305  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
306  return ERR_MEM;
307  }
308  if (p->tot_len != 0) {
309  /* chain header q in front of given pbuf p */
310  pbuf_chain(q, p);
311  }
312  /* { first pbuf q points to header pbuf } */
313  LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
314  } else {
315  /* first pbuf q equals given pbuf */
316  q = p;
317  if (pbuf_header(q, -header_size)) {
318  LWIP_ASSERT("Can't restore header we just removed!", 0);
319  return ERR_MEM;
320  }
321  }
322 
323  if(IP_IS_ANY_TYPE_VAL(pcb->local_ip)) {
324  /* Don't call ip_route() with IP_ANY_TYPE */
325  netif = ip_route(IP46_ADDR_ANY(IP_GET_TYPE(ipaddr)), ipaddr);
326  } else {
327  netif = ip_route(&pcb->local_ip, ipaddr);
328  }
329 
330  if (netif == NULL) {
331  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to "));
333  /* free any temporary header pbuf allocated by pbuf_header() */
334  if (q != p) {
335  pbuf_free(q);
336  }
337  return ERR_RTE;
338  }
339 
340 #if IP_SOF_BROADCAST
341  if (IP_IS_V4(ipaddr))
342  {
343  /* broadcast filter? */
344  if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) {
345  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
346  /* free any temporary header pbuf allocated by pbuf_header() */
347  if (q != p) {
348  pbuf_free(q);
349  }
350  return ERR_VAL;
351  }
352  }
353 #endif /* IP_SOF_BROADCAST */
354 
355  if (ip_addr_isany(&pcb->local_ip)) {
356  /* use outgoing network interface IP address as source address */
357  src_ip = ip_netif_get_local_ip(netif, ipaddr);
358 #if LWIP_IPV6
359  if (src_ip == NULL) {
360  if (q != p) {
361  pbuf_free(q);
362  }
363  return ERR_RTE;
364  }
365 #endif /* LWIP_IPV6 */
366  } else {
367  /* use RAW PCB local IP address as source address */
368  src_ip = &pcb->local_ip;
369  }
370 
371 #if LWIP_IPV6
372  /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542,
373  compute the checksum and update the checksum in the payload. */
374  if (IP_IS_V6(ipaddr) && pcb->chksum_reqd) {
375  u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ip_2_ip6(src_ip), ip_2_ip6(ipaddr));
376  LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2));
377  SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t));
378  }
379 #endif
380 
381  NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
382  err = ip_output_if(q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
384 
385  /* did we chain a header earlier? */
386  if (q != p) {
387  /* free the header */
388  pbuf_free(q);
389  }
390  return err;
391 }
392 
401 err_t
402 raw_send(struct raw_pcb *pcb, struct pbuf *p)
403 {
404  return raw_sendto(pcb, p, &pcb->remote_ip);
405 }
406 
416 void
417 raw_remove(struct raw_pcb *pcb)
418 {
419  struct raw_pcb *pcb2;
420  /* pcb to be removed is first in list? */
421  if (raw_pcbs == pcb) {
422  /* make list start at 2nd pcb */
423  raw_pcbs = raw_pcbs->next;
424  /* pcb not 1st in list */
425  } else {
426  for (pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
427  /* find pcb in raw_pcbs list */
428  if (pcb2->next != NULL && pcb2->next == pcb) {
429  /* remove pcb from list */
430  pcb2->next = pcb->next;
431  break;
432  }
433  }
434  }
435  memp_free(MEMP_RAW_PCB, pcb);
436 }
437 
449 struct raw_pcb *
450 raw_new(u8_t proto)
451 {
452  struct raw_pcb *pcb;
453 
454  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
455 
456  pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB);
457  /* could allocate RAW PCB? */
458  if (pcb != NULL) {
459  /* initialize PCB to all zeroes */
460  memset(pcb, 0, sizeof(struct raw_pcb));
461  pcb->protocol = proto;
462  pcb->ttl = RAW_TTL;
463  pcb->next = raw_pcbs;
464  raw_pcbs = pcb;
465  }
466  return pcb;
467 }
468 
484 struct raw_pcb *
485 raw_new_ip_type(u8_t type, u8_t proto)
486 {
487  struct raw_pcb *pcb;
488  pcb = raw_new(proto);
489 #if LWIP_IPV4 && LWIP_IPV6
490  if (pcb != NULL) {
491  IP_SET_TYPE_VAL(pcb->local_ip, type);
492  IP_SET_TYPE_VAL(pcb->remote_ip, type);
493  }
494 #else /* LWIP_IPV4 && LWIP_IPV6 */
495  LWIP_UNUSED_ARG(type);
496 #endif /* LWIP_IPV4 && LWIP_IPV6 */
497  return pcb;
498 }
499 
505 void raw_netif_ip_addr_changed(const ip_addr_t* old_addr, const ip_addr_t* new_addr)
506 {
507  struct raw_pcb* rpcb;
508 
509  if (!ip_addr_isany(old_addr) && !ip_addr_isany(new_addr)) {
510  for (rpcb = raw_pcbs; rpcb != NULL; rpcb = rpcb->next) {
511  /* PCB bound to current local interface address? */
512  if (ip_addr_cmp(&rpcb->local_ip, old_addr)) {
513  /* The PCB is bound to the old ipaddr and
514  * is set to bound to the new one instead */
515  ip_addr_copy(rpcb->local_ip, *new_addr);
516  }
517  }
518  }
519 }
520 
521 #endif /* LWIP_RAW */
ip_addr_set_ipaddr
#define ip_addr_set_ipaddr(dest, src)
Definition: ip_addr.h:308
SOF_BROADCAST
#define SOF_BROADCAST
Definition: ip.h:99
opt.h
ip_addr_cmp
#define ip_addr_cmp(addr1, addr2)
Definition: ip_addr.h:316
IP_IS_V6
#define IP_IS_V6(ipaddr)
Definition: ip_addr.h:296
pbuf::len
u16_t len
Definition: pbuf.h:159
s16_t
int16_t s16_t
Definition: arch.h:125
def.h
IP_IS_V4
#define IP_IS_V4(ipaddr)
Definition: ip_addr.h:295
LWIP_ASSERT
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:116
ip_current_dest_addr
#define ip_current_dest_addr()
Definition: ip.h:212
u16_t
uint16_t u16_t
Definition: arch.h:124
string.h
PBUF_IP
Definition: pbuf.h:80
IP46_ADDR_ANY
#define IP46_ADDR_ANY(type)
Definition: ip_addr.h:331
IP_IS_ANY_TYPE_VAL
#define IP_IS_ANY_TYPE_VAL(ipaddr)
Definition: ip_addr.h:297
ip_addr_isany
#define ip_addr_isany(ipaddr)
Definition: ip_addr.h:317
pbuf::tot_len
u16_t tot_len
Definition: pbuf.h:156
pbuf_free
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:715
ip_addr_isbroadcast
#define ip_addr_isbroadcast(addr, netif)
Definition: ip_addr.h:321
memp_malloc
void * memp_malloc(memp_t type)
Definition: memp.c:385
LWIP_DBG_TRACE
#define LWIP_DBG_TRACE
Definition: debug.h:83
raw.h
IP_ADDR_PCB_VERSION_MATCH_EXACT
#define IP_ADDR_PCB_VERSION_MATCH_EXACT(pcb, ipaddr)
Definition: ip_addr.h:240
NETIF_SET_HWADDRHINT
#define NETIF_SET_HWADDRHINT(netif, hint)
Definition: netif.h:475
memp_free
void memp_free(memp_t type, void *mem)
Definition: memp.c:469
IP_HLEN
#define IP_HLEN
Definition: ip4.h:64
RAW_DEBUG
#define RAW_DEBUG
Definition: lwipopts.h:453
ip_hdr
Definition: ip4.h:71
ip_addr_debug_print
#define ip_addr_debug_print(debug, ipaddr)
Definition: ip_addr.h:323
stats.h
ERR_MEM
Definition: err.h:65
LWIP_DBG_LEVEL_SERIOUS
#define LWIP_DBG_LEVEL_SERIOUS
Definition: debug.h:57
netif.h
ip_current_netif
#define ip_current_netif()
Definition: ip.h:133
pbuf_alloc
struct pbuf * pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type)
Definition: pbuf.c:248
u8_t
uint8_t u8_t
Definition: arch.h:122
ip_addr_t
ip6_addr_t ip_addr_t
Definition: ip_addr.h:290
IP_ADDR_PCB_VERSION_MATCH
#define IP_ADDR_PCB_VERSION_MATCH(addr, pcb)
Definition: ip_addr.h:239
ip_current_src_addr
#define ip_current_src_addr()
Definition: ip.h:210
netif
Definition: netif.h:233
ip_2_ip6
#define ip_2_ip6(ipaddr)
Definition: ip_addr.h:301
LWIP_UNUSED_ARG
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:315
pbuf_chain
void pbuf_chain(struct pbuf *head, struct pbuf *tail)
Definition: pbuf.c:883
IPH_PROTO
#define IPH_PROTO(hdr)
Definition: ip4.h:109
PBUF_RAM
Definition: pbuf.h:108
ERR_OK
Definition: err.h:63
err_t
s8_t err_t
Definition: err.h:57
ip_addr_copy
#define ip_addr_copy(dest, src)
Definition: ip_addr.h:305
IP6_HLEN
#define IP6_HLEN
Definition: ip6.h:62
ip6_addr.h
LWIP_DBG_LEVEL_WARNING
#define LWIP_DBG_LEVEL_WARNING
Definition: debug.h:55
IP_SET_TYPE_VAL
#define IP_SET_TYPE_VAL(ipaddr, iptype)
Definition: ip_addr.h:298
memset
void * memset(void *dst, int c, size_t length)
ip_get_option
#define ip_get_option(pcb, opt)
Definition: ip.h:215
memp.h
ERR_RTE
Definition: err.h:71
SMEMCPY
#define SMEMCPY(dst, src, len)
Definition: lwipopts.h:44
ERR_VAL
Definition: err.h:75
ip6_hdr
Definition: ip6.h:80
pbuf
Definition: pbuf.h:142
LWIP_DEBUGF
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:164
ip6.h
ip_addr.h
IP_HDR_GET_VERSION
#define IP_HDR_GET_VERSION(ptr)
Definition: ip.h:49
RAW_TTL
#define RAW_TTL
Definition: lwipopts.h:143
inet_chksum.h
IP6H_NEXTH
#define IP6H_NEXTH(hdr)
Definition: ip6.h:156
pbuf_header
u8_t pbuf_header(struct pbuf *p, s16_t header_size)
Definition: pbuf.c:665
pbuf::payload
void * payload
Definition: pbuf.h:147
IP_GET_TYPE
#define IP_GET_TYPE(ipaddr)
Definition: ip_addr.h:300
NULL
#define NULL
Definition: fat_string.h:17