1*ef8d499eSDavid van Moolenbroek /* LWIP service - ifdev.c - network interface devices */
2*ef8d499eSDavid van Moolenbroek
3*ef8d499eSDavid van Moolenbroek #include "lwip.h"
4*ef8d499eSDavid van Moolenbroek #include "mcast.h"
5*ef8d499eSDavid van Moolenbroek #include "ifaddr.h"
6*ef8d499eSDavid van Moolenbroek #include "rtsock.h"
7*ef8d499eSDavid van Moolenbroek #include "route.h"
8*ef8d499eSDavid van Moolenbroek #include "bpfdev.h"
9*ef8d499eSDavid van Moolenbroek
10*ef8d499eSDavid van Moolenbroek #include <net/if_media.h>
11*ef8d499eSDavid van Moolenbroek
12*ef8d499eSDavid van Moolenbroek /*
13*ef8d499eSDavid van Moolenbroek * The highest possible interface index number, plus one. We currently let
14*ef8d499eSDavid van Moolenbroek * lwIP choose the interface index. lwIP will generate a number between 1 and
15*ef8d499eSDavid van Moolenbroek * 255 inclusive. For efficiency, we use an array to look up an interface
16*ef8d499eSDavid van Moolenbroek * device object by its index. Thus, this array must be large enough to be
17*ef8d499eSDavid van Moolenbroek * indexed by the largest possible index number generated by lwIP. lwIP uses
18*ef8d499eSDavid van Moolenbroek * an unsigned 8-bit field to store the index number.
19*ef8d499eSDavid van Moolenbroek */
20*ef8d499eSDavid van Moolenbroek #define MAX_IFDEV (UINT8_MAX + 1)
21*ef8d499eSDavid van Moolenbroek
22*ef8d499eSDavid van Moolenbroek /* The table is indexed by the interface index minus one. */
23*ef8d499eSDavid van Moolenbroek static struct ifdev *ifdev_table[MAX_IFDEV]; /* index-based lookup table */
24*ef8d499eSDavid van Moolenbroek
25*ef8d499eSDavid van Moolenbroek static TAILQ_HEAD(, ifdev) ifdev_list; /* list of active interfaces */
26*ef8d499eSDavid van Moolenbroek
27*ef8d499eSDavid van Moolenbroek static struct ifdev *ifdev_loopback; /* loopback interface */
28*ef8d499eSDavid van Moolenbroek
29*ef8d499eSDavid van Moolenbroek /*
30*ef8d499eSDavid van Moolenbroek * The maximum number of virtual interface types--that is, interface types for
31*ef8d499eSDavid van Moolenbroek * which interfaces may be created and destroyed dynamically. The BSDs call
32*ef8d499eSDavid van Moolenbroek * these "clones". There should be enough slots for all types, which are
33*ef8d499eSDavid van Moolenbroek * registered by their respective modules through ifdev_register(). Increase
34*ef8d499eSDavid van Moolenbroek * as necessary.
35*ef8d499eSDavid van Moolenbroek */
36*ef8d499eSDavid van Moolenbroek #define MAX_VTYPE 4
37*ef8d499eSDavid van Moolenbroek
38*ef8d499eSDavid van Moolenbroek static struct {
39*ef8d499eSDavid van Moolenbroek const char *ifvt_name; /* interface name without digits (e.g. "lo") */
40*ef8d499eSDavid van Moolenbroek size_t ifvt_namelen; /* length of the name, excluding null term. */
41*ef8d499eSDavid van Moolenbroek int (*ifvt_create)(const char *); /* ifdev create function */
42*ef8d499eSDavid van Moolenbroek } ifdev_vtype[MAX_VTYPE];
43*ef8d499eSDavid van Moolenbroek
44*ef8d499eSDavid van Moolenbroek static unsigned int ifdev_vtypes; /* number of in-use vtype slots */
45*ef8d499eSDavid van Moolenbroek
46*ef8d499eSDavid van Moolenbroek #define IFDEV_MIN_MTU 1280 /* minimum interface MTU, required by IPv6 */
47*ef8d499eSDavid van Moolenbroek
48*ef8d499eSDavid van Moolenbroek /*
49*ef8d499eSDavid van Moolenbroek * Initialize the network interface devices module. This call must be issued
50*ef8d499eSDavid van Moolenbroek * before any virtual interfaces are initialized, because the virtual types
51*ef8d499eSDavid van Moolenbroek * array is initialized here.
52*ef8d499eSDavid van Moolenbroek */
53*ef8d499eSDavid van Moolenbroek void
ifdev_init(void)54*ef8d499eSDavid van Moolenbroek ifdev_init(void)
55*ef8d499eSDavid van Moolenbroek {
56*ef8d499eSDavid van Moolenbroek
57*ef8d499eSDavid van Moolenbroek memset(ifdev_table, 0, sizeof(ifdev_table));
58*ef8d499eSDavid van Moolenbroek
59*ef8d499eSDavid van Moolenbroek TAILQ_INIT(&ifdev_list);
60*ef8d499eSDavid van Moolenbroek
61*ef8d499eSDavid van Moolenbroek memset(ifdev_vtype, 0, sizeof(ifdev_vtype));
62*ef8d499eSDavid van Moolenbroek ifdev_vtypes = 0;
63*ef8d499eSDavid van Moolenbroek }
64*ef8d499eSDavid van Moolenbroek
65*ef8d499eSDavid van Moolenbroek /*
66*ef8d499eSDavid van Moolenbroek * Check all active interfaces to see if any tasks need to be performed. This
67*ef8d499eSDavid van Moolenbroek * function is called as part of each message loop iteration.
68*ef8d499eSDavid van Moolenbroek */
69*ef8d499eSDavid van Moolenbroek void
ifdev_poll(void)70*ef8d499eSDavid van Moolenbroek ifdev_poll(void)
71*ef8d499eSDavid van Moolenbroek {
72*ef8d499eSDavid van Moolenbroek struct ifdev *ifdev;
73*ef8d499eSDavid van Moolenbroek
74*ef8d499eSDavid van Moolenbroek /*
75*ef8d499eSDavid van Moolenbroek * Call the polling function of the active interfaces. Note that
76*ef8d499eSDavid van Moolenbroek * interfaces may not remove themselves as a result of polling!
77*ef8d499eSDavid van Moolenbroek */
78*ef8d499eSDavid van Moolenbroek TAILQ_FOREACH(ifdev, &ifdev_list, ifdev_next) {
79*ef8d499eSDavid van Moolenbroek if (ifdev->ifdev_ops->iop_poll != NULL)
80*ef8d499eSDavid van Moolenbroek ifdev->ifdev_ops->iop_poll(ifdev);
81*ef8d499eSDavid van Moolenbroek }
82*ef8d499eSDavid van Moolenbroek }
83*ef8d499eSDavid van Moolenbroek
84*ef8d499eSDavid van Moolenbroek /*
85*ef8d499eSDavid van Moolenbroek * Handle an incoming packet on an interface. This function assumes ownership
86*ef8d499eSDavid van Moolenbroek * of the packet buffers: the caller must no longer refer to it afterward. For
87*ef8d499eSDavid van Moolenbroek * packets looped back for a non-loopback interface, 'ifdev' is the loopback
88*ef8d499eSDavid van Moolenbroek * interface and 'netif' is the original (non-loopback) interface's netif. For
89*ef8d499eSDavid van Moolenbroek * other packets, 'ifdev' is the actual interface and 'netif' is NULL. The
90*ef8d499eSDavid van Moolenbroek * packet is passed to BPF devices only if 'to_bpf' is set.
91*ef8d499eSDavid van Moolenbroek */
92*ef8d499eSDavid van Moolenbroek void
ifdev_input(struct ifdev * ifdev,struct pbuf * pbuf,struct netif * netif,int to_bpf)93*ef8d499eSDavid van Moolenbroek ifdev_input(struct ifdev * ifdev, struct pbuf * pbuf, struct netif * netif,
94*ef8d499eSDavid van Moolenbroek int to_bpf)
95*ef8d499eSDavid van Moolenbroek {
96*ef8d499eSDavid van Moolenbroek struct bpfdev_link *bpfl;
97*ef8d499eSDavid van Moolenbroek err_t err;
98*ef8d499eSDavid van Moolenbroek
99*ef8d499eSDavid van Moolenbroek /*
100*ef8d499eSDavid van Moolenbroek * Looped-back packets are captured on the loopback device, not on the
101*ef8d499eSDavid van Moolenbroek * original interface. Similarly, we account the traffic to the
102*ef8d499eSDavid van Moolenbroek * loopback interface. This is a policy decision (inspired by NetBSD's
103*ef8d499eSDavid van Moolenbroek * behavior) and may be changed later.
104*ef8d499eSDavid van Moolenbroek */
105*ef8d499eSDavid van Moolenbroek if (to_bpf) {
106*ef8d499eSDavid van Moolenbroek TAILQ_FOREACH(bpfl, &ifdev->ifdev_bpf, bpfl_next)
107*ef8d499eSDavid van Moolenbroek bpfdev_input(bpfl, pbuf);
108*ef8d499eSDavid van Moolenbroek }
109*ef8d499eSDavid van Moolenbroek
110*ef8d499eSDavid van Moolenbroek ifdev->ifdev_data.ifi_ipackets++;
111*ef8d499eSDavid van Moolenbroek ifdev->ifdev_data.ifi_ibytes += pbuf->tot_len;
112*ef8d499eSDavid van Moolenbroek
113*ef8d499eSDavid van Moolenbroek if (pbuf->flags & PBUF_FLAG_LLMCAST)
114*ef8d499eSDavid van Moolenbroek ifdev->ifdev_data.ifi_imcasts++;
115*ef8d499eSDavid van Moolenbroek
116*ef8d499eSDavid van Moolenbroek /*
117*ef8d499eSDavid van Moolenbroek * For looped-back packets, we must bypass the regular netif input
118*ef8d499eSDavid van Moolenbroek * function (as that one is for link-layer packet handling) and instead
119*ef8d499eSDavid van Moolenbroek * pass it directly to the IP-layer packet handling function of lwIP.
120*ef8d499eSDavid van Moolenbroek */
121*ef8d499eSDavid van Moolenbroek if (netif != NULL)
122*ef8d499eSDavid van Moolenbroek err = ip_input(pbuf, netif);
123*ef8d499eSDavid van Moolenbroek else
124*ef8d499eSDavid van Moolenbroek err = ifdev->ifdev_netif.input(pbuf, &ifdev->ifdev_netif);
125*ef8d499eSDavid van Moolenbroek
126*ef8d499eSDavid van Moolenbroek if (err != ERR_OK)
127*ef8d499eSDavid van Moolenbroek pbuf_free(pbuf);
128*ef8d499eSDavid van Moolenbroek }
129*ef8d499eSDavid van Moolenbroek
130*ef8d499eSDavid van Moolenbroek /*
131*ef8d499eSDavid van Moolenbroek * Handle an outgoing packet on an interface. Return ERR_OK if the packet was
132*ef8d499eSDavid van Moolenbroek * transmitted or another lwIP ERR_ error code upon failure. Either way, the
133*ef8d499eSDavid van Moolenbroek * caller is responsible for freeing the packet buffers. If the packet is
134*ef8d499eSDavid van Moolenbroek * to be looped back to a non-loopback interface (because its destination is a
135*ef8d499eSDavid van Moolenbroek * local address), 'ifdev' is the loopback interface and 'netif' is set to the
136*ef8d499eSDavid van Moolenbroek * original interface's netif. In all other cases, 'ifdev' is the packet's
137*ef8d499eSDavid van Moolenbroek * source interface and 'netif' is NULL. The packet is passed to attached BPF
138*ef8d499eSDavid van Moolenbroek * devices only if 'to_bpf' is set. If 'hdrcmplt' is set, the source address
139*ef8d499eSDavid van Moolenbroek * of the data link header is already filled in; otherwise, the source address
140*ef8d499eSDavid van Moolenbroek * must be set to the device's source address, if applicable.
141*ef8d499eSDavid van Moolenbroek */
142*ef8d499eSDavid van Moolenbroek err_t
ifdev_output(struct ifdev * ifdev,struct pbuf * pbuf,struct netif * netif,int to_bpf,int hdrcmplt)143*ef8d499eSDavid van Moolenbroek ifdev_output(struct ifdev * ifdev, struct pbuf * pbuf, struct netif * netif,
144*ef8d499eSDavid van Moolenbroek int to_bpf, int hdrcmplt)
145*ef8d499eSDavid van Moolenbroek {
146*ef8d499eSDavid van Moolenbroek struct bpfdev_link *bpfl;
147*ef8d499eSDavid van Moolenbroek
148*ef8d499eSDavid van Moolenbroek /*
149*ef8d499eSDavid van Moolenbroek * If the interface and/or the link is down, discard the packet without
150*ef8d499eSDavid van Moolenbroek * reporting it to BPF or the actual interface module.
151*ef8d499eSDavid van Moolenbroek */
152*ef8d499eSDavid van Moolenbroek if (!ifdev_is_up(ifdev) || !ifdev_is_link_up(ifdev))
153*ef8d499eSDavid van Moolenbroek return ERR_IF; /* this should translate to ENETDOWN */
154*ef8d499eSDavid van Moolenbroek
155*ef8d499eSDavid van Moolenbroek /*
156*ef8d499eSDavid van Moolenbroek * If the link-layer header is not yet complete, fill in the source
157*ef8d499eSDavid van Moolenbroek * address now. This exception applies to BPF-generated packets only.
158*ef8d499eSDavid van Moolenbroek * Complete the header before passing the packet back to BPF, which
159*ef8d499eSDavid van Moolenbroek * should see the completed version of the packet.
160*ef8d499eSDavid van Moolenbroek */
161*ef8d499eSDavid van Moolenbroek if (!hdrcmplt && ifdev->ifdev_ops->iop_hdrcmplt != NULL)
162*ef8d499eSDavid van Moolenbroek ifdev->ifdev_ops->iop_hdrcmplt(ifdev, pbuf);
163*ef8d499eSDavid van Moolenbroek
164*ef8d499eSDavid van Moolenbroek /*
165*ef8d499eSDavid van Moolenbroek * As in ifdev_input(), we use the loopback interface for BPF and
166*ef8d499eSDavid van Moolenbroek * statistics even if the packet originates from a non-loopback device.
167*ef8d499eSDavid van Moolenbroek */
168*ef8d499eSDavid van Moolenbroek if (to_bpf) {
169*ef8d499eSDavid van Moolenbroek TAILQ_FOREACH(bpfl, &ifdev->ifdev_bpf, bpfl_next)
170*ef8d499eSDavid van Moolenbroek bpfdev_output(bpfl, pbuf);
171*ef8d499eSDavid van Moolenbroek }
172*ef8d499eSDavid van Moolenbroek
173*ef8d499eSDavid van Moolenbroek ifdev->ifdev_data.ifi_opackets++;
174*ef8d499eSDavid van Moolenbroek ifdev->ifdev_data.ifi_obytes += pbuf->tot_len;
175*ef8d499eSDavid van Moolenbroek
176*ef8d499eSDavid van Moolenbroek /*
177*ef8d499eSDavid van Moolenbroek * TODO: this is rather imprecise, because it works only when we set
178*ef8d499eSDavid van Moolenbroek * the pbuf flag explicitly ourselves. That happens only for UDP/RAW
179*ef8d499eSDavid van Moolenbroek * packets, and not for (e.g.) ND6 multicast traffic. We have reasons
180*ef8d499eSDavid van Moolenbroek * to set the flags ourselves anyway, namely to support MSG_MCAST and
181*ef8d499eSDavid van Moolenbroek * MSG_BCAST on loopback interfaces, but they should be complemented by
182*ef8d499eSDavid van Moolenbroek * additional checks here on, say, the destination ethernet address.
183*ef8d499eSDavid van Moolenbroek */
184*ef8d499eSDavid van Moolenbroek if (pbuf->flags & PBUF_FLAG_LLMCAST)
185*ef8d499eSDavid van Moolenbroek ifdev->ifdev_data.ifi_omcasts++;
186*ef8d499eSDavid van Moolenbroek
187*ef8d499eSDavid van Moolenbroek return ifdev->ifdev_ops->iop_output(ifdev, pbuf, netif);
188*ef8d499eSDavid van Moolenbroek }
189*ef8d499eSDavid van Moolenbroek
190*ef8d499eSDavid van Moolenbroek /*
191*ef8d499eSDavid van Moolenbroek * Transmit an IPv4 packet on an interface, as requested by lwIP. Pass on the
192*ef8d499eSDavid van Moolenbroek * packet to the interface's link processor (e.g., etharp), unless the packet
193*ef8d499eSDavid van Moolenbroek * should be rejected or blackholed according to route information, or it is to
194*ef8d499eSDavid van Moolenbroek * be looped back into the interface. The latter may occur if the destination
195*ef8d499eSDavid van Moolenbroek * address belongs to the interface. In that case, we send the packet over a
196*ef8d499eSDavid van Moolenbroek * loopback interface instead. In addition, if this is a multicast packet that
197*ef8d499eSDavid van Moolenbroek * should be looped back, send a copy over a loopback interface as well.
198*ef8d499eSDavid van Moolenbroek * Loopback interfaces themselves are exempt from these special cases.
199*ef8d499eSDavid van Moolenbroek */
200*ef8d499eSDavid van Moolenbroek static err_t
ifdev_output_v4(struct netif * netif,struct pbuf * pbuf,const ip4_addr_t * ipaddr)201*ef8d499eSDavid van Moolenbroek ifdev_output_v4(struct netif * netif, struct pbuf * pbuf,
202*ef8d499eSDavid van Moolenbroek const ip4_addr_t * ipaddr)
203*ef8d499eSDavid van Moolenbroek {
204*ef8d499eSDavid van Moolenbroek struct ifdev *ifdev = netif_get_ifdev(netif);
205*ef8d499eSDavid van Moolenbroek err_t err;
206*ef8d499eSDavid van Moolenbroek
207*ef8d499eSDavid van Moolenbroek assert(ifdev_loopback != NULL);
208*ef8d499eSDavid van Moolenbroek
209*ef8d499eSDavid van Moolenbroek /* Check for reject/blackhole routes. */
210*ef8d499eSDavid van Moolenbroek if (!route_output_v4(ifdev, ipaddr, &err))
211*ef8d499eSDavid van Moolenbroek return err;
212*ef8d499eSDavid van Moolenbroek
213*ef8d499eSDavid van Moolenbroek /* Handle looping of multicast packets on non-loopback interfaces. */
214*ef8d499eSDavid van Moolenbroek if (!ifdev_is_loopback(ifdev) && (pbuf->flags & PBUF_FLAG_MCASTLOOP))
215*ef8d499eSDavid van Moolenbroek (void)ifdev_output(ifdev_loopback, pbuf, netif,
216*ef8d499eSDavid van Moolenbroek FALSE /*to_bpf*/, TRUE /*hdrcmplt*/);
217*ef8d499eSDavid van Moolenbroek
218*ef8d499eSDavid van Moolenbroek /* Divert packets sent to the local interface address. */
219*ef8d499eSDavid van Moolenbroek if (!ifdev_is_loopback(ifdev) && ifdev->ifdev_v4set &&
220*ef8d499eSDavid van Moolenbroek ip4_addr_cmp(netif_ip4_addr(&ifdev->ifdev_netif), ipaddr))
221*ef8d499eSDavid van Moolenbroek ifdev = ifdev_loopback;
222*ef8d499eSDavid van Moolenbroek else
223*ef8d499eSDavid van Moolenbroek netif = NULL;
224*ef8d499eSDavid van Moolenbroek
225*ef8d499eSDavid van Moolenbroek if (ifdev->ifdev_ops->iop_output_v4 != NULL)
226*ef8d499eSDavid van Moolenbroek return ifdev->ifdev_ops->iop_output_v4(ifdev_get_netif(ifdev),
227*ef8d499eSDavid van Moolenbroek pbuf, ipaddr);
228*ef8d499eSDavid van Moolenbroek else
229*ef8d499eSDavid van Moolenbroek return ifdev_output(ifdev, pbuf, netif, TRUE /*to_bpf*/,
230*ef8d499eSDavid van Moolenbroek TRUE /*hdrcmplt*/);
231*ef8d499eSDavid van Moolenbroek }
232*ef8d499eSDavid van Moolenbroek
233*ef8d499eSDavid van Moolenbroek /*
234*ef8d499eSDavid van Moolenbroek * Transmit an IPv6 packet on an interface, as requested by lwIP. As for IPv4.
235*ef8d499eSDavid van Moolenbroek */
236*ef8d499eSDavid van Moolenbroek static err_t
ifdev_output_v6(struct netif * netif,struct pbuf * pbuf,const ip6_addr_t * ipaddr)237*ef8d499eSDavid van Moolenbroek ifdev_output_v6(struct netif * netif, struct pbuf * pbuf,
238*ef8d499eSDavid van Moolenbroek const ip6_addr_t * ipaddr)
239*ef8d499eSDavid van Moolenbroek {
240*ef8d499eSDavid van Moolenbroek struct ifdev *ifdev = netif_get_ifdev(netif);
241*ef8d499eSDavid van Moolenbroek err_t err;
242*ef8d499eSDavid van Moolenbroek
243*ef8d499eSDavid van Moolenbroek assert(ifdev_loopback != NULL);
244*ef8d499eSDavid van Moolenbroek
245*ef8d499eSDavid van Moolenbroek /* Check for reject/blackhole routes. */
246*ef8d499eSDavid van Moolenbroek if (!route_output_v6(ifdev, ipaddr, &err))
247*ef8d499eSDavid van Moolenbroek return err;
248*ef8d499eSDavid van Moolenbroek
249*ef8d499eSDavid van Moolenbroek /* Handle looping of multicast packets on non-loopback interfaces. */
250*ef8d499eSDavid van Moolenbroek if (!ifdev_is_loopback(ifdev) && (pbuf->flags & PBUF_FLAG_MCASTLOOP))
251*ef8d499eSDavid van Moolenbroek (void)ifdev_output(ifdev_loopback, pbuf, netif,
252*ef8d499eSDavid van Moolenbroek FALSE /*to_bpf*/, TRUE /*hdrcmplt*/);
253*ef8d499eSDavid van Moolenbroek
254*ef8d499eSDavid van Moolenbroek /* Divert packets sent to the local interface address. */
255*ef8d499eSDavid van Moolenbroek if (!ifdev_is_loopback(ifdev) &&
256*ef8d499eSDavid van Moolenbroek (netif_get_ip6_addr_match(&ifdev->ifdev_netif, ipaddr) != -1 ||
257*ef8d499eSDavid van Moolenbroek ip6_addr_ismulticast_iflocal(ipaddr)))
258*ef8d499eSDavid van Moolenbroek ifdev = ifdev_loopback;
259*ef8d499eSDavid van Moolenbroek else
260*ef8d499eSDavid van Moolenbroek netif = NULL;
261*ef8d499eSDavid van Moolenbroek
262*ef8d499eSDavid van Moolenbroek if (ifdev->ifdev_ops->iop_output_v6 != NULL)
263*ef8d499eSDavid van Moolenbroek return ifdev->ifdev_ops->iop_output_v6(ifdev_get_netif(ifdev),
264*ef8d499eSDavid van Moolenbroek pbuf, ipaddr);
265*ef8d499eSDavid van Moolenbroek else
266*ef8d499eSDavid van Moolenbroek return ifdev_output(ifdev, pbuf, netif, TRUE /*to_bpf*/,
267*ef8d499eSDavid van Moolenbroek TRUE /*hdrcmplt*/);
268*ef8d499eSDavid van Moolenbroek }
269*ef8d499eSDavid van Moolenbroek
270*ef8d499eSDavid van Moolenbroek /*
271*ef8d499eSDavid van Moolenbroek * Status callback function, called by lwIP whenever certain status changes are
272*ef8d499eSDavid van Moolenbroek * made on the netif. These changes may be initiated either by lwIP itself or
273*ef8d499eSDavid van Moolenbroek * by us. We use this callback to check lwIP-initiated state changes on local
274*ef8d499eSDavid van Moolenbroek * IPv6 addresses, using shadow state to filter out self-initiated changes.
275*ef8d499eSDavid van Moolenbroek *
276*ef8d499eSDavid van Moolenbroek * One day we might switch to the extended netif callback mechanism offered by
277*ef8d499eSDavid van Moolenbroek * lwIP. Currently, netif state changes are rare and it takes us little effort
278*ef8d499eSDavid van Moolenbroek * to find out whether anything changed, so there is no immediate need.
279*ef8d499eSDavid van Moolenbroek */
280*ef8d499eSDavid van Moolenbroek static void
ifdev_status_callback(struct netif * netif)281*ef8d499eSDavid van Moolenbroek ifdev_status_callback(struct netif * netif)
282*ef8d499eSDavid van Moolenbroek {
283*ef8d499eSDavid van Moolenbroek struct ifdev *ifdev = netif_get_ifdev(netif);
284*ef8d499eSDavid van Moolenbroek
285*ef8d499eSDavid van Moolenbroek ifaddr_v6_check(ifdev);
286*ef8d499eSDavid van Moolenbroek }
287*ef8d499eSDavid van Moolenbroek
288*ef8d499eSDavid van Moolenbroek /*
289*ef8d499eSDavid van Moolenbroek * Initialize the netif structure for a new interface. Most of this is handled
290*ef8d499eSDavid van Moolenbroek * by the specific interface module.
291*ef8d499eSDavid van Moolenbroek */
292*ef8d499eSDavid van Moolenbroek static err_t
ifdev_init_netif(struct netif * netif)293*ef8d499eSDavid van Moolenbroek ifdev_init_netif(struct netif * netif)
294*ef8d499eSDavid van Moolenbroek {
295*ef8d499eSDavid van Moolenbroek struct ifdev *ifdev = netif_get_ifdev(netif);
296*ef8d499eSDavid van Moolenbroek
297*ef8d499eSDavid van Moolenbroek assert(ifdev != NULL);
298*ef8d499eSDavid van Moolenbroek
299*ef8d499eSDavid van Moolenbroek netif->output = ifdev_output_v4;
300*ef8d499eSDavid van Moolenbroek netif->output_ip6 = ifdev_output_v6;
301*ef8d499eSDavid van Moolenbroek
302*ef8d499eSDavid van Moolenbroek netif->hwaddr_len = ifdev->ifdev_data.ifi_addrlen;
303*ef8d499eSDavid van Moolenbroek netif->mtu = ifdev->ifdev_data.ifi_mtu;
304*ef8d499eSDavid van Moolenbroek
305*ef8d499eSDavid van Moolenbroek netif_set_status_callback(netif, ifdev_status_callback);
306*ef8d499eSDavid van Moolenbroek
307*ef8d499eSDavid van Moolenbroek return ifdev->ifdev_ops->iop_init(ifdev, netif);
308*ef8d499eSDavid van Moolenbroek }
309*ef8d499eSDavid van Moolenbroek
310*ef8d499eSDavid van Moolenbroek /*
311*ef8d499eSDavid van Moolenbroek * Retrieve an interface device by its interface index. Return a pointer to
312*ef8d499eSDavid van Moolenbroek * the interface device if found, or NULL otherwise. If the given interface
313*ef8d499eSDavid van Moolenbroek * index is zero, this function will always return NULL.
314*ef8d499eSDavid van Moolenbroek */
315*ef8d499eSDavid van Moolenbroek struct ifdev *
ifdev_get_by_index(uint32_t ifindex)316*ef8d499eSDavid van Moolenbroek ifdev_get_by_index(uint32_t ifindex)
317*ef8d499eSDavid van Moolenbroek {
318*ef8d499eSDavid van Moolenbroek
319*ef8d499eSDavid van Moolenbroek if (ifindex >= __arraycount(ifdev_table))
320*ef8d499eSDavid van Moolenbroek return NULL;
321*ef8d499eSDavid van Moolenbroek
322*ef8d499eSDavid van Moolenbroek return ifdev_table[ifindex];
323*ef8d499eSDavid van Moolenbroek }
324*ef8d499eSDavid van Moolenbroek
325*ef8d499eSDavid van Moolenbroek /*
326*ef8d499eSDavid van Moolenbroek * Find an interface device by its name. Return a pointer to the interface
327*ef8d499eSDavid van Moolenbroek * device if found, or NULL otherwise.
328*ef8d499eSDavid van Moolenbroek */
329*ef8d499eSDavid van Moolenbroek struct ifdev *
ifdev_find_by_name(const char * name)330*ef8d499eSDavid van Moolenbroek ifdev_find_by_name(const char * name)
331*ef8d499eSDavid van Moolenbroek {
332*ef8d499eSDavid van Moolenbroek struct ifdev *ifdev;
333*ef8d499eSDavid van Moolenbroek
334*ef8d499eSDavid van Moolenbroek TAILQ_FOREACH(ifdev, &ifdev_list, ifdev_next) {
335*ef8d499eSDavid van Moolenbroek if (!strcmp(ifdev->ifdev_name, name))
336*ef8d499eSDavid van Moolenbroek return ifdev;
337*ef8d499eSDavid van Moolenbroek }
338*ef8d499eSDavid van Moolenbroek
339*ef8d499eSDavid van Moolenbroek return NULL;
340*ef8d499eSDavid van Moolenbroek }
341*ef8d499eSDavid van Moolenbroek
342*ef8d499eSDavid van Moolenbroek /*
343*ef8d499eSDavid van Moolenbroek * Given either NULL or a previously returned interface device object pointer,
344*ef8d499eSDavid van Moolenbroek * return the first or next interface device object pointer, or NULL if there
345*ef8d499eSDavid van Moolenbroek * are no more.
346*ef8d499eSDavid van Moolenbroek */
347*ef8d499eSDavid van Moolenbroek struct ifdev *
ifdev_enum(struct ifdev * last)348*ef8d499eSDavid van Moolenbroek ifdev_enum(struct ifdev * last)
349*ef8d499eSDavid van Moolenbroek {
350*ef8d499eSDavid van Moolenbroek
351*ef8d499eSDavid van Moolenbroek if (last == NULL)
352*ef8d499eSDavid van Moolenbroek return TAILQ_FIRST(&ifdev_list);
353*ef8d499eSDavid van Moolenbroek else
354*ef8d499eSDavid van Moolenbroek return TAILQ_NEXT(last, ifdev_next);
355*ef8d499eSDavid van Moolenbroek }
356*ef8d499eSDavid van Moolenbroek
357*ef8d499eSDavid van Moolenbroek /*
358*ef8d499eSDavid van Moolenbroek * Attach a BPF device as listener to this interface.
359*ef8d499eSDavid van Moolenbroek */
360*ef8d499eSDavid van Moolenbroek void
ifdev_attach_bpf(struct ifdev * ifdev,struct bpfdev_link * bpfl)361*ef8d499eSDavid van Moolenbroek ifdev_attach_bpf(struct ifdev * ifdev, struct bpfdev_link * bpfl)
362*ef8d499eSDavid van Moolenbroek {
363*ef8d499eSDavid van Moolenbroek
364*ef8d499eSDavid van Moolenbroek TAILQ_INSERT_TAIL(&ifdev->ifdev_bpf, bpfl, bpfl_next);
365*ef8d499eSDavid van Moolenbroek }
366*ef8d499eSDavid van Moolenbroek
367*ef8d499eSDavid van Moolenbroek /*
368*ef8d499eSDavid van Moolenbroek * Detach a previously attached BPF device from this interface.
369*ef8d499eSDavid van Moolenbroek */
370*ef8d499eSDavid van Moolenbroek void
ifdev_detach_bpf(struct ifdev * ifdev,struct bpfdev_link * bpfl)371*ef8d499eSDavid van Moolenbroek ifdev_detach_bpf(struct ifdev * ifdev, struct bpfdev_link * bpfl)
372*ef8d499eSDavid van Moolenbroek {
373*ef8d499eSDavid van Moolenbroek
374*ef8d499eSDavid van Moolenbroek TAILQ_REMOVE(&ifdev->ifdev_bpf, bpfl, bpfl_next);
375*ef8d499eSDavid van Moolenbroek }
376*ef8d499eSDavid van Moolenbroek
377*ef8d499eSDavid van Moolenbroek /*
378*ef8d499eSDavid van Moolenbroek * Register the calling party as interested in putting the interface in
379*ef8d499eSDavid van Moolenbroek * promiscuous mode. There may be multiple such parties, each of which can
380*ef8d499eSDavid van Moolenbroek * call this function once, after which they must call ifdev_clear_promisc()
381*ef8d499eSDavid van Moolenbroek * later. If possible, the interface is put in promiscuous mode if there is at
382*ef8d499eSDavid van Moolenbroek * least one interested party. Return TRUE on success, or FALSE on failure.
383*ef8d499eSDavid van Moolenbroek */
384*ef8d499eSDavid van Moolenbroek int
ifdev_set_promisc(struct ifdev * ifdev)385*ef8d499eSDavid van Moolenbroek ifdev_set_promisc(struct ifdev * ifdev)
386*ef8d499eSDavid van Moolenbroek {
387*ef8d499eSDavid van Moolenbroek
388*ef8d499eSDavid van Moolenbroek /*
389*ef8d499eSDavid van Moolenbroek * A bit silly, but we want to retain the ability to fail this call for
390*ef8d499eSDavid van Moolenbroek * other reasons in the future, with BPF handling that case properly.
391*ef8d499eSDavid van Moolenbroek */
392*ef8d499eSDavid van Moolenbroek if (ifdev->ifdev_promisc == UINT_MAX)
393*ef8d499eSDavid van Moolenbroek return FALSE;
394*ef8d499eSDavid van Moolenbroek
395*ef8d499eSDavid van Moolenbroek if (ifdev->ifdev_promisc++ == 0) {
396*ef8d499eSDavid van Moolenbroek ifdev_update_ifflags(ifdev,
397*ef8d499eSDavid van Moolenbroek ifdev->ifdev_ifflags | IFF_PROMISC);
398*ef8d499eSDavid van Moolenbroek
399*ef8d499eSDavid van Moolenbroek if (ifdev->ifdev_ops->iop_set_promisc != NULL)
400*ef8d499eSDavid van Moolenbroek ifdev->ifdev_ops->iop_set_promisc(ifdev, TRUE);
401*ef8d499eSDavid van Moolenbroek }
402*ef8d499eSDavid van Moolenbroek
403*ef8d499eSDavid van Moolenbroek return TRUE;
404*ef8d499eSDavid van Moolenbroek }
405*ef8d499eSDavid van Moolenbroek
406*ef8d499eSDavid van Moolenbroek /*
407*ef8d499eSDavid van Moolenbroek * Deregister a previously registered party interested in putting the interface
408*ef8d499eSDavid van Moolenbroek * in promiscuous mode. Once the last party deregisters, the device is pulled
409*ef8d499eSDavid van Moolenbroek * out of promiscuous mode.
410*ef8d499eSDavid van Moolenbroek */
411*ef8d499eSDavid van Moolenbroek void
ifdev_clear_promisc(struct ifdev * ifdev)412*ef8d499eSDavid van Moolenbroek ifdev_clear_promisc(struct ifdev * ifdev)
413*ef8d499eSDavid van Moolenbroek {
414*ef8d499eSDavid van Moolenbroek
415*ef8d499eSDavid van Moolenbroek assert(ifdev->ifdev_promisc > 0);
416*ef8d499eSDavid van Moolenbroek
417*ef8d499eSDavid van Moolenbroek if (--ifdev->ifdev_promisc == 0) {
418*ef8d499eSDavid van Moolenbroek if (ifdev->ifdev_ops->iop_set_promisc != NULL)
419*ef8d499eSDavid van Moolenbroek ifdev->ifdev_ops->iop_set_promisc(ifdev, FALSE);
420*ef8d499eSDavid van Moolenbroek
421*ef8d499eSDavid van Moolenbroek ifdev_update_ifflags(ifdev,
422*ef8d499eSDavid van Moolenbroek ifdev->ifdev_ifflags & ~IFF_PROMISC);
423*ef8d499eSDavid van Moolenbroek }
424*ef8d499eSDavid van Moolenbroek }
425*ef8d499eSDavid van Moolenbroek
426*ef8d499eSDavid van Moolenbroek /*
427*ef8d499eSDavid van Moolenbroek * Set NetBSD-style interface flags (IFF_) for an interface.
428*ef8d499eSDavid van Moolenbroek */
429*ef8d499eSDavid van Moolenbroek int
ifdev_set_ifflags(struct ifdev * ifdev,unsigned int ifflags)430*ef8d499eSDavid van Moolenbroek ifdev_set_ifflags(struct ifdev * ifdev, unsigned int ifflags)
431*ef8d499eSDavid van Moolenbroek {
432*ef8d499eSDavid van Moolenbroek int r;
433*ef8d499eSDavid van Moolenbroek
434*ef8d499eSDavid van Moolenbroek /* Check and update only the subset of flags that may be changed. */
435*ef8d499eSDavid van Moolenbroek ifflags &= ~(IFF_CANTCHANGE | IFF_LOOPBACK);
436*ef8d499eSDavid van Moolenbroek
437*ef8d499eSDavid van Moolenbroek /*
438*ef8d499eSDavid van Moolenbroek * Important: the callback function may call ifdev_update_ifflags()
439*ef8d499eSDavid van Moolenbroek * itself immediately, to update read-only flags such as IFF_RUNNING
440*ef8d499eSDavid van Moolenbroek * based on read-write flags such as IFF_UP. So as to make that work..
441*ef8d499eSDavid van Moolenbroek *
442*ef8d499eSDavid van Moolenbroek * 1) this function MUST succeed if the callback function succeeds;
443*ef8d499eSDavid van Moolenbroek * 2) this function MUST NOT make assumptions about the ifdev_ifflags
444*ef8d499eSDavid van Moolenbroek * field across the callback invocation.
445*ef8d499eSDavid van Moolenbroek *
446*ef8d499eSDavid van Moolenbroek * Conversely, the callback function should be aware that the flags
447*ef8d499eSDavid van Moolenbroek * field will still be updated with the flags. In this model, it is
448*ef8d499eSDavid van Moolenbroek * not possible for the callback function to silently change any of the
449*ef8d499eSDavid van Moolenbroek * given flags. If that is ever necessary, API changes are needed.
450*ef8d499eSDavid van Moolenbroek */
451*ef8d499eSDavid van Moolenbroek if ((r = ifdev->ifdev_ops->iop_set_ifflags(ifdev, ifflags)) != OK)
452*ef8d499eSDavid van Moolenbroek return r;
453*ef8d499eSDavid van Moolenbroek
454*ef8d499eSDavid van Moolenbroek /*
455*ef8d499eSDavid van Moolenbroek * On success, merge the updated subset with the subset that may not be
456*ef8d499eSDavid van Moolenbroek * changed.
457*ef8d499eSDavid van Moolenbroek */
458*ef8d499eSDavid van Moolenbroek ifflags |= ifdev->ifdev_ifflags & (IFF_CANTCHANGE | IFF_LOOPBACK);
459*ef8d499eSDavid van Moolenbroek
460*ef8d499eSDavid van Moolenbroek ifdev_update_ifflags(ifdev, ifflags);
461*ef8d499eSDavid van Moolenbroek
462*ef8d499eSDavid van Moolenbroek return OK;
463*ef8d499eSDavid van Moolenbroek }
464*ef8d499eSDavid van Moolenbroek
465*ef8d499eSDavid van Moolenbroek /*
466*ef8d499eSDavid van Moolenbroek * Update NetBSD-style interface flags (IFF_) for an interface, and perform any
467*ef8d499eSDavid van Moolenbroek * required operations as a result of certain flags changing. This function
468*ef8d499eSDavid van Moolenbroek * bypasses all input checks and directly changes the flags field to exactly
469*ef8d499eSDavid van Moolenbroek * the given set of flags.
470*ef8d499eSDavid van Moolenbroek */
471*ef8d499eSDavid van Moolenbroek void
ifdev_update_ifflags(struct ifdev * ifdev,unsigned int ifflags)472*ef8d499eSDavid van Moolenbroek ifdev_update_ifflags(struct ifdev * ifdev, unsigned int ifflags)
473*ef8d499eSDavid van Moolenbroek {
474*ef8d499eSDavid van Moolenbroek struct netif *netif;
475*ef8d499eSDavid van Moolenbroek
476*ef8d499eSDavid van Moolenbroek /*
477*ef8d499eSDavid van Moolenbroek * First update the flags field itself. The new value should be
478*ef8d499eSDavid van Moolenbroek * visible in the routing messages generated below, for example.
479*ef8d499eSDavid van Moolenbroek */
480*ef8d499eSDavid van Moolenbroek ifdev->ifdev_ifflags = ifflags;
481*ef8d499eSDavid van Moolenbroek
482*ef8d499eSDavid van Moolenbroek /*
483*ef8d499eSDavid van Moolenbroek * Then perform operations as a result of the flags field changing.
484*ef8d499eSDavid van Moolenbroek * For now, this is relevant for IFF_UP only.
485*ef8d499eSDavid van Moolenbroek */
486*ef8d499eSDavid van Moolenbroek netif = ifdev_get_netif(ifdev);
487*ef8d499eSDavid van Moolenbroek
488*ef8d499eSDavid van Moolenbroek if ((ifflags & IFF_UP) && !netif_is_up(netif)) {
489*ef8d499eSDavid van Moolenbroek netif_set_up(netif);
490*ef8d499eSDavid van Moolenbroek
491*ef8d499eSDavid van Moolenbroek rtsock_msg_ifinfo(ifdev);
492*ef8d499eSDavid van Moolenbroek
493*ef8d499eSDavid van Moolenbroek /*
494*ef8d499eSDavid van Moolenbroek * Check if all conditions are now met for link-local IPv6
495*ef8d499eSDavid van Moolenbroek * address assignment.
496*ef8d499eSDavid van Moolenbroek */
497*ef8d499eSDavid van Moolenbroek ifaddr_v6_set_linklocal(ifdev);
498*ef8d499eSDavid van Moolenbroek
499*ef8d499eSDavid van Moolenbroek /* See if we should also reset address states now. */
500*ef8d499eSDavid van Moolenbroek if (netif_is_link_up(netif))
501*ef8d499eSDavid van Moolenbroek ifaddr_v6_set_up(ifdev);
502*ef8d499eSDavid van Moolenbroek } else if (!(ifflags & IFF_UP) && netif_is_up(netif)) {
503*ef8d499eSDavid van Moolenbroek netif_set_down(netif);
504*ef8d499eSDavid van Moolenbroek
505*ef8d499eSDavid van Moolenbroek rtsock_msg_ifinfo(ifdev);
506*ef8d499eSDavid van Moolenbroek }
507*ef8d499eSDavid van Moolenbroek }
508*ef8d499eSDavid van Moolenbroek
509*ef8d499eSDavid van Moolenbroek /*
510*ef8d499eSDavid van Moolenbroek * Retrieve NetBSD-style interface capabilities (IFCAP_) for an interface: both
511*ef8d499eSDavid van Moolenbroek * the supported and the enabled capabilities.
512*ef8d499eSDavid van Moolenbroek */
513*ef8d499eSDavid van Moolenbroek void
ifdev_get_ifcap(struct ifdev * ifdev,uint64_t * ifcap,uint64_t * ifena)514*ef8d499eSDavid van Moolenbroek ifdev_get_ifcap(struct ifdev * ifdev, uint64_t * ifcap, uint64_t * ifena)
515*ef8d499eSDavid van Moolenbroek {
516*ef8d499eSDavid van Moolenbroek
517*ef8d499eSDavid van Moolenbroek *ifcap = 0;
518*ef8d499eSDavid van Moolenbroek *ifena = 0;
519*ef8d499eSDavid van Moolenbroek
520*ef8d499eSDavid van Moolenbroek if (ifdev->ifdev_ops->iop_get_ifcap != NULL)
521*ef8d499eSDavid van Moolenbroek ifdev->ifdev_ops->iop_get_ifcap(ifdev, ifcap, ifena);
522*ef8d499eSDavid van Moolenbroek }
523*ef8d499eSDavid van Moolenbroek
524*ef8d499eSDavid van Moolenbroek /*
525*ef8d499eSDavid van Moolenbroek * Set enabled NetBSD-style interface capabilities (IFCAP_) for an interface.
526*ef8d499eSDavid van Moolenbroek */
527*ef8d499eSDavid van Moolenbroek int
ifdev_set_ifcap(struct ifdev * ifdev,uint64_t ifena)528*ef8d499eSDavid van Moolenbroek ifdev_set_ifcap(struct ifdev * ifdev, uint64_t ifena)
529*ef8d499eSDavid van Moolenbroek {
530*ef8d499eSDavid van Moolenbroek
531*ef8d499eSDavid van Moolenbroek if (ifdev->ifdev_ops->iop_set_ifcap != NULL)
532*ef8d499eSDavid van Moolenbroek return ifdev->ifdev_ops->iop_set_ifcap(ifdev, ifena);
533*ef8d499eSDavid van Moolenbroek else
534*ef8d499eSDavid van Moolenbroek return EINVAL;
535*ef8d499eSDavid van Moolenbroek }
536*ef8d499eSDavid van Moolenbroek
537*ef8d499eSDavid van Moolenbroek /*
538*ef8d499eSDavid van Moolenbroek * Retrieve NetBSD-style media type (IFM_) for an interface. Return OK on
539*ef8d499eSDavid van Moolenbroek * success, with the current media type selection stored in 'ifcurrent', the
540*ef8d499eSDavid van Moolenbroek * driver-reported active media type in 'ifactive', and the link status in
541*ef8d499eSDavid van Moolenbroek * 'ifstatus'. Return a negative error code on failure.
542*ef8d499eSDavid van Moolenbroek */
543*ef8d499eSDavid van Moolenbroek int
ifdev_get_ifmedia(struct ifdev * ifdev,int * ifcurrent,int * ifactive)544*ef8d499eSDavid van Moolenbroek ifdev_get_ifmedia(struct ifdev * ifdev, int * ifcurrent, int * ifactive)
545*ef8d499eSDavid van Moolenbroek {
546*ef8d499eSDavid van Moolenbroek
547*ef8d499eSDavid van Moolenbroek if (ifdev->ifdev_ops->iop_get_ifmedia == NULL)
548*ef8d499eSDavid van Moolenbroek return ENOTTY;
549*ef8d499eSDavid van Moolenbroek
550*ef8d499eSDavid van Moolenbroek ifdev->ifdev_ops->iop_get_ifmedia(ifdev, ifcurrent, ifactive);
551*ef8d499eSDavid van Moolenbroek
552*ef8d499eSDavid van Moolenbroek return OK;
553*ef8d499eSDavid van Moolenbroek }
554*ef8d499eSDavid van Moolenbroek
555*ef8d499eSDavid van Moolenbroek /*
556*ef8d499eSDavid van Moolenbroek * Set NetBSD-style media type (IFM_) for an interface. Return OK on success,
557*ef8d499eSDavid van Moolenbroek * or a negative error code on failure.
558*ef8d499eSDavid van Moolenbroek */
559*ef8d499eSDavid van Moolenbroek int
ifdev_set_ifmedia(struct ifdev * ifdev,int ifmedia)560*ef8d499eSDavid van Moolenbroek ifdev_set_ifmedia(struct ifdev * ifdev, int ifmedia)
561*ef8d499eSDavid van Moolenbroek {
562*ef8d499eSDavid van Moolenbroek
563*ef8d499eSDavid van Moolenbroek if (ifdev->ifdev_ops->iop_set_ifmedia == NULL)
564*ef8d499eSDavid van Moolenbroek return ENOTTY;
565*ef8d499eSDavid van Moolenbroek
566*ef8d499eSDavid van Moolenbroek if (ifmedia < 0)
567*ef8d499eSDavid van Moolenbroek return EINVAL;
568*ef8d499eSDavid van Moolenbroek
569*ef8d499eSDavid van Moolenbroek return ifdev->ifdev_ops->iop_set_ifmedia(ifdev, ifmedia);
570*ef8d499eSDavid van Moolenbroek }
571*ef8d499eSDavid van Moolenbroek
572*ef8d499eSDavid van Moolenbroek /*
573*ef8d499eSDavid van Moolenbroek * Set the Maximum Transmission Unit for an interface. Return OK on success,
574*ef8d499eSDavid van Moolenbroek * or a negative error code on failure.
575*ef8d499eSDavid van Moolenbroek */
576*ef8d499eSDavid van Moolenbroek int
ifdev_set_mtu(struct ifdev * ifdev,unsigned int mtu)577*ef8d499eSDavid van Moolenbroek ifdev_set_mtu(struct ifdev * ifdev, unsigned int mtu)
578*ef8d499eSDavid van Moolenbroek {
579*ef8d499eSDavid van Moolenbroek
580*ef8d499eSDavid van Moolenbroek if (ifdev->ifdev_ops->iop_set_mtu == NULL)
581*ef8d499eSDavid van Moolenbroek return ENOTTY;
582*ef8d499eSDavid van Moolenbroek
583*ef8d499eSDavid van Moolenbroek if (mtu < IFDEV_MIN_MTU || mtu > UINT16_MAX ||
584*ef8d499eSDavid van Moolenbroek !ifdev->ifdev_ops->iop_set_mtu(ifdev, mtu))
585*ef8d499eSDavid van Moolenbroek return EINVAL;
586*ef8d499eSDavid van Moolenbroek
587*ef8d499eSDavid van Moolenbroek ifdev->ifdev_data.ifi_mtu = mtu;
588*ef8d499eSDavid van Moolenbroek ifdev->ifdev_netif.mtu = mtu;
589*ef8d499eSDavid van Moolenbroek
590*ef8d499eSDavid van Moolenbroek return OK;
591*ef8d499eSDavid van Moolenbroek }
592*ef8d499eSDavid van Moolenbroek
593*ef8d499eSDavid van Moolenbroek /*
594*ef8d499eSDavid van Moolenbroek * Set IPv6 Neighbor Discovery related flags.
595*ef8d499eSDavid van Moolenbroek */
596*ef8d499eSDavid van Moolenbroek int
ifdev_set_nd6flags(struct ifdev * ifdev,uint32_t nd6flags)597*ef8d499eSDavid van Moolenbroek ifdev_set_nd6flags(struct ifdev * ifdev, uint32_t nd6flags)
598*ef8d499eSDavid van Moolenbroek {
599*ef8d499eSDavid van Moolenbroek
600*ef8d499eSDavid van Moolenbroek /* For now, refuse setting any flags that are not even known. */
601*ef8d499eSDavid van Moolenbroek if ((nd6flags & ~(ND6_IFF_PERFORMNUD | ND6_IFF_ACCEPT_RTADV |
602*ef8d499eSDavid van Moolenbroek ND6_IFF_IFDISABLED | ND6_IFF_OVERRIDE_RTADV |
603*ef8d499eSDavid van Moolenbroek ND6_IFF_AUTO_LINKLOCAL)) != 0)
604*ef8d499eSDavid van Moolenbroek return EINVAL;
605*ef8d499eSDavid van Moolenbroek
606*ef8d499eSDavid van Moolenbroek /*
607*ef8d499eSDavid van Moolenbroek * Unfortunately, the mismatch between NetBSD and lwIP requires us to
608*ef8d499eSDavid van Moolenbroek * support but butcher ND6 flags. The current status is as follows:
609*ef8d499eSDavid van Moolenbroek *
610*ef8d499eSDavid van Moolenbroek * - ND6_IFF_PERFORMNUD: set by default as lwIP always implements NUD;
611*ef8d499eSDavid van Moolenbroek * changes are disregarded but possible, for dhcpcd(8).
612*ef8d499eSDavid van Moolenbroek * - ND6_IFF_ACCEPT_RTADV: disregarded but settable, for dhcpcd(8); in
613*ef8d499eSDavid van Moolenbroek * our case, lwIP always processes router advertisements but never
614*ef8d499eSDavid van Moolenbroek * autoconfigures addresses, so this flag has no meaning for us.
615*ef8d499eSDavid van Moolenbroek * - ND6_IFF_IFDISABLED: not supported; can only be cleared; we could
616*ef8d499eSDavid van Moolenbroek * probably do detection of link-local address collision and set this
617*ef8d499eSDavid van Moolenbroek * flag (and disable the interface if set) when that happens; TODO.
618*ef8d499eSDavid van Moolenbroek * - ND6_IFF_OVERRIDE_RTADV: same as _ACCEPT_ above.
619*ef8d499eSDavid van Moolenbroek * - ND6_IFF_AUTO_LINKLOCAL: supported, but not initialized based on
620*ef8d499eSDavid van Moolenbroek * the corresponding sysctl(7) flag for reasons mentioned in ifaddr.
621*ef8d499eSDavid van Moolenbroek */
622*ef8d499eSDavid van Moolenbroek if (nd6flags & ND6_IFF_IFDISABLED)
623*ef8d499eSDavid van Moolenbroek return EINVAL;
624*ef8d499eSDavid van Moolenbroek
625*ef8d499eSDavid van Moolenbroek ifdev->ifdev_nd6flags = nd6flags;
626*ef8d499eSDavid van Moolenbroek
627*ef8d499eSDavid van Moolenbroek return OK;
628*ef8d499eSDavid van Moolenbroek }
629*ef8d499eSDavid van Moolenbroek
630*ef8d499eSDavid van Moolenbroek /*
631*ef8d499eSDavid van Moolenbroek * Report an update to the interface's active hardware address that is *not*
632*ef8d499eSDavid van Moolenbroek * the result of a user action. If the 'is_factory' flag is set, the address
633*ef8d499eSDavid van Moolenbroek * is the factory (driver-given) address. This function is for use by
634*ef8d499eSDavid van Moolenbroek * interface modules, to update the internal state to their current external
635*ef8d499eSDavid van Moolenbroek * state.
636*ef8d499eSDavid van Moolenbroek */
637*ef8d499eSDavid van Moolenbroek void
ifdev_update_hwaddr(struct ifdev * ifdev,const uint8_t * hwaddr,int is_factory)638*ef8d499eSDavid van Moolenbroek ifdev_update_hwaddr(struct ifdev * ifdev, const uint8_t * hwaddr,
639*ef8d499eSDavid van Moolenbroek int is_factory)
640*ef8d499eSDavid van Moolenbroek {
641*ef8d499eSDavid van Moolenbroek
642*ef8d499eSDavid van Moolenbroek return ifaddr_dl_update(ifdev, hwaddr, is_factory);
643*ef8d499eSDavid van Moolenbroek }
644*ef8d499eSDavid van Moolenbroek
645*ef8d499eSDavid van Moolenbroek /*
646*ef8d499eSDavid van Moolenbroek * Insert a new interface device into the list of interface devices, at a
647*ef8d499eSDavid van Moolenbroek * location determined by policy.
648*ef8d499eSDavid van Moolenbroek */
649*ef8d499eSDavid van Moolenbroek static void
ifdev_insert(struct ifdev * ifdev)650*ef8d499eSDavid van Moolenbroek ifdev_insert(struct ifdev * ifdev)
651*ef8d499eSDavid van Moolenbroek {
652*ef8d499eSDavid van Moolenbroek struct ifdev *ifdev2;
653*ef8d499eSDavid van Moolenbroek const char *p;
654*ef8d499eSDavid van Moolenbroek unsigned int unit, unit2;
655*ef8d499eSDavid van Moolenbroek size_t namelen;
656*ef8d499eSDavid van Moolenbroek int found;
657*ef8d499eSDavid van Moolenbroek
658*ef8d499eSDavid van Moolenbroek /*
659*ef8d499eSDavid van Moolenbroek * While NetBSD can set up all interfaces in the order it wants them to
660*ef8d499eSDavid van Moolenbroek * appear in, we do not have such luxury: network device drivers come
661*ef8d499eSDavid van Moolenbroek * up and report to us in no particular predefined order, and we have
662*ef8d499eSDavid van Moolenbroek * no way to know how many and which will appear. The result is that
663*ef8d499eSDavid van Moolenbroek * we always have to create the loopback device first, something that
664*ef8d499eSDavid van Moolenbroek * is explicitly said to be bad in NetBSD. Instead, we create an
665*ef8d499eSDavid van Moolenbroek * illusion of a reasonable order by performing insertion sort on the
666*ef8d499eSDavid van Moolenbroek * interface list, using (for now) these rules, ordered by priority:
667*ef8d499eSDavid van Moolenbroek *
668*ef8d499eSDavid van Moolenbroek * 1. same-named devices are sorted by their unit number;
669*ef8d499eSDavid van Moolenbroek * 2. loopback interfaces are inserted after all other interfaces;
670*ef8d499eSDavid van Moolenbroek * 3. new devices are added at the end of their type category.
671*ef8d499eSDavid van Moolenbroek *
672*ef8d499eSDavid van Moolenbroek * In the future, other forms of real-vs-virtual sorting may be added.
673*ef8d499eSDavid van Moolenbroek */
674*ef8d499eSDavid van Moolenbroek
675*ef8d499eSDavid van Moolenbroek /* First check for same-named devices (#1). */
676*ef8d499eSDavid van Moolenbroek for (p = ifdev->ifdev_name; *p != '\0' && (*p < '0' || *p > '9'); p++);
677*ef8d499eSDavid van Moolenbroek
678*ef8d499eSDavid van Moolenbroek namelen = (size_t)(p - ifdev->ifdev_name);
679*ef8d499eSDavid van Moolenbroek
680*ef8d499eSDavid van Moolenbroek for (unit = 0; *p >= '0' && *p <= '9'; p++)
681*ef8d499eSDavid van Moolenbroek unit = unit * 10 + *p - '0';
682*ef8d499eSDavid van Moolenbroek
683*ef8d499eSDavid van Moolenbroek found = FALSE;
684*ef8d499eSDavid van Moolenbroek TAILQ_FOREACH(ifdev2, &ifdev_list, ifdev_next) {
685*ef8d499eSDavid van Moolenbroek if (!strncmp(ifdev->ifdev_name, ifdev2->ifdev_name, namelen) &&
686*ef8d499eSDavid van Moolenbroek *(p = &ifdev2->ifdev_name[namelen]) >= '0' && *p <= '9') {
687*ef8d499eSDavid van Moolenbroek for (unit2 = 0; *p >= '0' && *p <= '9'; p++)
688*ef8d499eSDavid van Moolenbroek unit2 = unit2 * 10 + *p - '0';
689*ef8d499eSDavid van Moolenbroek
690*ef8d499eSDavid van Moolenbroek assert(unit != unit2);
691*ef8d499eSDavid van Moolenbroek
692*ef8d499eSDavid van Moolenbroek found = TRUE;
693*ef8d499eSDavid van Moolenbroek if (unit2 > unit)
694*ef8d499eSDavid van Moolenbroek break;
695*ef8d499eSDavid van Moolenbroek } else if (found)
696*ef8d499eSDavid van Moolenbroek break;
697*ef8d499eSDavid van Moolenbroek }
698*ef8d499eSDavid van Moolenbroek
699*ef8d499eSDavid van Moolenbroek if (found) {
700*ef8d499eSDavid van Moolenbroek if (ifdev2 != NULL)
701*ef8d499eSDavid van Moolenbroek TAILQ_INSERT_BEFORE(ifdev2, ifdev, ifdev_next);
702*ef8d499eSDavid van Moolenbroek else
703*ef8d499eSDavid van Moolenbroek TAILQ_INSERT_TAIL(&ifdev_list, ifdev, ifdev_next);
704*ef8d499eSDavid van Moolenbroek
705*ef8d499eSDavid van Moolenbroek return;
706*ef8d499eSDavid van Moolenbroek }
707*ef8d499eSDavid van Moolenbroek
708*ef8d499eSDavid van Moolenbroek /*
709*ef8d499eSDavid van Moolenbroek * No same-named device found. Is this a loopback interface? If not,
710*ef8d499eSDavid van Moolenbroek * insert before the first loopback device, if any.
711*ef8d499eSDavid van Moolenbroek */
712*ef8d499eSDavid van Moolenbroek if (!ifdev_is_loopback(ifdev)) {
713*ef8d499eSDavid van Moolenbroek TAILQ_FOREACH(ifdev2, &ifdev_list, ifdev_next) {
714*ef8d499eSDavid van Moolenbroek if (ifdev_is_loopback(ifdev2)) {
715*ef8d499eSDavid van Moolenbroek TAILQ_INSERT_BEFORE(ifdev2, ifdev, ifdev_next);
716*ef8d499eSDavid van Moolenbroek
717*ef8d499eSDavid van Moolenbroek return;
718*ef8d499eSDavid van Moolenbroek }
719*ef8d499eSDavid van Moolenbroek }
720*ef8d499eSDavid van Moolenbroek }
721*ef8d499eSDavid van Moolenbroek
722*ef8d499eSDavid van Moolenbroek /*
723*ef8d499eSDavid van Moolenbroek * The given device is not a loopback device, or there was no loopback
724*ef8d499eSDavid van Moolenbroek * device in the list, possibly because it was empty. Add to the tail.
725*ef8d499eSDavid van Moolenbroek */
726*ef8d499eSDavid van Moolenbroek TAILQ_INSERT_TAIL(&ifdev_list, ifdev, ifdev_next);
727*ef8d499eSDavid van Moolenbroek }
728*ef8d499eSDavid van Moolenbroek
729*ef8d499eSDavid van Moolenbroek /*
730*ef8d499eSDavid van Moolenbroek * Add and initialize an interface device.
731*ef8d499eSDavid van Moolenbroek */
732*ef8d499eSDavid van Moolenbroek void
ifdev_add(struct ifdev * ifdev,const char * name,unsigned int ifflags,unsigned int iftype,size_t hdrlen,size_t addrlen,unsigned int dlt,unsigned int mtu,uint32_t nd6flags,const struct ifdev_ops * iop)733*ef8d499eSDavid van Moolenbroek ifdev_add(struct ifdev * ifdev, const char * name, unsigned int ifflags,
734*ef8d499eSDavid van Moolenbroek unsigned int iftype, size_t hdrlen, size_t addrlen, unsigned int dlt,
735*ef8d499eSDavid van Moolenbroek unsigned int mtu, uint32_t nd6flags, const struct ifdev_ops * iop)
736*ef8d499eSDavid van Moolenbroek {
737*ef8d499eSDavid van Moolenbroek unsigned int ifindex;
738*ef8d499eSDavid van Moolenbroek ip4_addr_t ip4addr_any, ip4addr_none;
739*ef8d499eSDavid van Moolenbroek
740*ef8d499eSDavid van Moolenbroek /*
741*ef8d499eSDavid van Moolenbroek * Since the call to netif_add() may end up invoking some of our
742*ef8d499eSDavid van Moolenbroek * callbacks (the add-multicast-address ones in particular), make sure
743*ef8d499eSDavid van Moolenbroek * that everything else is set up first. We cannot set up the index
744*ef8d499eSDavid van Moolenbroek * mapping until netif_add() returns, but this is currently no problem.
745*ef8d499eSDavid van Moolenbroek */
746*ef8d499eSDavid van Moolenbroek strlcpy(ifdev->ifdev_name, name, sizeof(ifdev->ifdev_name));
747*ef8d499eSDavid van Moolenbroek ifdev->ifdev_ifflags = 0; /* will be updated below */
748*ef8d499eSDavid van Moolenbroek ifdev->ifdev_dlt = dlt;
749*ef8d499eSDavid van Moolenbroek ifdev->ifdev_nd6flags = nd6flags;
750*ef8d499eSDavid van Moolenbroek ifdev->ifdev_ops = iop;
751*ef8d499eSDavid van Moolenbroek
752*ef8d499eSDavid van Moolenbroek memset(&ifdev->ifdev_data, 0, sizeof(ifdev->ifdev_data));
753*ef8d499eSDavid van Moolenbroek
754*ef8d499eSDavid van Moolenbroek assert(addrlen <= NETIF_MAX_HWADDR_LEN);
755*ef8d499eSDavid van Moolenbroek assert(mtu >= IFDEV_MIN_MTU && mtu <= UINT16_MAX);
756*ef8d499eSDavid van Moolenbroek
757*ef8d499eSDavid van Moolenbroek ifdev->ifdev_data.ifi_type = iftype;
758*ef8d499eSDavid van Moolenbroek ifdev->ifdev_data.ifi_hdrlen = hdrlen;
759*ef8d499eSDavid van Moolenbroek ifdev->ifdev_data.ifi_addrlen = addrlen;
760*ef8d499eSDavid van Moolenbroek ifdev->ifdev_data.ifi_link_state = LINK_STATE_UNKNOWN;
761*ef8d499eSDavid van Moolenbroek ifdev->ifdev_data.ifi_mtu = mtu;
762*ef8d499eSDavid van Moolenbroek
763*ef8d499eSDavid van Moolenbroek TAILQ_INIT(&ifdev->ifdev_bpf);
764*ef8d499eSDavid van Moolenbroek
765*ef8d499eSDavid van Moolenbroek ifaddr_init(ifdev);
766*ef8d499eSDavid van Moolenbroek
767*ef8d499eSDavid van Moolenbroek /*
768*ef8d499eSDavid van Moolenbroek * We have to assign an IPv4 address at netif addition time, but we may
769*ef8d499eSDavid van Moolenbroek * not have one yet, so pass in an "any" address for now. Hopefully
770*ef8d499eSDavid van Moolenbroek * lwIP will not mistake this for a real IPv4 address if we happen to
771*ef8d499eSDavid van Moolenbroek * enable the interface with only an IPv6 address later on.
772*ef8d499eSDavid van Moolenbroek */
773*ef8d499eSDavid van Moolenbroek ip4_addr_set_any(&ip4addr_any);
774*ef8d499eSDavid van Moolenbroek ip4_addr_set_u32(&ip4addr_none, PP_HTONL(INADDR_NONE));
775*ef8d499eSDavid van Moolenbroek
776*ef8d499eSDavid van Moolenbroek /*
777*ef8d499eSDavid van Moolenbroek * Insert the new interface device into a sensible place in the current
778*ef8d499eSDavid van Moolenbroek * list of interfaces.
779*ef8d499eSDavid van Moolenbroek */
780*ef8d499eSDavid van Moolenbroek ifdev_insert(ifdev);
781*ef8d499eSDavid van Moolenbroek
782*ef8d499eSDavid van Moolenbroek /*
783*ef8d499eSDavid van Moolenbroek * netif_add() can fail only as a result of the initialization callback
784*ef8d499eSDavid van Moolenbroek * failing, which is something that should never happen in our case.
785*ef8d499eSDavid van Moolenbroek */
786*ef8d499eSDavid van Moolenbroek if (netif_add(&ifdev->ifdev_netif, &ip4addr_any, &ip4addr_none,
787*ef8d499eSDavid van Moolenbroek &ip4addr_any, ifdev, ifdev_init_netif, iop->iop_input) == NULL)
788*ef8d499eSDavid van Moolenbroek panic("unable to add netif");
789*ef8d499eSDavid van Moolenbroek
790*ef8d499eSDavid van Moolenbroek /*
791*ef8d499eSDavid van Moolenbroek * Set up the index mapping. Since interface index zero never
792*ef8d499eSDavid van Moolenbroek * generated, table slot zero is always NULL. We could shift all
793*ef8d499eSDavid van Moolenbroek * elements by one to save four bytes, but there's no real point.
794*ef8d499eSDavid van Moolenbroek */
795*ef8d499eSDavid van Moolenbroek ifindex = netif_get_index(&ifdev->ifdev_netif);
796*ef8d499eSDavid van Moolenbroek
797*ef8d499eSDavid van Moolenbroek if (ifindex == 0 || ifindex >= __arraycount(ifdev_table))
798*ef8d499eSDavid van Moolenbroek panic("invalid lwIP-generated interface index %u", ifindex);
799*ef8d499eSDavid van Moolenbroek
800*ef8d499eSDavid van Moolenbroek ifdev_table[ifindex] = ifdev;
801*ef8d499eSDavid van Moolenbroek
802*ef8d499eSDavid van Moolenbroek /*
803*ef8d499eSDavid van Moolenbroek * Set the initial interface flags. Use the regular procedure for this
804*ef8d499eSDavid van Moolenbroek * just in case the interface module is crazy enough to set the
805*ef8d499eSDavid van Moolenbroek * interface up right away (which is never a good idea but still).
806*ef8d499eSDavid van Moolenbroek */
807*ef8d499eSDavid van Moolenbroek ifdev_update_ifflags(ifdev, ifflags);
808*ef8d499eSDavid van Moolenbroek
809*ef8d499eSDavid van Moolenbroek /*
810*ef8d499eSDavid van Moolenbroek * If this is the first loopback interface to be registered, save it as
811*ef8d499eSDavid van Moolenbroek * the loopback interface that we will use to loop back self-destined
812*ef8d499eSDavid van Moolenbroek * packets on other interfaces. Do this after setting the interface
813*ef8d499eSDavid van Moolenbroek * flags, since those are what we use to perform this loopback check.
814*ef8d499eSDavid van Moolenbroek */
815*ef8d499eSDavid van Moolenbroek if (ifdev_loopback == NULL && ifdev_is_loopback(ifdev))
816*ef8d499eSDavid van Moolenbroek ifdev_loopback = ifdev;
817*ef8d499eSDavid van Moolenbroek
818*ef8d499eSDavid van Moolenbroek /* Finally, announce the new interface. */
819*ef8d499eSDavid van Moolenbroek rtsock_msg_ifannounce(ifdev, TRUE /*arrival*/);
820*ef8d499eSDavid van Moolenbroek }
821*ef8d499eSDavid van Moolenbroek
822*ef8d499eSDavid van Moolenbroek /*
823*ef8d499eSDavid van Moolenbroek * Remove an interface device. Return OK on success, or a negative error code
824*ef8d499eSDavid van Moolenbroek * on failure. Only loopback interfaces may be refused for removal.
825*ef8d499eSDavid van Moolenbroek */
826*ef8d499eSDavid van Moolenbroek int
ifdev_remove(struct ifdev * ifdev)827*ef8d499eSDavid van Moolenbroek ifdev_remove(struct ifdev * ifdev)
828*ef8d499eSDavid van Moolenbroek {
829*ef8d499eSDavid van Moolenbroek struct bpfdev_link *bpfl;
830*ef8d499eSDavid van Moolenbroek
831*ef8d499eSDavid van Moolenbroek /*
832*ef8d499eSDavid van Moolenbroek * If this is the loopback interface used to loop back packets for
833*ef8d499eSDavid van Moolenbroek * other interfaces (typically lo0), we cannot afford to get rid of it.
834*ef8d499eSDavid van Moolenbroek */
835*ef8d499eSDavid van Moolenbroek if (ifdev == ifdev_loopback)
836*ef8d499eSDavid van Moolenbroek return EPERM;
837*ef8d499eSDavid van Moolenbroek
838*ef8d499eSDavid van Moolenbroek /*
839*ef8d499eSDavid van Moolenbroek * Take down the interface for the purpose of sending a routing
840*ef8d499eSDavid van Moolenbroek * message. NetBSD sends a RTM_IFINFO even if the interface was down
841*ef8d499eSDavid van Moolenbroek * already, and so we do not check whether IFF_UP was set at all here.
842*ef8d499eSDavid van Moolenbroek */
843*ef8d499eSDavid van Moolenbroek ifdev_update_ifflags(ifdev, ifdev->ifdev_ifflags & ~IFF_UP);
844*ef8d499eSDavid van Moolenbroek
845*ef8d499eSDavid van Moolenbroek /*
846*ef8d499eSDavid van Moolenbroek * Report all associated addresses as deleted. It is not necessary to
847*ef8d499eSDavid van Moolenbroek * actually delete the addresses, nor is that even possible in all
848*ef8d499eSDavid van Moolenbroek * cases. In particular, the active hardware address cannot be
849*ef8d499eSDavid van Moolenbroek * deleted. Since the active hardware address is used in all address
850*ef8d499eSDavid van Moolenbroek * change announcements, delete it at the very end.
851*ef8d499eSDavid van Moolenbroek */
852*ef8d499eSDavid van Moolenbroek ifaddr_v4_clear(ifdev);
853*ef8d499eSDavid van Moolenbroek ifaddr_v6_clear(ifdev);
854*ef8d499eSDavid van Moolenbroek ifaddr_dl_clear(ifdev);
855*ef8d499eSDavid van Moolenbroek
856*ef8d499eSDavid van Moolenbroek /*
857*ef8d499eSDavid van Moolenbroek * Delete all remaining routes associated with the interface. These
858*ef8d499eSDavid van Moolenbroek * are reported as well. We do this after clearing the addresses so as
859*ef8d499eSDavid van Moolenbroek * not to confuse the route deletion part of clearing addresses.
860*ef8d499eSDavid van Moolenbroek */
861*ef8d499eSDavid van Moolenbroek route_clear(ifdev);
862*ef8d499eSDavid van Moolenbroek
863*ef8d499eSDavid van Moolenbroek /* Finally, announce the interface itself as gone. */
864*ef8d499eSDavid van Moolenbroek rtsock_msg_ifannounce(ifdev, FALSE /*arrival*/);
865*ef8d499eSDavid van Moolenbroek
866*ef8d499eSDavid van Moolenbroek /*
867*ef8d499eSDavid van Moolenbroek * Free up all per-socket multicast membership structures associated to
868*ef8d499eSDavid van Moolenbroek * the interface. There is no need to leave the multicast groups.
869*ef8d499eSDavid van Moolenbroek */
870*ef8d499eSDavid van Moolenbroek mcast_clear(ifdev);
871*ef8d499eSDavid van Moolenbroek
872*ef8d499eSDavid van Moolenbroek /*
873*ef8d499eSDavid van Moolenbroek * Also tell attached BPF devices that the interface is now gone. Do
874*ef8d499eSDavid van Moolenbroek * not bother to reset the list.
875*ef8d499eSDavid van Moolenbroek */
876*ef8d499eSDavid van Moolenbroek TAILQ_FOREACH(bpfl, &ifdev->ifdev_bpf, bpfl_next)
877*ef8d499eSDavid van Moolenbroek bpfdev_detach(bpfl);
878*ef8d499eSDavid van Moolenbroek
879*ef8d499eSDavid van Moolenbroek /* Then perform the actual interface removal. */
880*ef8d499eSDavid van Moolenbroek netif_remove(&ifdev->ifdev_netif);
881*ef8d499eSDavid van Moolenbroek
882*ef8d499eSDavid van Moolenbroek TAILQ_REMOVE(&ifdev_list, ifdev, ifdev_next);
883*ef8d499eSDavid van Moolenbroek
884*ef8d499eSDavid van Moolenbroek assert(ifdev_table[ifdev_get_index(ifdev)] == ifdev);
885*ef8d499eSDavid van Moolenbroek ifdev_table[ifdev_get_index(ifdev)] = NULL;
886*ef8d499eSDavid van Moolenbroek
887*ef8d499eSDavid van Moolenbroek return OK;
888*ef8d499eSDavid van Moolenbroek }
889*ef8d499eSDavid van Moolenbroek
890*ef8d499eSDavid van Moolenbroek /*
891*ef8d499eSDavid van Moolenbroek * Return the loopback interface.
892*ef8d499eSDavid van Moolenbroek */
893*ef8d499eSDavid van Moolenbroek struct ifdev *
ifdev_get_loopback(void)894*ef8d499eSDavid van Moolenbroek ifdev_get_loopback(void)
895*ef8d499eSDavid van Moolenbroek {
896*ef8d499eSDavid van Moolenbroek
897*ef8d499eSDavid van Moolenbroek assert(ifdev_loopback != NULL);
898*ef8d499eSDavid van Moolenbroek
899*ef8d499eSDavid van Moolenbroek return ifdev_loopback;
900*ef8d499eSDavid van Moolenbroek }
901*ef8d499eSDavid van Moolenbroek
902*ef8d499eSDavid van Moolenbroek /*
903*ef8d499eSDavid van Moolenbroek * Report an update of the link state of the given interface, to 'unknown',
904*ef8d499eSDavid van Moolenbroek * 'up', or 'down', using NetBSD's LINK_STATE_ values. The link state is
905*ef8d499eSDavid van Moolenbroek * changed in the associated lwIP netif, and is reported on monitoring routing
906*ef8d499eSDavid van Moolenbroek * sockets. This function is for use by interface modules, to update the
907*ef8d499eSDavid van Moolenbroek * internal state to their current external state.
908*ef8d499eSDavid van Moolenbroek */
909*ef8d499eSDavid van Moolenbroek void
ifdev_update_link(struct ifdev * ifdev,int iflink)910*ef8d499eSDavid van Moolenbroek ifdev_update_link(struct ifdev * ifdev, int iflink)
911*ef8d499eSDavid van Moolenbroek {
912*ef8d499eSDavid van Moolenbroek struct netif *netif;
913*ef8d499eSDavid van Moolenbroek int was_up, is_up;
914*ef8d499eSDavid van Moolenbroek
915*ef8d499eSDavid van Moolenbroek ifdev->ifdev_data.ifi_link_state = iflink;
916*ef8d499eSDavid van Moolenbroek
917*ef8d499eSDavid van Moolenbroek /*
918*ef8d499eSDavid van Moolenbroek * For netif, 'up' and 'unknown' are the same link state: we simply try
919*ef8d499eSDavid van Moolenbroek * to send and receive packets in both cases. Thus, transitions from
920*ef8d499eSDavid van Moolenbroek * and to the 'down' link state are the ones that matter.
921*ef8d499eSDavid van Moolenbroek */
922*ef8d499eSDavid van Moolenbroek netif = ifdev_get_netif(ifdev);
923*ef8d499eSDavid van Moolenbroek
924*ef8d499eSDavid van Moolenbroek was_up = netif_is_link_up(netif);
925*ef8d499eSDavid van Moolenbroek is_up = (iflink != LINK_STATE_DOWN);
926*ef8d499eSDavid van Moolenbroek
927*ef8d499eSDavid van Moolenbroek if (was_up != is_up) {
928*ef8d499eSDavid van Moolenbroek if (is_up) {
929*ef8d499eSDavid van Moolenbroek netif_set_link_up(netif);
930*ef8d499eSDavid van Moolenbroek
931*ef8d499eSDavid van Moolenbroek /* See if we should also reset address states now. */
932*ef8d499eSDavid van Moolenbroek if (ifdev_is_up(ifdev))
933*ef8d499eSDavid van Moolenbroek ifaddr_v6_set_up(ifdev);
934*ef8d499eSDavid van Moolenbroek } else
935*ef8d499eSDavid van Moolenbroek netif_set_link_down(netif);
936*ef8d499eSDavid van Moolenbroek
937*ef8d499eSDavid van Moolenbroek rtsock_msg_ifinfo(ifdev);
938*ef8d499eSDavid van Moolenbroek }
939*ef8d499eSDavid van Moolenbroek }
940*ef8d499eSDavid van Moolenbroek
941*ef8d499eSDavid van Moolenbroek /*
942*ef8d499eSDavid van Moolenbroek * Register a virtual interface type, using a name prefix and a function that
943*ef8d499eSDavid van Moolenbroek * is called when creation of a virtual interface of that type is requested.
944*ef8d499eSDavid van Moolenbroek */
945*ef8d499eSDavid van Moolenbroek void
ifdev_register(const char * name,int (* create)(const char *))946*ef8d499eSDavid van Moolenbroek ifdev_register(const char * name, int (* create)(const char *))
947*ef8d499eSDavid van Moolenbroek {
948*ef8d499eSDavid van Moolenbroek
949*ef8d499eSDavid van Moolenbroek if (ifdev_vtypes == __arraycount(ifdev_vtype))
950*ef8d499eSDavid van Moolenbroek panic("too few slots for all virtual interface types");
951*ef8d499eSDavid van Moolenbroek
952*ef8d499eSDavid van Moolenbroek ifdev_vtype[ifdev_vtypes].ifvt_name = name;
953*ef8d499eSDavid van Moolenbroek ifdev_vtype[ifdev_vtypes].ifvt_namelen = strlen(name);
954*ef8d499eSDavid van Moolenbroek ifdev_vtype[ifdev_vtypes].ifvt_create = create;
955*ef8d499eSDavid van Moolenbroek ifdev_vtypes++;
956*ef8d499eSDavid van Moolenbroek }
957*ef8d499eSDavid van Moolenbroek
958*ef8d499eSDavid van Moolenbroek /*
959*ef8d499eSDavid van Moolenbroek * Verify that the given name is a valid interface name that can be used for
960*ef8d499eSDavid van Moolenbroek * creating a new interface. In particular, check that the given name is a
961*ef8d499eSDavid van Moolenbroek * valid interface name, consisting of an alphabetic string (the interface type
962*ef8d499eSDavid van Moolenbroek * or driver name) followed by a number string (the unit or instance number).
963*ef8d499eSDavid van Moolenbroek * Furthermore, make sure that the name does not already exist. Finally, see
964*ef8d499eSDavid van Moolenbroek * if the name prefix is reserved for a virtual interface type. If the given
965*ef8d499eSDavid van Moolenbroek * 'vtype_slot' pointer is not NULL, the prefix must be, and the virtual type
966*ef8d499eSDavid van Moolenbroek * slot number is returned in 'vtype_slot' on success. If 'vtype_slot' is
967*ef8d499eSDavid van Moolenbroek * NULL, the name must not have a virtual interface prefix, and an error is
968*ef8d499eSDavid van Moolenbroek * returned if it is. Since vtype slot numbers are meaningless outside of this
969*ef8d499eSDavid van Moolenbroek * module, external callers must always pass in NULL. This function returns OK
970*ef8d499eSDavid van Moolenbroek * on succes or a negative error code on error.
971*ef8d499eSDavid van Moolenbroek */
972*ef8d499eSDavid van Moolenbroek int
ifdev_check_name(const char * name,unsigned int * vtype_slot)973*ef8d499eSDavid van Moolenbroek ifdev_check_name(const char * name, unsigned int * vtype_slot)
974*ef8d499eSDavid van Moolenbroek {
975*ef8d499eSDavid van Moolenbroek const char *p;
976*ef8d499eSDavid van Moolenbroek size_t namelen;
977*ef8d499eSDavid van Moolenbroek unsigned int slot;
978*ef8d499eSDavid van Moolenbroek
979*ef8d499eSDavid van Moolenbroek /*
980*ef8d499eSDavid van Moolenbroek * First see if the name is valid at all. TODO: decide if we want to
981*ef8d499eSDavid van Moolenbroek * allow uppercase letters, dashes, and/or underscores.
982*ef8d499eSDavid van Moolenbroek */
983*ef8d499eSDavid van Moolenbroek for (p = name; *p >= 'a' && *p <= 'z'; p++);
984*ef8d499eSDavid van Moolenbroek
985*ef8d499eSDavid van Moolenbroek if (p == name || *p == '\0')
986*ef8d499eSDavid van Moolenbroek return EINVAL;
987*ef8d499eSDavid van Moolenbroek
988*ef8d499eSDavid van Moolenbroek namelen = (size_t)(p - name);
989*ef8d499eSDavid van Moolenbroek
990*ef8d499eSDavid van Moolenbroek for (; *p >= '0' && *p <= '9'; p++);
991*ef8d499eSDavid van Moolenbroek
992*ef8d499eSDavid van Moolenbroek if (*p != '\0')
993*ef8d499eSDavid van Moolenbroek return EINVAL;
994*ef8d499eSDavid van Moolenbroek
995*ef8d499eSDavid van Moolenbroek /* Then make sure that it does not already exist. */
996*ef8d499eSDavid van Moolenbroek if (ifdev_find_by_name(name) != NULL)
997*ef8d499eSDavid van Moolenbroek return EEXIST;
998*ef8d499eSDavid van Moolenbroek
999*ef8d499eSDavid van Moolenbroek /* See if there is a matching virtual interface type for the name. */
1000*ef8d499eSDavid van Moolenbroek for (slot = 0; slot < ifdev_vtypes; slot++) {
1001*ef8d499eSDavid van Moolenbroek if (ifdev_vtype[slot].ifvt_namelen == namelen &&
1002*ef8d499eSDavid van Moolenbroek !strncmp(ifdev_vtype[slot].ifvt_name, name, namelen))
1003*ef8d499eSDavid van Moolenbroek break;
1004*ef8d499eSDavid van Moolenbroek }
1005*ef8d499eSDavid van Moolenbroek
1006*ef8d499eSDavid van Moolenbroek /* The interpretation of the result depends on 'vtype_slot'. */
1007*ef8d499eSDavid van Moolenbroek if (vtype_slot != NULL) {
1008*ef8d499eSDavid van Moolenbroek if (slot == ifdev_vtypes)
1009*ef8d499eSDavid van Moolenbroek return EINVAL;
1010*ef8d499eSDavid van Moolenbroek
1011*ef8d499eSDavid van Moolenbroek *vtype_slot = slot;
1012*ef8d499eSDavid van Moolenbroek } else if (slot != ifdev_vtypes)
1013*ef8d499eSDavid van Moolenbroek return EINVAL;
1014*ef8d499eSDavid van Moolenbroek
1015*ef8d499eSDavid van Moolenbroek return OK;
1016*ef8d499eSDavid van Moolenbroek }
1017*ef8d499eSDavid van Moolenbroek
1018*ef8d499eSDavid van Moolenbroek /*
1019*ef8d499eSDavid van Moolenbroek * Create a new virtual interface. The virtual interface type is based on the
1020*ef8d499eSDavid van Moolenbroek * given name (without unit number). Return OK if the virtual interface has
1021*ef8d499eSDavid van Moolenbroek * been successfully created, or a negative error code otherwise. This
1022*ef8d499eSDavid van Moolenbroek * function is used both for the SIOCIFCREATE ioctl and internally.
1023*ef8d499eSDavid van Moolenbroek */
1024*ef8d499eSDavid van Moolenbroek int
ifdev_create(const char * name)1025*ef8d499eSDavid van Moolenbroek ifdev_create(const char * name)
1026*ef8d499eSDavid van Moolenbroek {
1027*ef8d499eSDavid van Moolenbroek unsigned int slot;
1028*ef8d499eSDavid van Moolenbroek int r;
1029*ef8d499eSDavid van Moolenbroek
1030*ef8d499eSDavid van Moolenbroek /* Verify that the given name is an acceptable interface name. */
1031*ef8d499eSDavid van Moolenbroek if ((r = ifdev_check_name(name, &slot)) != OK)
1032*ef8d499eSDavid van Moolenbroek return EINVAL;
1033*ef8d499eSDavid van Moolenbroek
1034*ef8d499eSDavid van Moolenbroek /* Let the virtual interface implementation handle the rest. */
1035*ef8d499eSDavid van Moolenbroek return ifdev_vtype[slot].ifvt_create(name);
1036*ef8d499eSDavid van Moolenbroek }
1037*ef8d499eSDavid van Moolenbroek
1038*ef8d499eSDavid van Moolenbroek /*
1039*ef8d499eSDavid van Moolenbroek * Destroy an interface, if possible.
1040*ef8d499eSDavid van Moolenbroek */
1041*ef8d499eSDavid van Moolenbroek int
ifdev_destroy(struct ifdev * ifdev)1042*ef8d499eSDavid van Moolenbroek ifdev_destroy(struct ifdev * ifdev)
1043*ef8d499eSDavid van Moolenbroek {
1044*ef8d499eSDavid van Moolenbroek
1045*ef8d499eSDavid van Moolenbroek if (ifdev->ifdev_ops->iop_destroy == NULL)
1046*ef8d499eSDavid van Moolenbroek return EINVAL;
1047*ef8d499eSDavid van Moolenbroek
1048*ef8d499eSDavid van Moolenbroek return ifdev->ifdev_ops->iop_destroy(ifdev);
1049*ef8d499eSDavid van Moolenbroek }
1050*ef8d499eSDavid van Moolenbroek
1051*ef8d499eSDavid van Moolenbroek /*
1052*ef8d499eSDavid van Moolenbroek * Enumerate the names of currently supported virtual interface types. Return
1053*ef8d499eSDavid van Moolenbroek * a pointer to the null-terminated name prefix of the Nth virtual interface
1054*ef8d499eSDavid van Moolenbroek * type if the (zero-based) N value is within range, or NULL otherwise.
1055*ef8d499eSDavid van Moolenbroek */
1056*ef8d499eSDavid van Moolenbroek const char *
ifdev_enum_vtypes(unsigned int num)1057*ef8d499eSDavid van Moolenbroek ifdev_enum_vtypes(unsigned int num)
1058*ef8d499eSDavid van Moolenbroek {
1059*ef8d499eSDavid van Moolenbroek
1060*ef8d499eSDavid van Moolenbroek if (num < ifdev_vtypes)
1061*ef8d499eSDavid van Moolenbroek return ifdev_vtype[num].ifvt_name;
1062*ef8d499eSDavid van Moolenbroek else
1063*ef8d499eSDavid van Moolenbroek return NULL;
1064*ef8d499eSDavid van Moolenbroek }
1065