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