if_tap.c revision 102052
1/* 2 * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * BASED ON: 27 * ------------------------------------------------------------------------- 28 * 29 * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 30 * Nottingham University 1987. 31 */ 32 33/* 34 * $FreeBSD: head/sys/net/if_tap.c 102052 2002-08-18 07:05:00Z sobomax $ 35 * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 36 */ 37 38#include "opt_inet.h" 39 40#include <sys/param.h> 41#include <sys/conf.h> 42#include <sys/filedesc.h> 43#include <sys/filio.h> 44#include <sys/kernel.h> 45#include <sys/malloc.h> 46#include <sys/mbuf.h> 47#include <sys/poll.h> 48#include <sys/proc.h> 49#include <sys/signalvar.h> 50#include <sys/socket.h> 51#include <sys/sockio.h> 52#include <sys/sysctl.h> 53#include <sys/systm.h> 54#include <sys/ttycom.h> 55#include <sys/uio.h> 56#include <sys/vnode.h> 57#include <machine/bus.h> /* XXX: Shouldn't really be required! */ 58#include <sys/rman.h> 59#include <sys/queue.h> 60 61#include <net/bpf.h> 62#include <net/ethernet.h> 63#include <net/if.h> 64#include <net/if_arp.h> 65#include <net/route.h> 66 67#include <netinet/in.h> 68 69#include <net/if_tapvar.h> 70#include <net/if_tap.h> 71 72 73#define CDEV_NAME "tap" 74#define CDEV_MAJOR 149 75#define TAPDEBUG if (tapdebug) printf 76 77#define TAP "tap" 78#define VMNET "vmnet" 79#define TAPMAXUNIT 0x7fff 80#define VMNET_DEV_MASK 0x00800000 81 /* 0x007f00ff */ 82 83/* module */ 84static int tapmodevent(module_t, int, void *); 85 86/* device */ 87static void tapclone(void *, char *, int, dev_t *); 88static void tapcreate(dev_t); 89 90/* network interface */ 91static void tapifstart(struct ifnet *); 92static int tapifioctl(struct ifnet *, u_long, caddr_t); 93static void tapifinit(void *); 94 95/* character device */ 96static d_open_t tapopen; 97static d_close_t tapclose; 98static 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)) != 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 int 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 = *(int *)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; 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, m); 790 splx(s); 791 792 if (m == 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 (m == NULL); 802 803 /* feed packet to bpf */ 804 if (ifp->if_bpf != NULL) 805 bpf_mtap(ifp, m); 806 807 /* xfer packet to user space */ 808 while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 809 len = min(uio->uio_resid, m->m_len); 810 if (len == 0) 811 break; 812 813 error = uiomove(mtod(m, caddr_t), len, uio); 814 m = m_free(m); 815 } 816 817 if (m != NULL) { 818 TAPDEBUG("%s%d dropping mbuf, minor = %#x\n", ifp->if_name, 819 ifp->if_unit, minor(dev)); 820 m_freem(m); 821 } 822 823 return (error); 824} /* tapread */ 825 826 827/* 828 * tapwrite 829 * 830 * the cdevsw write interface - an atomic write is a packet - or else! 831 */ 832static int 833tapwrite(dev, uio, flag) 834 dev_t dev; 835 struct uio *uio; 836 int flag; 837{ 838 struct tap_softc *tp = dev->si_drv1; 839 struct ifnet *ifp = &tp->tap_if; 840 struct mbuf *top = NULL, **mp = NULL, *m = NULL; 841 struct ether_header *eh = NULL; 842 int error = 0, tlen, mlen; 843 844 TAPDEBUG("%s%d writting, minor = %#x\n", 845 ifp->if_name, ifp->if_unit, minor(dev)); 846 847 if (uio->uio_resid == 0) 848 return (0); 849 850 if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 851 TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n", 852 ifp->if_name, ifp->if_unit, uio->uio_resid, minor(dev)); 853 854 return (EIO); 855 } 856 tlen = uio->uio_resid; 857 858 /* get a header mbuf */ 859 MGETHDR(m, M_DONTWAIT, MT_DATA); 860 if (m == NULL) 861 return (ENOBUFS); 862 mlen = MHLEN; 863 864 top = 0; 865 mp = ⊤ 866 while ((error == 0) && (uio->uio_resid > 0)) { 867 m->m_len = min(mlen, uio->uio_resid); 868 error = uiomove(mtod(m, caddr_t), m->m_len, uio); 869 *mp = m; 870 mp = &m->m_next; 871 if (uio->uio_resid > 0) { 872 MGET(m, M_DONTWAIT, MT_DATA); 873 if (m == NULL) { 874 error = ENOBUFS; 875 break; 876 } 877 mlen = MLEN; 878 } 879 } 880 if (error) { 881 ifp->if_ierrors ++; 882 if (top) 883 m_freem(top); 884 return (error); 885 } 886 887 top->m_pkthdr.len = tlen; 888 top->m_pkthdr.rcvif = ifp; 889 890 /* 891 * Ethernet bridge and bpf are handled in ether_input 892 * 893 * adjust mbuf and give packet to the ether_input 894 */ 895 896 eh = mtod(top, struct ether_header *); 897 m_adj(top, sizeof(struct ether_header)); 898 ether_input(ifp, eh, top); 899 ifp->if_ipackets ++; /* ibytes are counted in ether_input */ 900 901 return (0); 902} /* tapwrite */ 903 904 905/* 906 * tappoll 907 * 908 * the poll interface, this is only useful on reads 909 * really. the write detect always returns true, write never blocks 910 * anyway, it either accepts the packet or drops it 911 */ 912static int 913tappoll(dev, events, td) 914 dev_t dev; 915 int events; 916 struct thread *td; 917{ 918 struct tap_softc *tp = dev->si_drv1; 919 struct ifnet *ifp = &tp->tap_if; 920 int s, revents = 0; 921 922 TAPDEBUG("%s%d polling, minor = %#x\n", 923 ifp->if_name, ifp->if_unit, minor(dev)); 924 925 s = splimp(); 926 if (events & (POLLIN | POLLRDNORM)) { 927 if (ifp->if_snd.ifq_len > 0) { 928 TAPDEBUG("%s%d have data in queue. len = %d, " \ 929 "minor = %#x\n", ifp->if_name, ifp->if_unit, 930 ifp->if_snd.ifq_len, minor(dev)); 931 932 revents |= (events & (POLLIN | POLLRDNORM)); 933 } else { 934 TAPDEBUG("%s%d waiting for data, minor = %#x\n", 935 ifp->if_name, ifp->if_unit, minor(dev)); 936 937 selrecord(td, &tp->tap_rsel); 938 } 939 } 940 941 if (events & (POLLOUT | POLLWRNORM)) 942 revents |= (events & (POLLOUT | POLLWRNORM)); 943 944 splx(s); 945 return (revents); 946} /* tappoll */ 947