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