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