]>
Commit | Line | Data |
---|---|---|
6e6d4a8b JP |
1 | /** |
2 | * @file | |
3 | * Loop Interface | |
4 | * | |
5 | */ | |
6 | ||
7 | /* | |
8 | * Copyright (c) 2001-2004 Swedish Institute of Computer Science. | |
9 | * All rights reserved. | |
10 | * | |
11 | * Redistribution and use in source and binary forms, with or without modification, | |
12 | * are permitted provided that the following conditions are met: | |
13 | * | |
14 | * 1. Redistributions of source code must retain the above copyright notice, | |
15 | * this list of conditions and the following disclaimer. | |
16 | * 2. Redistributions in binary form must reproduce the above copyright notice, | |
17 | * this list of conditions and the following disclaimer in the documentation | |
18 | * and/or other materials provided with the distribution. | |
19 | * 3. The name of the author may not be used to endorse or promote products | |
20 | * derived from this software without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
23 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
24 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT | |
25 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
26 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT | |
27 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
30 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY | |
31 | * OF SUCH DAMAGE. | |
32 | * | |
33 | * This file is part of the lwIP TCP/IP stack. | |
34 | * | |
35 | * Author: Adam Dunkels <adam@sics.se> | |
36 | * | |
37 | */ | |
38 | #include "lwip/opt.h" | |
39 | ||
40 | #if LWIP_HAVE_LOOPIF | |
41 | ||
42 | #include "netif/loopif.h" | |
43 | #include "lwip/pbuf.h" | |
44 | #include "lwip/snmp.h" | |
45 | ||
46 | #include <string.h> | |
47 | ||
48 | #if !LWIP_LOOPIF_MULTITHREADING | |
49 | ||
50 | #include "lwip/sys.h" | |
51 | #include "lwip/mem.h" | |
52 | ||
53 | /* helper struct for the linked list of pbufs */ | |
54 | struct loopif_private { | |
55 | struct pbuf *first; | |
56 | struct pbuf *last; | |
57 | }; | |
58 | ||
59 | /** | |
60 | * Call loopif_poll() in the main loop of your application. This is to prevent | |
61 | * reentering non-reentrant functions like tcp_input(). Packets passed to | |
62 | * loopif_output() are put on a list that is passed to netif->input() by | |
63 | * loopif_poll(). | |
64 | * | |
65 | * @param netif the lwip network interface structure for this loopif | |
66 | */ | |
67 | void | |
68 | loopif_poll(struct netif *netif) | |
69 | { | |
70 | SYS_ARCH_DECL_PROTECT(lev); | |
71 | struct pbuf *in, *in_end; | |
72 | struct loopif_private *priv = (struct loopif_private*)netif->state; | |
73 | ||
74 | LWIP_ERROR("priv != NULL", (priv != NULL), return;); | |
75 | ||
76 | do { | |
77 | /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ | |
78 | SYS_ARCH_PROTECT(lev); | |
79 | in = priv->first; | |
80 | if(in) { | |
81 | in_end = in; | |
82 | while(in_end->len != in_end->tot_len) { | |
83 | LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); | |
84 | in_end = in_end->next; | |
85 | } | |
86 | /* 'in_end' now points to the last pbuf from 'in' */ | |
87 | if(in_end == priv->last) { | |
88 | /* this was the last pbuf in the list */ | |
89 | priv->first = priv->last = NULL; | |
90 | } else { | |
91 | /* pop the pbuf off the list */ | |
92 | priv->first = in_end->next; | |
93 | LWIP_ASSERT("should not be null since first != last!", priv->first != NULL); | |
94 | } | |
95 | } | |
96 | SYS_ARCH_UNPROTECT(lev); | |
97 | ||
98 | if(in != NULL) { | |
99 | if(in_end->next != NULL) { | |
100 | /* De-queue the pbuf from its successors on the 'priv' list. */ | |
101 | in_end->next = NULL; | |
102 | } | |
103 | if(netif->input(in, netif) != ERR_OK) { | |
104 | pbuf_free(in); | |
105 | } | |
106 | /* Don't reference the packet any more! */ | |
107 | in = NULL; | |
108 | in_end = NULL; | |
109 | } | |
110 | /* go on while there is a packet on the list */ | |
111 | } while(priv->first != NULL); | |
112 | } | |
113 | #endif /* LWIP_LOOPIF_MULTITHREADING */ | |
114 | ||
115 | /** | |
116 | * Send an IP packet over the loopback interface. | |
117 | * The pbuf is simply copied and handed back to netif->input. | |
118 | * In multithreaded mode, this is done directly since netif->input must put | |
119 | * the packet on a queue. | |
120 | * In callback mode, the packet is put on an internal queue and is fed to | |
121 | * netif->input by loopif_poll(). | |
122 | * | |
123 | * @param netif the lwip network interface structure for this loopif | |
124 | * @param p the (IP) packet to 'send' | |
125 | * @param ipaddr the ip address to send the packet to (not used for loopif) | |
126 | * @return ERR_OK if the packet has been sent | |
127 | * ERR_MEM if the pbuf used to copy the packet couldn't be allocated | |
128 | */ | |
129 | static err_t | |
130 | loopif_output(struct netif *netif, struct pbuf *p, | |
131 | struct ip_addr *ipaddr) | |
132 | { | |
133 | #if !LWIP_LOOPIF_MULTITHREADING | |
134 | SYS_ARCH_DECL_PROTECT(lev); | |
135 | struct loopif_private *priv; | |
136 | struct pbuf *last; | |
137 | #endif /* LWIP_LOOPIF_MULTITHREADING */ | |
138 | struct pbuf *r; | |
139 | err_t err; | |
140 | ||
141 | LWIP_UNUSED_ARG(ipaddr); | |
142 | ||
143 | /* Allocate a new pbuf */ | |
144 | r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); | |
145 | if (r == NULL) { | |
146 | return ERR_MEM; | |
147 | } | |
148 | ||
149 | /* Copy the whole pbuf queue p into the single pbuf r */ | |
150 | if ((err = pbuf_copy(r, p)) != ERR_OK) { | |
151 | pbuf_free(r); | |
152 | r = NULL; | |
153 | return err; | |
154 | } | |
155 | ||
156 | #if LWIP_LOOPIF_MULTITHREADING | |
157 | /* Multithreading environment, netif->input() is supposed to put the packet | |
158 | into a mailbox, so we can safely call it here without risking to re-enter | |
159 | functions that are not reentrant (TCP!!!) */ | |
160 | if(netif->input(r, netif) != ERR_OK) { | |
161 | pbuf_free(r); | |
162 | r = NULL; | |
163 | } | |
164 | #else /* LWIP_LOOPIF_MULTITHREADING */ | |
165 | /* Raw API without threads: put the packet on a linked list which gets emptied | |
166 | through calling loopif_poll(). */ | |
167 | priv = (struct loopif_private*)netif->state; | |
168 | ||
169 | /* let last point to the last pbuf in chain r */ | |
170 | for (last = r; last->next != NULL; last = last->next); | |
171 | SYS_ARCH_PROTECT(lev); | |
172 | if(priv->first != NULL) { | |
173 | LWIP_ASSERT("if first != NULL, last must also be != NULL", priv->last != NULL); | |
174 | priv->last->next = r; | |
175 | priv->last = last; | |
176 | } else { | |
177 | priv->first = r; | |
178 | priv->last = last; | |
179 | } | |
180 | SYS_ARCH_UNPROTECT(lev); | |
181 | #endif /* LWIP_LOOPIF_MULTITHREADING */ | |
182 | ||
183 | return ERR_OK; | |
184 | } | |
185 | ||
186 | /** | |
187 | * Initialize a lwip network interface structure for a loopback interface | |
188 | * | |
189 | * @param netif the lwip network interface structure for this loopif | |
190 | * @return ERR_OK if the loopif is initialized | |
191 | * ERR_MEM if private data couldn't be allocated | |
192 | */ | |
193 | err_t | |
194 | loopif_init(struct netif *netif) | |
195 | { | |
196 | #if !LWIP_LOOPIF_MULTITHREADING | |
197 | struct loopif_private *priv; | |
198 | ||
199 | priv = (struct loopif_private*)mem_malloc(sizeof(struct loopif_private)); | |
200 | if(priv == NULL) | |
201 | return ERR_MEM; | |
202 | priv->first = priv->last = NULL; | |
203 | netif->state = priv; | |
204 | #endif /* LWIP_LOOPIF_MULTITHREADING */ | |
205 | ||
206 | /* initialize the snmp variables and counters inside the struct netif | |
207 | * ifSpeed: no assumption can be made! | |
208 | */ | |
209 | NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0); | |
210 | ||
211 | netif->name[0] = 'l'; | |
212 | netif->name[1] = 'o'; | |
213 | netif->output = loopif_output; | |
214 | return ERR_OK; | |
215 | } | |
216 | ||
217 | #endif /* LWIP_HAVE_LOOPIF */ |