1 /* $NetBSD: if_srt.c,v 1.30 2019/04/27 06:18:15 pgoyette Exp $ */ 2 /* This file is in the public domain. */ 3 4 #include <sys/cdefs.h> 5 __KERNEL_RCSID(0, "$NetBSD: if_srt.c,v 1.30 2019/04/27 06:18:15 pgoyette Exp $"); 6 7 #ifdef _KERNEL_OPT 8 #include "opt_inet.h" 9 #endif 10 11 #if !defined(INET) && !defined(INET6) 12 #error "srt without INET/INET6?" 13 #endif 14 15 #ifndef SRT_MAXUNIT 16 #define SRT_MAXUNIT 255 17 #endif 18 19 /* include-file bug workarounds */ 20 #include <sys/types.h> /* sys/conf.h */ 21 #include <sys/resource.h> /* sys/resourcevar.h 22 * (uvm/uvm_param.h, sys/mbuf.h) 23 */ 24 #include <netinet/in.h> /* netinet/ip.h */ 25 #include <sys/param.h> /* sys/mbuf.h */ 26 #include <netinet/in_systm.h> /* netinet/ip.h */ 27 28 #include <sys/conf.h> 29 #include <sys/mbuf.h> 30 #include <sys/errno.h> 31 #include <sys/fcntl.h> 32 #include <sys/param.h> 33 #include <sys/ioctl.h> 34 #include <sys/module.h> 35 #include <sys/device.h> 36 #include <netinet/ip.h> 37 #include <netinet/ip6.h> 38 #include <netinet6/in6_var.h> 39 #include <netinet6/ip6_var.h> 40 #include <netinet6/nd6.h> 41 #include <netinet6/scope6_var.h> 42 #include <net/if_types.h> 43 44 #include "if_srt.h" 45 46 /* until we know what to pass to bpfattach.... */ 47 /* #define BPFILTER_NOW_AVAILABLE */ 48 49 struct srt_softc { 50 struct ifnet intf; /* XXX interface botch */ 51 int unit; 52 int nrt; 53 struct srt_rt **rts; 54 unsigned int flags; /* SSF_* values from if_srt.h */ 55 #define SSF_UCHG (SSF_MTULOCK) /* userland-changeable bits */ 56 unsigned int kflags; /* bits private to this file */ 57 #define SKF_CDEVOPEN 0x00000001 58 }; 59 60 #include "ioconf.h" 61 62 static struct srt_softc *softcv[SRT_MAXUNIT+1]; 63 static unsigned int global_flags; 64 65 static u_int srt_count; 66 67 #ifdef _MODULE 68 devmajor_t srt_bmajor = -1, srt_cmajor = -1; 69 #endif 70 71 static int srt_open(dev_t, int, int, struct lwp *); 72 static int srt_close(dev_t, int, int, struct lwp *); 73 static int srt_ioctl(dev_t, u_long, void *, int, struct lwp *); 74 75 const struct cdevsw srt_cdevsw = { 76 .d_open = srt_open, 77 .d_close = srt_close, 78 .d_read = nullread, 79 .d_write = nullwrite, 80 .d_ioctl = srt_ioctl, 81 .d_stop = nullstop, 82 .d_tty = notty, 83 .d_poll = nullpoll, 84 .d_mmap = nommap, 85 .d_kqfilter = nullkqfilter, 86 .d_discard = nodiscard, 87 .d_flag = D_OTHER 88 }; 89 90 /* Internal routines. */ 91 92 static unsigned int ipv4_masks[33] = { 93 0x00000000, /* /0 */ 94 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, /* /1 - /4 */ 95 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, /* /5 - /8 */ 96 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, /* /9 - /12 */ 97 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, /* /13 - /16 */ 98 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, /* /17 - /20 */ 99 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, /* /21 - /24 */ 100 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, /* /25 - /28 */ 101 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff /* /29 - /32 */ 102 }; 103 104 static void 105 update_mtu(struct srt_softc *sc) 106 { 107 int mtu; 108 int i; 109 struct srt_rt *r; 110 111 if (sc->flags & SSF_MTULOCK) 112 return; 113 mtu = 65535; 114 for (i = sc->nrt-1; i>=0; i--) { 115 r = sc->rts[i]; 116 if (r->u.dstifp->if_mtu < mtu) 117 mtu = r->u.dstifp->if_mtu; 118 } 119 sc->intf.if_mtu = mtu; 120 } 121 122 static struct srt_rt * 123 find_rt(struct srt_softc *sc, int af, ...) 124 { 125 int i; 126 struct srt_rt *r; 127 struct in_addr ia; 128 struct in6_addr ia6; 129 va_list ap; 130 131 ia.s_addr = 0; ia6.s6_addr[0] = 0; /* shut up incorrect -Wuninitialized */ 132 va_start(ap,af); 133 switch (af) { 134 case AF_INET: 135 ia = va_arg(ap,struct in_addr); 136 break; 137 case AF_INET6: 138 ia6 = va_arg(ap,struct in6_addr); 139 break; 140 default: 141 panic("if_srt find_rt: impossible address family"); 142 break; 143 } 144 va_end(ap); 145 for (i=0; i < sc->nrt; i++) { 146 r = sc->rts[i]; 147 if (r->af != af) 148 continue; 149 switch (af) { 150 case AF_INET: 151 if ((ia.s_addr & htonl(ipv4_masks[r->srcmask])) == 152 r->srcmatch.v4.s_addr) 153 return r; 154 break; 155 case AF_INET6: 156 if ((r->srcmask >= 8) && 157 memcmp(&ia6,&r->srcmatch.v6,r->srcmask / 8) != 0) 158 continue; 159 if ((r->srcmask % 8) && 160 ((ia6.s6_addr[r->srcmask / 8] ^ 161 r->srcmatch.v6.s6_addr[r->srcmask / 8]) & 162 0xff & (0xff00 >> (r->srcmask % 8)))) 163 continue; 164 return r; 165 default: 166 panic("if_srt find_rt: impossible address family 2"); 167 break; 168 } 169 } 170 return 0; 171 } 172 173 /* Network device interface. */ 174 175 static int 176 srt_if_ioctl(struct ifnet *ifp, u_long cmd, void *data) 177 { 178 struct ifaddr *ifa; 179 int s; 180 int err; 181 182 err = 0; 183 s = splnet(); 184 switch (cmd) { 185 case SIOCINITIFADDR: 186 ifa = (void *) data; 187 switch (ifa->ifa_addr->sa_family) { 188 #ifdef INET 189 case AF_INET: 190 break; 191 #endif 192 #ifdef INET6 193 case AF_INET6: 194 break; 195 #endif 196 default: 197 err = EAFNOSUPPORT; 198 break; 199 } 200 break; 201 default: 202 if ((err = ifioctl_common(ifp, cmd, data)) == ENETRESET) 203 err = 0; 204 break; 205 } 206 splx(s); 207 return err; 208 } 209 210 static int 211 srt_if_output( 212 struct ifnet *ifp, 213 struct mbuf *m, 214 const struct sockaddr *to, 215 const struct rtentry *rtp) 216 { 217 struct srt_softc *sc; 218 struct srt_rt *r; 219 220 sc = ifp->if_softc; 221 if (! (ifp->if_flags & IFF_UP)) { 222 m_freem(m); 223 return ENETDOWN; 224 } 225 switch (to->sa_family) { 226 #ifdef INET 227 case AF_INET: { 228 struct ip *ip; 229 ip = mtod(m,struct ip *); 230 r = find_rt(sc,AF_INET,ip->ip_src); 231 break; 232 } 233 #endif 234 #ifdef INET6 235 case AF_INET6: { 236 struct ip6_hdr *ip; 237 ip = mtod(m,struct ip6_hdr *); 238 r = find_rt(sc,AF_INET6,ip->ip6_src); 239 break; 240 } 241 #endif 242 default: 243 IF_DROP(&ifp->if_snd); 244 m_freem(m); 245 return EAFNOSUPPORT; 246 } 247 /* XXX Do we need to bpf_tap? Or do higher layers now handle that? */ 248 /* if_gif.c seems to imply the latter. */ 249 ifp->if_opackets ++; 250 if (! r) { 251 ifp->if_oerrors ++; 252 m_freem(m); 253 return 0; 254 } 255 if (! (m->m_flags & M_PKTHDR)) { 256 printf("srt_if_output no PKTHDR\n"); 257 m_freem(m); 258 return 0; 259 } 260 ifp->if_obytes += m->m_pkthdr.len; 261 if (! (r->u.dstifp->if_flags & IFF_UP)) { 262 m_freem(m); 263 return 0; /* XXX ENETDOWN? */ 264 } 265 /* XXX is 0 the right last arg here? */ 266 if (to->sa_family == AF_INET6) 267 return ip6_if_output(r->u.dstifp, r->u.dstifp, m, &r->dst.sin6, 0); 268 return if_output_lock(r->u.dstifp, r->u.dstifp, m, &r->dst.sa, 0); 269 } 270 271 static int 272 srt_clone_create(struct if_clone *cl, int unit) 273 { 274 struct srt_softc *sc; 275 int rv; 276 277 if (unit < 0 || unit > SRT_MAXUNIT) 278 return ENXIO; 279 if (softcv[unit]) 280 return EBUSY; 281 sc = malloc(sizeof(struct srt_softc), M_DEVBUF, M_WAITOK | M_ZERO); 282 sc->unit = unit; 283 sc->nrt = 0; 284 sc->rts = 0; 285 sc->flags = 0; 286 sc->kflags = 0; 287 if_initname(&sc->intf,cl->ifc_name,unit); 288 sc->intf.if_softc = sc; 289 sc->intf.if_mtu = 65535; 290 sc->intf.if_flags = IFF_POINTOPOINT; 291 sc->intf.if_type = IFT_OTHER; 292 sc->intf.if_ioctl = &srt_if_ioctl; 293 sc->intf.if_output = &srt_if_output; 294 sc->intf.if_dlt = DLT_RAW; 295 rv = if_attach(&sc->intf); 296 if (rv != 0) { 297 aprint_error("%s: if_initialize failed(%d)\n", 298 sc->intf.if_xname, rv); 299 free(sc, M_DEVBUF); 300 return rv; 301 } 302 if_alloc_sadl(&sc->intf); 303 #ifdef BPFILTER_NOW_AVAILABLE 304 bpf_attach(&sc->intf, 0, 0); 305 #endif 306 softcv[unit] = sc; 307 atomic_inc_uint(&srt_count); 308 return 0; 309 } 310 311 static int 312 srt_clone_destroy(struct ifnet *ifp) 313 { 314 struct srt_softc *sc; 315 316 sc = ifp->if_softc; 317 if ((ifp->if_flags & IFF_UP) || (sc->kflags & SKF_CDEVOPEN)) 318 return EBUSY; 319 #ifdef BPFILTER_NOW_AVAILABLE 320 bpf_detach(ifp); 321 #endif 322 if_detach(ifp); 323 if (sc->unit < 0 || sc->unit > SRT_MAXUNIT) { 324 panic("srt_clone_destroy: impossible unit %d\n",sc->unit); 325 } 326 if (softcv[sc->unit] != sc) { 327 panic("srt_clone_destroy: bad backpointer ([%d]=%p not %p)\n", 328 sc->unit, (void *)softcv[sc->unit], (void *)sc); 329 } 330 softcv[sc->unit] = 0; 331 free(sc, M_DEVBUF); 332 atomic_inc_uint(&srt_count); 333 return 0; 334 } 335 336 struct if_clone srt_clone = 337 IF_CLONE_INITIALIZER("srt", &srt_clone_create, &srt_clone_destroy); 338 339 void 340 srtattach(int n) 341 { 342 343 /* 344 * Nothing to do here, initialization is handled by the 345 * module initialization code in srtinit() below). 346 */ 347 } 348 349 static void 350 srtinit(void) 351 { 352 int i; 353 354 for (i = SRT_MAXUNIT; i >= 0; i--) 355 softcv[i] = 0; 356 global_flags = 0; 357 if_clone_attach(&srt_clone); 358 #ifdef _MODULE 359 devsw_attach("srt", NULL, &srt_bmajor, &srt_cdevsw, &srt_cmajor); 360 #endif 361 } 362 363 static int 364 srtdetach(void) 365 { 366 int error = 0; 367 int i; 368 369 if_clone_detach(&srt_clone); 370 #ifdef _MODULE 371 devsw_detach(NULL, &srt_cdevsw); 372 if (error != 0) { 373 if_clone_attach(&srt_clone); 374 return error; 375 } 376 #endif 377 378 for (i = SRT_MAXUNIT; i >= 0; i--) 379 if(softcv[i]) { 380 error = EBUSY; 381 #ifdef _MODULE 382 devsw_attach("srt", NULL, &srt_bmajor, 383 &srt_cdevsw, &srt_cmajor); 384 #endif 385 if_clone_attach(&srt_clone); 386 break; 387 } 388 389 return error; 390 } 391 392 /* Special-device interface. */ 393 394 static int 395 srt_open(dev_t dev, int flag, int mode, struct lwp *l) 396 { 397 int unit; 398 struct srt_softc *sc; 399 400 unit = minor(dev); 401 if (unit < 0 || unit > SRT_MAXUNIT) 402 return ENXIO; 403 sc = softcv[unit]; 404 if (sc == NULL) { 405 (void)srt_clone_create(&srt_clone, minor(dev)); 406 sc = softcv[unit]; 407 } 408 if (! sc) 409 return ENXIO; 410 sc->kflags |= SKF_CDEVOPEN; 411 return 0; 412 } 413 414 static int 415 srt_close(dev_t dev, int flag, int mode, struct lwp *l) 416 { 417 int unit; 418 struct srt_softc *sc; 419 420 unit = minor(dev); 421 if (unit < 0 || unit > SRT_MAXUNIT) 422 return ENXIO; 423 sc = softcv[unit]; 424 if (! sc) 425 return ENXIO; 426 sc->kflags &= ~SKF_CDEVOPEN; 427 return 0; 428 } 429 430 static int 431 srt_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 432 { 433 unsigned int f, i, n, o; 434 struct srt_softc *sc; 435 struct srt_rt *dr; 436 struct srt_rt *scr; 437 struct ifnet *ifp; 438 char nbuf[IFNAMSIZ]; 439 440 sc = softcv[minor(dev)]; 441 if (! sc) 442 panic("srt_ioctl: softc disappeared"); 443 switch (cmd) { 444 case SRT_GETNRT: 445 if (! (flag & FREAD)) 446 return EBADF; 447 *(unsigned int *)data = sc->nrt; 448 return 0; 449 case SRT_GETRT: 450 if (! (flag & FREAD)) 451 return EBADF; 452 dr = (struct srt_rt *) data; 453 if (dr->inx >= sc->nrt) 454 return EDOM; 455 scr = sc->rts[dr->inx]; 456 dr->af = scr->af; 457 dr->srcmatch = scr->srcmatch; 458 dr->srcmask = scr->srcmask; 459 strlcpy(&dr->u.dstifn[0], &scr->u.dstifp->if_xname[0], 460 IFNAMSIZ); 461 memcpy(&dr->dst, &scr->dst, scr->dst.sa.sa_len); 462 return 0; 463 case SRT_SETRT: 464 if (! (flag & FWRITE)) 465 return EBADF; 466 dr = (struct srt_rt *) data; 467 if (dr->inx > sc->nrt) 468 return EDOM; 469 strlcpy(&nbuf[0], &dr->u.dstifn[0], IFNAMSIZ); 470 nbuf[IFNAMSIZ-1] = '\0'; 471 if (dr->dst.sa.sa_family != dr->af) 472 return EIO; 473 switch (dr->af) { 474 #ifdef INET 475 case AF_INET: 476 if (dr->dst.sa.sa_len != sizeof(dr->dst.sin)) 477 return EIO; 478 if (dr->srcmask > 32) 479 return EIO; 480 break; 481 #endif 482 #ifdef INET6 483 case AF_INET6: 484 if (dr->dst.sa.sa_len != sizeof(dr->dst.sin6)) 485 return EIO; 486 if (dr->srcmask > 128) 487 return EIO; 488 break; 489 #endif 490 default: 491 return EAFNOSUPPORT; 492 } 493 ifp = ifunit(&nbuf[0]); 494 if (ifp == 0) 495 return ENXIO; /* needs translation */ 496 if (dr->inx == sc->nrt) { 497 struct srt_rt **tmp; 498 tmp = malloc((sc->nrt+1)*sizeof(*tmp), M_DEVBUF, 499 M_WAITOK); 500 if (tmp == 0) 501 return ENOBUFS; 502 tmp[sc->nrt] = 0; 503 if (sc->nrt > 0) { 504 memcpy(tmp, sc->rts, sc->nrt*sizeof(*tmp)); 505 free(sc->rts, M_DEVBUF); 506 } 507 sc->rts = tmp; 508 sc->nrt ++; 509 } 510 scr = sc->rts[dr->inx]; 511 if (scr == 0) { 512 scr = malloc(sizeof(struct srt_rt), M_DEVBUF,M_WAITOK); 513 if (scr == 0) 514 return ENOBUFS; 515 scr->inx = dr->inx; 516 scr->af = AF_UNSPEC; 517 sc->rts[dr->inx] = scr; 518 } 519 scr->af = dr->af; 520 scr->srcmatch = dr->srcmatch; 521 scr->srcmask = dr->srcmask; 522 scr->u.dstifp = ifp; 523 memcpy(&scr->dst,&dr->dst,dr->dst.sa.sa_len); 524 if (dr->af == AF_INET6) 525 in6_setzoneid(&scr->dst.sin6.sin6_addr, ifp->if_index); 526 update_mtu(sc); 527 return 0; 528 case SRT_DELRT: 529 if (! (flag & FWRITE)) 530 return EBADF; 531 i = *(unsigned int *)data; 532 if (i >= sc->nrt) 533 return EDOM; 534 scr = sc->rts[i]; 535 sc->rts[i] = 0; 536 free(scr, M_DEVBUF); 537 sc->nrt--; 538 if (i < sc->nrt) { 539 memcpy(sc->rts+i, sc->rts+i+1, 540 (sc->nrt-i) * sizeof(*sc->rts)); 541 } 542 if (sc->nrt == 0) { 543 free(sc->rts, M_DEVBUF); 544 sc->rts = 0; 545 sc->intf.if_flags &= ~IFF_UP; 546 } 547 update_mtu(sc); 548 return 0; 549 case SRT_SFLAGS: 550 if (! (flag & FWRITE)) 551 return EBADF; 552 f = *(unsigned int *)data & SSF_UCHG; 553 global_flags = (global_flags & ~SSF_UCHG) | (f & SSF_GLOBAL); 554 sc->flags = (sc->flags & ~SSF_UCHG) | (f & ~SSF_GLOBAL); 555 return 0; 556 case SRT_GFLAGS: 557 if (! (flag & FREAD)) 558 return EBADF; 559 *(unsigned int *)data = sc->flags | global_flags; 560 return 0; 561 case SRT_SGFLAGS: 562 if ((flag & (FWRITE | FREAD)) != (FWRITE | FREAD)) 563 return EBADF; 564 o = sc->flags | global_flags; 565 n = *(unsigned int *)data & SSF_UCHG; 566 global_flags = (global_flags & ~SSF_UCHG) | (n & SSF_GLOBAL); 567 sc->flags = (sc->flags & ~SSF_UCHG) | (n & ~SSF_GLOBAL); 568 *(unsigned int *)data = o; 569 return 0; 570 case SRT_DEBUG: 571 return 0; 572 break; 573 } 574 return ENOTTY; 575 } 576 577 /* 578 * Module infrastructure 579 */ 580 #include "if_module.h" 581 582 IF_MODULE(MODULE_CLASS_DRIVER, srt, NULL) 583