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