1*b5b8bc53Smvs /* $OpenBSD: if_mpe.c,v 1.105 2024/01/01 18:47:02 mvs Exp $ */
2384d604dSpyr
3384d604dSpyr /*
4384d604dSpyr * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@spootnik.org>
5384d604dSpyr *
6384d604dSpyr * Permission to use, copy, modify, and distribute this software for any
7384d604dSpyr * purpose with or without fee is hereby granted, provided that the above
8384d604dSpyr * copyright notice and this permission notice appear in all copies.
9384d604dSpyr *
10384d604dSpyr * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11384d604dSpyr * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12384d604dSpyr * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13384d604dSpyr * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14384d604dSpyr * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15384d604dSpyr * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16384d604dSpyr * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17384d604dSpyr */
18b896c3f8Spyr
19b896c3f8Spyr #include <sys/param.h>
20b896c3f8Spyr #include <sys/systm.h>
21b896c3f8Spyr #include <sys/mbuf.h>
22b896c3f8Spyr #include <sys/socket.h>
23b896c3f8Spyr #include <sys/sockio.h>
24b896c3f8Spyr #include <sys/ioctl.h>
25b896c3f8Spyr
26b896c3f8Spyr #include <net/if.h>
27c7b7b779Sbluhm #include <net/if_dl.h>
280deb6685Smpi #include <net/if_var.h>
29b896c3f8Spyr #include <net/if_types.h>
305aa9b43bSpyr #include <net/netisr.h>
31b896c3f8Spyr #include <net/route.h>
32b896c3f8Spyr
33b896c3f8Spyr #include <netinet/in.h>
34b896c3f8Spyr #include <netinet/ip.h>
35b896c3f8Spyr
36b896c3f8Spyr #ifdef INET6
3766c01e6aSmichele #include <netinet/ip6.h>
38b896c3f8Spyr #endif /* INET6 */
39b896c3f8Spyr
403dbb74bbSpyr #include "bpfilter.h"
413dbb74bbSpyr #if NBPFILTER > 0
423dbb74bbSpyr #include <net/bpf.h>
433dbb74bbSpyr #endif
443dbb74bbSpyr
45b896c3f8Spyr #include <netmpls/mpls.h>
46b896c3f8Spyr
472f1dccd9Sdlg
482f1dccd9Sdlg
49b896c3f8Spyr #ifdef MPLS_DEBUG
50b896c3f8Spyr #define DPRINTF(x) do { if (mpedebug) printf x ; } while (0)
51b896c3f8Spyr #else
52b896c3f8Spyr #define DPRINTF(x)
53b896c3f8Spyr #endif
54b896c3f8Spyr
552f1dccd9Sdlg struct mpe_softc {
562f1dccd9Sdlg struct ifnet sc_if; /* the interface */
57f1dea89cSdlg int sc_txhprio;
58a61f5d85Sdlg int sc_rxhprio;
59296ad859Sdlg unsigned int sc_rdomain;
602f1dccd9Sdlg struct ifaddr sc_ifa;
612f1dccd9Sdlg struct sockaddr_mpls sc_smpls;
62119f8e2bSdlg
63119f8e2bSdlg int sc_dead;
642f1dccd9Sdlg };
652f1dccd9Sdlg
662f1dccd9Sdlg #define MPE_HDRLEN sizeof(struct shim_hdr)
672f1dccd9Sdlg #define MPE_MTU 1500
682f1dccd9Sdlg #define MPE_MTU_MIN 256
692f1dccd9Sdlg #define MPE_MTU_MAX 8192
702f1dccd9Sdlg
71b896c3f8Spyr void mpeattach(int);
726a969fa2Sdlg int mpe_output(struct ifnet *, struct mbuf *, struct sockaddr *,
73b896c3f8Spyr struct rtentry *);
746a969fa2Sdlg int mpe_ioctl(struct ifnet *, u_long, caddr_t);
756a969fa2Sdlg void mpe_start(struct ifnet *);
76b896c3f8Spyr int mpe_clone_create(struct if_clone *, int);
77b896c3f8Spyr int mpe_clone_destroy(struct ifnet *);
78c6de5097Sdlg void mpe_input(struct ifnet *, struct mbuf *);
79b896c3f8Spyr
80b896c3f8Spyr struct if_clone mpe_cloner =
81b896c3f8Spyr IF_CLONE_INITIALIZER("mpe", mpe_clone_create, mpe_clone_destroy);
82b896c3f8Spyr
838b3356d2Smichele extern int mpls_mapttl_ip;
8441a5659aSmikeb #ifdef INET6
858b3356d2Smichele extern int mpls_mapttl_ip6;
8641a5659aSmikeb #endif
878b3356d2Smichele
88b896c3f8Spyr void
mpeattach(int nmpe)89b896c3f8Spyr mpeattach(int nmpe)
90b896c3f8Spyr {
91b896c3f8Spyr if_clone_attach(&mpe_cloner);
92b896c3f8Spyr }
93b896c3f8Spyr
94b896c3f8Spyr int
mpe_clone_create(struct if_clone * ifc,int unit)95b896c3f8Spyr mpe_clone_create(struct if_clone *ifc, int unit)
96b896c3f8Spyr {
9726e9ef71Sdlg struct mpe_softc *sc;
98b896c3f8Spyr struct ifnet *ifp;
99b896c3f8Spyr
100c14615c1Sdlg sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK|M_CANFAIL|M_ZERO);
101c14615c1Sdlg if (sc == NULL)
102c14615c1Sdlg return (ENOMEM);
103c14615c1Sdlg
10426e9ef71Sdlg ifp = &sc->sc_if;
105b896c3f8Spyr snprintf(ifp->if_xname, sizeof ifp->if_xname, "mpe%d", unit);
106807bde9bSpyr ifp->if_flags = IFF_POINTOPOINT;
10799bf4b5fSmpi ifp->if_xflags = IFXF_CLONED;
10826e9ef71Sdlg ifp->if_softc = sc;
109807bde9bSpyr ifp->if_mtu = MPE_MTU;
1106a969fa2Sdlg ifp->if_ioctl = mpe_ioctl;
1112e3db693Sdlg ifp->if_bpf_mtap = p2p_bpf_mtap;
1122e3db693Sdlg ifp->if_input = p2p_input;
1136a969fa2Sdlg ifp->if_output = mpe_output;
1146a969fa2Sdlg ifp->if_start = mpe_start;
115b896c3f8Spyr ifp->if_type = IFT_MPLS;
116b896c3f8Spyr ifp->if_hdrlen = MPE_HDRLEN;
117119f8e2bSdlg
118119f8e2bSdlg sc->sc_dead = 0;
119119f8e2bSdlg
120*b5b8bc53Smvs if_counters_alloc(ifp);
121b896c3f8Spyr if_attach(ifp);
122b896c3f8Spyr if_alloc_sadl(ifp);
1232e3db693Sdlg
124b896c3f8Spyr #if NBPFILTER > 0
125c3dd9049Syasuoka bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
126b896c3f8Spyr #endif
127b896c3f8Spyr
128f1dea89cSdlg sc->sc_txhprio = 0;
129a61f5d85Sdlg sc->sc_rxhprio = IF_HDRPRIO_PACKET;
130296ad859Sdlg sc->sc_rdomain = 0;
13118a44669Sbluhm refcnt_init_trace(&sc->sc_ifa.ifa_refcnt, DT_REFCNT_IDX_IFADDR);
13226e9ef71Sdlg sc->sc_ifa.ifa_ifp = ifp;
13326e9ef71Sdlg sc->sc_ifa.ifa_addr = sdltosa(ifp->if_sadl);
13426e9ef71Sdlg sc->sc_smpls.smpls_len = sizeof(sc->sc_smpls);
13526e9ef71Sdlg sc->sc_smpls.smpls_family = AF_MPLS;
136106d177cSmpi
137b896c3f8Spyr return (0);
138b896c3f8Spyr }
139b896c3f8Spyr
140b896c3f8Spyr int
mpe_clone_destroy(struct ifnet * ifp)141b896c3f8Spyr mpe_clone_destroy(struct ifnet *ifp)
142b896c3f8Spyr {
14326e9ef71Sdlg struct mpe_softc *sc = ifp->if_softc;
144b896c3f8Spyr
14518e29477Sdlg NET_LOCK();
14618e29477Sdlg CLR(ifp->if_flags, IFF_RUNNING);
147119f8e2bSdlg sc->sc_dead = 1;
148119f8e2bSdlg
14926e9ef71Sdlg if (sc->sc_smpls.smpls_label) {
150296ad859Sdlg rt_ifa_del(&sc->sc_ifa, RTF_MPLS|RTF_LOCAL,
151296ad859Sdlg smplstosa(&sc->sc_smpls), sc->sc_rdomain);
152106d177cSmpi }
15318e29477Sdlg NET_UNLOCK();
154106d177cSmpi
15518e29477Sdlg ifq_barrier(&ifp->if_snd);
156119f8e2bSdlg
157b896c3f8Spyr if_detach(ifp);
15818a44669Sbluhm if (refcnt_rele(&sc->sc_ifa.ifa_refcnt) == 0) {
15918a44669Sbluhm panic("%s: ifa refcnt has %u refs", __func__,
16018a44669Sbluhm sc->sc_ifa.ifa_refcnt.r_refs);
16118a44669Sbluhm }
16226e9ef71Sdlg free(sc, M_DEVBUF, sizeof *sc);
163b896c3f8Spyr return (0);
164b896c3f8Spyr }
165b896c3f8Spyr
166b896c3f8Spyr /*
167b896c3f8Spyr * Start output on the mpe interface.
168b896c3f8Spyr */
169b896c3f8Spyr void
mpe_start(struct ifnet * ifp)1706339f48fSdlg mpe_start(struct ifnet *ifp)
171b896c3f8Spyr {
172f0b1bf0bSdlg struct mpe_softc *sc = ifp->if_softc;
173b896c3f8Spyr struct mbuf *m;
1746339f48fSdlg struct sockaddr *sa;
1756339f48fSdlg struct sockaddr smpls = { .sa_family = AF_MPLS };
176769a1feaSclaudio struct rtentry *rt;
1776339f48fSdlg struct ifnet *ifp0;
178b896c3f8Spyr
1796339f48fSdlg while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) {
1806339f48fSdlg sa = mtod(m, struct sockaddr *);
181f0b1bf0bSdlg rt = rtalloc(sa, RT_RESOLVE, sc->sc_rdomain);
1823df9a1b0Smpi if (!rtisvalid(rt)) {
183769a1feaSclaudio m_freem(m);
1843df9a1b0Smpi rtfree(rt);
1853df9a1b0Smpi continue;
1863df9a1b0Smpi }
1873df9a1b0Smpi
1886339f48fSdlg ifp0 = if_get(rt->rt_ifidx);
1896339f48fSdlg if (ifp0 == NULL) {
1903df9a1b0Smpi m_freem(m);
1913df9a1b0Smpi rtfree(rt);
192769a1feaSclaudio continue;
193769a1feaSclaudio }
1946339f48fSdlg
1956339f48fSdlg m_adj(m, sa->sa_len);
1966339f48fSdlg
197769a1feaSclaudio #if NBPFILTER > 0
1986339f48fSdlg if (ifp->if_bpf) {
199769a1feaSclaudio /* remove MPLS label before passing packet to bpf */
200769a1feaSclaudio m->m_data += sizeof(struct shim_hdr);
201769a1feaSclaudio m->m_len -= sizeof(struct shim_hdr);
202769a1feaSclaudio m->m_pkthdr.len -= sizeof(struct shim_hdr);
2036339f48fSdlg bpf_mtap_af(ifp->if_bpf, m->m_pkthdr.ph_family,
2046339f48fSdlg m, BPF_DIRECTION_OUT);
205769a1feaSclaudio m->m_data -= sizeof(struct shim_hdr);
206769a1feaSclaudio m->m_len += sizeof(struct shim_hdr);
207769a1feaSclaudio m->m_pkthdr.len += sizeof(struct shim_hdr);
208769a1feaSclaudio }
209769a1feaSclaudio #endif
210db4e5757Sdlg
211db4e5757Sdlg m->m_pkthdr.ph_rtableid = sc->sc_rdomain;
212957fd304Sdlg CLR(m->m_flags, M_BCAST|M_MCAST);
213db4e5757Sdlg
2146339f48fSdlg mpls_output(ifp0, m, &smpls, rt);
215aa0313afSdlg if_put(ifp0);
21627ae666cSmpi rtfree(rt);
217b896c3f8Spyr }
218b896c3f8Spyr }
219b896c3f8Spyr
220b896c3f8Spyr int
mpe_output(struct ifnet * ifp,struct mbuf * m,struct sockaddr * dst,struct rtentry * rt)2216a969fa2Sdlg mpe_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
222b896c3f8Spyr struct rtentry *rt)
223b896c3f8Spyr {
224f1dea89cSdlg struct mpe_softc *sc;
2256339f48fSdlg struct rt_mpls *rtmpls;
226769a1feaSclaudio struct shim_hdr shim;
227b896c3f8Spyr int error;
228f1dea89cSdlg int txprio;
2296339f48fSdlg uint8_t ttl = mpls_defttl;
230f1dea89cSdlg uint8_t tos, prio;
231aa0313afSdlg size_t ttloff;
2326339f48fSdlg socklen_t slen;
233769a1feaSclaudio
234aa0313afSdlg if (!rtisvalid(rt) || !ISSET(rt->rt_flags, RTF_MPLS)) {
235aa0313afSdlg m_freem(m);
236aa0313afSdlg return (ENETUNREACH);
237aa0313afSdlg }
238aa0313afSdlg
239aa0313afSdlg if (dst->sa_family == AF_LINK && ISSET(rt->rt_flags, RTF_LOCAL)) {
240c6de5097Sdlg mpe_input(ifp, m);
241c6de5097Sdlg return (0);
242c6de5097Sdlg }
243c6de5097Sdlg
244769a1feaSclaudio #ifdef DIAGNOSTIC
2455ee8afe3Smpi if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid)) {
246769a1feaSclaudio printf("%s: trying to send packet on wrong domain. "
247769a1feaSclaudio "if %d vs. mbuf %d\n", ifp->if_xname,
2485ee8afe3Smpi ifp->if_rdomain, rtable_l2(m->m_pkthdr.ph_rtableid));
249769a1feaSclaudio }
250769a1feaSclaudio #endif
2516339f48fSdlg
2526339f48fSdlg rtmpls = (struct rt_mpls *)rt->rt_llinfo;
2536339f48fSdlg if (rtmpls->mpls_operation != MPLS_OP_PUSH) {
2546339f48fSdlg m_freem(m);
255aa0313afSdlg return (ENETUNREACH);
2566339f48fSdlg }
2576339f48fSdlg
258b896c3f8Spyr error = 0;
2593dbb74bbSpyr switch (dst->sa_family) {
260f1dea89cSdlg case AF_INET: {
261f1dea89cSdlg struct ip *ip = mtod(m, struct ip *);
262f1dea89cSdlg tos = ip->ip_tos;
263aa0313afSdlg ttloff = offsetof(struct ip, ip_ttl);
2646339f48fSdlg slen = sizeof(struct sockaddr_in);
265769a1feaSclaudio break;
266f1dea89cSdlg }
2676339f48fSdlg #ifdef INET6
268f1dea89cSdlg case AF_INET6: {
269f1dea89cSdlg struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
270f1dea89cSdlg uint32_t flow = bemtoh32(&ip6->ip6_flow);
271f1dea89cSdlg tos = flow >> 20;
272aa0313afSdlg ttloff = offsetof(struct ip6_hdr, ip6_hlim);
2736339f48fSdlg slen = sizeof(struct sockaddr_in6);
2746339f48fSdlg break;
275f1dea89cSdlg }
2766339f48fSdlg #endif
2773dbb74bbSpyr default:
278769a1feaSclaudio m_freem(m);
279aa0313afSdlg return (EPFNOSUPPORT);
280aa0313afSdlg }
281aa0313afSdlg
282aa0313afSdlg if (mpls_mapttl_ip) {
283aa0313afSdlg /* assumes the ip header is already contig */
284aa0313afSdlg ttl = *(mtod(m, uint8_t *) + ttloff);
2853b0a6083Sclaudio }
286769a1feaSclaudio
287f1dea89cSdlg sc = ifp->if_softc;
288f1dea89cSdlg txprio = sc->sc_txhprio;
289f1dea89cSdlg
290f1dea89cSdlg switch (txprio) {
291f1dea89cSdlg case IF_HDRPRIO_PACKET:
292f1dea89cSdlg prio = m->m_pkthdr.pf.prio;
293f1dea89cSdlg break;
294f1dea89cSdlg case IF_HDRPRIO_PAYLOAD:
295f1dea89cSdlg prio = IFQ_TOS2PRIO(tos);
296f1dea89cSdlg break;
297f1dea89cSdlg default:
298f1dea89cSdlg prio = txprio;
299f1dea89cSdlg break;
300f1dea89cSdlg }
301f1dea89cSdlg
302f1dea89cSdlg shim.shim_label = rtmpls->mpls_label | htonl(prio << MPLS_EXP_OFFSET) |
303f1dea89cSdlg MPLS_BOS_MASK | htonl(ttl);
3046339f48fSdlg
3056339f48fSdlg m = m_prepend(m, sizeof(shim), M_NOWAIT);
3066339f48fSdlg if (m == NULL) {
3076339f48fSdlg error = ENOMEM;
3086339f48fSdlg goto out;
3096339f48fSdlg }
3106339f48fSdlg *mtod(m, struct shim_hdr *) = shim;
3116339f48fSdlg
3126339f48fSdlg m = m_prepend(m, slen, M_WAITOK);
3136339f48fSdlg if (m == NULL) {
3146339f48fSdlg error = ENOMEM;
3156339f48fSdlg goto out;
3166339f48fSdlg }
3176339f48fSdlg memcpy(mtod(m, struct sockaddr *), rt->rt_gateway, slen);
3186339f48fSdlg mtod(m, struct sockaddr *)->sa_len = slen; /* to be sure */
319769a1feaSclaudio
320aa0313afSdlg m->m_pkthdr.ph_family = dst->sa_family;
321aa0313afSdlg
322c38eb4ffSmpi error = if_enqueue(ifp, m);
3233dbb74bbSpyr out:
3243dbb74bbSpyr if (error)
3253dbb74bbSpyr ifp->if_oerrors++;
326b896c3f8Spyr return (error);
327b896c3f8Spyr }
328b896c3f8Spyr
329b896c3f8Spyr int
mpe_set_label(struct mpe_softc * sc,uint32_t label,unsigned int rdomain)330296ad859Sdlg mpe_set_label(struct mpe_softc *sc, uint32_t label, unsigned int rdomain)
331296ad859Sdlg {
332296ad859Sdlg int error;
333296ad859Sdlg
334119f8e2bSdlg if (sc->sc_dead)
335119f8e2bSdlg return (ENXIO);
336119f8e2bSdlg
337296ad859Sdlg if (sc->sc_smpls.smpls_label) {
338296ad859Sdlg /* remove old MPLS route */
339296ad859Sdlg rt_ifa_del(&sc->sc_ifa, RTF_MPLS|RTF_LOCAL,
340296ad859Sdlg smplstosa(&sc->sc_smpls), sc->sc_rdomain);
341296ad859Sdlg }
342296ad859Sdlg
343296ad859Sdlg /* add new MPLS route */
344296ad859Sdlg sc->sc_smpls.smpls_label = label;
345296ad859Sdlg sc->sc_rdomain = rdomain;
346296ad859Sdlg
347f8890659Skn /* only install with a label or mpe_clone_destroy() will ignore it */
348f8890659Skn if (sc->sc_smpls.smpls_label == MPLS_LABEL2SHIM(0))
349f8890659Skn return 0;
350f8890659Skn
351296ad859Sdlg error = rt_ifa_add(&sc->sc_ifa, RTF_MPLS|RTF_LOCAL,
352296ad859Sdlg smplstosa(&sc->sc_smpls), sc->sc_rdomain);
353296ad859Sdlg if (error)
354296ad859Sdlg sc->sc_smpls.smpls_label = 0;
355296ad859Sdlg
356296ad859Sdlg return (error);
357296ad859Sdlg }
358296ad859Sdlg
359296ad859Sdlg int
mpe_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)3606a969fa2Sdlg mpe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
361b896c3f8Spyr {
3621313aa79Sdlg struct mpe_softc *sc = ifp->if_softc;
363b896c3f8Spyr struct ifreq *ifr;
364b896c3f8Spyr struct shim_hdr shim;
36511c698ddSmpi int error = 0;
366b896c3f8Spyr
367b896c3f8Spyr ifr = (struct ifreq *)data;
368b896c3f8Spyr switch (cmd) {
369b896c3f8Spyr case SIOCSIFADDR:
370b896c3f8Spyr break;
371b896c3f8Spyr case SIOCSIFFLAGS:
372b896c3f8Spyr if (ifp->if_flags & IFF_UP)
373b896c3f8Spyr ifp->if_flags |= IFF_RUNNING;
374b896c3f8Spyr else
375b896c3f8Spyr ifp->if_flags &= ~IFF_RUNNING;
376b896c3f8Spyr break;
377807bde9bSpyr case SIOCSIFMTU:
378807bde9bSpyr if (ifr->ifr_mtu < MPE_MTU_MIN ||
379807bde9bSpyr ifr->ifr_mtu > MPE_MTU_MAX)
380807bde9bSpyr error = EINVAL;
381807bde9bSpyr else
382807bde9bSpyr ifp->if_mtu = ifr->ifr_mtu;
383807bde9bSpyr break;
384b896c3f8Spyr case SIOCGETLABEL:
3851313aa79Sdlg shim.shim_label = MPLS_SHIM2LABEL(sc->sc_smpls.smpls_label);
386fc9d54dbSdlg if (shim.shim_label == 0) {
387fc9d54dbSdlg error = EADDRNOTAVAIL;
388fc9d54dbSdlg break;
389fc9d54dbSdlg }
39082e354c7Spyr error = copyout(&shim, ifr->ifr_data, sizeof(shim));
391b896c3f8Spyr break;
392b896c3f8Spyr case SIOCSETLABEL:
39318e29477Sdlg error = copyin(ifr->ifr_data, &shim, sizeof(shim));
39418e29477Sdlg if (error != 0)
395b896c3f8Spyr break;
396b3bacb7cSmichele if (shim.shim_label > MPLS_LABEL_MAX ||
397b3bacb7cSmichele shim.shim_label <= MPLS_LABEL_RESERVED_MAX) {
398b896c3f8Spyr error = EINVAL;
399b896c3f8Spyr break;
400b896c3f8Spyr }
401a8b0ba14Sdlg shim.shim_label = MPLS_LABEL2SHIM(shim.shim_label);
402119f8e2bSdlg if (sc->sc_smpls.smpls_label != shim.shim_label) {
403119f8e2bSdlg error = mpe_set_label(sc, shim.shim_label,
404119f8e2bSdlg sc->sc_rdomain);
405119f8e2bSdlg }
406296ad859Sdlg break;
407fc9d54dbSdlg case SIOCDELLABEL:
408fc9d54dbSdlg if (sc->sc_smpls.smpls_label != MPLS_LABEL2SHIM(0)) {
409fc9d54dbSdlg rt_ifa_del(&sc->sc_ifa, RTF_MPLS|RTF_LOCAL,
410fc9d54dbSdlg smplstosa(&sc->sc_smpls), sc->sc_rdomain);
411fc9d54dbSdlg }
412b37ade80Skn sc->sc_smpls.smpls_label = MPLS_LABEL2SHIM(0);
413fc9d54dbSdlg break;
414fc9d54dbSdlg
415296ad859Sdlg case SIOCSLIFPHYRTABLE:
416296ad859Sdlg if (ifr->ifr_rdomainid < 0 ||
417296ad859Sdlg ifr->ifr_rdomainid > RT_TABLEID_MAX ||
418296ad859Sdlg !rtable_exists(ifr->ifr_rdomainid) ||
419296ad859Sdlg ifr->ifr_rdomainid != rtable_l2(ifr->ifr_rdomainid)) {
420296ad859Sdlg error = EINVAL;
421769a1feaSclaudio break;
422106d177cSmpi }
423119f8e2bSdlg if (sc->sc_rdomain != ifr->ifr_rdomainid) {
424296ad859Sdlg error = mpe_set_label(sc, sc->sc_smpls.smpls_label,
425296ad859Sdlg ifr->ifr_rdomainid);
426119f8e2bSdlg }
427296ad859Sdlg break;
428296ad859Sdlg case SIOCGLIFPHYRTABLE:
429296ad859Sdlg ifr->ifr_rdomainid = sc->sc_rdomain;
430296ad859Sdlg break;
431296ad859Sdlg
432f1dea89cSdlg case SIOCSTXHPRIO:
433b9e5cef3Sdlg error = if_txhprio_l3_check(ifr->ifr_hdrprio);
434b9e5cef3Sdlg if (error != 0)
435f1dea89cSdlg break;
436f1dea89cSdlg
437f1dea89cSdlg sc->sc_txhprio = ifr->ifr_hdrprio;
438f1dea89cSdlg break;
439f1dea89cSdlg case SIOCGTXHPRIO:
440f1dea89cSdlg ifr->ifr_hdrprio = sc->sc_txhprio;
441f1dea89cSdlg break;
442f1dea89cSdlg
443a61f5d85Sdlg case SIOCSRXHPRIO:
444b9e5cef3Sdlg error = if_rxhprio_l3_check(ifr->ifr_hdrprio);
445b9e5cef3Sdlg if (error != 0)
446a61f5d85Sdlg break;
447a61f5d85Sdlg
448a61f5d85Sdlg sc->sc_rxhprio = ifr->ifr_hdrprio;
449a61f5d85Sdlg break;
450a61f5d85Sdlg case SIOCGRXHPRIO:
451a61f5d85Sdlg ifr->ifr_hdrprio = sc->sc_rxhprio;
452a61f5d85Sdlg break;
453a61f5d85Sdlg
454b896c3f8Spyr default:
455b896c3f8Spyr return (ENOTTY);
456b896c3f8Spyr }
457b896c3f8Spyr
458b896c3f8Spyr return (error);
459b896c3f8Spyr }
4605aa9b43bSpyr
4615aa9b43bSpyr void
mpe_input(struct ifnet * ifp,struct mbuf * m)462c6de5097Sdlg mpe_input(struct ifnet *ifp, struct mbuf *m)
4635aa9b43bSpyr {
464a61f5d85Sdlg struct mpe_softc *sc = ifp->if_softc;
465c6de5097Sdlg struct shim_hdr *shim;
466b63ffc37Sdlg struct mbuf *n;
467a61f5d85Sdlg uint8_t ttl, tos;
468a61f5d85Sdlg uint32_t exp;
469a61f5d85Sdlg int rxprio = sc->sc_rxhprio;
4705aa9b43bSpyr
471c6de5097Sdlg shim = mtod(m, struct shim_hdr *);
472a61f5d85Sdlg exp = ntohl(shim->shim_label & MPLS_EXP_MASK) >> MPLS_EXP_OFFSET;
473b63ffc37Sdlg if (!MPLS_BOS_ISSET(shim->shim_label))
474b63ffc37Sdlg goto drop;
475b63ffc37Sdlg
476c6de5097Sdlg ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
477c6de5097Sdlg m_adj(m, sizeof(*shim));
478c6de5097Sdlg
479b63ffc37Sdlg n = m;
480b63ffc37Sdlg while (n->m_len == 0) {
481b63ffc37Sdlg n = n->m_next;
482b63ffc37Sdlg if (n == NULL)
483b63ffc37Sdlg goto drop;
484b63ffc37Sdlg }
485b63ffc37Sdlg
486b63ffc37Sdlg switch (*mtod(n, uint8_t *) >> 4) {
487a61f5d85Sdlg case 4: {
488a61f5d85Sdlg struct ip *ip;
489a61f5d85Sdlg if (m->m_len < sizeof(*ip)) {
490a61f5d85Sdlg m = m_pullup(m, sizeof(*ip));
491a61f5d85Sdlg if (m == NULL)
492a61f5d85Sdlg return;
493a61f5d85Sdlg }
494a61f5d85Sdlg ip = mtod(m, struct ip *);
495a61f5d85Sdlg tos = ip->ip_tos;
496a61f5d85Sdlg
497b63ffc37Sdlg if (mpls_mapttl_ip) {
49848e57f09Sdlg m = mpls_ip_adjttl(m, ttl);
499c6de5097Sdlg if (m == NULL)
500c6de5097Sdlg return;
501c6de5097Sdlg }
5022e3db693Sdlg
503b63ffc37Sdlg m->m_pkthdr.ph_family = AF_INET;
504b63ffc37Sdlg break;
505a61f5d85Sdlg }
506b63ffc37Sdlg #ifdef INET6
507a61f5d85Sdlg case 6: {
508a61f5d85Sdlg struct ip6_hdr *ip6;
509a61f5d85Sdlg uint32_t flow;
510a61f5d85Sdlg if (m->m_len < sizeof(*ip6)) {
511a61f5d85Sdlg m = m_pullup(m, sizeof(*ip6));
512a61f5d85Sdlg if (m == NULL)
513a61f5d85Sdlg return;
514a61f5d85Sdlg }
515a61f5d85Sdlg ip6 = mtod(m, struct ip6_hdr *);
516a61f5d85Sdlg flow = bemtoh32(&ip6->ip6_flow);
517a61f5d85Sdlg tos = flow >> 20;
518a61f5d85Sdlg
519b63ffc37Sdlg if (mpls_mapttl_ip6) {
52048e57f09Sdlg m = mpls_ip6_adjttl(m, ttl);
521b63ffc37Sdlg if (m == NULL)
522b63ffc37Sdlg return;
523b63ffc37Sdlg }
5242e3db693Sdlg
525b63ffc37Sdlg m->m_pkthdr.ph_family = AF_INET6;
526b63ffc37Sdlg break;
527a61f5d85Sdlg }
528b63ffc37Sdlg #endif /* INET6 */
529b63ffc37Sdlg default:
530b63ffc37Sdlg goto drop;
5318b3356d2Smichele }
5328b3356d2Smichele
533a61f5d85Sdlg switch (rxprio) {
534a61f5d85Sdlg case IF_HDRPRIO_PACKET:
535a61f5d85Sdlg /* nop */
536a61f5d85Sdlg break;
537a61f5d85Sdlg case IF_HDRPRIO_OUTER:
538a61f5d85Sdlg m->m_pkthdr.pf.prio = exp;
539a61f5d85Sdlg break;
540a61f5d85Sdlg case IF_HDRPRIO_PAYLOAD:
541a61f5d85Sdlg m->m_pkthdr.pf.prio = IFQ_TOS2PRIO(tos);
542a61f5d85Sdlg break;
543a61f5d85Sdlg default:
544a61f5d85Sdlg m->m_pkthdr.pf.prio = rxprio;
545a61f5d85Sdlg break;
546a61f5d85Sdlg }
547a61f5d85Sdlg
5482e3db693Sdlg if_vinput(ifp, m);
549b63ffc37Sdlg return;
550b63ffc37Sdlg drop:
551b63ffc37Sdlg m_freem(m);
5525aa9b43bSpyr }
553