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