if_tap.c revision 83366
180679Salfred/* 280679Salfred * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com> 380679Salfred * All rights reserved. 480679Salfred * 580679Salfred * Redistribution and use in source and binary forms, with or without 680679Salfred * modification, are permitted provided that the following conditions 780679Salfred * are met: 880679Salfred * 1. Redistributions of source code must retain the above copyright 980679Salfred * notice, this list of conditions and the following disclaimer. 1080679Salfred * 2. Redistributions in binary form must reproduce the above copyright 1180679Salfred * notice, this list of conditions and the following disclaimer in the 1280679Salfred * documentation and/or other materials provided with the distribution. 1380679Salfred * 1480679Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1580679Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1680679Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1780679Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1880679Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1980679Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2080679Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2180679Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2280679Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2380679Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2480679Salfred * SUCH DAMAGE. 2580679Salfred * 2680679Salfred * BASED ON: 2780679Salfred * ------------------------------------------------------------------------- 2880679Salfred * 2980679Salfred * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 3080679Salfred * Nottingham University 1987. 3180679Salfred */ 3280679Salfred 3381278Sru/* 3481278Sru * $FreeBSD: head/sys/net/if_tap.c 83366 2001-09-12 08:38:13Z julian $ 3581278Sru * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 3680679Salfred */ 3780679Salfred 3880679Salfred#include "opt_inet.h" 3980679Salfred 4080679Salfred#include <sys/param.h> 4180679Salfred#include <sys/conf.h> 4280679Salfred#include <sys/filedesc.h> 4380679Salfred#include <sys/filio.h> 4480679Salfred#include <sys/kernel.h> 4580679Salfred#include <sys/malloc.h> 4680679Salfred#include <sys/mbuf.h> 4780679Salfred#include <sys/poll.h> 4880679Salfred#include <sys/proc.h> 4980679Salfred#include <sys/signalvar.h> 5080679Salfred#include <sys/socket.h> 5180679Salfred#include <sys/sockio.h> 5280679Salfred#include <sys/sysctl.h> 5380679Salfred#include <sys/systm.h> 5480679Salfred#include <sys/ttycom.h> 5580679Salfred#include <sys/uio.h> 5681278Sru#include <sys/vnode.h> 5780679Salfred#include <machine/bus.h> /* XXX: Shouldn't really be required! */ 5880679Salfred#include <sys/rman.h> 5981278Sru#include <sys/queue.h> 6080679Salfred 6180679Salfred#include <net/bpf.h> 6280679Salfred#include <net/ethernet.h> 6380679Salfred#include <net/if.h> 6481278Sru#include <net/if_arp.h> 6580679Salfred#include <net/route.h> 6680679Salfred 6780679Salfred#include <netinet/in.h> 6880679Salfred 6980679Salfred#include <net/if_tapvar.h> 7080679Salfred#include <net/if_tap.h> 7180679Salfred 7280679Salfred 7381278Sru#define CDEV_NAME "tap" 7481278Sru#define CDEV_MAJOR 149 7580679Salfred#define TAPDEBUG if (tapdebug) printf 7680679Salfred 7780679Salfred#define TAP "tap" 7880679Salfred#define VMNET "vmnet" 7980679Salfred#define TAPMAXUNIT 0x7fff 8080679Salfred#define VMNET_DEV_MASK 0x00800000 8180679Salfred /* 0x007f00ff */ 8280679Salfred 8380679Salfred/* module */ 8480679Salfredstatic int tapmodevent __P((module_t, int, void *)); 8580679Salfred 8680679Salfred/* device */ 8781278Srustatic void tapclone __P((void *, char *, int, dev_t *)); 8880679Salfredstatic void tapcreate __P((dev_t)); 8980679Salfred 9080679Salfred/* network interface */ 9180679Salfredstatic void tapifstart __P((struct ifnet *)); 9280679Salfredstatic int tapifioctl __P((struct ifnet *, u_long, caddr_t)); 9380679Salfredstatic void tapifinit __P((void *)); 9480679Salfred 9580679Salfred/* character device */ 9680679Salfredstatic d_open_t tapopen; 9780679Salfredstatic d_close_t tapclose; 9880679Salfredstatic d_read_t tapread; 99static d_write_t tapwrite; 100static d_ioctl_t tapioctl; 101static d_poll_t tappoll; 102 103static struct cdevsw tap_cdevsw = { 104 /* open */ tapopen, 105 /* close */ tapclose, 106 /* read */ tapread, 107 /* write */ tapwrite, 108 /* ioctl */ tapioctl, 109 /* poll */ tappoll, 110 /* mmap */ nommap, 111 /* startegy */ nostrategy, 112 /* dev name */ CDEV_NAME, 113 /* dev major */ CDEV_MAJOR, 114 /* dump */ nodump, 115 /* psize */ nopsize, 116 /* flags */ 0, 117}; 118 119static int tapdebug = 0; /* debug flag */ 120static SLIST_HEAD(, tap_softc) taphead; /* first device */ 121static udev_t tapbasedev = NOUDEV; /* base device */ 122static struct rman tapdevunits[2]; /* device units */ 123#define tapunits tapdevunits 124#define vmnetunits (tapdevunits + 1) 125 126MALLOC_DECLARE(M_TAP); 127MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 128SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 129DEV_MODULE(if_tap, tapmodevent, NULL); 130 131/* 132 * tapmodevent 133 * 134 * module event handler 135 */ 136static int 137tapmodevent(mod, type, data) 138 module_t mod; 139 int type; 140 void *data; 141{ 142 static eventhandler_tag eh_tag = NULL; 143 struct tap_softc *tp = NULL; 144 struct ifnet *ifp = NULL; 145 int error, s; 146 147 switch (type) { 148 case MOD_LOAD: 149 /* initialize resources */ 150 tapunits->rm_type = RMAN_ARRAY; 151 tapunits->rm_descr = "open tap units"; 152 vmnetunits->rm_type = RMAN_ARRAY; 153 vmnetunits->rm_descr = "open vmnet units"; 154 155 error = rman_init(tapunits); 156 if (error != 0) 157 goto bail; 158 159 error = rman_init(vmnetunits); 160 if (error != 0) 161 goto bail1; 162 163 error = rman_manage_region(tapunits, 0, TAPMAXUNIT); 164 if (error != 0) 165 goto bail2; 166 167 error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT); 168 if (error != 0) 169 goto bail2; 170 171 /* intitialize device */ 172 173 SLIST_INIT(&taphead); 174 175 eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 176 if (eh_tag == NULL) { 177 error = ENOMEM; 178 goto bail2; 179 } 180 181 if (!devfs_present) { 182 error = cdevsw_add(&tap_cdevsw); 183 if (error != 0) { 184 EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 185 goto bail2; 186 } 187 } 188 189 return (0); 190bail2: 191 rman_fini(vmnetunits); 192bail1: 193 rman_fini(tapunits); 194bail: 195 return (error); 196 197 case MOD_UNLOAD: 198 SLIST_FOREACH(tp, &taphead, tap_next) 199 if (tp->tap_unit != NULL) 200 return (EBUSY); 201 202 EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 203 204 error = rman_fini(tapunits); 205 KASSERT((error == 0), ("Could not fini tap units")); 206 error = rman_fini(vmnetunits); 207 KASSERT((error == 0), ("Could not fini vmnet units")); 208 209 while ((tp = SLIST_FIRST(&taphead)) != NULL) { 210 SLIST_REMOVE_HEAD(&taphead, tap_next); 211 212 ifp = &tp->tap_if; 213 214 TAPDEBUG("detaching %s%d\n", ifp->if_name,ifp->if_unit); 215 216 KASSERT(!(tp->tap_flags & TAP_OPEN), 217 ("%s%d flags is out of sync", ifp->if_name, 218 ifp->if_unit)); 219 220 /* XXX makedev check? nah.. not right now :) */ 221 222 s = splimp(); 223 ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 224 splx(s); 225 226 FREE(tp, M_TAP); 227 } 228 229 if (tapbasedev != NOUDEV) 230 destroy_dev(udev2dev(tapbasedev, 0)); 231 232 if (!devfs_present) 233 cdevsw_remove(&tap_cdevsw); 234 235 break; 236 237 default: 238 return (EOPNOTSUPP); 239 } 240 241 return (0); 242} /* tapmodevent */ 243 244 245/* 246 * DEVFS handler 247 * 248 * We need to support two kind of devices - tap and vmnet 249 */ 250static void 251tapclone(arg, name, namelen, dev) 252 void *arg; 253 char *name; 254 int namelen; 255 dev_t *dev; 256{ 257 int unit, minor = 0 /* XXX avoid warning */ , error; 258 char *device_name = name; 259 struct resource *r = NULL; 260 261 if (*dev != NODEV) 262 return; 263 264 if (strcmp(device_name, TAP) == 0) { 265 /* get first free tap unit */ 266 r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1, 267 RF_ALLOCATED | RF_ACTIVE, NULL); 268 unit = rman_get_start(r); 269 minor = unit2minor(unit); 270 } 271 else if (strcmp(device_name, VMNET) == 0) { 272 /* get first free vmnet unit */ 273 r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1, 274 RF_ALLOCATED | RF_ACTIVE, NULL); 275 unit = rman_get_start(r); 276 minor = unit2minor(unit) | VMNET_DEV_MASK; 277 } 278 279 if (r != NULL) { /* need cloning */ 280 TAPDEBUG("%s%d is available. minor = %#x\n", 281 device_name, unit, minor); 282 283 error = rman_release_resource(r); 284 KASSERT((error == 0), ("Could not release tap/vmnet unit")); 285 286 /* check if device for the unit has been created */ 287 *dev = makedev(CDEV_MAJOR, minor); 288 if ((*dev)->si_flags & SI_NAMED) { 289 TAPDEBUG("%s%d device exists. minor = %#x\n", 290 device_name, unit, minor); 291 return; /* device has been created */ 292 } 293 } else { /* try to match name/unit, first try tap then vmnet */ 294 device_name = TAP; 295 if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 296 device_name = VMNET; 297 298 if (dev_stdclone(name, NULL, device_name, &unit) != 1) 299 return; 300 301 minor = unit2minor(unit) | VMNET_DEV_MASK; 302 } else 303 minor = unit2minor(unit); 304 } 305 306 TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor); 307 308 *dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d", 309 device_name, unit); 310 311 if (tapbasedev == NOUDEV) 312 tapbasedev = (*dev)->si_udev; 313 else { 314 (*dev)->si_flags |= SI_CHEAPCLONE; 315 dev_depends(udev2dev(tapbasedev, 0), *dev); 316 } 317} /* tapclone */ 318 319 320/* 321 * tapcreate 322 * 323 * to create interface 324 */ 325static void 326tapcreate(dev) 327 dev_t dev; 328{ 329 struct ifnet *ifp = NULL; 330 struct tap_softc *tp = NULL; 331 unsigned short macaddr_hi; 332 int unit, s; 333 char *name = NULL; 334 335 /* allocate driver storage and create device */ 336 MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 337 SLIST_INSERT_HEAD(&taphead, tp, tap_next); 338 339 unit = dev2unit(dev) & TAPMAXUNIT; 340 341 /* select device: tap or vmnet */ 342 if (minor(dev) & VMNET_DEV_MASK) { 343 name = VMNET; 344 tp->tap_flags |= TAP_VMNET; 345 } else 346 name = TAP; 347 348 TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 349 350 if (!(dev->si_flags & SI_NAMED)) 351 dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 352 0600, "%s%d", name, unit); 353 354 /* generate fake MAC address: 00 bd xx xx xx unit_no */ 355 macaddr_hi = htons(0x00bd); 356 bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 357 bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 358 tp->arpcom.ac_enaddr[5] = (u_char)unit; 359 360 /* fill the rest and attach interface */ 361 ifp = &tp->tap_if; 362 ifp->if_softc = tp; 363 ifp->if_unit = unit; 364 ifp->if_name = name; 365 ifp->if_init = tapifinit; 366 ifp->if_output = ether_output; 367 ifp->if_start = tapifstart; 368 ifp->if_ioctl = tapifioctl; 369 ifp->if_mtu = ETHERMTU; 370 ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 371 ifp->if_snd.ifq_maxlen = ifqmaxlen; 372 373 dev->si_drv1 = tp; 374 375 s = splimp(); 376 ether_ifattach(ifp, ETHER_BPF_SUPPORTED); 377 splx(s); 378 379 tp->tap_flags |= TAP_INITED; 380 381 TAPDEBUG("interface %s%d is created. minor = %#x\n", 382 ifp->if_name, ifp->if_unit, minor(dev)); 383} /* tapcreate */ 384 385 386/* 387 * tapopen 388 * 389 * to open tunnel. must be superuser 390 */ 391static int 392tapopen(dev, flag, mode, td) 393 dev_t dev; 394 int flag; 395 int mode; 396 struct thread *td; 397{ 398 struct tap_softc *tp = NULL; 399 int unit, error; 400 struct resource *r = NULL; 401 402 if ((error = suser_td(td)) != 0) 403 return (error); 404 405 unit = dev2unit(dev) & TAPMAXUNIT; 406 407 if (minor(dev) & VMNET_DEV_MASK) 408 r = rman_reserve_resource(vmnetunits, unit, unit, 1, 409 RF_ALLOCATED | RF_ACTIVE, NULL); 410 else 411 r = rman_reserve_resource(tapunits, unit, unit, 1, 412 RF_ALLOCATED | RF_ACTIVE, NULL); 413 414 if (r == NULL) 415 return (EBUSY); 416 417 dev->si_flags &= ~SI_CHEAPCLONE; 418 419 tp = dev->si_drv1; 420 if (tp == NULL) { 421 tapcreate(dev); 422 tp = dev->si_drv1; 423 } 424 425 KASSERT(!(tp->tap_flags & TAP_OPEN), 426 ("%s%d flags is out of sync", tp->tap_if.if_name, unit)); 427 428 bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 429 430 tp->tap_unit = r; 431 tp->tap_pid = td->td_proc->p_pid; 432 tp->tap_flags |= TAP_OPEN; 433 434 TAPDEBUG("%s%d is open. minor = %#x\n", 435 tp->tap_if.if_name, unit, minor(dev)); 436 437 return (0); 438} /* tapopen */ 439 440 441/* 442 * tapclose 443 * 444 * close the device - mark i/f down & delete routing info 445 */ 446static int 447tapclose(dev, foo, bar, td) 448 dev_t dev; 449 int foo; 450 int bar; 451 struct thread *td; 452{ 453 int s, error; 454 struct tap_softc *tp = dev->si_drv1; 455 struct ifnet *ifp = &tp->tap_if; 456 457 KASSERT((tp->tap_unit != NULL), 458 ("%s%d is not open", ifp->if_name, ifp->if_unit)); 459 460 /* junk all pending output */ 461 IF_DRAIN(&ifp->if_snd); 462 463 /* 464 * do not bring the interface down, and do not anything with 465 * interface, if we are in VMnet mode. just close the device. 466 */ 467 468 if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 469 s = splimp(); 470 if_down(ifp); 471 if (ifp->if_flags & IFF_RUNNING) { 472 /* find internet addresses and delete routes */ 473 struct ifaddr *ifa = NULL; 474 475 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 476 if (ifa->ifa_addr->sa_family == AF_INET) { 477 rtinit(ifa, (int)RTM_DELETE, 0); 478 479 /* remove address from interface */ 480 bzero(ifa->ifa_addr, 481 sizeof(*(ifa->ifa_addr))); 482 bzero(ifa->ifa_dstaddr, 483 sizeof(*(ifa->ifa_dstaddr))); 484 bzero(ifa->ifa_netmask, 485 sizeof(*(ifa->ifa_netmask))); 486 } 487 } 488 489 ifp->if_flags &= ~IFF_RUNNING; 490 } 491 splx(s); 492 } 493 494 funsetown(tp->tap_sigio); 495 selwakeup(&tp->tap_rsel); 496 497 tp->tap_flags &= ~TAP_OPEN; 498 tp->tap_pid = 0; 499 error = rman_release_resource(tp->tap_unit); 500 KASSERT((error == 0), 501 ("%s%d could not release unit", ifp->if_name, ifp->if_unit)); 502 tp->tap_unit = NULL; 503 504 TAPDEBUG("%s%d is closed. minor = %#x\n", 505 ifp->if_name, ifp->if_unit, minor(dev)); 506 507 return (0); 508} /* tapclose */ 509 510 511/* 512 * tapifinit 513 * 514 * network interface initialization function 515 */ 516static void 517tapifinit(xtp) 518 void *xtp; 519{ 520 struct tap_softc *tp = (struct tap_softc *)xtp; 521 struct ifnet *ifp = &tp->tap_if; 522 523 TAPDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit); 524 525 ifp->if_flags |= IFF_RUNNING; 526 ifp->if_flags &= ~IFF_OACTIVE; 527 528 /* attempt to start output */ 529 tapifstart(ifp); 530} /* tapifinit */ 531 532 533/* 534 * tapifioctl 535 * 536 * Process an ioctl request on network interface 537 */ 538int 539tapifioctl(ifp, cmd, data) 540 struct ifnet *ifp; 541 u_long cmd; 542 caddr_t data; 543{ 544 struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 545 struct ifstat *ifs = NULL; 546 int s, dummy; 547 548 switch (cmd) { 549 case SIOCSIFADDR: 550 case SIOCGIFADDR: 551 case SIOCSIFMTU: 552 s = splimp(); 553 dummy = ether_ioctl(ifp, cmd, data); 554 splx(s); 555 return (dummy); 556 557 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 558 case SIOCADDMULTI: 559 case SIOCDELMULTI: 560 break; 561 562 case SIOCGIFSTATUS: 563 s = splimp(); 564 ifs = (struct ifstat *)data; 565 dummy = strlen(ifs->ascii); 566 if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 567 snprintf(ifs->ascii + dummy, 568 sizeof(ifs->ascii) - dummy, 569 "\tOpened by PID %d\n", tp->tap_pid); 570 splx(s); 571 break; 572 573 default: 574 return (EINVAL); 575 } 576 577 return (0); 578} /* tapifioctl */ 579 580 581/* 582 * tapifstart 583 * 584 * queue packets from higher level ready to put out 585 */ 586static void 587tapifstart(ifp) 588 struct ifnet *ifp; 589{ 590 struct tap_softc *tp = ifp->if_softc; 591 int s; 592 593 TAPDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit); 594 595 /* 596 * do not junk pending output if we are in VMnet mode. 597 * XXX: can this do any harm because of queue overflow? 598 */ 599 600 if (((tp->tap_flags & TAP_VMNET) == 0) && 601 ((tp->tap_flags & TAP_READY) != TAP_READY)) { 602 struct mbuf *m = NULL; 603 604 TAPDEBUG("%s%d not ready, tap_flags = 0x%x\n", ifp->if_name, 605 ifp->if_unit, tp->tap_flags); 606 607 s = splimp(); 608 do { 609 IF_DEQUEUE(&ifp->if_snd, m); 610 if (m != NULL) 611 m_freem(m); 612 ifp->if_oerrors ++; 613 } while (m != NULL); 614 splx(s); 615 616 return; 617 } 618 619 s = splimp(); 620 ifp->if_flags |= IFF_OACTIVE; 621 622 if (ifp->if_snd.ifq_len != 0) { 623 if (tp->tap_flags & TAP_RWAIT) { 624 tp->tap_flags &= ~TAP_RWAIT; 625 wakeup((caddr_t)tp); 626 } 627 628 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 629 pgsigio(tp->tap_sigio, SIGIO, 0); 630 631 selwakeup(&tp->tap_rsel); 632 ifp->if_opackets ++; /* obytes are counted in ether_output */ 633 } 634 635 ifp->if_flags &= ~IFF_OACTIVE; 636 splx(s); 637} /* tapifstart */ 638 639 640/* 641 * tapioctl 642 * 643 * the cdevsw interface is now pretty minimal 644 */ 645static int 646tapioctl(dev, cmd, data, flag, td) 647 dev_t dev; 648 u_long cmd; 649 caddr_t data; 650 int flag; 651 struct thread *td; 652{ 653 struct tap_softc *tp = dev->si_drv1; 654 struct ifnet *ifp = &tp->tap_if; 655 struct tapinfo *tapp = NULL; 656 int s; 657 short f; 658 659 switch (cmd) { 660 case TAPSIFINFO: 661 s = splimp(); 662 tapp = (struct tapinfo *)data; 663 ifp->if_mtu = tapp->mtu; 664 ifp->if_type = tapp->type; 665 ifp->if_baudrate = tapp->baudrate; 666 splx(s); 667 break; 668 669 case TAPGIFINFO: 670 tapp = (struct tapinfo *)data; 671 tapp->mtu = ifp->if_mtu; 672 tapp->type = ifp->if_type; 673 tapp->baudrate = ifp->if_baudrate; 674 break; 675 676 case TAPSDEBUG: 677 tapdebug = *(int *)data; 678 break; 679 680 case TAPGDEBUG: 681 *(int *)data = tapdebug; 682 break; 683 684 case FIONBIO: 685 break; 686 687 case FIOASYNC: 688 s = splimp(); 689 if (*(int *)data) 690 tp->tap_flags |= TAP_ASYNC; 691 else 692 tp->tap_flags &= ~TAP_ASYNC; 693 splx(s); 694 break; 695 696 case FIONREAD: 697 s = splimp(); 698 if (ifp->if_snd.ifq_head) { 699 struct mbuf *mb = ifp->if_snd.ifq_head; 700 701 for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 702 *(int *)data += mb->m_len; 703 } else 704 *(int *)data = 0; 705 splx(s); 706 break; 707 708 case FIOSETOWN: 709 return (fsetown(*(int *)data, &tp->tap_sigio)); 710 711 case FIOGETOWN: 712 *(int *)data = fgetown(tp->tap_sigio); 713 return (0); 714 715 /* this is deprecated, FIOSETOWN should be used instead */ 716 case TIOCSPGRP: 717 return (fsetown(-(*(int *)data), &tp->tap_sigio)); 718 719 /* this is deprecated, FIOGETOWN should be used instead */ 720 case TIOCGPGRP: 721 *(int *)data = -fgetown(tp->tap_sigio); 722 return (0); 723 724 /* VMware/VMnet port ioctl's */ 725 726 case SIOCGIFFLAGS: /* get ifnet flags */ 727 bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 728 break; 729 730 case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 731 f = *(short *)data; 732 f &= 0x0fff; 733 f &= ~IFF_CANTCHANGE; 734 f |= IFF_UP; 735 736 s = splimp(); 737 ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 738 splx(s); 739 break; 740 741 case OSIOCGIFADDR: /* get MAC address of the remote side */ 742 case SIOCGIFADDR: 743 bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 744 break; 745 746 case SIOCSIFADDR: /* set MAC address of the remote side */ 747 bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 748 break; 749 750 default: 751 return (ENOTTY); 752 } 753 return (0); 754} /* tapioctl */ 755 756 757/* 758 * tapread 759 * 760 * the cdevsw read interface - reads a packet at a time, or at 761 * least as much of a packet as can be read 762 */ 763static int 764tapread(dev, uio, flag) 765 dev_t dev; 766 struct uio *uio; 767 int flag; 768{ 769 struct tap_softc *tp = dev->si_drv1; 770 struct ifnet *ifp = &tp->tap_if; 771 struct mbuf *m = NULL, *m0 = NULL; 772 int error = 0, len, s; 773 774 TAPDEBUG("%s%d reading, minor = %#x\n", 775 ifp->if_name, ifp->if_unit, minor(dev)); 776 777 if ((tp->tap_flags & TAP_READY) != TAP_READY) { 778 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n", 779 ifp->if_name, ifp->if_unit, minor(dev), tp->tap_flags); 780 781 return (EHOSTDOWN); 782 } 783 784 tp->tap_flags &= ~TAP_RWAIT; 785 786 /* sleep until we get a packet */ 787 do { 788 s = splimp(); 789 IF_DEQUEUE(&ifp->if_snd, m0); 790 splx(s); 791 792 if (m0 == NULL) { 793 if (flag & IO_NDELAY) 794 return (EWOULDBLOCK); 795 796 tp->tap_flags |= TAP_RWAIT; 797 error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0); 798 if (error) 799 return (error); 800 } 801 } while (m0 == NULL); 802 803 /* feed packet to bpf */ 804 if (ifp->if_bpf != NULL) 805 bpf_mtap(ifp, m0); 806 807 /* xfer packet to user space */ 808 while ((m0 != NULL) && (uio->uio_resid > 0) && (error == 0)) { 809 len = min(uio->uio_resid, m0->m_len); 810 if (len == 0) 811 break; 812 813 error = uiomove(mtod(m0, caddr_t), len, uio); 814 MFREE(m0, m); 815 m0 = m; 816 } 817 818 if (m0 != NULL) { 819 TAPDEBUG("%s%d dropping mbuf, minor = %#x\n", ifp->if_name, 820 ifp->if_unit, minor(dev)); 821 m_freem(m0); 822 } 823 824 return (error); 825} /* tapread */ 826 827 828/* 829 * tapwrite 830 * 831 * the cdevsw write interface - an atomic write is a packet - or else! 832 */ 833static int 834tapwrite(dev, uio, flag) 835 dev_t dev; 836 struct uio *uio; 837 int flag; 838{ 839 struct tap_softc *tp = dev->si_drv1; 840 struct ifnet *ifp = &tp->tap_if; 841 struct mbuf *top = NULL, **mp = NULL, *m = NULL; 842 struct ether_header *eh = NULL; 843 int error = 0, tlen, mlen; 844 845 TAPDEBUG("%s%d writting, minor = %#x\n", 846 ifp->if_name, ifp->if_unit, minor(dev)); 847 848 if (uio->uio_resid == 0) 849 return (0); 850 851 if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 852 TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n", 853 ifp->if_name, ifp->if_unit, uio->uio_resid, minor(dev)); 854 855 return (EIO); 856 } 857 tlen = uio->uio_resid; 858 859 /* get a header mbuf */ 860 MGETHDR(m, M_DONTWAIT, MT_DATA); 861 if (m == NULL) 862 return (ENOBUFS); 863 mlen = MHLEN; 864 865 top = 0; 866 mp = ⊤ 867 while ((error == 0) && (uio->uio_resid > 0)) { 868 m->m_len = min(mlen, uio->uio_resid); 869 error = uiomove(mtod(m, caddr_t), m->m_len, uio); 870 *mp = m; 871 mp = &m->m_next; 872 if (uio->uio_resid > 0) { 873 MGET(m, M_DONTWAIT, MT_DATA); 874 if (m == NULL) { 875 error = ENOBUFS; 876 break; 877 } 878 mlen = MLEN; 879 } 880 } 881 if (error) { 882 ifp->if_ierrors ++; 883 if (top) 884 m_freem(top); 885 return (error); 886 } 887 888 top->m_pkthdr.len = tlen; 889 top->m_pkthdr.rcvif = ifp; 890 891 /* 892 * Ethernet bridge and bpf are handled in ether_input 893 * 894 * adjust mbuf and give packet to the ether_input 895 */ 896 897 eh = mtod(top, struct ether_header *); 898 m_adj(top, sizeof(struct ether_header)); 899 ether_input(ifp, eh, top); 900 ifp->if_ipackets ++; /* ibytes are counted in ether_input */ 901 902 return (0); 903} /* tapwrite */ 904 905 906/* 907 * tappoll 908 * 909 * the poll interface, this is only useful on reads 910 * really. the write detect always returns true, write never blocks 911 * anyway, it either accepts the packet or drops it 912 */ 913static int 914tappoll(dev, events, td) 915 dev_t dev; 916 int events; 917 struct thread *td; 918{ 919 struct tap_softc *tp = dev->si_drv1; 920 struct ifnet *ifp = &tp->tap_if; 921 int s, revents = 0; 922 923 TAPDEBUG("%s%d polling, minor = %#x\n", 924 ifp->if_name, ifp->if_unit, minor(dev)); 925 926 s = splimp(); 927 if (events & (POLLIN | POLLRDNORM)) { 928 if (ifp->if_snd.ifq_len > 0) { 929 TAPDEBUG("%s%d have data in queue. len = %d, " \ 930 "minor = %#x\n", ifp->if_name, ifp->if_unit, 931 ifp->if_snd.ifq_len, minor(dev)); 932 933 revents |= (events & (POLLIN | POLLRDNORM)); 934 } else { 935 TAPDEBUG("%s%d waiting for data, minor = %#x\n", 936 ifp->if_name, ifp->if_unit, minor(dev)); 937 938 selrecord(curthread, &tp->tap_rsel); 939 } 940 } 941 942 if (events & (POLLOUT | POLLWRNORM)) 943 revents |= (events & (POLLOUT | POLLWRNORM)); 944 945 splx(s); 946 return (revents); 947} /* tappoll */ 948