Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / lwip / core / raw.c
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/inet.h"
48 #include "lwip/ip_addr.h"
49 #include "lwip/netif.h"
50 #include "lwip/raw.h"
51 #include "lwip/stats.h"
52 #include "lwip/snmp.h"
53 #include "arch/perf.h"
54
55 #include <string.h>
56
57 /** The list of RAW PCBs */
58 static struct raw_pcb *raw_pcbs;
59
60 /**
61  * Determine if in incoming IP packet is covered by a RAW PCB
62  * and if so, pass it to a user-provided receive callback function.
63  *
64  * Given an incoming IP datagram (as a chain of pbufs) this function
65  * finds a corresponding RAW PCB and calls the corresponding receive
66  * callback function.
67  *
68  * @param p pbuf to be demultiplexed to a RAW PCB.
69  * @param inp network interface on which the datagram was received.
70  * @return - 1 if the packet has been eaten by a RAW PCB receive
71  *           callback function. The caller MAY NOT not reference the
72  *           packet any longer, and MAY NOT call pbuf_free().
73  * @return - 0 if packet is not eaten (pbuf is still referenced by the
74  *           caller).
75  *
76  */
77 u8_t
78 raw_input(struct pbuf *p, struct netif *inp)
79 {
80   struct raw_pcb *pcb, *prev;
81   struct ip_hdr *iphdr;
82   s16_t proto;
83   u8_t eaten = 0;
84
85   LWIP_UNUSED_ARG(inp);
86
87   iphdr = p->payload;
88   proto = IPH_PROTO(iphdr);
89
90   prev = NULL;
91   pcb = raw_pcbs;
92   /* loop through all raw pcbs until the packet is eaten by one */
93   /* this allows multiple pcbs to match against the packet by design */
94   while ((eaten == 0) && (pcb != NULL)) {
95     if (pcb->protocol == proto) {
96       /* receive callback function available? */
97       if (pcb->recv != NULL) {
98         /* the receive callback function did not eat the packet? */
99         if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0)
100         {
101           /* receive function ate the packet */
102           p = NULL;
103           eaten = 1;
104           if (prev != NULL) {
105           /* move the pcb to the front of raw_pcbs so that is
106              found faster next time */
107             prev->next = pcb->next;
108             pcb->next = raw_pcbs;
109             raw_pcbs = pcb;
110           }
111         }
112       }
113       /* no receive callback function was set for this raw PCB */
114       /* drop the packet */
115     }
116     prev = pcb;
117     pcb = pcb->next;
118   }
119   return eaten;
120 }
121
122 /**
123  * Bind a RAW PCB.
124  *
125  * @param pcb RAW PCB to be bound with a local address ipaddr.
126  * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to
127  * bind to all local interfaces.
128  *
129  * @return lwIP error code.
130  * - ERR_OK. Successful. No error occured.
131  * - ERR_USE. The specified IP address is already bound to by
132  * another RAW PCB.
133  *
134  * @see raw_disconnect()
135  */
136 err_t
137 raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)
138 {
139   ip_addr_set(&pcb->local_ip, ipaddr);
140   return ERR_OK;
141 }
142
143 /**
144  * Connect an RAW PCB. This function is required by upper layers
145  * of lwip. Using the raw api you could use raw_sendto() instead
146  *
147  * This will associate the RAW PCB with the remote address.
148  *
149  * @param pcb RAW PCB to be connected with remote address ipaddr and port.
150  * @param ipaddr remote IP address to connect with.
151  *
152  * @return lwIP error code
153  *
154  * @see raw_disconnect() and raw_sendto()
155  */
156 err_t
157 raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)
158 {
159   ip_addr_set(&pcb->remote_ip, ipaddr);
160   return ERR_OK;
161 }
162
163
164 /**
165  * Set the callback function for received packets that match the
166  * raw PCB's protocol and binding. 
167  * 
168  * The callback function MUST either
169  * - eat the packet by calling pbuf_free() and returning non-zero. The
170  *   packet will not be passed to other raw PCBs or other protocol layers.
171  * - not free the packet, and return zero. The packet will be matched
172  *   against further PCBs and/or forwarded to another protocol layers.
173  * 
174  * @return non-zero if the packet was free()d, zero if the packet remains
175  * available for others.
176  */
177 void
178 raw_recv(struct raw_pcb *pcb,
179          u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p,
180                       struct ip_addr *addr),
181          void *recv_arg)
182 {
183   /* remember recv() callback and user data */
184   pcb->recv = recv;
185   pcb->recv_arg = recv_arg;
186 }
187
188 /**
189  * Send the raw IP packet to the given address. Note that actually you cannot
190  * modify the IP headers (this is inconsistent with the receive callback where
191  * you actually get the IP headers), you can only specify the IP payload here.
192  * It requires some more changes in lwIP. (there will be a raw_send() function
193  * then.)
194  *
195  * @param pcb the raw pcb which to send
196  * @param p the IP payload to send
197  * @param ipaddr the destination address of the IP packet
198  *
199  */
200 err_t
201 raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
202 {
203   err_t err;
204   struct netif *netif;
205   struct ip_addr *src_ip;
206   struct pbuf *q; /* q will be sent down the stack */
207   
208   LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_sendto\n"));
209   
210   /* not enough space to add an IP header to first pbuf in given p chain? */
211   if (pbuf_header(p, IP_HLEN)) {
212     /* allocate header in new pbuf */
213     q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
214     /* new header pbuf could not be allocated? */
215     if (q == NULL) {
216       LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 2, ("raw_sendto: could not allocate header\n"));
217       return ERR_MEM;
218     }
219     /* chain header q in front of given pbuf p */
220     pbuf_chain(q, p);
221     /* { first pbuf q points to header pbuf } */
222     LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
223   }  else {
224     /* first pbuf q equals given pbuf */
225     q = p;
226     if(pbuf_header(q, -IP_HLEN)) {
227       LWIP_ASSERT("Can't restore header we just removed!", 0);
228       return ERR_MEM;
229     }
230   }
231   
232   if ((netif = ip_route(ipaddr)) == NULL) {
233     LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));
234     /* free any temporary header pbuf allocated by pbuf_header() */
235     if (q != p) {
236       pbuf_free(q);
237     }
238     return ERR_RTE;
239   }
240
241   if (ip_addr_isany(&pcb->local_ip)) {
242     /* use outgoing network interface IP address as source address */
243     src_ip = &(netif->ip_addr);
244   } else {
245     /* use RAW PCB local IP address as source address */
246     src_ip = &(pcb->local_ip);
247   }
248
249 #if LWIP_NETIF_HWADDRHINT
250   netif->addr_hint = &(pcb->addr_hint);
251 #endif /* LWIP_NETIF_HWADDRHINT*/
252   err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
253 #if LWIP_NETIF_HWADDRHINT
254   netif->addr_hint = NULL;
255 #endif /* LWIP_NETIF_HWADDRHINT*/
256
257   /* did we chain a header earlier? */
258   if (q != p) {
259     /* free the header */
260     pbuf_free(q);
261   }
262   return err;
263 }
264
265 /**
266  * Send the raw IP packet to the address given by raw_connect()
267  *
268  * @param pcb the raw pcb which to send
269  * @param p the IP payload to send
270  *
271  */
272 err_t
273 raw_send(struct raw_pcb *pcb, struct pbuf *p)
274 {
275   return raw_sendto(pcb, p, &pcb->remote_ip);
276 }
277
278 /**
279  * Remove an RAW PCB.
280  *
281  * @param pcb RAW PCB to be removed. The PCB is removed from the list of
282  * RAW PCB's and the data structure is freed from memory.
283  *
284  * @see raw_new()
285  */
286 void
287 raw_remove(struct raw_pcb *pcb)
288 {
289   struct raw_pcb *pcb2;
290   /* pcb to be removed is first in list? */
291   if (raw_pcbs == pcb) {
292     /* make list start at 2nd pcb */
293     raw_pcbs = raw_pcbs->next;
294     /* pcb not 1st in list */
295   } else {
296     for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
297       /* find pcb in raw_pcbs list */
298       if (pcb2->next != NULL && pcb2->next == pcb) {
299         /* remove pcb from list */
300         pcb2->next = pcb->next;
301       }
302     }
303   }
304   memp_free(MEMP_RAW_PCB, pcb);
305 }
306
307 /**
308  * Create a RAW PCB.
309  *
310  * @return The RAW PCB which was created. NULL if the PCB data structure
311  * could not be allocated.
312  *
313  * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)
314  *
315  * @see raw_remove()
316  */
317 struct raw_pcb *
318 raw_new(u8_t proto) {
319   struct raw_pcb *pcb;
320
321   LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_new\n"));
322
323   pcb = memp_malloc(MEMP_RAW_PCB);
324   /* could allocate RAW PCB? */
325   if (pcb != NULL) {
326     /* initialize PCB to all zeroes */
327     memset(pcb, 0, sizeof(struct raw_pcb));
328     pcb->protocol = proto;
329     pcb->ttl = RAW_TTL;
330     pcb->next = raw_pcbs;
331     raw_pcbs = pcb;
332   }
333   return pcb;
334 }
335
336 #endif /* LWIP_RAW */