1/* $NetBSD: if_srt.c,v 1.32 2021/06/16 00:21:19 riastradh 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.32 2021/06/16 00:21:19 riastradh 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 49struct 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 62static struct srt_softc *softcv[SRT_MAXUNIT+1]; 63static unsigned int global_flags; 64 65static u_int srt_count; 66 67#ifdef _MODULE 68devmajor_t srt_bmajor = -1, srt_cmajor = -1; 69#endif 70 71static int srt_open(dev_t, int, int, struct lwp *); 72static int srt_close(dev_t, int, int, struct lwp *); 73static int srt_ioctl(dev_t, u_long, void *, int, struct lwp *); 74 75const 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 92static 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 104static void 105update_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 122static struct srt_rt * 123find_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 175static int 176srt_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 210static int 211srt_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 if_statinc(ifp, if_opackets); 250 if (! r) { 251 if_statinc(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 if_statadd(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 271static int 272srt_clone_create(struct if_clone *cl, int unit) 273{ 274 struct srt_softc *sc; 275 276 if (unit < 0 || unit > SRT_MAXUNIT) 277 return ENXIO; 278 if (softcv[unit]) 279 return EBUSY; 280 sc = malloc(sizeof(struct srt_softc), M_DEVBUF, M_WAITOK | M_ZERO); 281 sc->unit = unit; 282 sc->nrt = 0; 283 sc->rts = 0; 284 sc->flags = 0; 285 sc->kflags = 0; 286 if_initname(&sc->intf,cl->ifc_name,unit); 287 sc->intf.if_softc = sc; 288 sc->intf.if_mtu = 65535; 289 sc->intf.if_flags = IFF_POINTOPOINT; 290 sc->intf.if_type = IFT_OTHER; 291 sc->intf.if_ioctl = &srt_if_ioctl; 292 sc->intf.if_output = &srt_if_output; 293 sc->intf.if_dlt = DLT_RAW; 294 if_attach(&sc->intf); 295 if_alloc_sadl(&sc->intf); 296#ifdef BPFILTER_NOW_AVAILABLE 297 bpf_attach(&sc->intf, 0, 0); 298#endif 299 softcv[unit] = sc; 300 atomic_inc_uint(&srt_count); 301 return 0; 302} 303 304static int 305srt_clone_destroy(struct ifnet *ifp) 306{ 307 struct srt_softc *sc; 308 309 sc = ifp->if_softc; 310 if ((ifp->if_flags & IFF_UP) || (sc->kflags & SKF_CDEVOPEN)) 311 return EBUSY; 312#ifdef BPFILTER_NOW_AVAILABLE 313 bpf_detach(ifp); 314#endif 315 if_detach(ifp); 316 if (sc->unit < 0 || sc->unit > SRT_MAXUNIT) { 317 panic("srt_clone_destroy: impossible unit %d\n",sc->unit); 318 } 319 if (softcv[sc->unit] != sc) { 320 panic("srt_clone_destroy: bad backpointer ([%d]=%p not %p)\n", 321 sc->unit, (void *)softcv[sc->unit], (void *)sc); 322 } 323 softcv[sc->unit] = 0; 324 free(sc, M_DEVBUF); 325 atomic_inc_uint(&srt_count); 326 return 0; 327} 328 329struct if_clone srt_clone = 330 IF_CLONE_INITIALIZER("srt", &srt_clone_create, &srt_clone_destroy); 331 332void 333srtattach(int n) 334{ 335 336 /* 337 * Nothing to do here, initialization is handled by the 338 * module initialization code in srtinit() below). 339 */ 340} 341 342static void 343srtinit(void) 344{ 345 int i; 346 347 for (i = SRT_MAXUNIT; i >= 0; i--) 348 softcv[i] = 0; 349 global_flags = 0; 350 if_clone_attach(&srt_clone); 351#ifdef _MODULE 352 devsw_attach("srt", NULL, &srt_bmajor, &srt_cdevsw, &srt_cmajor); 353#endif 354} 355 356static int 357srtdetach(void) 358{ 359 int error = 0; 360 int i; 361 362 if_clone_detach(&srt_clone); 363#ifdef _MODULE 364 devsw_detach(NULL, &srt_cdevsw); 365 if (error != 0) { 366 if_clone_attach(&srt_clone); 367 return error; 368 } 369#endif 370 371 for (i = SRT_MAXUNIT; i >= 0; i--) 372 if(softcv[i]) { 373 error = EBUSY; 374#ifdef _MODULE 375 devsw_attach("srt", NULL, &srt_bmajor, 376 &srt_cdevsw, &srt_cmajor); 377#endif 378 if_clone_attach(&srt_clone); 379 break; 380 } 381 382 return error; 383} 384 385/* Special-device interface. */ 386 387static int 388srt_open(dev_t dev, int flag, int mode, struct lwp *l) 389{ 390 int unit; 391 struct srt_softc *sc; 392 393 unit = minor(dev); 394 if (unit < 0 || unit > SRT_MAXUNIT) 395 return ENXIO; 396 sc = softcv[unit]; 397 if (sc == NULL) { 398 (void)srt_clone_create(&srt_clone, minor(dev)); 399 sc = softcv[unit]; 400 } 401 if (! sc) 402 return ENXIO; 403 sc->kflags |= SKF_CDEVOPEN; 404 return 0; 405} 406 407static int 408srt_close(dev_t dev, int flag, int mode, struct lwp *l) 409{ 410 int unit; 411 struct srt_softc *sc; 412 413 unit = minor(dev); 414 if (unit < 0 || unit > SRT_MAXUNIT) 415 return ENXIO; 416 sc = softcv[unit]; 417 if (! sc) 418 return ENXIO; 419 sc->kflags &= ~SKF_CDEVOPEN; 420 return 0; 421} 422 423static int 424srt_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 425{ 426 unsigned int f, i, n, o; 427 struct srt_softc *sc; 428 struct srt_rt *dr; 429 struct srt_rt *scr; 430 struct ifnet *ifp; 431 char nbuf[IFNAMSIZ]; 432 433 sc = softcv[minor(dev)]; 434 if (! sc) 435 panic("srt_ioctl: softc disappeared"); 436 switch (cmd) { 437 case SRT_GETNRT: 438 if (! (flag & FREAD)) 439 return EBADF; 440 *(unsigned int *)data = sc->nrt; 441 return 0; 442 case SRT_GETRT: 443 if (! (flag & FREAD)) 444 return EBADF; 445 dr = (struct srt_rt *) data; 446 if (dr->inx >= sc->nrt) 447 return EDOM; 448 scr = sc->rts[dr->inx]; 449 dr->af = scr->af; 450 dr->srcmatch = scr->srcmatch; 451 dr->srcmask = scr->srcmask; 452 strlcpy(&dr->u.dstifn[0], &scr->u.dstifp->if_xname[0], 453 IFNAMSIZ); 454 memcpy(&dr->dst, &scr->dst, scr->dst.sa.sa_len); 455 return 0; 456 case SRT_SETRT: 457 if (! (flag & FWRITE)) 458 return EBADF; 459 dr = (struct srt_rt *) data; 460 if (dr->inx > sc->nrt) 461 return EDOM; 462 strlcpy(&nbuf[0], &dr->u.dstifn[0], IFNAMSIZ); 463 nbuf[IFNAMSIZ-1] = '\0'; 464 if (dr->dst.sa.sa_family != dr->af) 465 return EIO; 466 switch (dr->af) { 467#ifdef INET 468 case AF_INET: 469 if (dr->dst.sa.sa_len != sizeof(dr->dst.sin)) 470 return EIO; 471 if (dr->srcmask > 32) 472 return EIO; 473 break; 474#endif 475#ifdef INET6 476 case AF_INET6: 477 if (dr->dst.sa.sa_len != sizeof(dr->dst.sin6)) 478 return EIO; 479 if (dr->srcmask > 128) 480 return EIO; 481 break; 482#endif 483 default: 484 return EAFNOSUPPORT; 485 } 486 ifp = ifunit(&nbuf[0]); 487 if (ifp == 0) 488 return ENXIO; /* needs translation */ 489 if (dr->inx == sc->nrt) { 490 struct srt_rt **tmp; 491 tmp = malloc((sc->nrt+1)*sizeof(*tmp), M_DEVBUF, 492 M_WAITOK); 493 if (tmp == 0) 494 return ENOBUFS; 495 tmp[sc->nrt] = 0; 496 if (sc->nrt > 0) { 497 memcpy(tmp, sc->rts, sc->nrt*sizeof(*tmp)); 498 free(sc->rts, M_DEVBUF); 499 } 500 sc->rts = tmp; 501 sc->nrt ++; 502 } 503 scr = sc->rts[dr->inx]; 504 if (scr == 0) { 505 scr = malloc(sizeof(struct srt_rt), M_DEVBUF,M_WAITOK); 506 if (scr == 0) 507 return ENOBUFS; 508 scr->inx = dr->inx; 509 scr->af = AF_UNSPEC; 510 sc->rts[dr->inx] = scr; 511 } 512 scr->af = dr->af; 513 scr->srcmatch = dr->srcmatch; 514 scr->srcmask = dr->srcmask; 515 scr->u.dstifp = ifp; 516 memcpy(&scr->dst,&dr->dst,dr->dst.sa.sa_len); 517 if (dr->af == AF_INET6) 518 in6_setzoneid(&scr->dst.sin6.sin6_addr, ifp->if_index); 519 update_mtu(sc); 520 return 0; 521 case SRT_DELRT: 522 if (! (flag & FWRITE)) 523 return EBADF; 524 i = *(unsigned int *)data; 525 if (i >= sc->nrt) 526 return EDOM; 527 scr = sc->rts[i]; 528 sc->rts[i] = 0; 529 free(scr, M_DEVBUF); 530 sc->nrt--; 531 if (i < sc->nrt) { 532 memcpy(sc->rts+i, sc->rts+i+1, 533 (sc->nrt-i) * sizeof(*sc->rts)); 534 } 535 if (sc->nrt == 0) { 536 free(sc->rts, M_DEVBUF); 537 sc->rts = 0; 538 sc->intf.if_flags &= ~IFF_UP; 539 } 540 update_mtu(sc); 541 return 0; 542 case SRT_SFLAGS: 543 if (! (flag & FWRITE)) 544 return EBADF; 545 f = *(unsigned int *)data & SSF_UCHG; 546 global_flags = (global_flags & ~SSF_UCHG) | (f & SSF_GLOBAL); 547 sc->flags = (sc->flags & ~SSF_UCHG) | (f & ~SSF_GLOBAL); 548 return 0; 549 case SRT_GFLAGS: 550 if (! (flag & FREAD)) 551 return EBADF; 552 *(unsigned int *)data = sc->flags | global_flags; 553 return 0; 554 case SRT_SGFLAGS: 555 if ((flag & (FWRITE | FREAD)) != (FWRITE | FREAD)) 556 return EBADF; 557 o = sc->flags | global_flags; 558 n = *(unsigned int *)data & SSF_UCHG; 559 global_flags = (global_flags & ~SSF_UCHG) | (n & SSF_GLOBAL); 560 sc->flags = (sc->flags & ~SSF_UCHG) | (n & ~SSF_GLOBAL); 561 *(unsigned int *)data = o; 562 return 0; 563 case SRT_DEBUG: 564 return 0; 565 break; 566 } 567 return ENOTTY; 568} 569 570/* 571 * Module infrastructure 572 */ 573#include "if_module.h" 574 575IF_MODULE(MODULE_CLASS_DRIVER, srt, NULL) 576