1 /* $OpenBSD: if_mpe.c,v 1.64 2018/01/09 15:24:24 bluhm Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@spootnik.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 #include "mpe.h" 19 20 #include <sys/param.h> 21 #include <sys/systm.h> 22 #include <sys/mbuf.h> 23 #include <sys/socket.h> 24 #include <sys/sockio.h> 25 #include <sys/ioctl.h> 26 27 #include <net/if.h> 28 #include <net/if_dl.h> 29 #include <net/if_var.h> 30 #include <net/if_types.h> 31 #include <net/netisr.h> 32 #include <net/route.h> 33 34 #include <netinet/in.h> 35 #include <netinet/ip.h> 36 37 #ifdef INET6 38 #include <netinet/ip6.h> 39 #endif /* INET6 */ 40 41 #include "bpfilter.h" 42 #if NBPFILTER > 0 43 #include <net/bpf.h> 44 #endif 45 46 #include <netmpls/mpls.h> 47 48 #ifdef MPLS_DEBUG 49 #define DPRINTF(x) do { if (mpedebug) printf x ; } while (0) 50 #else 51 #define DPRINTF(x) 52 #endif 53 54 void mpeattach(int); 55 int mpeoutput(struct ifnet *, struct mbuf *, struct sockaddr *, 56 struct rtentry *); 57 int mpeioctl(struct ifnet *, u_long, caddr_t); 58 void mpestart(struct ifnet *); 59 int mpe_clone_create(struct if_clone *, int); 60 int mpe_clone_destroy(struct ifnet *); 61 62 LIST_HEAD(, mpe_softc) mpeif_list; 63 struct if_clone mpe_cloner = 64 IF_CLONE_INITIALIZER("mpe", mpe_clone_create, mpe_clone_destroy); 65 66 extern int mpls_mapttl_ip; 67 #ifdef INET6 68 extern int mpls_mapttl_ip6; 69 #endif 70 71 void 72 mpeattach(int nmpe) 73 { 74 LIST_INIT(&mpeif_list); 75 if_clone_attach(&mpe_cloner); 76 } 77 78 int 79 mpe_clone_create(struct if_clone *ifc, int unit) 80 { 81 struct ifnet *ifp; 82 struct mpe_softc *mpeif; 83 84 mpeif = malloc(sizeof(*mpeif), M_DEVBUF, M_WAITOK|M_ZERO); 85 mpeif->sc_unit = unit; 86 ifp = &mpeif->sc_if; 87 snprintf(ifp->if_xname, sizeof ifp->if_xname, "mpe%d", unit); 88 ifp->if_flags = IFF_POINTOPOINT; 89 ifp->if_xflags = IFXF_CLONED; 90 ifp->if_softc = mpeif; 91 ifp->if_mtu = MPE_MTU; 92 ifp->if_ioctl = mpeioctl; 93 ifp->if_output = mpeoutput; 94 ifp->if_start = mpestart; 95 ifp->if_type = IFT_MPLS; 96 ifp->if_hdrlen = MPE_HDRLEN; 97 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); 98 if_attach(ifp); 99 if_alloc_sadl(ifp); 100 #if NBPFILTER > 0 101 bpfattach(&ifp->if_bpf, ifp, DLT_LOOP, sizeof(u_int32_t)); 102 #endif 103 104 mpeif->sc_ifa.ifa_ifp = ifp; 105 mpeif->sc_ifa.ifa_addr = sdltosa(ifp->if_sadl); 106 mpeif->sc_smpls.smpls_len = sizeof(mpeif->sc_smpls); 107 mpeif->sc_smpls.smpls_family = AF_MPLS; 108 109 LIST_INSERT_HEAD(&mpeif_list, mpeif, sc_list); 110 111 return (0); 112 } 113 114 int 115 mpe_clone_destroy(struct ifnet *ifp) 116 { 117 struct mpe_softc *mpeif = ifp->if_softc; 118 119 LIST_REMOVE(mpeif, sc_list); 120 121 if (mpeif->sc_smpls.smpls_label) { 122 rt_ifa_del(&mpeif->sc_ifa, RTF_MPLS, 123 smplstosa(&mpeif->sc_smpls)); 124 } 125 126 if_detach(ifp); 127 free(mpeif, M_DEVBUF, sizeof *mpeif); 128 return (0); 129 } 130 131 struct sockaddr_storage mpedst; 132 /* 133 * Start output on the mpe interface. 134 */ 135 void 136 mpestart(struct ifnet *ifp0) 137 { 138 struct mbuf *m; 139 struct sockaddr *sa = sstosa(&mpedst); 140 sa_family_t af; 141 struct rtentry *rt; 142 struct ifnet *ifp; 143 144 for (;;) { 145 IFQ_DEQUEUE(&ifp0->if_snd, m); 146 if (m == NULL) 147 return; 148 149 af = *mtod(m, sa_family_t *); 150 m_adj(m, sizeof(af)); 151 switch (af) { 152 case AF_INET: 153 bzero(sa, sizeof(struct sockaddr_in)); 154 satosin(sa)->sin_family = af; 155 satosin(sa)->sin_len = sizeof(struct sockaddr_in); 156 bcopy(mtod(m, caddr_t), &satosin(sa)->sin_addr, 157 sizeof(in_addr_t)); 158 m_adj(m, sizeof(in_addr_t)); 159 break; 160 default: 161 m_freem(m); 162 continue; 163 } 164 165 rt = rtalloc(sa, RT_RESOLVE, 0); 166 if (!rtisvalid(rt)) { 167 m_freem(m); 168 rtfree(rt); 169 continue; 170 } 171 172 ifp = if_get(rt->rt_ifidx); 173 if (ifp == NULL) { 174 m_freem(m); 175 rtfree(rt); 176 continue; 177 } 178 #if NBPFILTER > 0 179 if (ifp0->if_bpf) { 180 /* remove MPLS label before passing packet to bpf */ 181 m->m_data += sizeof(struct shim_hdr); 182 m->m_len -= sizeof(struct shim_hdr); 183 m->m_pkthdr.len -= sizeof(struct shim_hdr); 184 bpf_mtap_af(ifp0->if_bpf, af, m, BPF_DIRECTION_OUT); 185 m->m_data -= sizeof(struct shim_hdr); 186 m->m_len += sizeof(struct shim_hdr); 187 m->m_pkthdr.len += sizeof(struct shim_hdr); 188 } 189 #endif 190 /* XXX lie, but mpls_output looks only at sa_family */ 191 sa->sa_family = AF_MPLS; 192 193 mpls_output(ifp, m, sa, rt); 194 if_put(ifp); 195 rtfree(rt); 196 } 197 } 198 199 int 200 mpeoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 201 struct rtentry *rt) 202 { 203 struct shim_hdr shim; 204 int error; 205 int off; 206 in_addr_t addr; 207 u_int8_t op = 0; 208 209 #ifdef DIAGNOSTIC 210 if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid)) { 211 printf("%s: trying to send packet on wrong domain. " 212 "if %d vs. mbuf %d\n", ifp->if_xname, 213 ifp->if_rdomain, rtable_l2(m->m_pkthdr.ph_rtableid)); 214 } 215 #endif 216 m->m_pkthdr.ph_ifidx = ifp->if_index; 217 /* XXX assumes MPLS is always in rdomain 0 */ 218 m->m_pkthdr.ph_rtableid = 0; 219 220 error = 0; 221 switch (dst->sa_family) { 222 case AF_INET: 223 if (!rt || !(rt->rt_flags & RTF_MPLS)) { 224 m_freem(m); 225 error = ENETUNREACH; 226 goto out; 227 } 228 shim.shim_label = 229 ((struct rt_mpls *)rt->rt_llinfo)->mpls_label; 230 shim.shim_label |= MPLS_BOS_MASK; 231 op = ((struct rt_mpls *)rt->rt_llinfo)->mpls_operation; 232 if (op != MPLS_OP_PUSH) { 233 m_freem(m); 234 error = ENETUNREACH; 235 goto out; 236 } 237 if (mpls_mapttl_ip) { 238 struct ip *ip; 239 ip = mtod(m, struct ip *); 240 shim.shim_label |= htonl(ip->ip_ttl) & MPLS_TTL_MASK; 241 } else 242 shim.shim_label |= htonl(mpls_defttl) & MPLS_TTL_MASK; 243 off = sizeof(sa_family_t) + sizeof(in_addr_t); 244 M_PREPEND(m, sizeof(shim) + off, M_DONTWAIT); 245 if (m == NULL) { 246 error = ENOBUFS; 247 goto out; 248 } 249 *mtod(m, sa_family_t *) = AF_INET; 250 addr = satosin(rt->rt_gateway)->sin_addr.s_addr; 251 m_copyback(m, sizeof(sa_family_t), sizeof(in_addr_t), 252 &addr, M_NOWAIT); 253 break; 254 default: 255 m_freem(m); 256 error = EPFNOSUPPORT; 257 goto out; 258 } 259 260 m_copyback(m, off, sizeof(shim), (caddr_t)&shim, M_NOWAIT); 261 262 error = if_enqueue(ifp, m); 263 out: 264 if (error) 265 ifp->if_oerrors++; 266 return (error); 267 } 268 269 int 270 mpeioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 271 { 272 struct mpe_softc *ifm; 273 struct ifreq *ifr; 274 struct shim_hdr shim; 275 int error = 0; 276 277 ifr = (struct ifreq *)data; 278 switch (cmd) { 279 case SIOCSIFADDR: 280 if (!ISSET(ifp->if_flags, IFF_UP)) 281 if_up(ifp); 282 break; 283 case SIOCSIFFLAGS: 284 if (ifp->if_flags & IFF_UP) 285 ifp->if_flags |= IFF_RUNNING; 286 else 287 ifp->if_flags &= ~IFF_RUNNING; 288 break; 289 case SIOCSIFMTU: 290 if (ifr->ifr_mtu < MPE_MTU_MIN || 291 ifr->ifr_mtu > MPE_MTU_MAX) 292 error = EINVAL; 293 else 294 ifp->if_mtu = ifr->ifr_mtu; 295 break; 296 case SIOCGETLABEL: 297 ifm = ifp->if_softc; 298 shim.shim_label = 299 ((ntohl(ifm->sc_smpls.smpls_label & MPLS_LABEL_MASK)) >> 300 MPLS_LABEL_OFFSET); 301 error = copyout(&shim, ifr->ifr_data, sizeof(shim)); 302 break; 303 case SIOCSETLABEL: 304 ifm = ifp->if_softc; 305 if ((error = copyin(ifr->ifr_data, &shim, sizeof(shim)))) 306 break; 307 if (shim.shim_label > MPLS_LABEL_MAX || 308 shim.shim_label <= MPLS_LABEL_RESERVED_MAX) { 309 error = EINVAL; 310 break; 311 } 312 shim.shim_label = htonl(shim.shim_label << MPLS_LABEL_OFFSET); 313 if (ifm->sc_smpls.smpls_label == shim.shim_label) 314 break; 315 LIST_FOREACH(ifm, &mpeif_list, sc_list) { 316 if (ifm != ifp->if_softc && 317 ifm->sc_smpls.smpls_label == shim.shim_label) { 318 error = EEXIST; 319 break; 320 } 321 } 322 if (error) 323 break; 324 /* 325 * force interface up for now, 326 * linkstate of MPLS route is not tracked 327 */ 328 if (!ISSET(ifp->if_flags, IFF_UP)) 329 if_up(ifp); 330 ifm = ifp->if_softc; 331 if (ifm->sc_smpls.smpls_label) { 332 /* remove old MPLS route */ 333 rt_ifa_del(&ifm->sc_ifa, RTF_MPLS, 334 smplstosa(&ifm->sc_smpls)); 335 } 336 /* add new MPLS route */ 337 ifm->sc_smpls.smpls_label = shim.shim_label; 338 error = rt_ifa_add(&ifm->sc_ifa, RTF_MPLS, 339 smplstosa(&ifm->sc_smpls)); 340 if (error) { 341 ifm->sc_smpls.smpls_label = 0; 342 break; 343 } 344 break; 345 case SIOCSIFRDOMAIN: 346 /* must readd the MPLS "route" for our label */ 347 /* XXX does not make sense, the MPLS route is on rtable 0 */ 348 ifm = ifp->if_softc; 349 if (ifr->ifr_rdomainid != ifp->if_rdomain) { 350 if (ifm->sc_smpls.smpls_label) { 351 rt_ifa_add(&ifm->sc_ifa, RTF_MPLS, 352 smplstosa(&ifm->sc_smpls)); 353 } 354 } 355 /* return with ENOTTY so that the parent handler finishes */ 356 return (ENOTTY); 357 default: 358 return (ENOTTY); 359 } 360 361 return (error); 362 } 363 364 void 365 mpe_input(struct mbuf *m, struct ifnet *ifp, struct sockaddr_mpls *smpls, 366 u_int8_t ttl) 367 { 368 struct ip *ip; 369 int hlen; 370 371 /* label -> AF lookup */ 372 373 if (mpls_mapttl_ip) { 374 if (m->m_len < sizeof (struct ip) && 375 (m = m_pullup(m, sizeof(struct ip))) == NULL) 376 return; 377 ip = mtod(m, struct ip *); 378 hlen = ip->ip_hl << 2; 379 if (m->m_len < hlen) { 380 if ((m = m_pullup(m, hlen)) == NULL) 381 return; 382 ip = mtod(m, struct ip *); 383 } 384 385 if (in_cksum(m, hlen) != 0) { 386 m_freem(m); 387 return; 388 } 389 390 /* set IP ttl from MPLS ttl */ 391 ip->ip_ttl = ttl; 392 393 /* recalculate checksum */ 394 ip->ip_sum = 0; 395 ip->ip_sum = in_cksum(m, hlen); 396 } 397 398 /* new receive if and move into correct rtable */ 399 m->m_pkthdr.ph_ifidx = ifp->if_index; 400 m->m_pkthdr.ph_rtableid = ifp->if_rdomain; 401 402 #if NBPFILTER > 0 403 if (ifp->if_bpf) 404 bpf_mtap_af(ifp->if_bpf, AF_INET, m, BPF_DIRECTION_IN); 405 #endif 406 407 ipv4_input(ifp, m); 408 } 409 410 #ifdef INET6 411 void 412 mpe_input6(struct mbuf *m, struct ifnet *ifp, struct sockaddr_mpls *smpls, 413 u_int8_t ttl) 414 { 415 struct ip6_hdr *ip6hdr; 416 417 /* label -> AF lookup */ 418 419 if (mpls_mapttl_ip6) { 420 if (m->m_len < sizeof (struct ip6_hdr) && 421 (m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) 422 return; 423 424 ip6hdr = mtod(m, struct ip6_hdr *); 425 426 /* set IPv6 ttl from MPLS ttl */ 427 ip6hdr->ip6_hlim = ttl; 428 } 429 430 /* new receive if and move into correct rtable */ 431 m->m_pkthdr.ph_ifidx = ifp->if_index; 432 m->m_pkthdr.ph_rtableid = ifp->if_rdomain; 433 434 #if NBPFILTER > 0 435 if (ifp->if_bpf) 436 bpf_mtap_af(ifp->if_bpf, AF_INET6, m, BPF_DIRECTION_IN); 437 #endif 438 439 ipv6_input(ifp, m); 440 } 441 #endif /* INET6 */ 442