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