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