1 /* $OpenBSD: mpls_input.c,v 1.21 2009/04/29 19:26:52 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 if (rt_mpls->mpls_operation & MPLS_OP_POP) { 236 hasbos = MPLS_BOS_ISSET(shim->shim_label); 237 if (hasbos) { 238 m = mpls_shim_pop(m); 239 #if NMPE > 0 240 if (rt->rt_ifp->if_type == IFT_MPLS) { 241 mpe_input(m, rt->rt_ifp, smpls, ttl); 242 goto done; 243 } 244 #endif 245 /* last label but we have no clue so drop */ 246 m_freem(m); 247 goto done; 248 } 249 } 250 251 /* refetch label */ 252 shim = mtod(m, struct shim_hdr *); 253 ifp = rt->rt_ifp; 254 255 if (ifp != NULL) 256 break; 257 258 RTFREE(rt); 259 rt = NULL; 260 } 261 262 if (rt == NULL) { 263 m_freem(m); 264 goto done; 265 } 266 267 /* write back TTL */ 268 shim->shim_label = (shim->shim_label & ~MPLS_TTL_MASK) | htonl(ttl); 269 270 #ifdef MPLS_DEBUG 271 printf("MPLS: sending on %s outlabel %x dst af %d in %d out %d\n", 272 ifp->if_xname, ntohl(shim->shim_label), smpls->smpls_family, 273 MPLS_LABEL_GET(smpls->smpls_label), 274 MPLS_LABEL_GET(rt_mpls->mpls_label)); 275 #endif 276 277 (*ifp->if_output)(ifp, m, smplstosa(smpls), rt); 278 done: 279 if (rt) 280 RTFREE(rt); 281 } 282 283 void 284 mpls_ip_input(struct mbuf *m, u_int8_t ttl) 285 { 286 struct ip *ip; 287 int s, 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; 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; 298 ip = mtod(m, struct ip *); 299 } 300 301 if (in_cksum(m, hlen) != 0) { 302 m_free(m); 303 return; 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 314 s = splnet(); 315 IF_ENQUEUE(&ipintrq, m); 316 schednetisr(NETISR_IP); 317 splx(s); 318 } 319 320 void 321 mpls_ip6_input(struct mbuf *m, u_int8_t ttl) 322 { 323 struct ip6_hdr *ip6hdr; 324 int s; 325 326 if (mpls_mapttl_ip6) { 327 if (m->m_len < sizeof (struct ip6_hdr) && 328 (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) 329 return; 330 331 ip6hdr = mtod(m, struct ip6_hdr *); 332 333 /* set IPv6 ttl from MPLS ttl */ 334 ip6hdr->ip6_hlim = ttl; 335 } 336 337 s = splnet(); 338 IF_ENQUEUE(&ip6intrq, m); 339 schednetisr(NETISR_IPV6); 340 splx(s); 341 } 342