xref: /openbsd-src/sys/net/if_mpe.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1 /* $OpenBSD: if_mpe.c,v 1.64 2018/01/09 15:24:24 bluhm Exp $ */
2 
3 /*
4  * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@spootnik.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 #include "mpe.h"
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/mbuf.h>
23 #include <sys/socket.h>
24 #include <sys/sockio.h>
25 #include <sys/ioctl.h>
26 
27 #include <net/if.h>
28 #include <net/if_dl.h>
29 #include <net/if_var.h>
30 #include <net/if_types.h>
31 #include <net/netisr.h>
32 #include <net/route.h>
33 
34 #include <netinet/in.h>
35 #include <netinet/ip.h>
36 
37 #ifdef INET6
38 #include <netinet/ip6.h>
39 #endif /* INET6 */
40 
41 #include "bpfilter.h"
42 #if NBPFILTER > 0
43 #include <net/bpf.h>
44 #endif
45 
46 #include <netmpls/mpls.h>
47 
48 #ifdef MPLS_DEBUG
49 #define DPRINTF(x)    do { if (mpedebug) printf x ; } while (0)
50 #else
51 #define DPRINTF(x)
52 #endif
53 
54 void	mpeattach(int);
55 int	mpeoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
56 		       struct rtentry *);
57 int	mpeioctl(struct ifnet *, u_long, caddr_t);
58 void	mpestart(struct ifnet *);
59 int	mpe_clone_create(struct if_clone *, int);
60 int	mpe_clone_destroy(struct ifnet *);
61 
62 LIST_HEAD(, mpe_softc)	mpeif_list;
63 struct if_clone	mpe_cloner =
64     IF_CLONE_INITIALIZER("mpe", mpe_clone_create, mpe_clone_destroy);
65 
66 extern int	mpls_mapttl_ip;
67 #ifdef INET6
68 extern int	mpls_mapttl_ip6;
69 #endif
70 
71 void
72 mpeattach(int nmpe)
73 {
74 	LIST_INIT(&mpeif_list);
75 	if_clone_attach(&mpe_cloner);
76 }
77 
78 int
79 mpe_clone_create(struct if_clone *ifc, int unit)
80 {
81 	struct ifnet		*ifp;
82 	struct mpe_softc	*mpeif;
83 
84 	mpeif = malloc(sizeof(*mpeif), M_DEVBUF, M_WAITOK|M_ZERO);
85 	mpeif->sc_unit = unit;
86 	ifp = &mpeif->sc_if;
87 	snprintf(ifp->if_xname, sizeof ifp->if_xname, "mpe%d", unit);
88 	ifp->if_flags = IFF_POINTOPOINT;
89 	ifp->if_xflags = IFXF_CLONED;
90 	ifp->if_softc = mpeif;
91 	ifp->if_mtu = MPE_MTU;
92 	ifp->if_ioctl = mpeioctl;
93 	ifp->if_output = mpeoutput;
94 	ifp->if_start = mpestart;
95 	ifp->if_type = IFT_MPLS;
96 	ifp->if_hdrlen = MPE_HDRLEN;
97 	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
98 	if_attach(ifp);
99 	if_alloc_sadl(ifp);
100 #if NBPFILTER > 0
101 	bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t));
102 #endif
103 
104 	mpeif->sc_ifa.ifa_ifp = ifp;
105 	mpeif->sc_ifa.ifa_addr = sdltosa(ifp->if_sadl);
106 	mpeif->sc_smpls.smpls_len = sizeof(mpeif->sc_smpls);
107 	mpeif->sc_smpls.smpls_family = AF_MPLS;
108 
109 	LIST_INSERT_HEAD(&mpeif_list, mpeif, sc_list);
110 
111 	return (0);
112 }
113 
114 int
115 mpe_clone_destroy(struct ifnet *ifp)
116 {
117 	struct mpe_softc	*mpeif = ifp->if_softc;
118 
119 	LIST_REMOVE(mpeif, sc_list);
120 
121 	if (mpeif->sc_smpls.smpls_label) {
122 		rt_ifa_del(&mpeif->sc_ifa, RTF_MPLS,
123 		    smplstosa(&mpeif->sc_smpls));
124 	}
125 
126 	if_detach(ifp);
127 	free(mpeif, M_DEVBUF, sizeof *mpeif);
128 	return (0);
129 }
130 
131 struct sockaddr_storage	 mpedst;
132 /*
133  * Start output on the mpe interface.
134  */
135 void
136 mpestart(struct ifnet *ifp0)
137 {
138 	struct mbuf		*m;
139 	struct sockaddr		*sa = sstosa(&mpedst);
140 	sa_family_t		 af;
141 	struct rtentry		*rt;
142 	struct ifnet		*ifp;
143 
144 	for (;;) {
145 		IFQ_DEQUEUE(&ifp0->if_snd, m);
146 		if (m == NULL)
147 			return;
148 
149 		af = *mtod(m, sa_family_t *);
150 		m_adj(m, sizeof(af));
151 		switch (af) {
152 		case AF_INET:
153 			bzero(sa, sizeof(struct sockaddr_in));
154 			satosin(sa)->sin_family = af;
155 			satosin(sa)->sin_len = sizeof(struct sockaddr_in);
156 			bcopy(mtod(m, caddr_t), &satosin(sa)->sin_addr,
157 			    sizeof(in_addr_t));
158 			m_adj(m, sizeof(in_addr_t));
159 			break;
160 		default:
161 			m_freem(m);
162 			continue;
163 		}
164 
165 		rt = rtalloc(sa, RT_RESOLVE, 0);
166 		if (!rtisvalid(rt)) {
167 			m_freem(m);
168 			rtfree(rt);
169 			continue;
170 		}
171 
172 		ifp = if_get(rt->rt_ifidx);
173 		if (ifp == NULL) {
174 			m_freem(m);
175 			rtfree(rt);
176 			continue;
177 		}
178 #if NBPFILTER > 0
179 		if (ifp0->if_bpf) {
180 			/* remove MPLS label before passing packet to bpf */
181 			m->m_data += sizeof(struct shim_hdr);
182 			m->m_len -= sizeof(struct shim_hdr);
183 			m->m_pkthdr.len -= sizeof(struct shim_hdr);
184 			bpf_mtap_af(ifp0->if_bpf, af, m, BPF_DIRECTION_OUT);
185 			m->m_data -= sizeof(struct shim_hdr);
186 			m->m_len += sizeof(struct shim_hdr);
187 			m->m_pkthdr.len += sizeof(struct shim_hdr);
188 		}
189 #endif
190 		/* XXX lie, but mpls_output looks only at sa_family */
191 		sa->sa_family = AF_MPLS;
192 
193 		mpls_output(ifp, m, sa, rt);
194 		if_put(ifp);
195 		rtfree(rt);
196 	}
197 }
198 
199 int
200 mpeoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
201 	struct rtentry *rt)
202 {
203 	struct shim_hdr	shim;
204 	int		error;
205 	int		off;
206 	in_addr_t	addr;
207 	u_int8_t	op = 0;
208 
209 #ifdef DIAGNOSTIC
210 	if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid)) {
211 		printf("%s: trying to send packet on wrong domain. "
212 		    "if %d vs. mbuf %d\n", ifp->if_xname,
213 		    ifp->if_rdomain, rtable_l2(m->m_pkthdr.ph_rtableid));
214 	}
215 #endif
216 	m->m_pkthdr.ph_ifidx = ifp->if_index;
217 	/* XXX assumes MPLS is always in rdomain 0 */
218 	m->m_pkthdr.ph_rtableid = 0;
219 
220 	error = 0;
221 	switch (dst->sa_family) {
222 	case AF_INET:
223 		if (!rt || !(rt->rt_flags & RTF_MPLS)) {
224 			m_freem(m);
225 			error = ENETUNREACH;
226 			goto out;
227 		}
228 		shim.shim_label =
229 		    ((struct rt_mpls *)rt->rt_llinfo)->mpls_label;
230 		shim.shim_label |= MPLS_BOS_MASK;
231 		op =  ((struct rt_mpls *)rt->rt_llinfo)->mpls_operation;
232 		if (op != MPLS_OP_PUSH) {
233 			m_freem(m);
234 			error = ENETUNREACH;
235 			goto out;
236 		}
237 		if (mpls_mapttl_ip) {
238 			struct ip	*ip;
239 			ip = mtod(m, struct ip *);
240 			shim.shim_label |= htonl(ip->ip_ttl) & MPLS_TTL_MASK;
241 		} else
242 			shim.shim_label |= htonl(mpls_defttl) & MPLS_TTL_MASK;
243 		off = sizeof(sa_family_t) + sizeof(in_addr_t);
244 		M_PREPEND(m, sizeof(shim) + off, M_DONTWAIT);
245 		if (m == NULL) {
246 			error = ENOBUFS;
247 			goto out;
248 		}
249 		*mtod(m, sa_family_t *) = AF_INET;
250 		addr = satosin(rt->rt_gateway)->sin_addr.s_addr;
251 		m_copyback(m, sizeof(sa_family_t), sizeof(in_addr_t),
252 		    &addr, M_NOWAIT);
253 		break;
254 	default:
255 		m_freem(m);
256 		error = EPFNOSUPPORT;
257 		goto out;
258 	}
259 
260 	m_copyback(m, off, sizeof(shim), (caddr_t)&shim, M_NOWAIT);
261 
262 	error = if_enqueue(ifp, m);
263 out:
264 	if (error)
265 		ifp->if_oerrors++;
266 	return (error);
267 }
268 
269 int
270 mpeioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
271 {
272 	struct mpe_softc	*ifm;
273 	struct ifreq		*ifr;
274 	struct shim_hdr		 shim;
275 	int			 error = 0;
276 
277 	ifr = (struct ifreq *)data;
278 	switch (cmd) {
279 	case SIOCSIFADDR:
280 		if (!ISSET(ifp->if_flags, IFF_UP))
281 			if_up(ifp);
282 		break;
283 	case SIOCSIFFLAGS:
284 		if (ifp->if_flags & IFF_UP)
285 			ifp->if_flags |= IFF_RUNNING;
286 		else
287 			ifp->if_flags &= ~IFF_RUNNING;
288 		break;
289 	case SIOCSIFMTU:
290 		if (ifr->ifr_mtu < MPE_MTU_MIN ||
291 		    ifr->ifr_mtu > MPE_MTU_MAX)
292 			error = EINVAL;
293 		else
294 			ifp->if_mtu = ifr->ifr_mtu;
295 		break;
296 	case SIOCGETLABEL:
297 		ifm = ifp->if_softc;
298 		shim.shim_label =
299 		    ((ntohl(ifm->sc_smpls.smpls_label & MPLS_LABEL_MASK)) >>
300 		    MPLS_LABEL_OFFSET);
301 		error = copyout(&shim, ifr->ifr_data, sizeof(shim));
302 		break;
303 	case SIOCSETLABEL:
304 		ifm = ifp->if_softc;
305 		if ((error = copyin(ifr->ifr_data, &shim, sizeof(shim))))
306 			break;
307 		if (shim.shim_label > MPLS_LABEL_MAX ||
308 		    shim.shim_label <= MPLS_LABEL_RESERVED_MAX) {
309 			error = EINVAL;
310 			break;
311 		}
312 		shim.shim_label = htonl(shim.shim_label << MPLS_LABEL_OFFSET);
313 		if (ifm->sc_smpls.smpls_label == shim.shim_label)
314 			break;
315 		LIST_FOREACH(ifm, &mpeif_list, sc_list) {
316 			if (ifm != ifp->if_softc &&
317 			    ifm->sc_smpls.smpls_label == shim.shim_label) {
318 				error = EEXIST;
319 				break;
320 			}
321 		}
322 		if (error)
323 			break;
324 		/*
325 		 * force interface up for now,
326 		 * linkstate of MPLS route is not tracked
327 		 */
328 		if (!ISSET(ifp->if_flags, IFF_UP))
329 			if_up(ifp);
330 		ifm = ifp->if_softc;
331 		if (ifm->sc_smpls.smpls_label) {
332 			/* remove old MPLS route */
333 			rt_ifa_del(&ifm->sc_ifa, RTF_MPLS,
334 			    smplstosa(&ifm->sc_smpls));
335 		}
336 		/* add new MPLS route */
337 		ifm->sc_smpls.smpls_label = shim.shim_label;
338 		error = rt_ifa_add(&ifm->sc_ifa, RTF_MPLS,
339 		    smplstosa(&ifm->sc_smpls));
340 		if (error) {
341 			ifm->sc_smpls.smpls_label = 0;
342 			break;
343 		}
344 		break;
345 	case SIOCSIFRDOMAIN:
346 		/* must readd the MPLS "route" for our label */
347 		/* XXX does not make sense, the MPLS route is on rtable 0 */
348 		ifm = ifp->if_softc;
349 		if (ifr->ifr_rdomainid != ifp->if_rdomain) {
350 			if (ifm->sc_smpls.smpls_label) {
351 				rt_ifa_add(&ifm->sc_ifa, RTF_MPLS,
352 				    smplstosa(&ifm->sc_smpls));
353 			}
354 		}
355 		/* return with ENOTTY so that the parent handler finishes */
356 		return (ENOTTY);
357 	default:
358 		return (ENOTTY);
359 	}
360 
361 	return (error);
362 }
363 
364 void
365 mpe_input(struct mbuf *m, struct ifnet *ifp, struct sockaddr_mpls *smpls,
366     u_int8_t ttl)
367 {
368 	struct ip	*ip;
369 	int		 hlen;
370 
371 	/* label -> AF lookup */
372 
373 	if (mpls_mapttl_ip) {
374 		if (m->m_len < sizeof (struct ip) &&
375 		    (m = m_pullup(m, sizeof(struct ip))) == NULL)
376 			return;
377 		ip = mtod(m, struct ip *);
378 		hlen = ip->ip_hl << 2;
379 		if (m->m_len < hlen) {
380 			if ((m = m_pullup(m, hlen)) == NULL)
381 				return;
382 			ip = mtod(m, struct ip *);
383 		}
384 
385 		if (in_cksum(m, hlen) != 0) {
386 			m_freem(m);
387 			return;
388 		}
389 
390 		/* set IP ttl from MPLS ttl */
391 		ip->ip_ttl = ttl;
392 
393 		/* recalculate checksum */
394 		ip->ip_sum = 0;
395 		ip->ip_sum = in_cksum(m, hlen);
396 	}
397 
398 	/* new receive if and move into correct rtable */
399 	m->m_pkthdr.ph_ifidx = ifp->if_index;
400 	m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
401 
402 #if NBPFILTER > 0
403 	if (ifp->if_bpf)
404 		bpf_mtap_af(ifp->if_bpf, AF_INET, m, BPF_DIRECTION_IN);
405 #endif
406 
407 	ipv4_input(ifp, m);
408 }
409 
410 #ifdef INET6
411 void
412 mpe_input6(struct mbuf *m, struct ifnet *ifp, struct sockaddr_mpls *smpls,
413     u_int8_t ttl)
414 {
415 	struct ip6_hdr *ip6hdr;
416 
417 	/* label -> AF lookup */
418 
419 	if (mpls_mapttl_ip6) {
420 		if (m->m_len < sizeof (struct ip6_hdr) &&
421 		    (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL)
422 			return;
423 
424 		ip6hdr = mtod(m, struct ip6_hdr *);
425 
426 		/* set IPv6 ttl from MPLS ttl */
427 		ip6hdr->ip6_hlim = ttl;
428 	}
429 
430 	/* new receive if and move into correct rtable */
431 	m->m_pkthdr.ph_ifidx = ifp->if_index;
432 	m->m_pkthdr.ph_rtableid = ifp->if_rdomain;
433 
434 #if NBPFILTER > 0
435 	if (ifp->if_bpf)
436 		bpf_mtap_af(ifp->if_bpf, AF_INET6, m, BPF_DIRECTION_IN);
437 #endif
438 
439 	ipv6_input(ifp, m);
440 }
441 #endif	/* INET6 */
442