MeterLogger
raw.c
Go to the documentation of this file.
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 /*
10  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
11  * All rights reserved.
12  *
13  * Redistribution and use in source and binary forms, with or without modification,
14  * are permitted provided that the following conditions are met:
15  *
16  * 1. Redistributions of source code must retain the above copyright notice,
17  * this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright notice,
19  * this list of conditions and the following disclaimer in the documentation
20  * and/or other materials provided with the distribution.
21  * 3. The name of the author may not be used to endorse or promote products
22  * derived from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
25  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
27  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
29  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33  * OF SUCH DAMAGE.
34  *
35  * This file is part of the lwIP TCP/IP stack.
36  *
37  * Author: Adam Dunkels <adam@sics.se>
38  *
39  */
40 
41 #include "lwip/opt.h"
42 
43 #if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
44 
45 #include "lwip/def.h"
46 #include "lwip/memp.h"
47 #include "lwip/ip_addr.h"
48 #include "lwip/netif.h"
49 #include "lwip/raw.h"
50 #include "lwip/stats.h"
51 #include "arch/perf.h"
52 
53 #include <string.h>
54 
55 #ifdef MEMLEAK_DEBUG
56 static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
57 #endif
58 
59 /** The list of RAW PCBs */
60 static struct raw_pcb *raw_pcbs;
61 
62 /**
63  * Determine if in incoming IP packet is covered by a RAW PCB
64  * and if so, pass it to a user-provided receive callback function.
65  *
66  * Given an incoming IP datagram (as a chain of pbufs) this function
67  * finds a corresponding RAW PCB and calls the corresponding receive
68  * callback function.
69  *
70  * @param p pbuf to be demultiplexed to a RAW PCB.
71  * @param inp network interface on which the datagram was received.
72  * @return - 1 if the packet has been eaten by a RAW PCB receive
73  * callback function. The caller MAY NOT not reference the
74  * packet any longer, and MAY NOT call pbuf_free().
75  * @return - 0 if packet is not eaten (pbuf is still referenced by the
76  * caller).
77  *
78  */
80 raw_input(struct pbuf *p, struct netif *inp)
81 {
82  struct raw_pcb *pcb, *prev;
83  struct ip_hdr *iphdr;
84  s16_t proto;
85  u8_t eaten = 0;
86 
87  LWIP_UNUSED_ARG(inp);
88 
89  iphdr = (struct ip_hdr *)p->payload;
90  proto = IPH_PROTO(iphdr);
91 
92  prev = NULL;
93  pcb = raw_pcbs;
94  /* loop through all raw pcbs until the packet is eaten by one */
95  /* this allows multiple pcbs to match against the packet by design */
96  while ((eaten == 0) && (pcb != NULL)) {
97  if ((pcb->protocol == proto) &&
98  (ip_addr_isany(&pcb->local_ip) ||
99  ip_addr_cmp(&(pcb->local_ip), &current_iphdr_dest))) {
100 #if IP_SOF_BROADCAST_RECV
101  /* broadcast filter? */
102  if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&current_iphdr_dest, inp))
103 #endif /* IP_SOF_BROADCAST_RECV */
104  {
105  /* receive callback function available? */
106  if (pcb->recv != NULL) {
107  /* the receive callback function did not eat the packet? */
108  if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) {
109  /* receive function ate the packet */
110  p = NULL;
111  eaten = 1;
112  if (prev != NULL) {
113  /* move the pcb to the front of raw_pcbs so that is
114  found faster next time */
115  prev->next = pcb->next;
116  pcb->next = raw_pcbs;
117  raw_pcbs = pcb;
118  }
119  }
120  }
121  /* no receive callback function was set for this raw PCB */
122  }
123  /* drop the packet */
124  }
125  prev = pcb;
126  pcb = pcb->next;
127  }
128  return eaten;
129 }
130 
131 /**
132  * Bind a RAW PCB.
133  *
134  * @param pcb RAW PCB to be bound with a local address ipaddr.
135  * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
136  * bind to all local interfaces.
137  *
138  * @return lwIP error code.
139  * - ERR_OK. Successful. No error occured.
140  * - ERR_USE. The specified IP address is already bound to by
141  * another RAW PCB.
142  *
143  * @see raw_disconnect()
144  */
146 raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr)
147 {
148  ip_addr_set(&pcb->local_ip, ipaddr);
149  return ERR_OK;
150 }
151 
152 /**
153  * Connect an RAW PCB. This function is required by upper layers
154  * of lwip. Using the raw api you could use raw_sendto() instead
155  *
156  * This will associate the RAW PCB with the remote address.
157  *
158  * @param pcb RAW PCB to be connected with remote address ipaddr and port.
159  * @param ipaddr remote IP address to connect with.
160  *
161  * @return lwIP error code
162  *
163  * @see raw_disconnect() and raw_sendto()
164  */
166 raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr)
167 {
168  ip_addr_set(&pcb->remote_ip, ipaddr);
169  return ERR_OK;
170 }
171 
172 
173 /**
174  * Set the callback function for received packets that match the
175  * raw PCB's protocol and binding.
176  *
177  * The callback function MUST either
178  * - eat the packet by calling pbuf_free() and returning non-zero. The
179  * packet will not be passed to other raw PCBs or other protocol layers.
180  * - not free the packet, and return zero. The packet will be matched
181  * against further PCBs and/or forwarded to another protocol layers.
182  *
183  * @return non-zero if the packet was free()d, zero if the packet remains
184  * available for others.
185  */
187 raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg)
188 {
189  /* remember recv() callback and user data */
190  pcb->recv = recv;
191  pcb->recv_arg = recv_arg;
192 }
193 
194 /**
195  * Send the raw IP packet to the given address. Note that actually you cannot
196  * modify the IP headers (this is inconsistent with the receive callback where
197  * you actually get the IP headers), you can only specify the IP payload here.
198  * It requires some more changes in lwIP. (there will be a raw_send() function
199  * then.)
200  *
201  * @param pcb the raw pcb which to send
202  * @param p the IP payload to send
203  * @param ipaddr the destination address of the IP packet
204  *
205  */
207 raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr)
208 {
209  err_t err;
210  struct netif *netif;
211  ip_addr_t *src_ip;
212  struct pbuf *q; /* q will be sent down the stack */
213 
214  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
215 
216  /* not enough space to add an IP header to first pbuf in given p chain? */
217  if (pbuf_header(p, IP_HLEN)) {
218  /* allocate header in new pbuf */
219  q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
220  /* new header pbuf could not be allocated? */
221  if (q == NULL) {
222  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
223  return ERR_MEM;
224  }
225  if (p->tot_len != 0) {
226  /* chain header q in front of given pbuf p */
227  pbuf_chain(q, p);
228  }
229  /* { first pbuf q points to header pbuf } */
230  LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
231  } else {
232  /* first pbuf q equals given pbuf */
233  q = p;
234  if(pbuf_header(q, -IP_HLEN)) {
235  LWIP_ASSERT("Can't restore header we just removed!", 0);
236  return ERR_MEM;
237  }
238  }
239 
240  if ((netif = ip_route(ipaddr)) == NULL) {
241  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
242  ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr)));
243  /* free any temporary header pbuf allocated by pbuf_header() */
244  if (q != p) {
245  pbuf_free(q);
246  }
247  return ERR_RTE;
248  }
249 
250 #if IP_SOF_BROADCAST
251  /* broadcast filter? */
252  if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) {
253  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
254  /* free any temporary header pbuf allocated by pbuf_header() */
255  if (q != p) {
256  pbuf_free(q);
257  }
258  return ERR_VAL;
259  }
260 #endif /* IP_SOF_BROADCAST */
261 
262  if (ip_addr_isany(&pcb->local_ip)) {
263  /* use outgoing network interface IP address as source address */
264  src_ip = &(netif->ip_addr);
265  } else {
266  /* use RAW PCB local IP address as source address */
267  src_ip = &(pcb->local_ip);
268  }
269 
270 #if LWIP_NETIF_HWADDRHINT
271  netif->addr_hint = &(pcb->addr_hint);
272 #endif /* LWIP_NETIF_HWADDRHINT*/
273  err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
274 #if LWIP_NETIF_HWADDRHINT
275  netif->addr_hint = NULL;
276 #endif /* LWIP_NETIF_HWADDRHINT*/
277 
278  /* did we chain a header earlier? */
279  if (q != p) {
280  /* free the header */
281  pbuf_free(q);
282  }
283  return err;
284 }
285 
286 /**
287  * Send the raw IP packet to the address given by raw_connect()
288  *
289  * @param pcb the raw pcb which to send
290  * @param p the IP payload to send
291  *
292  */
294 raw_send(struct raw_pcb *pcb, struct pbuf *p)
295 {
296  return raw_sendto(pcb, p, &pcb->remote_ip);
297 }
298 
299 /**
300  * Remove an RAW PCB.
301  *
302  * @param pcb RAW PCB to be removed. The PCB is removed from the list of
303  * RAW PCB's and the data structure is freed from memory.
304  *
305  * @see raw_new()
306  */
308 raw_remove(struct raw_pcb *pcb)
309 {
310  struct raw_pcb *pcb2;
311  /* pcb to be removed is first in list? */
312  if (raw_pcbs == pcb) {
313  /* make list start at 2nd pcb */
314  raw_pcbs = raw_pcbs->next;
315  /* pcb not 1st in list */
316  } else {
317  for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
318  /* find pcb in raw_pcbs list */
319  if (pcb2->next != NULL && pcb2->next == pcb) {
320  /* remove pcb from list */
321  pcb2->next = pcb->next;
322  }
323  }
324  }
325  memp_free(MEMP_RAW_PCB, pcb);
326 }
327 
328 /**
329  * Create a RAW PCB.
330  *
331  * @return The RAW PCB which was created. NULL if the PCB data structure
332  * could not be allocated.
333  *
334  * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)
335  *
336  * @see raw_remove()
337  */
338 struct raw_pcb * ICACHE_FLASH_ATTR
339 raw_new(u8_t proto)
340 {
341  struct raw_pcb *pcb;
342 
343  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n"));
344 
345  pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB);
346  /* could allocate RAW PCB? */
347  if (pcb != NULL) {
348  /* initialize PCB to all zeroes */
349  os_memset(pcb, 0, sizeof(struct raw_pcb));
350  pcb->protocol = proto;
351  pcb->ttl = RAW_TTL;
352  pcb->next = raw_pcbs;
353  raw_pcbs = pcb;
354  }
355  return pcb;
356 }
357 
358 #endif /* LWIP_RAW */
u16_t tot_len
Definition: pbuf.h:90
#define ip4_addr3_16(ipaddr)
Definition: ip_addr.h:228
void memp_free(memp_t type, void *mem) ICACHE_FLASH_ATTR
Definition: memp.c:438
#define ip_current_src_addr()
Definition: ip.h:199
#define ip_addr_set(dest, src)
Definition: ip_addr.h:164
#define U16_F
Definition: cc.h:61
signed short s16_t
Definition: cc.h:55
ip_addr_t current_iphdr_dest
Definition: ip.c:110
#define ERR_VAL
Definition: err.h:58
#define NULL
Definition: def.h:47
#define RAW_TTL
Definition: opt.h:650
#define LWIP_DBG_TRACE
Definition: debug.h:56
const ip_addr_t ip_addr_any ICACHE_RODATA_ATTR
Definition: ip_addr.c:44
#define ICACHE_FLASH_ATTR
Definition: c_types.h:99
void * memp_malloc(memp_t type) ICACHE_FLASH_ATTR
Definition: memp.c:393
Definition: pbuf.h:58
struct netif * ip_route(ip_addr_t *dest) ICACHE_FLASH_ATTR
Definition: ip.c:125
#define ERR_RTE
Definition: err.h:56
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:94
#define os_memset
Definition: osapi.h:38
#define ip_addr_cmp(addr1, addr2)
Definition: ip_addr.h:198
#define LWIP_DBG_LEVEL_SERIOUS
Definition: debug.h:46
#define RAW_DEBUG
Definition: opt.h:1889
#define ERR_OK
Definition: err.h:52
err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif) ICACHE_FLASH_ATTR
Definition: ip.c:1259
Definition: pbuf.h:76
s8_t err_t
Definition: err.h:47
typedefPACK_STRUCT_END struct ip_addr ip_addr_t
Definition: ip_addr.h:64
#define LWIP_DBG_LEVEL_WARNING
Definition: debug.h:45
Definition: netif.h:139
#define ip4_addr4_16(ipaddr)
Definition: ip_addr.h:229
ip_addr_t ip_addr
Definition: netif.h:144
void pbuf_chain(struct pbuf *head, struct pbuf *tail) ICACHE_FLASH_ATTR
Definition: pbuf.c:864
#define ip_addr_isany(addr1)
Definition: ip_addr.h:200
#define SOF_BROADCAST
Definition: ip.h:102
u8_t pbuf_free(struct pbuf *p) ICACHE_FLASH_ATTR
Definition: pbuf.c:685
#define ip_addr_isbroadcast(ipaddr, netif)
Definition: ip_addr.h:202
Definition: ip.h:116
#define IP_HLEN
Definition: ip.h:50
u8_t pbuf_header(struct pbuf *p, s16_t header_size) ICACHE_FLASH_ATTR
Definition: pbuf.c:573
#define ip4_addr1_16(ipaddr)
Definition: ip_addr.h:226
unsigned char u8_t
Definition: cc.h:52
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:65
void * payload
Definition: pbuf.h:81
Definition: pbuf.h:52
#define ip4_addr2_16(ipaddr)
Definition: ip_addr.h:227
#define ERR_MEM
Definition: err.h:53
#define LWIP_UNUSED_ARG(x)
Definition: arch.h:73
#define IPH_PROTO(hdr)
Definition: ip.h:151
struct pbuf * pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type) ICACHE_FLASH_ATTR
Definition: pbuf.c:234