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