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