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