xref: /openbsd-src/sys/netmpls/mpls_input.c (revision c90a81c56dcebd6a1b73fe4aff9b03385b8e63b3)
1 /*	$OpenBSD: mpls_input.c,v 1.68 2018/01/12 06:57:56 jca Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Claudio Jeker <claudio@openbsd.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 
19 #include "mpe.h"
20 
21 #include <sys/param.h>
22 #include <sys/mbuf.h>
23 #include <sys/systm.h>
24 #include <sys/socket.h>
25 
26 #include <net/if.h>
27 #include <net/if_var.h>
28 #include <net/if_types.h>
29 #include <net/netisr.h>
30 #include <net/route.h>
31 
32 #include <netinet/in.h>
33 #include <netinet/ip.h>
34 #include <netinet/ip_var.h>
35 #include <netinet/ip_icmp.h>
36 
37 #ifdef INET6
38 #include <netinet/ip6.h>
39 #endif /* INET6 */
40 
41 #include <netmpls/mpls.h>
42 
43 #ifdef MPLS_DEBUG
44 #define MPLS_LABEL_GET(l)	((ntohl((l) & MPLS_LABEL_MASK)) >> MPLS_LABEL_OFFSET)
45 #define MPLS_TTL_GET(l)		(ntohl((l) & MPLS_TTL_MASK))
46 #endif
47 
48 struct mbuf	*mpls_ip_adjttl(struct mbuf *, u_int8_t);
49 #ifdef INET6
50 struct mbuf	*mpls_ip6_adjttl(struct mbuf *, u_int8_t);
51 #endif
52 
53 struct mbuf	*mpls_do_error(struct mbuf *, int, int, int);
54 
55 void
56 mpls_input(struct ifnet *ifp, struct mbuf *m)
57 {
58 	struct sockaddr_mpls *smpls;
59 	struct sockaddr_mpls sa_mpls;
60 	struct shim_hdr	*shim;
61 	struct rtentry *rt;
62 	struct rt_mpls *rt_mpls;
63 	uint8_t ttl;
64 	int hasbos;
65 
66 	if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
67 		m_freem(m);
68 		return;
69 	}
70 
71 	/* drop all broadcast and multicast packets */
72 	if (m->m_flags & (M_BCAST | M_MCAST)) {
73 		m_freem(m);
74 		return;
75 	}
76 
77 	if (m->m_len < sizeof(*shim)) {
78 		m = m_pullup(m, sizeof(*shim));
79 		if (m == NULL)
80 			return;
81 	}
82 
83 	shim = mtod(m, struct shim_hdr *);
84 #ifdef MPLS_DEBUG
85 	printf("mpls_input: iface %s label=%d, ttl=%d BoS %d\n",
86 	    ifp->if_xname, MPLS_LABEL_GET(shim->shim_label),
87 	    MPLS_TTL_GET(shim->shim_label),
88 	    MPLS_BOS_ISSET(shim->shim_label));
89 #endif
90 
91 	/* check and decrement TTL */
92 	ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
93 	if (--ttl == 0) {
94 		/* TTL exceeded */
95 		m = mpls_do_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0);
96 		if (m == NULL)
97 			return;
98 
99 		shim = mtod(m, struct shim_hdr *);
100 		ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
101 	}
102 	hasbos = MPLS_BOS_ISSET(shim->shim_label);
103 
104 	bzero(&sa_mpls, sizeof(sa_mpls));
105 	smpls = &sa_mpls;
106 	smpls->smpls_family = AF_MPLS;
107 	smpls->smpls_len = sizeof(*smpls);
108 	smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
109 
110 	if (ntohl(smpls->smpls_label) < MPLS_LABEL_RESERVED_MAX) {
111 		m = mpls_shim_pop(m);
112 		if (m == NULL)
113 			return;
114 		if (!hasbos) {
115 			/*
116 			 * RFC 4182 relaxes the position of the
117 			 * explicit NULL labels. They no longer need
118 			 * to be at the beginning of the stack.
119 			 * In this case the label is ignored and the decision
120 			 * is made based on the lower one.
121 			 */
122 			shim = mtod(m, struct shim_hdr *);
123 			smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
124 			hasbos = MPLS_BOS_ISSET(shim->shim_label);
125 		} else {
126 			switch (ntohl(smpls->smpls_label)) {
127 			case MPLS_LABEL_IPV4NULL:
128 do_v4:
129 				if ((m = mpls_ip_adjttl(m, ttl)) == NULL)
130 					return;
131 				ipv4_input(ifp, m);
132 				return;
133 #ifdef INET6
134 			case MPLS_LABEL_IPV6NULL:
135 do_v6:
136 				if ((m = mpls_ip6_adjttl(m, ttl)) == NULL)
137 					return;
138 				ipv6_input(ifp, m);
139 				return;
140 #endif	/* INET6 */
141 			case MPLS_LABEL_IMPLNULL:
142 				if (m->m_len < sizeof(u_char) &&
143 				    (m = m_pullup(m, sizeof(u_char))) == NULL)
144 					return;
145 				switch (*mtod(m, u_char *) >> 4) {
146 				case IPVERSION:
147 					goto do_v4;
148 #ifdef INET6
149 				case IPV6_VERSION >> 4:
150 					goto do_v6;
151 #endif
152 				default:
153 					m_freem(m);
154 					return;
155 				}
156 			default:
157 				/* Other cases are not handled for now */
158 				m_freem(m);
159 				return;
160 			}
161 		}
162 	}
163 
164 	ifp = NULL;
165 
166 	rt = rtalloc(smplstosa(smpls), RT_RESOLVE, m->m_pkthdr.ph_rtableid);
167 	if (rt == NULL) {
168 		/* no entry for this label */
169 #ifdef MPLS_DEBUG
170 		printf("MPLS_DEBUG: label not found\n");
171 #endif
172 		m_freem(m);
173 		return;
174 	}
175 
176 	rt_mpls = (struct rt_mpls *)rt->rt_llinfo;
177 	if (rt_mpls == NULL || (rt->rt_flags & RTF_MPLS) == 0) {
178 #ifdef MPLS_DEBUG
179 		printf("MPLS_DEBUG: no MPLS information attached\n");
180 #endif
181 		m_freem(m);
182 		goto done;
183 	}
184 
185 	switch (rt_mpls->mpls_operation) {
186 	case MPLS_OP_POP:
187 		m = mpls_shim_pop(m);
188 		if (m == NULL)
189 			goto done;
190 		if (!hasbos)
191 			/* just forward to gw */
192 			break;
193 
194 		/* last label popped so decide where to push it to */
195 		ifp = if_get(rt->rt_ifidx);
196 		if (ifp == NULL) {
197 			m_freem(m);
198 			goto done;
199 		}
200 #if NMPE > 0
201 		if (ifp->if_type == IFT_MPLS) {
202 			smpls = satosmpls(rt_key(rt));
203 			mpe_input(m, ifp, smpls, ttl);
204 			goto done;
205 		}
206 #endif
207 		if (ifp->if_type == IFT_MPLSTUNNEL) {
208 			ifp->if_output(ifp, m, rt_key(rt), rt);
209 			goto done;
210 		}
211 
212 		KASSERT(rt->rt_gateway);
213 
214 		switch(rt->rt_gateway->sa_family) {
215 		case AF_INET:
216 			if ((m = mpls_ip_adjttl(m, ttl)) == NULL)
217 				goto done;
218 			break;
219 #ifdef INET6
220 		case AF_INET6:
221 			if ((m = mpls_ip6_adjttl(m, ttl)) == NULL)
222 				goto done;
223 			break;
224 #endif
225 		default:
226 			m_freem(m);
227 			goto done;
228 		}
229 
230 		/* shortcut sending out the packet */
231 		if (!ISSET(ifp->if_xflags, IFXF_MPLS))
232 			(*ifp->if_output)(ifp, m, rt->rt_gateway, rt);
233 		else
234 			(*ifp->if_ll_output)(ifp, m, rt->rt_gateway, rt);
235 		goto done;
236 	case MPLS_OP_PUSH:
237 		/* this does not make much sense but it does not hurt */
238 		m = mpls_shim_push(m, rt_mpls);
239 		break;
240 	case MPLS_OP_SWAP:
241 		m = mpls_shim_swap(m, rt_mpls);
242 		break;
243 	default:
244 		m_freem(m);
245 		goto done;
246 	}
247 
248 	if (m == NULL)
249 		goto done;
250 
251 	/* refetch label and write back TTL */
252 	shim = mtod(m, struct shim_hdr *);
253 	shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | htonl(ttl);
254 
255 	ifp = if_get(rt->rt_ifidx);
256 	if (ifp == NULL) {
257 		m_freem(m);
258 		goto done;
259 	}
260 #ifdef MPLS_DEBUG
261 	printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n",
262     	    ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family,
263 	    MPLS_LABEL_GET(smpls->smpls_label),
264 	    MPLS_LABEL_GET(rt_mpls->mpls_label));
265 #endif
266 
267 	/* Output iface is not MPLS-enabled */
268 	if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
269 #ifdef MPLS_DEBUG
270 		printf("MPLS_DEBUG: interface %s not mpls enabled\n",
271 		    ifp->if_xname);
272 #endif
273 		m_freem(m);
274 		goto done;
275 	}
276 
277 	(*ifp->if_ll_output)(ifp, m, smplstosa(smpls), rt);
278 done:
279 	if_put(ifp);
280 	rtfree(rt);
281 }
282 
283 struct mbuf *
284 mpls_ip_adjttl(struct mbuf *m, u_int8_t ttl)
285 {
286 	struct ip *ip;
287 	int hlen;
288 
289 	if (mpls_mapttl_ip) {
290 		if (m->m_len < sizeof(struct ip) &&
291 		    (m = m_pullup(m, sizeof(struct ip))) == NULL)
292 			return NULL;
293 		ip = mtod(m, struct ip *);
294 		hlen = ip->ip_hl << 2;
295 		if (m->m_len < hlen) {
296 			if ((m = m_pullup(m, hlen)) == NULL)
297 				return NULL;
298 			ip = mtod(m, struct ip *);
299 		}
300 		/* make sure we have a valid header */
301 		if (in_cksum(m, hlen) != 0) {
302 			m_freem(m);
303 			return NULL;
304 		}
305 
306 		/* set IP ttl from MPLS ttl */
307 		ip->ip_ttl = ttl;
308 
309 		/* recalculate checksum */
310 		ip->ip_sum = 0;
311 		ip->ip_sum = in_cksum(m, hlen);
312 	}
313 	return m;
314 }
315 
316 #ifdef INET6
317 struct mbuf *
318 mpls_ip6_adjttl(struct mbuf *m, u_int8_t ttl)
319 {
320 	struct ip6_hdr *ip6hdr;
321 
322 	if (mpls_mapttl_ip6) {
323 		if (m->m_len < sizeof(struct ip6_hdr) &&
324 		    (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL)
325 			return NULL;
326 
327 		ip6hdr = mtod(m, struct ip6_hdr *);
328 
329 		/* set IPv6 ttl from MPLS ttl */
330 		ip6hdr->ip6_hlim = ttl;
331 	}
332 	return m;
333 }
334 #endif	/* INET6 */
335 
336 struct mbuf *
337 mpls_do_error(struct mbuf *m, int type, int code, int destmtu)
338 {
339 	struct shim_hdr stack[MPLS_INKERNEL_LOOP_MAX];
340 	struct sockaddr_mpls sa_mpls;
341 	struct sockaddr_mpls *smpls;
342 	struct rtentry *rt = NULL;
343 	struct shim_hdr *shim;
344 	struct in_ifaddr *ia;
345 	struct icmp *icp;
346 	struct ip *ip;
347 	int nstk, error;
348 
349 	for (nstk = 0; nstk < MPLS_INKERNEL_LOOP_MAX; nstk++) {
350 		if (m->m_len < sizeof(*shim) &&
351 		    (m = m_pullup(m, sizeof(*shim))) == NULL)
352 			return (NULL);
353 		stack[nstk] = *mtod(m, struct shim_hdr *);
354 		m_adj(m, sizeof(*shim));
355 		if (MPLS_BOS_ISSET(stack[nstk].shim_label))
356 			break;
357 	}
358 	shim = &stack[0];
359 
360 	if (m->m_len < sizeof(u_char) &&
361 	    (m = m_pullup(m, sizeof(u_char))) == NULL)
362 		return (NULL);
363 	switch (*mtod(m, u_char *) >> 4) {
364 	case IPVERSION:
365 		if (m->m_len < sizeof(*ip) &&
366 		    (m = m_pullup(m, sizeof(*ip))) == NULL)
367 			return (NULL);
368 		m = icmp_do_error(m, type, code, 0, destmtu);
369 		if (m == NULL)
370 			return (NULL);
371 
372 		if (icmp_do_exthdr(m, ICMP_EXT_MPLS, 1, stack,
373 		    (nstk + 1) * sizeof(*shim)))
374 			return (NULL);
375 
376 		/* set ip_src to something usable, based on the MPLS label */
377 		bzero(&sa_mpls, sizeof(sa_mpls));
378 		smpls = &sa_mpls;
379 		smpls->smpls_family = AF_MPLS;
380 		smpls->smpls_len = sizeof(*smpls);
381 		smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
382 
383 		rt = rtalloc(smplstosa(smpls), RT_RESOLVE, 0);
384 		if (rt == NULL) {
385 			/* no entry for this label */
386 			m_freem(m);
387 			return (NULL);
388 		}
389 		if (rt->rt_ifa->ifa_addr->sa_family == AF_INET)
390 			ia = ifatoia(rt->rt_ifa);
391 		else {
392 			/* XXX this needs fixing, if the MPLS is on an IP
393 			 * less interface we need to find some other IP to
394 			 * use as source.
395 			 */
396 			rtfree(rt);
397 			m_freem(m);
398 			return (NULL);
399 		}
400 		/* It is safe to dereference ``ia'' iff ``rt'' is valid. */
401 		error = icmp_reflect(m, NULL, ia);
402 		rtfree(rt);
403 		if (error)
404 			return (NULL);
405 
406 		ip = mtod(m, struct ip *);
407 		/* stuff to fix up which is normaly done in ip_output */
408 		ip->ip_v = IPVERSION;
409 		ip->ip_id = htons(ip_randomid());
410 		ip->ip_sum = 0;
411 		ip->ip_sum = in_cksum(m, sizeof(*ip));
412 
413 		/* stolen from icmp_send() */
414 		icp = (struct icmp *)(mtod(m, caddr_t) + sizeof(*ip));
415 		icp->icmp_cksum = 0;
416 		icp->icmp_cksum = in4_cksum(m, 0, sizeof(*ip),
417 		    ntohs(ip->ip_len) - sizeof(*ip));
418 
419 		break;
420 #ifdef INET6
421 	case IPV6_VERSION >> 4:
422 #endif
423 	default:
424 		m_freem(m);
425 		return (NULL);
426 	}
427 
428 	/* add mpls stack back to new packet */
429 	M_PREPEND(m, (nstk + 1) * sizeof(*shim), M_NOWAIT);
430 	if (m == NULL)
431 		return (NULL);
432 	m_copyback(m, 0, (nstk + 1) * sizeof(*shim), stack, M_NOWAIT);
433 
434 	/* change TTL to default */
435 	shim = mtod(m, struct shim_hdr *);
436 	shim->shim_label =
437 	    (shim->shim_label & ~MPLS_TTL_MASK) | htonl(mpls_defttl);
438 
439 	return (m);
440 }
441