xref: /openbsd/sys/net/if_rport.c (revision 45a062b0)
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