1 /* $OpenBSD: mpls_input.c,v 1.20 2009/04/28 12:07:43 michele 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/in_var.h> 34 #include <netinet/in_systm.h> 35 #include <netinet/ip.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 int mplsqmaxlen = IFQ_MAXLEN; 49 extern int mpls_inkloop; 50 51 #ifdef MPLS_DEBUG 52 #define MPLS_LABEL_GET(l) ((ntohl((l) & MPLS_LABEL_MASK)) >> MPLS_LABEL_OFFSET) 53 #define MPLS_TTL_GET(l) (ntohl((l) & MPLS_TTL_MASK)) 54 #endif 55 56 extern int mpls_mapttl_ip; 57 extern int mpls_mapttl_ip6; 58 59 void 60 mpls_init(void) 61 { 62 mplsintrq.ifq_maxlen = mplsqmaxlen; 63 } 64 65 void 66 mplsintr(void) 67 { 68 struct mbuf *m; 69 int s; 70 71 for (;;) { 72 /* Get next datagram of input queue */ 73 s = splnet(); 74 IF_DEQUEUE(&mplsintrq, m); 75 splx(s); 76 if (m == NULL) 77 return; 78 #ifdef DIAGNOSTIC 79 if ((m->m_flags & M_PKTHDR) == 0) 80 panic("ipintr no HDR"); 81 #endif 82 mpls_input(m); 83 } 84 } 85 86 void 87 mpls_input(struct mbuf *m) 88 { 89 struct ifnet *ifp = m->m_pkthdr.rcvif; 90 struct sockaddr_mpls *smpls; 91 struct sockaddr_mpls sa_mpls; 92 struct shim_hdr *shim; 93 struct rtentry *rt = NULL; 94 struct rt_mpls *rt_mpls; 95 u_int8_t ttl; 96 int i, hasbos; 97 98 if (!mpls_enable) { 99 m_freem(m); 100 return; 101 } 102 103 /* drop all broadcast and multicast packets */ 104 if (m->m_flags & (M_BCAST | M_MCAST)) { 105 m_freem(m); 106 return; 107 } 108 109 if (m->m_len < sizeof(*shim)) 110 if ((m = m_pullup(m, sizeof(*shim))) == NULL) 111 return; 112 113 shim = mtod(m, struct shim_hdr *); 114 115 #ifdef MPLS_DEBUG 116 printf("mpls_input: iface %s label=%d, ttl=%d BoS %d\n", 117 ifp->if_xname, MPLS_LABEL_GET(shim->shim_label), 118 MPLS_TTL_GET(shim->shim_label), 119 MPLS_BOS_ISSET(shim->shim_label)); 120 #endif /* MPLS_DEBUG */ 121 122 /* check and decrement TTL */ 123 ttl = ntohl(shim->shim_label & MPLS_TTL_MASK); 124 if (ttl <= 1) { 125 /* TTL exceeded */ 126 /* 127 * XXX if possible hand packet up to network layer so that an 128 * ICMP TTL exceeded can be sent back. 129 */ 130 m_freem(m); 131 return; 132 } 133 ttl--; 134 135 for (i = 0; i < mpls_inkloop; i++) { 136 bzero(&sa_mpls, sizeof(sa_mpls)); 137 smpls = &sa_mpls; 138 smpls->smpls_family = AF_MPLS; 139 smpls->smpls_len = sizeof(*smpls); 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 156 case MPLS_LABEL_IPV4NULL: 157 if (hasbos) { 158 mpls_ip_input(m, ttl); 159 goto done; 160 } else 161 continue; 162 163 case MPLS_LABEL_IPV6NULL: 164 if (hasbos) { 165 mpls_ip6_input(m, ttl); 166 goto done; 167 } else 168 continue; 169 default: 170 m_freem(m); 171 goto done; 172 } 173 /* Other cases are not handled for now */ 174 } 175 176 rt = rtalloc1(smplstosa(smpls), 1, 0); 177 178 if (rt == NULL) { 179 /* no entry for this label */ 180 #ifdef MPLS_DEBUG 181 printf("MPLS_DEBUG: label not found\n"); 182 #endif 183 m_freem(m); 184 goto done; 185 } 186 187 rt->rt_use++; 188 smpls = satosmpls(rt_key(rt)); 189 rt_mpls = (struct rt_mpls *)rt->rt_llinfo; 190 191 if (rt_mpls == NULL || (rt->rt_flags & RTF_MPLS) == 0) { 192 #ifdef MPLS_DEBUG 193 printf("MPLS_DEBUG: no MPLS information " 194 "attached\n"); 195 #endif 196 m_freem(m); 197 goto done; 198 } 199 200 if (rt_mpls->mpls_operation == MPLS_OP_LOCAL) { 201 /* Packet is for us */ 202 hasbos = MPLS_BOS_ISSET(shim->shim_label); 203 if (!hasbos) { 204 #ifdef MPLS_DEBUG 205 printf("MPLS_DEBUG: packet malformed\n"); 206 #endif 207 m_freem(m); 208 goto done; 209 } 210 m = mpls_shim_pop(m); 211 212 if (!rt->rt_gateway) { 213 #ifdef MPLS_DEBUG 214 printf("MPLS_DEBUG: no layer 3 informations " 215 "attached\n"); 216 #endif 217 m_freem(m); 218 goto done; 219 } 220 221 switch(rt->rt_gateway->sa_family) { 222 case AF_INET: 223 mpls_ip_input(m, ttl); 224 break; 225 case AF_INET6: 226 mpls_ip6_input(m, ttl); 227 break; 228 default: 229 m_freem(m); 230 } 231 232 goto done; 233 } 234 235 switch (rt_mpls->mpls_operation & (MPLS_OP_PUSH | MPLS_OP_POP | 236 MPLS_OP_SWAP)){ 237 238 case MPLS_OP_POP: 239 hasbos = MPLS_BOS_ISSET(shim->shim_label); 240 m = mpls_shim_pop(m); 241 if (hasbos) { 242 #if NMPE > 0 243 if (rt->rt_ifp->if_type == IFT_MPLS) { 244 mpe_input(m, rt->rt_ifp, smpls, ttl); 245 goto done; 246 } 247 #endif 248 /* last label but we have no clue so drop */ 249 m_freem(m); 250 goto done; 251 } 252 break; 253 case MPLS_OP_PUSH: 254 m = mpls_shim_push(m, rt_mpls); 255 break; 256 case MPLS_OP_SWAP: 257 m = mpls_shim_swap(m, rt_mpls); 258 break; 259 default: 260 m_freem(m); 261 goto done; 262 } 263 264 if (m == NULL) 265 goto done; 266 267 /* refetch label */ 268 shim = mtod(m, struct shim_hdr *); 269 ifp = rt->rt_ifp; 270 271 if (ifp != NULL) 272 break; 273 274 RTFREE(rt); 275 rt = NULL; 276 } 277 278 if (rt == NULL) { 279 m_freem(m); 280 goto done; 281 } 282 283 /* write back TTL */ 284 shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | htonl(ttl); 285 286 #ifdef MPLS_DEBUG 287 printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n", 288 ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family, 289 MPLS_LABEL_GET(smpls->smpls_label), 290 MPLS_LABEL_GET(rt_mpls->mpls_label)); 291 #endif 292 293 (*ifp->if_output)(ifp, m, smplstosa(smpls), rt); 294 done: 295 if (rt) 296 RTFREE(rt); 297 } 298 299 void 300 mpls_ip_input(struct mbuf *m, u_int8_t ttl) 301 { 302 struct ip *ip; 303 int s, hlen; 304 305 if (mpls_mapttl_ip) { 306 if (m->m_len < sizeof (struct ip) && 307 (m = m_pullup(m, sizeof(struct ip))) == NULL) 308 return; 309 ip = mtod(m, struct ip *); 310 hlen = ip->ip_hl << 2; 311 if (m->m_len < hlen) { 312 if ((m = m_pullup(m, hlen)) == NULL) 313 return; 314 ip = mtod(m, struct ip *); 315 } 316 317 if (in_cksum(m, hlen) != 0) { 318 m_free(m); 319 return; 320 } 321 322 /* set IP ttl from MPLS ttl */ 323 ip->ip_ttl = ttl; 324 325 /* recalculate checksum */ 326 ip->ip_sum = 0; 327 ip->ip_sum = in_cksum(m, hlen); 328 } 329 330 s = splnet(); 331 IF_ENQUEUE(&ipintrq, m); 332 schednetisr(NETISR_IP); 333 splx(s); 334 } 335 336 void 337 mpls_ip6_input(struct mbuf *m, u_int8_t ttl) 338 { 339 struct ip6_hdr *ip6hdr; 340 int s; 341 342 if (mpls_mapttl_ip6) { 343 if (m->m_len < sizeof (struct ip6_hdr) && 344 (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) 345 return; 346 347 ip6hdr = mtod(m, struct ip6_hdr *); 348 349 /* set IPv6 ttl from MPLS ttl */ 350 ip6hdr->ip6_hlim = ttl; 351 } 352 353 s = splnet(); 354 IF_ENQUEUE(&ip6intrq, m); 355 schednetisr(NETISR_IPV6); 356 splx(s); 357 } 358