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