if_tap.c revision 111119
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 111119 2003-02-19 05:47:46Z imp $ 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 182 return (0); 183bail2: 184 rman_fini(vmnetunits); 185bail1: 186 rman_fini(tapunits); 187bail: 188 return (error); 189 190 case MOD_UNLOAD: 191 SLIST_FOREACH(tp, &taphead, tap_next) 192 if (tp->tap_unit != NULL) 193 return (EBUSY); 194 195 EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 196 197 error = rman_fini(tapunits); 198 KASSERT((error == 0), ("Could not fini tap units")); 199 error = rman_fini(vmnetunits); 200 KASSERT((error == 0), ("Could not fini vmnet units")); 201 202 while ((tp = SLIST_FIRST(&taphead)) != NULL) { 203 SLIST_REMOVE_HEAD(&taphead, tap_next); 204 205 ifp = &tp->tap_if; 206 207 TAPDEBUG("detaching %s%d\n", ifp->if_name,ifp->if_unit); 208 209 KASSERT(!(tp->tap_flags & TAP_OPEN), 210 ("%s%d flags is out of sync", ifp->if_name, 211 ifp->if_unit)); 212 213 /* XXX makedev check? nah.. not right now :) */ 214 215 s = splimp(); 216 ether_ifdetach(ifp); 217 splx(s); 218 219 free(tp, M_TAP); 220 } 221 222 if (tapbasedev != NOUDEV) 223 destroy_dev(udev2dev(tapbasedev, 0)); 224 225 226 break; 227 228 default: 229 return (EOPNOTSUPP); 230 } 231 232 return (0); 233} /* tapmodevent */ 234 235 236/* 237 * DEVFS handler 238 * 239 * We need to support two kind of devices - tap and vmnet 240 */ 241static void 242tapclone(arg, name, namelen, dev) 243 void *arg; 244 char *name; 245 int namelen; 246 dev_t *dev; 247{ 248 int unit, minor = 0 /* XXX avoid warning */ , error; 249 char *device_name = name; 250 struct resource *r = NULL; 251 252 if (*dev != NODEV) 253 return; 254 255 if (strcmp(device_name, TAP) == 0) { 256 /* get first free tap unit */ 257 r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1, 258 RF_ALLOCATED | RF_ACTIVE, NULL); 259 unit = rman_get_start(r); 260 minor = unit2minor(unit); 261 } 262 else if (strcmp(device_name, VMNET) == 0) { 263 /* get first free vmnet unit */ 264 r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1, 265 RF_ALLOCATED | RF_ACTIVE, NULL); 266 unit = rman_get_start(r); 267 minor = unit2minor(unit) | VMNET_DEV_MASK; 268 } 269 270 if (r != NULL) { /* need cloning */ 271 TAPDEBUG("%s%d is available. minor = %#x\n", 272 device_name, unit, minor); 273 274 error = rman_release_resource(r); 275 KASSERT((error == 0), ("Could not release tap/vmnet unit")); 276 277 /* check if device for the unit has been created */ 278 *dev = makedev(CDEV_MAJOR, minor); 279 if ((*dev)->si_flags & SI_NAMED) { 280 TAPDEBUG("%s%d device exists. minor = %#x\n", 281 device_name, unit, minor); 282 return; /* device has been created */ 283 } 284 } else { /* try to match name/unit, first try tap then vmnet */ 285 device_name = TAP; 286 if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 287 device_name = VMNET; 288 289 if (dev_stdclone(name, NULL, device_name, &unit) != 1) 290 return; 291 292 minor = unit2minor(unit) | VMNET_DEV_MASK; 293 } else 294 minor = unit2minor(unit); 295 } 296 297 TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor); 298 299 *dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d", 300 device_name, unit); 301 302 if (tapbasedev == NOUDEV) 303 tapbasedev = (*dev)->si_udev; 304 else { 305 (*dev)->si_flags |= SI_CHEAPCLONE; 306 dev_depends(udev2dev(tapbasedev, 0), *dev); 307 } 308} /* tapclone */ 309 310 311/* 312 * tapcreate 313 * 314 * to create interface 315 */ 316static void 317tapcreate(dev) 318 dev_t dev; 319{ 320 struct ifnet *ifp = NULL; 321 struct tap_softc *tp = NULL; 322 unsigned short macaddr_hi; 323 int unit, s; 324 char *name = NULL; 325 326 /* allocate driver storage and create device */ 327 MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 328 SLIST_INSERT_HEAD(&taphead, tp, tap_next); 329 330 unit = dev2unit(dev) & TAPMAXUNIT; 331 332 /* select device: tap or vmnet */ 333 if (minor(dev) & VMNET_DEV_MASK) { 334 name = VMNET; 335 tp->tap_flags |= TAP_VMNET; 336 } else 337 name = TAP; 338 339 TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev)); 340 341 if (!(dev->si_flags & SI_NAMED)) 342 dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 343 0600, "%s%d", name, unit); 344 345 /* generate fake MAC address: 00 bd xx xx xx unit_no */ 346 macaddr_hi = htons(0x00bd); 347 bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 348 bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 349 tp->arpcom.ac_enaddr[5] = (u_char)unit; 350 351 /* fill the rest and attach interface */ 352 ifp = &tp->tap_if; 353 ifp->if_softc = tp; 354 ifp->if_unit = unit; 355 ifp->if_name = name; 356 ifp->if_init = tapifinit; 357 ifp->if_start = tapifstart; 358 ifp->if_ioctl = tapifioctl; 359 ifp->if_mtu = ETHERMTU; 360 ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 361 ifp->if_snd.ifq_maxlen = ifqmaxlen; 362 363 dev->si_drv1 = tp; 364 365 s = splimp(); 366 ether_ifattach(ifp, tp->arpcom.ac_enaddr); 367 splx(s); 368 369 tp->tap_flags |= TAP_INITED; 370 371 TAPDEBUG("interface %s%d is created. minor = %#x\n", 372 ifp->if_name, ifp->if_unit, minor(dev)); 373} /* tapcreate */ 374 375 376/* 377 * tapopen 378 * 379 * to open tunnel. must be superuser 380 */ 381static int 382tapopen(dev, flag, mode, td) 383 dev_t dev; 384 int flag; 385 int mode; 386 struct thread *td; 387{ 388 struct tap_softc *tp = NULL; 389 int unit, error; 390 struct resource *r = NULL; 391 392 if ((error = suser(td)) != 0) 393 return (error); 394 395 unit = dev2unit(dev) & TAPMAXUNIT; 396 397 if (minor(dev) & VMNET_DEV_MASK) 398 r = rman_reserve_resource(vmnetunits, unit, unit, 1, 399 RF_ALLOCATED | RF_ACTIVE, NULL); 400 else 401 r = rman_reserve_resource(tapunits, unit, unit, 1, 402 RF_ALLOCATED | RF_ACTIVE, NULL); 403 404 if (r == NULL) 405 return (EBUSY); 406 407 dev->si_flags &= ~SI_CHEAPCLONE; 408 409 tp = dev->si_drv1; 410 if (tp == NULL) { 411 tapcreate(dev); 412 tp = dev->si_drv1; 413 } 414 415 KASSERT(!(tp->tap_flags & TAP_OPEN), 416 ("%s%d flags is out of sync", tp->tap_if.if_name, unit)); 417 418 bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 419 420 tp->tap_unit = r; 421 tp->tap_pid = td->td_proc->p_pid; 422 tp->tap_flags |= TAP_OPEN; 423 424 TAPDEBUG("%s%d is open. minor = %#x\n", 425 tp->tap_if.if_name, unit, minor(dev)); 426 427 return (0); 428} /* tapopen */ 429 430 431/* 432 * tapclose 433 * 434 * close the device - mark i/f down & delete routing info 435 */ 436static int 437tapclose(dev, foo, bar, td) 438 dev_t dev; 439 int foo; 440 int bar; 441 struct thread *td; 442{ 443 int s, error; 444 struct tap_softc *tp = dev->si_drv1; 445 struct ifnet *ifp = &tp->tap_if; 446 447 KASSERT((tp->tap_unit != NULL), 448 ("%s%d is not open", ifp->if_name, ifp->if_unit)); 449 450 /* junk all pending output */ 451 IF_DRAIN(&ifp->if_snd); 452 453 /* 454 * do not bring the interface down, and do not anything with 455 * interface, if we are in VMnet mode. just close the device. 456 */ 457 458 if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 459 s = splimp(); 460 if_down(ifp); 461 if (ifp->if_flags & IFF_RUNNING) { 462 /* find internet addresses and delete routes */ 463 struct ifaddr *ifa = NULL; 464 465 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 466 if (ifa->ifa_addr->sa_family == AF_INET) { 467 rtinit(ifa, (int)RTM_DELETE, 0); 468 469 /* remove address from interface */ 470 bzero(ifa->ifa_addr, 471 sizeof(*(ifa->ifa_addr))); 472 bzero(ifa->ifa_dstaddr, 473 sizeof(*(ifa->ifa_dstaddr))); 474 bzero(ifa->ifa_netmask, 475 sizeof(*(ifa->ifa_netmask))); 476 } 477 } 478 479 ifp->if_flags &= ~IFF_RUNNING; 480 } 481 splx(s); 482 } 483 484 funsetown(&tp->tap_sigio); 485 selwakeup(&tp->tap_rsel); 486 487 tp->tap_flags &= ~TAP_OPEN; 488 tp->tap_pid = 0; 489 error = rman_release_resource(tp->tap_unit); 490 KASSERT((error == 0), 491 ("%s%d could not release unit", ifp->if_name, ifp->if_unit)); 492 tp->tap_unit = NULL; 493 494 TAPDEBUG("%s%d is closed. minor = %#x\n", 495 ifp->if_name, ifp->if_unit, minor(dev)); 496 497 return (0); 498} /* tapclose */ 499 500 501/* 502 * tapifinit 503 * 504 * network interface initialization function 505 */ 506static void 507tapifinit(xtp) 508 void *xtp; 509{ 510 struct tap_softc *tp = (struct tap_softc *)xtp; 511 struct ifnet *ifp = &tp->tap_if; 512 513 TAPDEBUG("initializing %s%d\n", ifp->if_name, ifp->if_unit); 514 515 ifp->if_flags |= IFF_RUNNING; 516 ifp->if_flags &= ~IFF_OACTIVE; 517 518 /* attempt to start output */ 519 tapifstart(ifp); 520} /* tapifinit */ 521 522 523/* 524 * tapifioctl 525 * 526 * Process an ioctl request on network interface 527 */ 528static int 529tapifioctl(ifp, cmd, data) 530 struct ifnet *ifp; 531 u_long cmd; 532 caddr_t data; 533{ 534 struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 535 struct ifstat *ifs = NULL; 536 int s, dummy; 537 538 switch (cmd) { 539 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 540 case SIOCADDMULTI: 541 case SIOCDELMULTI: 542 break; 543 544 case SIOCGIFSTATUS: 545 s = splimp(); 546 ifs = (struct ifstat *)data; 547 dummy = strlen(ifs->ascii); 548 if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 549 snprintf(ifs->ascii + dummy, 550 sizeof(ifs->ascii) - dummy, 551 "\tOpened by PID %d\n", tp->tap_pid); 552 splx(s); 553 break; 554 555 default: 556 s = splimp(); 557 dummy = ether_ioctl(ifp, cmd, data); 558 splx(s); 559 return (dummy); 560 } 561 562 return (0); 563} /* tapifioctl */ 564 565 566/* 567 * tapifstart 568 * 569 * queue packets from higher level ready to put out 570 */ 571static void 572tapifstart(ifp) 573 struct ifnet *ifp; 574{ 575 struct tap_softc *tp = ifp->if_softc; 576 int s; 577 578 TAPDEBUG("%s%d starting\n", ifp->if_name, ifp->if_unit); 579 580 /* 581 * do not junk pending output if we are in VMnet mode. 582 * XXX: can this do any harm because of queue overflow? 583 */ 584 585 if (((tp->tap_flags & TAP_VMNET) == 0) && 586 ((tp->tap_flags & TAP_READY) != TAP_READY)) { 587 struct mbuf *m = NULL; 588 589 TAPDEBUG("%s%d not ready, tap_flags = 0x%x\n", ifp->if_name, 590 ifp->if_unit, tp->tap_flags); 591 592 s = splimp(); 593 do { 594 IF_DEQUEUE(&ifp->if_snd, m); 595 if (m != NULL) 596 m_freem(m); 597 ifp->if_oerrors ++; 598 } while (m != NULL); 599 splx(s); 600 601 return; 602 } 603 604 s = splimp(); 605 ifp->if_flags |= IFF_OACTIVE; 606 607 if (ifp->if_snd.ifq_len != 0) { 608 if (tp->tap_flags & TAP_RWAIT) { 609 tp->tap_flags &= ~TAP_RWAIT; 610 wakeup((caddr_t)tp); 611 } 612 613 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 614 pgsigio(&tp->tap_sigio, SIGIO, 0); 615 616 selwakeup(&tp->tap_rsel); 617 ifp->if_opackets ++; /* obytes are counted in ether_output */ 618 } 619 620 ifp->if_flags &= ~IFF_OACTIVE; 621 splx(s); 622} /* tapifstart */ 623 624 625/* 626 * tapioctl 627 * 628 * the cdevsw interface is now pretty minimal 629 */ 630static int 631tapioctl(dev, cmd, data, flag, td) 632 dev_t dev; 633 u_long cmd; 634 caddr_t data; 635 int flag; 636 struct thread *td; 637{ 638 struct tap_softc *tp = dev->si_drv1; 639 struct ifnet *ifp = &tp->tap_if; 640 struct tapinfo *tapp = NULL; 641 int s; 642 int f; 643 644 switch (cmd) { 645 case TAPSIFINFO: 646 s = splimp(); 647 tapp = (struct tapinfo *)data; 648 ifp->if_mtu = tapp->mtu; 649 ifp->if_type = tapp->type; 650 ifp->if_baudrate = tapp->baudrate; 651 splx(s); 652 break; 653 654 case TAPGIFINFO: 655 tapp = (struct tapinfo *)data; 656 tapp->mtu = ifp->if_mtu; 657 tapp->type = ifp->if_type; 658 tapp->baudrate = ifp->if_baudrate; 659 break; 660 661 case TAPSDEBUG: 662 tapdebug = *(int *)data; 663 break; 664 665 case TAPGDEBUG: 666 *(int *)data = tapdebug; 667 break; 668 669 case FIONBIO: 670 break; 671 672 case FIOASYNC: 673 s = splimp(); 674 if (*(int *)data) 675 tp->tap_flags |= TAP_ASYNC; 676 else 677 tp->tap_flags &= ~TAP_ASYNC; 678 splx(s); 679 break; 680 681 case FIONREAD: 682 s = splimp(); 683 if (ifp->if_snd.ifq_head) { 684 struct mbuf *mb = ifp->if_snd.ifq_head; 685 686 for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 687 *(int *)data += mb->m_len; 688 } else 689 *(int *)data = 0; 690 splx(s); 691 break; 692 693 case FIOSETOWN: 694 return (fsetown(*(int *)data, &tp->tap_sigio)); 695 696 case FIOGETOWN: 697 *(int *)data = fgetown(&tp->tap_sigio); 698 return (0); 699 700 /* this is deprecated, FIOSETOWN should be used instead */ 701 case TIOCSPGRP: 702 return (fsetown(-(*(int *)data), &tp->tap_sigio)); 703 704 /* this is deprecated, FIOGETOWN should be used instead */ 705 case TIOCGPGRP: 706 *(int *)data = -fgetown(&tp->tap_sigio); 707 return (0); 708 709 /* VMware/VMnet port ioctl's */ 710 711 case SIOCGIFFLAGS: /* get ifnet flags */ 712 bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 713 break; 714 715 case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */ 716 f = *(int *)data; 717 f &= 0x0fff; 718 f &= ~IFF_CANTCHANGE; 719 f |= IFF_UP; 720 721 s = splimp(); 722 ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 723 splx(s); 724 break; 725 726 case OSIOCGIFADDR: /* get MAC address of the remote side */ 727 case SIOCGIFADDR: 728 bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 729 break; 730 731 case SIOCSIFADDR: /* set MAC address of the remote side */ 732 bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 733 break; 734 735 default: 736 return (ENOTTY); 737 } 738 return (0); 739} /* tapioctl */ 740 741 742/* 743 * tapread 744 * 745 * the cdevsw read interface - reads a packet at a time, or at 746 * least as much of a packet as can be read 747 */ 748static int 749tapread(dev, uio, flag) 750 dev_t dev; 751 struct uio *uio; 752 int flag; 753{ 754 struct tap_softc *tp = dev->si_drv1; 755 struct ifnet *ifp = &tp->tap_if; 756 struct mbuf *m = NULL; 757 int error = 0, len, s; 758 759 TAPDEBUG("%s%d reading, minor = %#x\n", 760 ifp->if_name, ifp->if_unit, minor(dev)); 761 762 if ((tp->tap_flags & TAP_READY) != TAP_READY) { 763 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n", 764 ifp->if_name, ifp->if_unit, minor(dev), tp->tap_flags); 765 766 return (EHOSTDOWN); 767 } 768 769 tp->tap_flags &= ~TAP_RWAIT; 770 771 /* sleep until we get a packet */ 772 do { 773 s = splimp(); 774 IF_DEQUEUE(&ifp->if_snd, m); 775 splx(s); 776 777 if (m == NULL) { 778 if (flag & IO_NDELAY) 779 return (EWOULDBLOCK); 780 781 tp->tap_flags |= TAP_RWAIT; 782 error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0); 783 if (error) 784 return (error); 785 } 786 } while (m == NULL); 787 788 /* feed packet to bpf */ 789 BPF_MTAP(ifp, m); 790 791 /* xfer packet to user space */ 792 while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) { 793 len = min(uio->uio_resid, m->m_len); 794 if (len == 0) 795 break; 796 797 error = uiomove(mtod(m, caddr_t), len, uio); 798 m = m_free(m); 799 } 800 801 if (m != NULL) { 802 TAPDEBUG("%s%d dropping mbuf, minor = %#x\n", ifp->if_name, 803 ifp->if_unit, minor(dev)); 804 m_freem(m); 805 } 806 807 return (error); 808} /* tapread */ 809 810 811/* 812 * tapwrite 813 * 814 * the cdevsw write interface - an atomic write is a packet - or else! 815 */ 816static int 817tapwrite(dev, uio, flag) 818 dev_t dev; 819 struct uio *uio; 820 int flag; 821{ 822 struct tap_softc *tp = dev->si_drv1; 823 struct ifnet *ifp = &tp->tap_if; 824 struct mbuf *top = NULL, **mp = NULL, *m = NULL; 825 int error = 0, tlen, mlen; 826 827 TAPDEBUG("%s%d writting, minor = %#x\n", 828 ifp->if_name, ifp->if_unit, minor(dev)); 829 830 if (uio->uio_resid == 0) 831 return (0); 832 833 if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 834 TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n", 835 ifp->if_name, ifp->if_unit, uio->uio_resid, minor(dev)); 836 837 return (EIO); 838 } 839 tlen = uio->uio_resid; 840 841 /* get a header mbuf */ 842 MGETHDR(m, M_DONTWAIT, MT_DATA); 843 if (m == NULL) 844 return (ENOBUFS); 845 mlen = MHLEN; 846 847 top = 0; 848 mp = ⊤ 849 while ((error == 0) && (uio->uio_resid > 0)) { 850 m->m_len = min(mlen, uio->uio_resid); 851 error = uiomove(mtod(m, caddr_t), m->m_len, uio); 852 *mp = m; 853 mp = &m->m_next; 854 if (uio->uio_resid > 0) { 855 MGET(m, M_DONTWAIT, MT_DATA); 856 if (m == NULL) { 857 error = ENOBUFS; 858 break; 859 } 860 mlen = MLEN; 861 } 862 } 863 if (error) { 864 ifp->if_ierrors ++; 865 if (top) 866 m_freem(top); 867 return (error); 868 } 869 870 top->m_pkthdr.len = tlen; 871 top->m_pkthdr.rcvif = ifp; 872 873 /* Pass packet up to parent. */ 874 (*ifp->if_input)(ifp, top); 875 ifp->if_ipackets ++; /* ibytes are counted in parent */ 876 877 return (0); 878} /* tapwrite */ 879 880 881/* 882 * tappoll 883 * 884 * the poll interface, this is only useful on reads 885 * really. the write detect always returns true, write never blocks 886 * anyway, it either accepts the packet or drops it 887 */ 888static int 889tappoll(dev, events, td) 890 dev_t dev; 891 int events; 892 struct thread *td; 893{ 894 struct tap_softc *tp = dev->si_drv1; 895 struct ifnet *ifp = &tp->tap_if; 896 int s, revents = 0; 897 898 TAPDEBUG("%s%d polling, minor = %#x\n", 899 ifp->if_name, ifp->if_unit, minor(dev)); 900 901 s = splimp(); 902 if (events & (POLLIN | POLLRDNORM)) { 903 if (ifp->if_snd.ifq_len > 0) { 904 TAPDEBUG("%s%d have data in queue. len = %d, " \ 905 "minor = %#x\n", ifp->if_name, ifp->if_unit, 906 ifp->if_snd.ifq_len, minor(dev)); 907 908 revents |= (events & (POLLIN | POLLRDNORM)); 909 } else { 910 TAPDEBUG("%s%d waiting for data, minor = %#x\n", 911 ifp->if_name, ifp->if_unit, minor(dev)); 912 913 selrecord(td, &tp->tap_rsel); 914 } 915 } 916 917 if (events & (POLLOUT | POLLWRNORM)) 918 revents |= (events & (POLLOUT | POLLWRNORM)); 919 920 splx(s); 921 return (revents); 922} /* tappoll */ 923