xref: /openbsd-src/sys/netmpls/mpls_input.c (revision 9b9d2a55a62c8e82206c25f94fcc7f4e2765250e)
1 /*	$OpenBSD: mpls_input.c,v 1.47 2015/07/29 00:04:03 rzalamena 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 int	mpls_ip_adjttl(struct mbuf *, u_int8_t);
49 #ifdef INET6
50 int	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_init(void)
57 {
58 }
59 
60 void
61 mpls_input(struct ifnet *ifp, struct mbuf *m)
62 {
63 	struct sockaddr_mpls *smpls;
64 	struct sockaddr_mpls sa_mpls;
65 	struct shim_hdr	*shim;
66 	struct rtentry *rt = NULL;
67 	struct rt_mpls *rt_mpls;
68 	u_int8_t ttl;
69 	int i, hasbos;
70 
71 	if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
72 		m_freem(m);
73 		return;
74 	}
75 
76 	/* drop all broadcast and multicast packets */
77 	if (m->m_flags & (M_BCAST | M_MCAST)) {
78 		m_freem(m);
79 		return;
80 	}
81 
82 	if (m->m_len < sizeof(*shim))
83 		if ((m = m_pullup(m, sizeof(*shim))) == NULL)
84 			return;
85 
86 	shim = mtod(m, struct shim_hdr *);
87 
88 #ifdef MPLS_DEBUG
89 	printf("mpls_input: iface %s label=%d, ttl=%d BoS %d\n",
90 	    ifp->if_xname, MPLS_LABEL_GET(shim->shim_label),
91 	    MPLS_TTL_GET(shim->shim_label),
92 	    MPLS_BOS_ISSET(shim->shim_label));
93 #endif
94 
95 	/* check and decrement TTL */
96 	ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
97 	if (ttl-- <= 1) {
98 		/* TTL exceeded */
99 		m = mpls_do_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, 0);
100 		if (m == NULL)
101 			return;
102 		shim = mtod(m, struct shim_hdr *);
103 		ttl = ntohl(shim->shim_label & MPLS_TTL_MASK);
104 	}
105 
106 	bzero(&sa_mpls, sizeof(sa_mpls));
107 	smpls = &sa_mpls;
108 	smpls->smpls_family = AF_MPLS;
109 	smpls->smpls_len = sizeof(*smpls);
110 	for (i = 0; i < mpls_inkloop; i++) {
111 		smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
112 
113 #ifdef MPLS_DEBUG
114 		printf("smpls af %d len %d in_label %d in_ifindex %d\n",
115 		    smpls->smpls_family, smpls->smpls_len,
116 		    MPLS_LABEL_GET(smpls->smpls_label),
117 		    ifp->if_index);
118 #endif
119 
120 		if (ntohl(smpls->smpls_label) < MPLS_LABEL_RESERVED_MAX) {
121 			hasbos = MPLS_BOS_ISSET(shim->shim_label);
122 			m = mpls_shim_pop(m);
123 			shim = mtod(m, struct shim_hdr *);
124 
125 			switch (ntohl(smpls->smpls_label)) {
126 			case MPLS_LABEL_IPV4NULL:
127 				/*
128 				 * RFC 4182 relaxes the position of the
129 				 * explicit NULL labels. The no longer need
130 				 * to be at the beginning of the stack.
131 				 */
132 				if (hasbos) {
133 do_v4:
134 					if (mpls_ip_adjttl(m, ttl))
135 						goto done;
136 					niq_enqueue(&ipintrq, m);
137 					goto done;
138 				}
139 				continue;
140 #ifdef INET6
141 			case MPLS_LABEL_IPV6NULL:
142 				if (hasbos) {
143 do_v6:
144 					if (mpls_ip6_adjttl(m, ttl))
145 						goto done;
146 					niq_enqueue(&ip6intrq, m);
147 					goto done;
148 				}
149 				continue;
150 #endif	/* INET6 */
151 			case MPLS_LABEL_IMPLNULL:
152 				if (hasbos) {
153 					switch (*mtod(m, u_char *) >> 4) {
154 					case IPVERSION:
155 						goto do_v4;
156 #ifdef INET6
157 					case IPV6_VERSION >> 4:
158 						goto do_v6;
159 #endif
160 					default:
161 						m_freem(m);
162 						goto done;
163 					}
164 				}
165 				/* FALLTHROUGH */
166 			default:
167 				/* Other cases are not handled for now */
168 				m_freem(m);
169 				goto done;
170 			}
171 		}
172 
173 		KERNEL_LOCK();
174 		rt = rtalloc(smplstosa(smpls), RT_REPORT|RT_RESOLVE, 0);
175 		KERNEL_UNLOCK();
176 		if (rt == NULL) {
177 			/* no entry for this label */
178 #ifdef MPLS_DEBUG
179 			printf("MPLS_DEBUG: label not found\n");
180 #endif
181 			m_freem(m);
182 			goto done;
183 		}
184 
185 		rt->rt_use++;
186 		rt_mpls = (struct rt_mpls *)rt->rt_llinfo;
187 
188 		if (rt_mpls == NULL || (rt->rt_flags & RTF_MPLS) == 0) {
189 #ifdef MPLS_DEBUG
190 			printf("MPLS_DEBUG: no MPLS information "
191 			    "attached\n");
192 #endif
193 			m_freem(m);
194 			goto done;
195 		}
196 
197 		hasbos = MPLS_BOS_ISSET(shim->shim_label);
198 		switch (rt_mpls->mpls_operation) {
199 		case MPLS_OP_LOCAL:
200 			/* Packet is for us */
201 			m = mpls_shim_pop(m);
202 			if (!hasbos)
203 				/* redo lookup with next label */
204 				break;
205 
206 			if (!rt->rt_gateway) {
207 				m_freem(m);
208 				goto done;
209 			}
210 
211 			switch(rt->rt_gateway->sa_family) {
212 			case AF_INET:
213 				if (mpls_ip_adjttl(m, ttl))
214 					break;
215 				niq_enqueue(&ipintrq, m);
216 				break;
217 #ifdef INET6
218 			case AF_INET6:
219 				if (mpls_ip6_adjttl(m, ttl))
220 					break;
221 				niq_enqueue(&ip6intrq, m);
222 				break;
223 #endif
224 			default:
225 				m_freem(m);
226 			}
227 			goto done;
228 		case MPLS_OP_POP:
229 			m = mpls_shim_pop(m);
230 			if (!hasbos)
231 				/* redo lookup with next label */
232 				break;
233 
234 			ifp = rt->rt_ifp;
235 #if NMPE > 0
236 			if (ifp->if_type == IFT_MPLS) {
237 				smpls = satosmpls(rt_key(rt));
238 				mpe_input(m, rt->rt_ifp, smpls, ttl);
239 				goto done;
240 			}
241 #endif
242 			if (ifp->if_type == IFT_MPLSTUNNEL) {
243 				ifp->if_output(ifp, m, rt_key(rt), rt);
244 				goto done;
245 			}
246 
247 			if (!rt->rt_gateway) {
248 				m_freem(m);
249 				goto done;
250 			}
251 
252 			switch(rt->rt_gateway->sa_family) {
253 			case AF_INET:
254 				if (mpls_ip_adjttl(m, ttl))
255 					goto done;
256 				break;
257 #ifdef INET6
258 			case AF_INET6:
259 				if (mpls_ip6_adjttl(m, ttl))
260 					goto done;
261 				break;
262 #endif
263 			default:
264 				m_freem(m);
265 				goto done;
266 			}
267 
268 			/* Output iface is not MPLS-enabled */
269 			if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
270 				m_freem(m);
271 				goto done;
272 			}
273 
274 			(*ifp->if_ll_output)(ifp, m, rt->rt_gateway, rt);
275 			goto done;
276 		case MPLS_OP_PUSH:
277 			m = mpls_shim_push(m, rt_mpls);
278 			break;
279 		case MPLS_OP_SWAP:
280 			m = mpls_shim_swap(m, rt_mpls);
281 			break;
282 		}
283 
284 		if (m == NULL)
285 			goto done;
286 
287 		/* refetch label */
288 		shim = mtod(m, struct shim_hdr *);
289 
290 		ifp = rt->rt_ifp;
291 		if (ifp != NULL && rt_mpls->mpls_operation != MPLS_OP_LOCAL)
292 			break;
293 
294 		KERNEL_LOCK();
295 		rtfree(rt);
296 		KERNEL_UNLOCK();
297 		rt = NULL;
298 	}
299 
300 	if (rt == NULL) {
301 		m_freem(m);
302 		goto done;
303 	}
304 
305 	/* write back TTL */
306 	shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | htonl(ttl);
307 
308 #ifdef MPLS_DEBUG
309 	printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n",
310     	    ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family,
311 	    MPLS_LABEL_GET(smpls->smpls_label),
312 	    MPLS_LABEL_GET(rt_mpls->mpls_label));
313 #endif
314 
315 	/* Output iface is not MPLS-enabled */
316 	if (!ISSET(ifp->if_xflags, IFXF_MPLS)) {
317 #ifdef MPLS_DEBUG
318 		printf("MPLS_DEBUG: interface not mpls enabled\n");
319 #endif
320 		goto done;
321 	}
322 
323 	KERNEL_LOCK();
324 	(*ifp->if_ll_output)(ifp, m, smplstosa(smpls), rt);
325 	KERNEL_UNLOCK();
326 done:
327 	if (rt) {
328 		KERNEL_LOCK();
329 		rtfree(rt);
330 		KERNEL_UNLOCK();
331 	}
332 }
333 
334 int
335 mpls_ip_adjttl(struct mbuf *m, u_int8_t ttl)
336 {
337 	struct ip *ip;
338 	int hlen;
339 
340 	if (mpls_mapttl_ip) {
341 		if (m->m_len < sizeof(struct ip) &&
342 		    (m = m_pullup(m, sizeof(struct ip))) == NULL)
343 			return -1;
344 		ip = mtod(m, struct ip *);
345 		hlen = ip->ip_hl << 2;
346 		if (m->m_len < hlen) {
347 			if ((m = m_pullup(m, hlen)) == NULL)
348 				return -1;
349 			ip = mtod(m, struct ip *);
350 		}
351 		/* make sure we have a valid header */
352 		if (in_cksum(m, hlen) != 0) {
353 			m_free(m);
354 			return -1;
355 		}
356 
357 		/* set IP ttl from MPLS ttl */
358 		ip->ip_ttl = ttl;
359 
360 		/* recalculate checksum */
361 		ip->ip_sum = 0;
362 		ip->ip_sum = in_cksum(m, hlen);
363 	}
364 	return 0;
365 }
366 
367 #ifdef INET6
368 int
369 mpls_ip6_adjttl(struct mbuf *m, u_int8_t ttl)
370 {
371 	struct ip6_hdr *ip6hdr;
372 
373 	if (mpls_mapttl_ip6) {
374 		if (m->m_len < sizeof(struct ip6_hdr) &&
375 		    (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL)
376 			return -1;
377 
378 		ip6hdr = mtod(m, struct ip6_hdr *);
379 
380 		/* set IPv6 ttl from MPLS ttl */
381 		ip6hdr->ip6_hlim = ttl;
382 	}
383 	return 0;
384 }
385 #endif	/* INET6 */
386 
387 struct mbuf *
388 mpls_do_error(struct mbuf *m, int type, int code, int destmtu)
389 {
390 	struct shim_hdr stack[MPLS_INKERNEL_LOOP_MAX];
391 	struct sockaddr_mpls sa_mpls;
392 	struct sockaddr_mpls *smpls;
393 	struct rtentry *rt = NULL;
394 	struct shim_hdr *shim;
395 	struct in_ifaddr *ia;
396 	struct icmp *icp;
397 	struct ip *ip;
398 	int nstk;
399 
400 	for (nstk = 0; nstk < MPLS_INKERNEL_LOOP_MAX; nstk++) {
401 		if (m->m_len < sizeof(*shim) &&
402 		    (m = m_pullup(m, sizeof(*ip))) == NULL)
403 			return (NULL);
404 		stack[nstk] = *mtod(m, struct shim_hdr *);
405 		m_adj(m, sizeof(*shim));
406 		if (MPLS_BOS_ISSET(stack[nstk].shim_label))
407 			break;
408 	}
409 	shim = &stack[0];
410 
411 	switch (*mtod(m, u_char *) >> 4) {
412 	case IPVERSION:
413 		if (m->m_len < sizeof(*ip) &&
414 		    (m = m_pullup(m, sizeof(*ip))) == NULL)
415 			return (NULL);
416 		m = icmp_do_error(m, type, code, 0, destmtu);
417 		if (m == NULL)
418 			return (NULL);
419 
420 		if (icmp_do_exthdr(m, ICMP_EXT_MPLS, 1, stack,
421 		    (nstk + 1) * sizeof(*shim)))
422 			return (NULL);
423 
424 		/* set ip_src to something usable, based on the MPLS label */
425 		bzero(&sa_mpls, sizeof(sa_mpls));
426 		smpls = &sa_mpls;
427 		smpls->smpls_family = AF_MPLS;
428 		smpls->smpls_len = sizeof(*smpls);
429 		smpls->smpls_label = shim->shim_label & MPLS_LABEL_MASK;
430 
431 		KERNEL_LOCK();
432 		rt = rtalloc(smplstosa(smpls), RT_REPORT|RT_RESOLVE, 0);
433 		KERNEL_UNLOCK();
434 		if (rt == NULL) {
435 			/* no entry for this label */
436 			m_freem(m);
437 			return (NULL);
438 		}
439 		if (rt->rt_ifa->ifa_addr->sa_family == AF_INET)
440 			ia = ifatoia(rt->rt_ifa);
441 		else {
442 			/* XXX this needs fixing, if the MPLS is on an IP
443 			 * less interface we need to find some other IP to
444 			 * use as source.
445 			 */
446 			KERNEL_LOCK();
447 			rtfree(rt);
448 			KERNEL_UNLOCK();
449 			m_freem(m);
450 			return (NULL);
451 		}
452 		rt->rt_use++;
453 		KERNEL_LOCK();
454 		rtfree(rt);
455 		if (icmp_reflect(m, NULL, ia)) {
456 			KERNEL_UNLOCK();
457 			return (NULL);
458 		}
459 		KERNEL_UNLOCK();
460 
461 		ip = mtod(m, struct ip *);
462 		/* stuff to fix up which is normaly done in ip_output */
463 		ip->ip_v = IPVERSION;
464 		ip->ip_id = htons(ip_randomid());
465 		ip->ip_sum = 0;
466 		ip->ip_sum = in_cksum(m, sizeof(*ip));
467 
468 		/* stolen from icmp_send() */
469 		icp = (struct icmp *)(mtod(m, caddr_t) + sizeof(*ip));
470 		icp->icmp_cksum = 0;
471 		icp->icmp_cksum = in4_cksum(m, 0, sizeof(*ip),
472 		    ntohs(ip->ip_len) - sizeof(*ip));
473 
474 		break;
475 #ifdef INET6
476 	case IPV6_VERSION >> 4:
477 #endif
478 	default:
479 		m_freem(m);
480 		return (NULL);
481 	}
482 
483 	/* add mpls stack back to new packet */
484 	M_PREPEND(m, (nstk + 1) * sizeof(*shim), M_NOWAIT);
485 	if (m == NULL)
486 		return (NULL);
487 	m_copyback(m, 0, (nstk + 1) * sizeof(*shim), stack, M_NOWAIT);
488 
489 	/* change TTL to default */
490 	shim = mtod(m, struct shim_hdr *);
491 	shim->shim_label =
492 	    (shim->shim_label & ~MPLS_TTL_MASK) | htonl(mpls_defttl);
493 
494 	return (m);
495 }
496