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