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