1*45a062b0Sdlg /* $OpenBSD: if_rport.c,v 1.1 2024/08/31 04:17:14 dlg Exp $ */
2*45a062b0Sdlg
3*45a062b0Sdlg /*
4*45a062b0Sdlg * Copyright (c) 2023 David Gwynne <dlg@openbsd.org>
5*45a062b0Sdlg *
6*45a062b0Sdlg * Permission to use, copy, modify, and distribute this software for any
7*45a062b0Sdlg * purpose with or without fee is hereby granted, provided that the above
8*45a062b0Sdlg * copyright notice and this permission notice appear in all copies.
9*45a062b0Sdlg *
10*45a062b0Sdlg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*45a062b0Sdlg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*45a062b0Sdlg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*45a062b0Sdlg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*45a062b0Sdlg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*45a062b0Sdlg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*45a062b0Sdlg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*45a062b0Sdlg */
18*45a062b0Sdlg
19*45a062b0Sdlg #include <sys/param.h>
20*45a062b0Sdlg #include <sys/systm.h>
21*45a062b0Sdlg #include <sys/mbuf.h>
22*45a062b0Sdlg #include <sys/socket.h>
23*45a062b0Sdlg #include <sys/sockio.h>
24*45a062b0Sdlg #include <sys/syslog.h>
25*45a062b0Sdlg #include <sys/queue.h>
26*45a062b0Sdlg
27*45a062b0Sdlg #include <net/if.h>
28*45a062b0Sdlg #include <net/if_var.h>
29*45a062b0Sdlg #include <net/if_types.h>
30*45a062b0Sdlg #include <net/route.h>
31*45a062b0Sdlg
32*45a062b0Sdlg #include <netinet/in.h>
33*45a062b0Sdlg #include <netinet/in_var.h>
34*45a062b0Sdlg #include <netinet/ip.h>
35*45a062b0Sdlg #include <netinet/ip_var.h>
36*45a062b0Sdlg #include <netinet/ip_ipip.h>
37*45a062b0Sdlg #include <netinet/ip_ecn.h>
38*45a062b0Sdlg
39*45a062b0Sdlg #ifdef INET6
40*45a062b0Sdlg #include <netinet6/in6_var.h>
41*45a062b0Sdlg #include <netinet/ip6.h>
42*45a062b0Sdlg #include <netinet6/ip6_var.h>
43*45a062b0Sdlg #endif /* INET6 */
44*45a062b0Sdlg
45*45a062b0Sdlg #include "bpfilter.h"
46*45a062b0Sdlg #if NBPFILTER > 0
47*45a062b0Sdlg #include <net/bpf.h>
48*45a062b0Sdlg #endif
49*45a062b0Sdlg
50*45a062b0Sdlg #ifdef MPLS
51*45a062b0Sdlg #include <netmpls/mpls.h>
52*45a062b0Sdlg #endif
53*45a062b0Sdlg
54*45a062b0Sdlg #include "pf.h"
55*45a062b0Sdlg #if NPF > 0
56*45a062b0Sdlg #include <net/pfvar.h>
57*45a062b0Sdlg #endif
58*45a062b0Sdlg
59*45a062b0Sdlg #define RPORT_MTU_MIN 1280
60*45a062b0Sdlg #define RPORT_MTU_MAX 32768 /* LOMTU, but could be higher */
61*45a062b0Sdlg #define RPORT_MTU_DEFAULT RPORT_MTU_MAX
62*45a062b0Sdlg
63*45a062b0Sdlg struct rport_softc {
64*45a062b0Sdlg struct ifnet sc_if;
65*45a062b0Sdlg
66*45a062b0Sdlg unsigned int sc_peer_idx;
67*45a062b0Sdlg };
68*45a062b0Sdlg
69*45a062b0Sdlg static int rport_clone_create(struct if_clone *, int);
70*45a062b0Sdlg static int rport_clone_destroy(struct ifnet *);
71*45a062b0Sdlg
72*45a062b0Sdlg static int rport_ioctl(struct ifnet *, u_long, caddr_t);
73*45a062b0Sdlg static int rport_output(struct ifnet *, struct mbuf *, struct sockaddr *,
74*45a062b0Sdlg struct rtentry *);
75*45a062b0Sdlg static int rport_enqueue(struct ifnet *, struct mbuf *);
76*45a062b0Sdlg static void rport_start(struct ifqueue *);
77*45a062b0Sdlg static void rport_input(struct ifnet *, struct mbuf *);
78*45a062b0Sdlg
79*45a062b0Sdlg static int rport_up(struct rport_softc *);
80*45a062b0Sdlg static int rport_down(struct rport_softc *);
81*45a062b0Sdlg
82*45a062b0Sdlg static int rport_set_parent(struct rport_softc *,
83*45a062b0Sdlg const struct if_parent *);
84*45a062b0Sdlg static int rport_get_parent(struct rport_softc *, struct if_parent *);
85*45a062b0Sdlg static int rport_del_parent(struct rport_softc *);
86*45a062b0Sdlg
87*45a062b0Sdlg static struct if_clone rport_cloner =
88*45a062b0Sdlg IF_CLONE_INITIALIZER("rport", rport_clone_create, rport_clone_destroy);
89*45a062b0Sdlg
90*45a062b0Sdlg static struct rwlock rport_interfaces_lock =
91*45a062b0Sdlg RWLOCK_INITIALIZER("rports");
92*45a062b0Sdlg
93*45a062b0Sdlg void
rportattach(int count)94*45a062b0Sdlg rportattach(int count)
95*45a062b0Sdlg {
96*45a062b0Sdlg if_clone_attach(&rport_cloner);
97*45a062b0Sdlg }
98*45a062b0Sdlg
99*45a062b0Sdlg static int
rport_clone_create(struct if_clone * ifc,int unit)100*45a062b0Sdlg rport_clone_create(struct if_clone *ifc, int unit)
101*45a062b0Sdlg {
102*45a062b0Sdlg struct rport_softc *sc;
103*45a062b0Sdlg struct ifnet *ifp;
104*45a062b0Sdlg
105*45a062b0Sdlg sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_ZERO);
106*45a062b0Sdlg ifp = &sc->sc_if;
107*45a062b0Sdlg
108*45a062b0Sdlg snprintf(ifp->if_xname, sizeof(ifp->if_xname),
109*45a062b0Sdlg "%s%d", ifc->ifc_name, unit);
110*45a062b0Sdlg
111*45a062b0Sdlg ifp->if_mtu = RPORT_MTU_DEFAULT;
112*45a062b0Sdlg ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
113*45a062b0Sdlg ifp->if_xflags = IFXF_CLONED | IFXF_MPSAFE;
114*45a062b0Sdlg ifp->if_ioctl = rport_ioctl;
115*45a062b0Sdlg ifp->if_bpf_mtap = p2p_bpf_mtap;
116*45a062b0Sdlg ifp->if_output = rport_output;
117*45a062b0Sdlg ifp->if_enqueue = rport_enqueue;
118*45a062b0Sdlg ifp->if_qstart = rport_start;
119*45a062b0Sdlg ifp->if_input = rport_input;
120*45a062b0Sdlg ifp->if_rtrequest = p2p_rtrequest;
121*45a062b0Sdlg ifp->if_type = IFT_TUNNEL;
122*45a062b0Sdlg ifp->if_softc = sc;
123*45a062b0Sdlg
124*45a062b0Sdlg if_attach(ifp);
125*45a062b0Sdlg if_alloc_sadl(ifp);
126*45a062b0Sdlg if_counters_alloc(ifp);
127*45a062b0Sdlg
128*45a062b0Sdlg #if NBPFILTER > 0
129*45a062b0Sdlg bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(uint32_t));
130*45a062b0Sdlg #endif
131*45a062b0Sdlg
132*45a062b0Sdlg return (0);
133*45a062b0Sdlg }
134*45a062b0Sdlg
135*45a062b0Sdlg int
rport_clone_destroy(struct ifnet * ifp)136*45a062b0Sdlg rport_clone_destroy(struct ifnet *ifp)
137*45a062b0Sdlg {
138*45a062b0Sdlg struct rport_softc *sc = ifp->if_softc;
139*45a062b0Sdlg
140*45a062b0Sdlg NET_LOCK();
141*45a062b0Sdlg if (ISSET(ifp->if_flags, IFF_RUNNING))
142*45a062b0Sdlg rport_down(sc);
143*45a062b0Sdlg rport_del_parent(sc);
144*45a062b0Sdlg NET_UNLOCK();
145*45a062b0Sdlg
146*45a062b0Sdlg if_detach(ifp);
147*45a062b0Sdlg
148*45a062b0Sdlg free(sc, M_DEVBUF, sizeof(*sc));
149*45a062b0Sdlg
150*45a062b0Sdlg return (0);
151*45a062b0Sdlg }
152*45a062b0Sdlg
153*45a062b0Sdlg static int
rport_output(struct ifnet * ifp,struct mbuf * m,struct sockaddr * dst,struct rtentry * rt)154*45a062b0Sdlg rport_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
155*45a062b0Sdlg struct rtentry *rt)
156*45a062b0Sdlg {
157*45a062b0Sdlg struct m_tag *mtag;
158*45a062b0Sdlg int error = 0;
159*45a062b0Sdlg
160*45a062b0Sdlg if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
161*45a062b0Sdlg error = ENETDOWN;
162*45a062b0Sdlg goto drop;
163*45a062b0Sdlg }
164*45a062b0Sdlg
165*45a062b0Sdlg switch (dst->sa_family) {
166*45a062b0Sdlg case AF_INET:
167*45a062b0Sdlg #ifdef INET6
168*45a062b0Sdlg case AF_INET6:
169*45a062b0Sdlg #endif
170*45a062b0Sdlg #ifdef MPLS
171*45a062b0Sdlg case AF_MPLS:
172*45a062b0Sdlg #endif
173*45a062b0Sdlg break;
174*45a062b0Sdlg default:
175*45a062b0Sdlg error = EAFNOSUPPORT;
176*45a062b0Sdlg goto drop;
177*45a062b0Sdlg }
178*45a062b0Sdlg
179*45a062b0Sdlg /* Try to limit infinite recursion through misconfiguration. */
180*45a062b0Sdlg mtag = NULL;
181*45a062b0Sdlg while ((mtag = m_tag_find(m, PACKET_TAG_GRE, mtag)) != NULL) {
182*45a062b0Sdlg if (*(int *)(mtag + 1) == ifp->if_index) {
183*45a062b0Sdlg error = EIO;
184*45a062b0Sdlg goto drop;
185*45a062b0Sdlg }
186*45a062b0Sdlg }
187*45a062b0Sdlg
188*45a062b0Sdlg mtag = m_tag_get(PACKET_TAG_GRE, sizeof(ifp->if_index), M_NOWAIT);
189*45a062b0Sdlg if (mtag == NULL) {
190*45a062b0Sdlg error = ENOBUFS;
191*45a062b0Sdlg goto drop;
192*45a062b0Sdlg }
193*45a062b0Sdlg *(int *)(mtag + 1) = ifp->if_index;
194*45a062b0Sdlg m_tag_prepend(m, mtag);
195*45a062b0Sdlg
196*45a062b0Sdlg m->m_flags &= ~(M_BCAST|M_MCAST);
197*45a062b0Sdlg m->m_pkthdr.ph_family = dst->sa_family;
198*45a062b0Sdlg #if NPF > 0
199*45a062b0Sdlg pf_pkt_addr_changed(m);
200*45a062b0Sdlg #endif
201*45a062b0Sdlg
202*45a062b0Sdlg error = if_enqueue(ifp, m);
203*45a062b0Sdlg if (error)
204*45a062b0Sdlg counters_inc(ifp->if_counters, ifc_oerrors);
205*45a062b0Sdlg
206*45a062b0Sdlg return (error);
207*45a062b0Sdlg
208*45a062b0Sdlg drop:
209*45a062b0Sdlg m_freem(m);
210*45a062b0Sdlg return (error);
211*45a062b0Sdlg }
212*45a062b0Sdlg
213*45a062b0Sdlg static int
rport_enqueue(struct ifnet * ifp,struct mbuf * m)214*45a062b0Sdlg rport_enqueue(struct ifnet *ifp, struct mbuf *m)
215*45a062b0Sdlg {
216*45a062b0Sdlg struct ifqueue *ifq = &ifp->if_snd;
217*45a062b0Sdlg int error;
218*45a062b0Sdlg
219*45a062b0Sdlg error = ifq_enqueue(ifq, m);
220*45a062b0Sdlg if (error)
221*45a062b0Sdlg return (error);
222*45a062b0Sdlg
223*45a062b0Sdlg /*
224*45a062b0Sdlg * always defer handover of packets to the peer to the ifq
225*45a062b0Sdlg * bundle task to provide control over the NET_LOCK scope.
226*45a062b0Sdlg */
227*45a062b0Sdlg task_add(ifq->ifq_softnet, &ifq->ifq_bundle);
228*45a062b0Sdlg
229*45a062b0Sdlg return (0);
230*45a062b0Sdlg }
231*45a062b0Sdlg
232*45a062b0Sdlg static void
rport_start(struct ifqueue * ifq)233*45a062b0Sdlg rport_start(struct ifqueue *ifq)
234*45a062b0Sdlg {
235*45a062b0Sdlg struct ifnet *ifp = ifq->ifq_if;
236*45a062b0Sdlg struct rport_softc *sc = ifp->if_softc;
237*45a062b0Sdlg struct ifnet *ifp0;
238*45a062b0Sdlg struct mbuf *m;
239*45a062b0Sdlg
240*45a062b0Sdlg ifp0 = if_get(sc->sc_peer_idx);
241*45a062b0Sdlg if (ifp0 == NULL || !ISSET(ifp0->if_flags, IFF_RUNNING)) {
242*45a062b0Sdlg ifq_purge(ifq);
243*45a062b0Sdlg if_put(ifp0);
244*45a062b0Sdlg return;
245*45a062b0Sdlg }
246*45a062b0Sdlg
247*45a062b0Sdlg NET_LOCK_SHARED();
248*45a062b0Sdlg while ((m = ifq_dequeue(ifq)) != NULL) {
249*45a062b0Sdlg #if NBPFILTER > 0
250*45a062b0Sdlg caddr_t if_bpf = READ_ONCE(ifp->if_bpf);
251*45a062b0Sdlg if (if_bpf && bpf_mtap_af(if_bpf, m->m_pkthdr.ph_family,
252*45a062b0Sdlg m, BPF_DIRECTION_OUT)) {
253*45a062b0Sdlg m_freem(m);
254*45a062b0Sdlg continue;
255*45a062b0Sdlg }
256*45a062b0Sdlg #endif
257*45a062b0Sdlg
258*45a062b0Sdlg if_vinput(ifp0, m);
259*45a062b0Sdlg }
260*45a062b0Sdlg NET_UNLOCK_SHARED();
261*45a062b0Sdlg
262*45a062b0Sdlg if_put(ifp0);
263*45a062b0Sdlg }
264*45a062b0Sdlg
265*45a062b0Sdlg static void
rport_input(struct ifnet * ifp,struct mbuf * m)266*45a062b0Sdlg rport_input(struct ifnet *ifp, struct mbuf *m)
267*45a062b0Sdlg {
268*45a062b0Sdlg switch (m->m_pkthdr.ph_family) {
269*45a062b0Sdlg case AF_INET:
270*45a062b0Sdlg ipv4_input(ifp, m);
271*45a062b0Sdlg break;
272*45a062b0Sdlg #ifdef INET6
273*45a062b0Sdlg case AF_INET6:
274*45a062b0Sdlg ipv6_input(ifp, m);
275*45a062b0Sdlg break;
276*45a062b0Sdlg #endif
277*45a062b0Sdlg #ifdef MPLS
278*45a062b0Sdlg case AF_MPLS:
279*45a062b0Sdlg mpls_input(ifp, m);
280*45a062b0Sdlg break;
281*45a062b0Sdlg #endif
282*45a062b0Sdlg default:
283*45a062b0Sdlg counters_inc(ifp->if_counters, ifc_noproto);
284*45a062b0Sdlg m_freem(m);
285*45a062b0Sdlg break;
286*45a062b0Sdlg }
287*45a062b0Sdlg }
288*45a062b0Sdlg
289*45a062b0Sdlg static int
rport_up(struct rport_softc * sc)290*45a062b0Sdlg rport_up(struct rport_softc *sc)
291*45a062b0Sdlg {
292*45a062b0Sdlg NET_ASSERT_LOCKED();
293*45a062b0Sdlg
294*45a062b0Sdlg SET(sc->sc_if.if_flags, IFF_RUNNING);
295*45a062b0Sdlg
296*45a062b0Sdlg return (0);
297*45a062b0Sdlg }
298*45a062b0Sdlg
299*45a062b0Sdlg static int
rport_down(struct rport_softc * sc)300*45a062b0Sdlg rport_down(struct rport_softc *sc)
301*45a062b0Sdlg {
302*45a062b0Sdlg NET_ASSERT_LOCKED();
303*45a062b0Sdlg
304*45a062b0Sdlg CLR(sc->sc_if.if_flags, IFF_RUNNING);
305*45a062b0Sdlg
306*45a062b0Sdlg return (0);
307*45a062b0Sdlg }
308*45a062b0Sdlg
309*45a062b0Sdlg static int
rport_set_parent(struct rport_softc * sc,const struct if_parent * p)310*45a062b0Sdlg rport_set_parent(struct rport_softc *sc, const struct if_parent *p)
311*45a062b0Sdlg {
312*45a062b0Sdlg struct ifnet *ifp = &sc->sc_if;
313*45a062b0Sdlg struct ifnet *ifp0;
314*45a062b0Sdlg struct rport_softc *sc0;
315*45a062b0Sdlg int error;
316*45a062b0Sdlg
317*45a062b0Sdlg error = rw_enter(&rport_interfaces_lock, RW_WRITE | RW_INTR);
318*45a062b0Sdlg if (error != 0)
319*45a062b0Sdlg return (error);
320*45a062b0Sdlg
321*45a062b0Sdlg ifp0 = if_unit(p->ifp_parent);
322*45a062b0Sdlg if (ifp0 == NULL) {
323*45a062b0Sdlg error = EINVAL;
324*45a062b0Sdlg goto leave;
325*45a062b0Sdlg }
326*45a062b0Sdlg
327*45a062b0Sdlg if (ifp0 == ifp) {
328*45a062b0Sdlg error = EINVAL;
329*45a062b0Sdlg goto leave;
330*45a062b0Sdlg }
331*45a062b0Sdlg
332*45a062b0Sdlg if (ifp0->if_input != rport_input) {
333*45a062b0Sdlg error = EPROTONOSUPPORT;
334*45a062b0Sdlg goto put;
335*45a062b0Sdlg }
336*45a062b0Sdlg
337*45a062b0Sdlg sc0 = ifp0->if_softc;
338*45a062b0Sdlg
339*45a062b0Sdlg if (sc->sc_peer_idx == ifp0->if_index) {
340*45a062b0Sdlg /* nop */
341*45a062b0Sdlg KASSERT(sc0->sc_peer_idx == ifp->if_index);
342*45a062b0Sdlg goto put;
343*45a062b0Sdlg }
344*45a062b0Sdlg
345*45a062b0Sdlg if (sc->sc_peer_idx != 0 || sc0->sc_peer_idx != 0) {
346*45a062b0Sdlg error = EBUSY;
347*45a062b0Sdlg goto put;
348*45a062b0Sdlg }
349*45a062b0Sdlg
350*45a062b0Sdlg /* commit */
351*45a062b0Sdlg sc->sc_peer_idx = ifp0->if_index;
352*45a062b0Sdlg sc0->sc_peer_idx = ifp->if_index;
353*45a062b0Sdlg
354*45a062b0Sdlg put:
355*45a062b0Sdlg if_put(ifp0);
356*45a062b0Sdlg leave:
357*45a062b0Sdlg rw_exit(&rport_interfaces_lock);
358*45a062b0Sdlg
359*45a062b0Sdlg return (error);
360*45a062b0Sdlg }
361*45a062b0Sdlg
362*45a062b0Sdlg static int
rport_get_parent(struct rport_softc * sc,struct if_parent * p)363*45a062b0Sdlg rport_get_parent(struct rport_softc *sc, struct if_parent *p)
364*45a062b0Sdlg {
365*45a062b0Sdlg struct ifnet *ifp0;
366*45a062b0Sdlg int error = 0;
367*45a062b0Sdlg
368*45a062b0Sdlg ifp0 = if_get(sc->sc_peer_idx);
369*45a062b0Sdlg if (ifp0 == NULL)
370*45a062b0Sdlg error = EADDRNOTAVAIL;
371*45a062b0Sdlg else {
372*45a062b0Sdlg if (strlcpy(p->ifp_parent, ifp0->if_xname,
373*45a062b0Sdlg sizeof(p->ifp_parent)) >= sizeof(p->ifp_parent))
374*45a062b0Sdlg panic("%s strlcpy", __func__);
375*45a062b0Sdlg }
376*45a062b0Sdlg if_put(ifp0);
377*45a062b0Sdlg
378*45a062b0Sdlg return (error);
379*45a062b0Sdlg }
380*45a062b0Sdlg
381*45a062b0Sdlg static int
rport_del_parent(struct rport_softc * sc)382*45a062b0Sdlg rport_del_parent(struct rport_softc *sc)
383*45a062b0Sdlg {
384*45a062b0Sdlg struct rport_softc *sc0;
385*45a062b0Sdlg struct ifnet *ifp0;
386*45a062b0Sdlg int error;
387*45a062b0Sdlg
388*45a062b0Sdlg error = rw_enter(&rport_interfaces_lock, RW_WRITE | RW_INTR);
389*45a062b0Sdlg if (error != 0)
390*45a062b0Sdlg return (error);
391*45a062b0Sdlg
392*45a062b0Sdlg ifp0 = if_get(sc->sc_peer_idx);
393*45a062b0Sdlg sc->sc_peer_idx = 0;
394*45a062b0Sdlg
395*45a062b0Sdlg if (ifp0 != NULL) {
396*45a062b0Sdlg sc0 = ifp0->if_softc;
397*45a062b0Sdlg sc0->sc_peer_idx = 0;
398*45a062b0Sdlg }
399*45a062b0Sdlg if_put(ifp0);
400*45a062b0Sdlg
401*45a062b0Sdlg rw_exit(&rport_interfaces_lock);
402*45a062b0Sdlg
403*45a062b0Sdlg return (0);
404*45a062b0Sdlg }
405*45a062b0Sdlg
406*45a062b0Sdlg static int
rport_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)407*45a062b0Sdlg rport_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
408*45a062b0Sdlg {
409*45a062b0Sdlg struct rport_softc *sc = ifp->if_softc;
410*45a062b0Sdlg struct ifreq *ifr = (struct ifreq *)data;
411*45a062b0Sdlg int error = 0;
412*45a062b0Sdlg
413*45a062b0Sdlg switch (cmd) {
414*45a062b0Sdlg case SIOCSIFADDR:
415*45a062b0Sdlg break;
416*45a062b0Sdlg case SIOCSIFFLAGS:
417*45a062b0Sdlg if (ISSET(ifp->if_flags, IFF_UP)) {
418*45a062b0Sdlg if (!ISSET(ifp->if_flags, IFF_RUNNING))
419*45a062b0Sdlg error = rport_up(sc);
420*45a062b0Sdlg } else {
421*45a062b0Sdlg if (ISSET(ifp->if_flags, IFF_RUNNING))
422*45a062b0Sdlg error = rport_down(sc);
423*45a062b0Sdlg }
424*45a062b0Sdlg break;
425*45a062b0Sdlg
426*45a062b0Sdlg case SIOCADDMULTI:
427*45a062b0Sdlg case SIOCDELMULTI:
428*45a062b0Sdlg break;
429*45a062b0Sdlg
430*45a062b0Sdlg case SIOCSIFMTU:
431*45a062b0Sdlg if (ifr->ifr_mtu < RPORT_MTU_MIN ||
432*45a062b0Sdlg ifr->ifr_mtu > RPORT_MTU_MAX) {
433*45a062b0Sdlg error = EINVAL;
434*45a062b0Sdlg break;
435*45a062b0Sdlg }
436*45a062b0Sdlg
437*45a062b0Sdlg ifp->if_mtu = ifr->ifr_mtu;
438*45a062b0Sdlg break;
439*45a062b0Sdlg
440*45a062b0Sdlg case SIOCSIFPARENT:
441*45a062b0Sdlg error = rport_set_parent(sc, (struct if_parent *)data);
442*45a062b0Sdlg break;
443*45a062b0Sdlg case SIOCGIFPARENT:
444*45a062b0Sdlg error = rport_get_parent(sc, (struct if_parent *)data);
445*45a062b0Sdlg break;
446*45a062b0Sdlg case SIOCDIFPARENT:
447*45a062b0Sdlg error = rport_del_parent(sc);
448*45a062b0Sdlg break;
449*45a062b0Sdlg
450*45a062b0Sdlg default:
451*45a062b0Sdlg error = ENOTTY;
452*45a062b0Sdlg break;
453*45a062b0Sdlg }
454*45a062b0Sdlg
455*45a062b0Sdlg return (error);
456*45a062b0Sdlg }
457