1*ef8d499eSDavid van Moolenbroek /* LWIP service - loopif.c - loopback interfaces */
2*ef8d499eSDavid van Moolenbroek /*
3*ef8d499eSDavid van Moolenbroek * There is always at least one loopback device. This device is used also to
4*ef8d499eSDavid van Moolenbroek * loop back packets sent on other interfaces to the local interface address.
5*ef8d499eSDavid van Moolenbroek * Therefore, not all packets on the loopback device have a source or
6*ef8d499eSDavid van Moolenbroek * destination address corresponding to the loopback device.
7*ef8d499eSDavid van Moolenbroek */
8*ef8d499eSDavid van Moolenbroek
9*ef8d499eSDavid van Moolenbroek #include "lwip.h"
10*ef8d499eSDavid van Moolenbroek
11*ef8d499eSDavid van Moolenbroek /*
12*ef8d499eSDavid van Moolenbroek * As a safety measure, if lwIP somehow gets stuck in a loop replying to its
13*ef8d499eSDavid van Moolenbroek * own packets on a loopback interface, stop with immediately feeding packets
14*ef8d499eSDavid van Moolenbroek * back into lwIP after this many packets. The remaining packets will still be
15*ef8d499eSDavid van Moolenbroek * delivered, but not before the main message loop has had a chance to run.
16*ef8d499eSDavid van Moolenbroek */
17*ef8d499eSDavid van Moolenbroek #define LOOPIF_LIMIT 65536
18*ef8d499eSDavid van Moolenbroek
19*ef8d499eSDavid van Moolenbroek /*
20*ef8d499eSDavid van Moolenbroek * The MTU is restricted to 65531 bytes, because we need space for a 4-byte
21*ef8d499eSDavid van Moolenbroek * header to identify the original interface of the packet.
22*ef8d499eSDavid van Moolenbroek */
23*ef8d499eSDavid van Moolenbroek #define LOOPIF_MAX_MTU (UINT16_MAX - sizeof(uint32_t)) /* maximum MTU */
24*ef8d499eSDavid van Moolenbroek #define LOOPIF_DEF_MTU LOOPIF_MAX_MTU /* default MTU */
25*ef8d499eSDavid van Moolenbroek
26*ef8d499eSDavid van Moolenbroek #define NR_LOOPIF 2 /* number of loopback devices */
27*ef8d499eSDavid van Moolenbroek
28*ef8d499eSDavid van Moolenbroek struct loopif {
29*ef8d499eSDavid van Moolenbroek struct ifdev loopif_ifdev; /* interface device, MUST be first */
30*ef8d499eSDavid van Moolenbroek struct pbuf *loopif_head; /* head of pending loopback packets */
31*ef8d499eSDavid van Moolenbroek struct pbuf **loopif_tailp; /* tail ptr-ptr of pending packets */
32*ef8d499eSDavid van Moolenbroek TAILQ_ENTRY(loopif) loopif_next; /* next in free list */
33*ef8d499eSDavid van Moolenbroek } loopif_array[NR_LOOPIF];
34*ef8d499eSDavid van Moolenbroek
35*ef8d499eSDavid van Moolenbroek static TAILQ_HEAD(, loopif) loopif_freelist; /* free loop interfaces list */
36*ef8d499eSDavid van Moolenbroek static TAILQ_HEAD(, loopif) loopif_activelist; /* active loop interfaces */
37*ef8d499eSDavid van Moolenbroek
38*ef8d499eSDavid van Moolenbroek #define loopif_get_netif(loopif) (ifdev_get_netif(&(loopif)->loopif_ifdev))
39*ef8d499eSDavid van Moolenbroek
40*ef8d499eSDavid van Moolenbroek static unsigned int loopif_cksum_flags;
41*ef8d499eSDavid van Moolenbroek
42*ef8d499eSDavid van Moolenbroek static int loopif_create(const char *name);
43*ef8d499eSDavid van Moolenbroek
44*ef8d499eSDavid van Moolenbroek static const struct ifdev_ops loopif_ops;
45*ef8d499eSDavid van Moolenbroek
46*ef8d499eSDavid van Moolenbroek /*
47*ef8d499eSDavid van Moolenbroek * Initialize the loopback interface module.
48*ef8d499eSDavid van Moolenbroek */
49*ef8d499eSDavid van Moolenbroek void
loopif_init(void)50*ef8d499eSDavid van Moolenbroek loopif_init(void)
51*ef8d499eSDavid van Moolenbroek {
52*ef8d499eSDavid van Moolenbroek unsigned int slot;
53*ef8d499eSDavid van Moolenbroek
54*ef8d499eSDavid van Moolenbroek /* Initialize the lists of loopback interfaces. */
55*ef8d499eSDavid van Moolenbroek TAILQ_INIT(&loopif_freelist);
56*ef8d499eSDavid van Moolenbroek TAILQ_INIT(&loopif_activelist);
57*ef8d499eSDavid van Moolenbroek
58*ef8d499eSDavid van Moolenbroek for (slot = 0; slot < __arraycount(loopif_array); slot++)
59*ef8d499eSDavid van Moolenbroek TAILQ_INSERT_TAIL(&loopif_freelist, &loopif_array[slot],
60*ef8d499eSDavid van Moolenbroek loopif_next);
61*ef8d499eSDavid van Moolenbroek
62*ef8d499eSDavid van Moolenbroek /*
63*ef8d499eSDavid van Moolenbroek * The default is to perform no checksumming on loopback interfaces,
64*ef8d499eSDavid van Moolenbroek * except for ICMP messages because otherwise we would need additional
65*ef8d499eSDavid van Moolenbroek * changes in the code receiving those. In fact, for future
66*ef8d499eSDavid van Moolenbroek * compatibility, disable only those flags that we manage ourselves.
67*ef8d499eSDavid van Moolenbroek */
68*ef8d499eSDavid van Moolenbroek loopif_cksum_flags = NETIF_CHECKSUM_ENABLE_ALL &
69*ef8d499eSDavid van Moolenbroek ~(NETIF_CHECKSUM_GEN_IP | NETIF_CHECKSUM_CHECK_IP |
70*ef8d499eSDavid van Moolenbroek NETIF_CHECKSUM_GEN_UDP | NETIF_CHECKSUM_CHECK_UDP |
71*ef8d499eSDavid van Moolenbroek NETIF_CHECKSUM_GEN_TCP | NETIF_CHECKSUM_CHECK_TCP);
72*ef8d499eSDavid van Moolenbroek
73*ef8d499eSDavid van Moolenbroek /* Tell the ifdev module that users may create more loopif devices. */
74*ef8d499eSDavid van Moolenbroek ifdev_register("lo", loopif_create);
75*ef8d499eSDavid van Moolenbroek }
76*ef8d499eSDavid van Moolenbroek
77*ef8d499eSDavid van Moolenbroek /*
78*ef8d499eSDavid van Moolenbroek * Polling function, invoked after each message loop iteration. Forward any
79*ef8d499eSDavid van Moolenbroek * packets received on the output side of the loopback device during this
80*ef8d499eSDavid van Moolenbroek * loop iteration, to the input side of the device.
81*ef8d499eSDavid van Moolenbroek */
82*ef8d499eSDavid van Moolenbroek static void
loopif_poll(struct ifdev * ifdev)83*ef8d499eSDavid van Moolenbroek loopif_poll(struct ifdev * ifdev)
84*ef8d499eSDavid van Moolenbroek {
85*ef8d499eSDavid van Moolenbroek struct loopif *loopif = (struct loopif *)ifdev;
86*ef8d499eSDavid van Moolenbroek struct pbuf *pbuf, **pnext;
87*ef8d499eSDavid van Moolenbroek struct ifdev *oifdev;
88*ef8d499eSDavid van Moolenbroek struct netif *netif;
89*ef8d499eSDavid van Moolenbroek uint32_t oifindex;
90*ef8d499eSDavid van Moolenbroek unsigned int count;
91*ef8d499eSDavid van Moolenbroek static int warned = FALSE;
92*ef8d499eSDavid van Moolenbroek
93*ef8d499eSDavid van Moolenbroek count = 0;
94*ef8d499eSDavid van Moolenbroek
95*ef8d499eSDavid van Moolenbroek while ((pbuf = loopif->loopif_head) != NULL) {
96*ef8d499eSDavid van Moolenbroek /*
97*ef8d499eSDavid van Moolenbroek * Prevent endless loops. Keep in mind that packets may be
98*ef8d499eSDavid van Moolenbroek * added to the queue as part of processing packets from the
99*ef8d499eSDavid van Moolenbroek * queue here, so the queue itself will never reach this
100*ef8d499eSDavid van Moolenbroek * length. As such the limit can (and must) be fairly high.
101*ef8d499eSDavid van Moolenbroek *
102*ef8d499eSDavid van Moolenbroek * In any case, if this warning is shown, that basically means
103*ef8d499eSDavid van Moolenbroek * that a bug in lwIP has been triggered. There should be no
104*ef8d499eSDavid van Moolenbroek * such bugs, so if there are, they should be fixed in lwIP.
105*ef8d499eSDavid van Moolenbroek */
106*ef8d499eSDavid van Moolenbroek if (count++ == LOOPIF_LIMIT) {
107*ef8d499eSDavid van Moolenbroek if (!warned) {
108*ef8d499eSDavid van Moolenbroek printf("LWIP: excess loopback traffic, "
109*ef8d499eSDavid van Moolenbroek "throttling output\n");
110*ef8d499eSDavid van Moolenbroek warned = TRUE;
111*ef8d499eSDavid van Moolenbroek }
112*ef8d499eSDavid van Moolenbroek
113*ef8d499eSDavid van Moolenbroek break;
114*ef8d499eSDavid van Moolenbroek }
115*ef8d499eSDavid van Moolenbroek
116*ef8d499eSDavid van Moolenbroek pnext = pchain_end(pbuf);
117*ef8d499eSDavid van Moolenbroek
118*ef8d499eSDavid van Moolenbroek if ((loopif->loopif_head = *pnext) == NULL)
119*ef8d499eSDavid van Moolenbroek loopif->loopif_tailp = &loopif->loopif_head;
120*ef8d499eSDavid van Moolenbroek *pnext = NULL;
121*ef8d499eSDavid van Moolenbroek
122*ef8d499eSDavid van Moolenbroek /*
123*ef8d499eSDavid van Moolenbroek * Get the original interface for the packet, which if non-zero
124*ef8d499eSDavid van Moolenbroek * must also be used to pass the packet back to. The interface
125*ef8d499eSDavid van Moolenbroek * should still exist in all cases, but better safe than sorry.
126*ef8d499eSDavid van Moolenbroek */
127*ef8d499eSDavid van Moolenbroek memcpy(&oifindex, pbuf->payload, sizeof(oifindex));
128*ef8d499eSDavid van Moolenbroek
129*ef8d499eSDavid van Moolenbroek util_pbuf_header(pbuf, -(int)sizeof(oifindex));
130*ef8d499eSDavid van Moolenbroek
131*ef8d499eSDavid van Moolenbroek if (oifindex != 0 &&
132*ef8d499eSDavid van Moolenbroek (oifdev = ifdev_get_by_index(oifindex)) != NULL)
133*ef8d499eSDavid van Moolenbroek netif = ifdev_get_netif(oifdev);
134*ef8d499eSDavid van Moolenbroek else
135*ef8d499eSDavid van Moolenbroek netif = NULL;
136*ef8d499eSDavid van Moolenbroek
137*ef8d499eSDavid van Moolenbroek /*
138*ef8d499eSDavid van Moolenbroek * Loopback devices hand packets to BPF on output only. Doing
139*ef8d499eSDavid van Moolenbroek * so on input as well would duplicate all captured packets.
140*ef8d499eSDavid van Moolenbroek */
141*ef8d499eSDavid van Moolenbroek ifdev_input(ifdev, pbuf, netif, FALSE /*to_bpf*/);
142*ef8d499eSDavid van Moolenbroek }
143*ef8d499eSDavid van Moolenbroek }
144*ef8d499eSDavid van Moolenbroek
145*ef8d499eSDavid van Moolenbroek /*
146*ef8d499eSDavid van Moolenbroek * Process a packet as output on a loopback interface. Packets cannot be
147*ef8d499eSDavid van Moolenbroek * passed back into lwIP right away, nor can the original packets be passed
148*ef8d499eSDavid van Moolenbroek * back into lwIP. Therefore, make a copy of the packet, and pass it back to
149*ef8d499eSDavid van Moolenbroek * lwIP at the end of the current message loop iteration.
150*ef8d499eSDavid van Moolenbroek */
151*ef8d499eSDavid van Moolenbroek static err_t
loopif_output(struct ifdev * ifdev,struct pbuf * pbuf,struct netif * netif)152*ef8d499eSDavid van Moolenbroek loopif_output(struct ifdev * ifdev, struct pbuf * pbuf, struct netif * netif)
153*ef8d499eSDavid van Moolenbroek {
154*ef8d499eSDavid van Moolenbroek struct loopif *loopif = (struct loopif *)ifdev;
155*ef8d499eSDavid van Moolenbroek struct ifdev *oifdev;
156*ef8d499eSDavid van Moolenbroek struct pbuf *pcopy;
157*ef8d499eSDavid van Moolenbroek uint32_t oifindex;
158*ef8d499eSDavid van Moolenbroek
159*ef8d499eSDavid van Moolenbroek /* Reject oversized packets immediately. This should not happen. */
160*ef8d499eSDavid van Moolenbroek if (pbuf->tot_len > UINT16_MAX - sizeof(oifindex)) {
161*ef8d499eSDavid van Moolenbroek printf("LWIP: attempt to send oversized loopback packet\n");
162*ef8d499eSDavid van Moolenbroek
163*ef8d499eSDavid van Moolenbroek return ERR_MEM;
164*ef8d499eSDavid van Moolenbroek }
165*ef8d499eSDavid van Moolenbroek
166*ef8d499eSDavid van Moolenbroek /*
167*ef8d499eSDavid van Moolenbroek * If the service is low on memory, this is a likely place where
168*ef8d499eSDavid van Moolenbroek * allocation failures will occur. Thus, do not print anything here.
169*ef8d499eSDavid van Moolenbroek * The user can diagnose such problems with interface statistics.
170*ef8d499eSDavid van Moolenbroek */
171*ef8d499eSDavid van Moolenbroek pcopy = pchain_alloc(PBUF_RAW, sizeof(oifindex) + pbuf->tot_len);
172*ef8d499eSDavid van Moolenbroek if (pcopy == NULL) {
173*ef8d499eSDavid van Moolenbroek ifdev_output_drop(ifdev);
174*ef8d499eSDavid van Moolenbroek
175*ef8d499eSDavid van Moolenbroek return ERR_MEM;
176*ef8d499eSDavid van Moolenbroek }
177*ef8d499eSDavid van Moolenbroek
178*ef8d499eSDavid van Moolenbroek /*
179*ef8d499eSDavid van Moolenbroek * If the packet was purposely diverted from a non-loopback interface
180*ef8d499eSDavid van Moolenbroek * to this interface, we have to remember the original interface, so
181*ef8d499eSDavid van Moolenbroek * that we can pass back the packet to that interface as well. If we
182*ef8d499eSDavid van Moolenbroek * don't, packets to link-local addresses assigned to non-loopback
183*ef8d499eSDavid van Moolenbroek * interfaces will not be processed correctly.
184*ef8d499eSDavid van Moolenbroek */
185*ef8d499eSDavid van Moolenbroek if (netif != NULL) {
186*ef8d499eSDavid van Moolenbroek oifdev = netif_get_ifdev(netif);
187*ef8d499eSDavid van Moolenbroek oifindex = ifdev_get_index(oifdev);
188*ef8d499eSDavid van Moolenbroek } else
189*ef8d499eSDavid van Moolenbroek oifindex = 0;
190*ef8d499eSDavid van Moolenbroek
191*ef8d499eSDavid van Moolenbroek assert(pcopy->len >= sizeof(oifindex));
192*ef8d499eSDavid van Moolenbroek
193*ef8d499eSDavid van Moolenbroek memcpy(pcopy->payload, &oifindex, sizeof(oifindex));
194*ef8d499eSDavid van Moolenbroek
195*ef8d499eSDavid van Moolenbroek util_pbuf_header(pcopy, -(int)sizeof(oifindex));
196*ef8d499eSDavid van Moolenbroek
197*ef8d499eSDavid van Moolenbroek if (pbuf_copy(pcopy, pbuf) != ERR_OK)
198*ef8d499eSDavid van Moolenbroek panic("unexpected pbuf copy failure");
199*ef8d499eSDavid van Moolenbroek
200*ef8d499eSDavid van Moolenbroek pcopy->flags |= pbuf->flags & (PBUF_FLAG_LLMCAST | PBUF_FLAG_LLBCAST);
201*ef8d499eSDavid van Moolenbroek
202*ef8d499eSDavid van Moolenbroek util_pbuf_header(pcopy, sizeof(oifindex));
203*ef8d499eSDavid van Moolenbroek
204*ef8d499eSDavid van Moolenbroek *loopif->loopif_tailp = pcopy;
205*ef8d499eSDavid van Moolenbroek loopif->loopif_tailp = pchain_end(pcopy);
206*ef8d499eSDavid van Moolenbroek
207*ef8d499eSDavid van Moolenbroek return ERR_OK;
208*ef8d499eSDavid van Moolenbroek }
209*ef8d499eSDavid van Moolenbroek
210*ef8d499eSDavid van Moolenbroek /*
211*ef8d499eSDavid van Moolenbroek * Initialization function for a loopback-type netif interface, called from
212*ef8d499eSDavid van Moolenbroek * lwIP at interface creation time.
213*ef8d499eSDavid van Moolenbroek */
214*ef8d499eSDavid van Moolenbroek static err_t
loopif_init_netif(struct ifdev * ifdev,struct netif * netif)215*ef8d499eSDavid van Moolenbroek loopif_init_netif(struct ifdev * ifdev, struct netif * netif)
216*ef8d499eSDavid van Moolenbroek {
217*ef8d499eSDavid van Moolenbroek
218*ef8d499eSDavid van Moolenbroek netif->name[0] = 'l';
219*ef8d499eSDavid van Moolenbroek netif->name[1] = 'o';
220*ef8d499eSDavid van Moolenbroek
221*ef8d499eSDavid van Moolenbroek /*
222*ef8d499eSDavid van Moolenbroek * FIXME: unfortunately, lwIP does not allow one to enable multicast on
223*ef8d499eSDavid van Moolenbroek * an interface without also enabling multicast management traffic
224*ef8d499eSDavid van Moolenbroek * (that is, IGMP and MLD). Thus, for now, joining multicast groups
225*ef8d499eSDavid van Moolenbroek * and assigning local IPv6 addresses will incur such traffic even on
226*ef8d499eSDavid van Moolenbroek * loopback interfaces. For now this is preferable over not supporting
227*ef8d499eSDavid van Moolenbroek * multicast on loopback interfaces at all.
228*ef8d499eSDavid van Moolenbroek */
229*ef8d499eSDavid van Moolenbroek netif->flags |= NETIF_FLAG_IGMP | NETIF_FLAG_MLD6;
230*ef8d499eSDavid van Moolenbroek
231*ef8d499eSDavid van Moolenbroek NETIF_SET_CHECKSUM_CTRL(netif, loopif_cksum_flags);
232*ef8d499eSDavid van Moolenbroek
233*ef8d499eSDavid van Moolenbroek return ERR_OK;
234*ef8d499eSDavid van Moolenbroek }
235*ef8d499eSDavid van Moolenbroek
236*ef8d499eSDavid van Moolenbroek /*
237*ef8d499eSDavid van Moolenbroek * Create a new loopback device.
238*ef8d499eSDavid van Moolenbroek */
239*ef8d499eSDavid van Moolenbroek static int
loopif_create(const char * name)240*ef8d499eSDavid van Moolenbroek loopif_create(const char * name)
241*ef8d499eSDavid van Moolenbroek {
242*ef8d499eSDavid van Moolenbroek struct loopif *loopif;
243*ef8d499eSDavid van Moolenbroek
244*ef8d499eSDavid van Moolenbroek /* Find a free loopback interface slot, if available. */
245*ef8d499eSDavid van Moolenbroek if (TAILQ_EMPTY(&loopif_freelist))
246*ef8d499eSDavid van Moolenbroek return ENOBUFS;
247*ef8d499eSDavid van Moolenbroek
248*ef8d499eSDavid van Moolenbroek loopif = TAILQ_FIRST(&loopif_freelist);
249*ef8d499eSDavid van Moolenbroek TAILQ_REMOVE(&loopif_freelist, loopif, loopif_next);
250*ef8d499eSDavid van Moolenbroek
251*ef8d499eSDavid van Moolenbroek /* Initialize the loopif structure. */
252*ef8d499eSDavid van Moolenbroek TAILQ_INSERT_HEAD(&loopif_activelist, loopif, loopif_next);
253*ef8d499eSDavid van Moolenbroek
254*ef8d499eSDavid van Moolenbroek loopif->loopif_head = NULL;
255*ef8d499eSDavid van Moolenbroek loopif->loopif_tailp = &loopif->loopif_head;
256*ef8d499eSDavid van Moolenbroek
257*ef8d499eSDavid van Moolenbroek /*
258*ef8d499eSDavid van Moolenbroek * For simplicity and efficiency, we do not prepend the address family
259*ef8d499eSDavid van Moolenbroek * (IPv4/IPv6) to the packet for BPF, which means our loopback devices
260*ef8d499eSDavid van Moolenbroek * are of type DLT_RAW rather than (NetBSD's) DLT_NULL.
261*ef8d499eSDavid van Moolenbroek */
262*ef8d499eSDavid van Moolenbroek ifdev_add(&loopif->loopif_ifdev, name, IFF_LOOPBACK | IFF_MULTICAST,
263*ef8d499eSDavid van Moolenbroek IFT_LOOP, 0 /*hdrlen*/, 0 /*addrlen*/, DLT_RAW, LOOPIF_MAX_MTU,
264*ef8d499eSDavid van Moolenbroek 0 /*nd6flags*/, &loopif_ops);
265*ef8d499eSDavid van Moolenbroek
266*ef8d499eSDavid van Moolenbroek ifdev_update_link(&loopif->loopif_ifdev, LINK_STATE_UP);
267*ef8d499eSDavid van Moolenbroek
268*ef8d499eSDavid van Moolenbroek return OK;
269*ef8d499eSDavid van Moolenbroek }
270*ef8d499eSDavid van Moolenbroek
271*ef8d499eSDavid van Moolenbroek /*
272*ef8d499eSDavid van Moolenbroek * Destroy an existing loopback device.
273*ef8d499eSDavid van Moolenbroek */
274*ef8d499eSDavid van Moolenbroek static int
loopif_destroy(struct ifdev * ifdev)275*ef8d499eSDavid van Moolenbroek loopif_destroy(struct ifdev * ifdev)
276*ef8d499eSDavid van Moolenbroek {
277*ef8d499eSDavid van Moolenbroek struct loopif *loopif = (struct loopif *)ifdev;
278*ef8d499eSDavid van Moolenbroek struct pbuf *pbuf, **pnext;
279*ef8d499eSDavid van Moolenbroek int r;
280*ef8d499eSDavid van Moolenbroek
281*ef8d499eSDavid van Moolenbroek /*
282*ef8d499eSDavid van Moolenbroek * The ifdev module may refuse to remove this interface if it is the
283*ef8d499eSDavid van Moolenbroek * loopback interface used to loop back packets for other interfaces.
284*ef8d499eSDavid van Moolenbroek */
285*ef8d499eSDavid van Moolenbroek if ((r = ifdev_remove(&loopif->loopif_ifdev)) != OK)
286*ef8d499eSDavid van Moolenbroek return r;
287*ef8d499eSDavid van Moolenbroek
288*ef8d499eSDavid van Moolenbroek /*
289*ef8d499eSDavid van Moolenbroek * Clean up. The loopback queue can be non-empty only if we have been
290*ef8d499eSDavid van Moolenbroek * throttling in case of a feedback loop.
291*ef8d499eSDavid van Moolenbroek */
292*ef8d499eSDavid van Moolenbroek while ((pbuf = loopif->loopif_head) != NULL) {
293*ef8d499eSDavid van Moolenbroek pnext = pchain_end(pbuf);
294*ef8d499eSDavid van Moolenbroek
295*ef8d499eSDavid van Moolenbroek if ((loopif->loopif_head = *pnext) == NULL)
296*ef8d499eSDavid van Moolenbroek loopif->loopif_tailp = &loopif->loopif_head;
297*ef8d499eSDavid van Moolenbroek *pnext = NULL;
298*ef8d499eSDavid van Moolenbroek
299*ef8d499eSDavid van Moolenbroek pbuf_free(pbuf);
300*ef8d499eSDavid van Moolenbroek }
301*ef8d499eSDavid van Moolenbroek
302*ef8d499eSDavid van Moolenbroek TAILQ_REMOVE(&loopif_activelist, loopif, loopif_next);
303*ef8d499eSDavid van Moolenbroek
304*ef8d499eSDavid van Moolenbroek TAILQ_INSERT_HEAD(&loopif_freelist, loopif, loopif_next);
305*ef8d499eSDavid van Moolenbroek
306*ef8d499eSDavid van Moolenbroek return OK;
307*ef8d499eSDavid van Moolenbroek }
308*ef8d499eSDavid van Moolenbroek
309*ef8d499eSDavid van Moolenbroek /*
310*ef8d499eSDavid van Moolenbroek * Set NetBSD-style interface flags (IFF_) for a loopback interface.
311*ef8d499eSDavid van Moolenbroek */
312*ef8d499eSDavid van Moolenbroek static int
loopif_set_ifflags(struct ifdev * ifdev,unsigned int ifflags)313*ef8d499eSDavid van Moolenbroek loopif_set_ifflags(struct ifdev * ifdev, unsigned int ifflags)
314*ef8d499eSDavid van Moolenbroek {
315*ef8d499eSDavid van Moolenbroek struct loopif *loopif = (struct loopif *)ifdev;
316*ef8d499eSDavid van Moolenbroek
317*ef8d499eSDavid van Moolenbroek /*
318*ef8d499eSDavid van Moolenbroek * Only the IFF_UP flag may be set and cleared. We adjust the
319*ef8d499eSDavid van Moolenbroek * IFF_RUNNING flag immediately based on this flag. This is a bit
320*ef8d499eSDavid van Moolenbroek * dangerous, but the caller takes this possibility into account.
321*ef8d499eSDavid van Moolenbroek */
322*ef8d499eSDavid van Moolenbroek if ((ifflags & ~IFF_UP) != 0)
323*ef8d499eSDavid van Moolenbroek return EINVAL;
324*ef8d499eSDavid van Moolenbroek
325*ef8d499eSDavid van Moolenbroek if (ifflags & IFF_UP)
326*ef8d499eSDavid van Moolenbroek ifdev_update_ifflags(&loopif->loopif_ifdev,
327*ef8d499eSDavid van Moolenbroek ifdev_get_ifflags(&loopif->loopif_ifdev) | IFF_RUNNING);
328*ef8d499eSDavid van Moolenbroek else
329*ef8d499eSDavid van Moolenbroek ifdev_update_ifflags(&loopif->loopif_ifdev,
330*ef8d499eSDavid van Moolenbroek ifdev_get_ifflags(&loopif->loopif_ifdev) & ~IFF_RUNNING);
331*ef8d499eSDavid van Moolenbroek
332*ef8d499eSDavid van Moolenbroek return OK;
333*ef8d499eSDavid van Moolenbroek }
334*ef8d499eSDavid van Moolenbroek
335*ef8d499eSDavid van Moolenbroek /*
336*ef8d499eSDavid van Moolenbroek * Set the Maximum Transmission Unit for this interface. Return TRUE if the
337*ef8d499eSDavid van Moolenbroek * new value is acceptable, in which case the caller will do the rest. Return
338*ef8d499eSDavid van Moolenbroek * FALSE otherwise.
339*ef8d499eSDavid van Moolenbroek */
340*ef8d499eSDavid van Moolenbroek static int
loopif_set_mtu(struct ifdev * ifdev __unused,unsigned int mtu)341*ef8d499eSDavid van Moolenbroek loopif_set_mtu(struct ifdev * ifdev __unused, unsigned int mtu)
342*ef8d499eSDavid van Moolenbroek {
343*ef8d499eSDavid van Moolenbroek
344*ef8d499eSDavid van Moolenbroek return (mtu <= LOOPIF_MAX_MTU);
345*ef8d499eSDavid van Moolenbroek }
346*ef8d499eSDavid van Moolenbroek
347*ef8d499eSDavid van Moolenbroek static const struct ifdev_ops loopif_ops = {
348*ef8d499eSDavid van Moolenbroek .iop_init = loopif_init_netif,
349*ef8d499eSDavid van Moolenbroek .iop_input = ip_input,
350*ef8d499eSDavid van Moolenbroek .iop_output = loopif_output,
351*ef8d499eSDavid van Moolenbroek .iop_poll = loopif_poll,
352*ef8d499eSDavid van Moolenbroek .iop_set_ifflags = loopif_set_ifflags,
353*ef8d499eSDavid van Moolenbroek .iop_set_mtu = loopif_set_mtu,
354*ef8d499eSDavid van Moolenbroek .iop_destroy = loopif_destroy,
355*ef8d499eSDavid van Moolenbroek };
356*ef8d499eSDavid van Moolenbroek
357*ef8d499eSDavid van Moolenbroek /*
358*ef8d499eSDavid van Moolenbroek * Set and/or retrieve a per-protocol loopback checksumming option through
359*ef8d499eSDavid van Moolenbroek * sysctl(7).
360*ef8d499eSDavid van Moolenbroek */
361*ef8d499eSDavid van Moolenbroek ssize_t
loopif_cksum(struct rmib_call * call,struct rmib_node * node __unused,struct rmib_oldp * oldp,struct rmib_newp * newp)362*ef8d499eSDavid van Moolenbroek loopif_cksum(struct rmib_call * call, struct rmib_node * node __unused,
363*ef8d499eSDavid van Moolenbroek struct rmib_oldp * oldp, struct rmib_newp * newp)
364*ef8d499eSDavid van Moolenbroek {
365*ef8d499eSDavid van Moolenbroek struct loopif *loopif;
366*ef8d499eSDavid van Moolenbroek unsigned int flags;
367*ef8d499eSDavid van Moolenbroek int r, val;
368*ef8d499eSDavid van Moolenbroek
369*ef8d499eSDavid van Moolenbroek /*
370*ef8d499eSDavid van Moolenbroek * The third name field is the protocol. We ignore the domain (the
371*ef8d499eSDavid van Moolenbroek * second field), thus sharing settings between PF_INET and PF_INET6.
372*ef8d499eSDavid van Moolenbroek * This is necessary because lwIP does not support TCP/UDP checksumming
373*ef8d499eSDavid van Moolenbroek * flags on a per-domain basis.
374*ef8d499eSDavid van Moolenbroek */
375*ef8d499eSDavid van Moolenbroek switch (call->call_oname[2]) {
376*ef8d499eSDavid van Moolenbroek case IPPROTO_IP:
377*ef8d499eSDavid van Moolenbroek flags = NETIF_CHECKSUM_GEN_IP | NETIF_CHECKSUM_CHECK_IP;
378*ef8d499eSDavid van Moolenbroek break;
379*ef8d499eSDavid van Moolenbroek case IPPROTO_UDP:
380*ef8d499eSDavid van Moolenbroek flags = NETIF_CHECKSUM_GEN_UDP | NETIF_CHECKSUM_CHECK_UDP;
381*ef8d499eSDavid van Moolenbroek break;
382*ef8d499eSDavid van Moolenbroek case IPPROTO_TCP:
383*ef8d499eSDavid van Moolenbroek flags = NETIF_CHECKSUM_GEN_TCP | NETIF_CHECKSUM_CHECK_TCP;
384*ef8d499eSDavid van Moolenbroek break;
385*ef8d499eSDavid van Moolenbroek default:
386*ef8d499eSDavid van Moolenbroek return EINVAL;
387*ef8d499eSDavid van Moolenbroek }
388*ef8d499eSDavid van Moolenbroek
389*ef8d499eSDavid van Moolenbroek /* Copy out the old (current) checksumming option. */
390*ef8d499eSDavid van Moolenbroek if (oldp != NULL) {
391*ef8d499eSDavid van Moolenbroek val = !!(loopif_cksum_flags & flags);
392*ef8d499eSDavid van Moolenbroek
393*ef8d499eSDavid van Moolenbroek if ((r = rmib_copyout(oldp, 0, &val, sizeof(val))) < 0)
394*ef8d499eSDavid van Moolenbroek return r;
395*ef8d499eSDavid van Moolenbroek }
396*ef8d499eSDavid van Moolenbroek
397*ef8d499eSDavid van Moolenbroek if (newp != NULL) {
398*ef8d499eSDavid van Moolenbroek if ((r = rmib_copyin(newp, &val, sizeof(val))) != OK)
399*ef8d499eSDavid van Moolenbroek return r;
400*ef8d499eSDavid van Moolenbroek
401*ef8d499eSDavid van Moolenbroek if (val)
402*ef8d499eSDavid van Moolenbroek loopif_cksum_flags |= flags;
403*ef8d499eSDavid van Moolenbroek else
404*ef8d499eSDavid van Moolenbroek loopif_cksum_flags &= ~flags;
405*ef8d499eSDavid van Moolenbroek
406*ef8d499eSDavid van Moolenbroek /*
407*ef8d499eSDavid van Moolenbroek * Apply the new checksum flags to all loopback interfaces.
408*ef8d499eSDavid van Moolenbroek * Technically, this may result in dropped packets when
409*ef8d499eSDavid van Moolenbroek * enabling checksumming on a throttled loopif, but that is a
410*ef8d499eSDavid van Moolenbroek * case so rare and unimportant that we ignore it.
411*ef8d499eSDavid van Moolenbroek */
412*ef8d499eSDavid van Moolenbroek TAILQ_FOREACH(loopif, &loopif_activelist, loopif_next) {
413*ef8d499eSDavid van Moolenbroek NETIF_SET_CHECKSUM_CTRL(loopif_get_netif(loopif),
414*ef8d499eSDavid van Moolenbroek loopif_cksum_flags);
415*ef8d499eSDavid van Moolenbroek }
416*ef8d499eSDavid van Moolenbroek }
417*ef8d499eSDavid van Moolenbroek
418*ef8d499eSDavid van Moolenbroek /* Return the length of the node. */
419*ef8d499eSDavid van Moolenbroek return sizeof(val);
420*ef8d499eSDavid van Moolenbroek }
421