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