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