if_tap.c revision 71602
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 71602 2001-01-24 20:59:34Z phk $ 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 58#include <net/bpf.h> 59#include <net/ethernet.h> 60#include <net/if.h> 61#include <net/if_arp.h> 62#include <net/route.h> 63 64#include <netinet/in.h> 65 66#include <net/if_tapvar.h> 67#include <net/if_tap.h> 68 69 70#define CDEV_NAME "tap" 71#define CDEV_MAJOR 149 72#define TAPDEBUG if (tapdebug) printf 73 74#define TAP "tap" 75#define VMNET "vmnet" 76#define VMNET_DEV_MASK 0x00010000 77 78/* module */ 79static int tapmodevent __P((module_t, int, void *)); 80 81/* device */ 82static void tapclone __P((void *, char *, int, dev_t *)); 83static void tapcreate __P((dev_t)); 84 85/* network interface */ 86static void tapifstart __P((struct ifnet *)); 87static int tapifioctl __P((struct ifnet *, u_long, caddr_t)); 88static void tapifinit __P((void *)); 89 90/* character device */ 91static d_open_t tapopen; 92static d_close_t tapclose; 93static d_read_t tapread; 94static d_write_t tapwrite; 95static d_ioctl_t tapioctl; 96static d_poll_t tappoll; 97 98static struct cdevsw tap_cdevsw = { 99 /* open */ tapopen, 100 /* close */ tapclose, 101 /* read */ tapread, 102 /* write */ tapwrite, 103 /* ioctl */ tapioctl, 104 /* poll */ tappoll, 105 /* mmap */ nommap, 106 /* startegy */ nostrategy, 107 /* dev name */ CDEV_NAME, 108 /* dev major */ CDEV_MAJOR, 109 /* dump */ nodump, 110 /* psize */ nopsize, 111 /* flags */ 0, 112 /* bmaj */ -1 113}; 114 115static int taprefcnt = 0; /* module ref. counter */ 116static int taplastunit = -1; /* max. open unit number */ 117static int tapdebug = 0; /* debug flag */ 118 119MALLOC_DECLARE(M_TAP); 120MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 121SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 122DEV_MODULE(if_tap, tapmodevent, NULL); 123 124/* 125 * tapmodevent 126 * 127 * module event handler 128 */ 129static int 130tapmodevent(mod, type, data) 131 module_t mod; 132 int type; 133 void *data; 134{ 135 static int attached = 0; 136 static eventhandler_tag eh_tag = NULL; 137 138 switch (type) { 139 case MOD_LOAD: 140 if (attached) 141 return (EEXIST); 142 143 eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000); 144 cdevsw_add(&tap_cdevsw); 145 attached = 1; 146 break; 147 148 case MOD_UNLOAD: { 149 int unit; 150 151 if (taprefcnt > 0) 152 return (EBUSY); 153 154 EVENTHANDLER_DEREGISTER(dev_clone, eh_tag); 155 cdevsw_remove(&tap_cdevsw); 156 157 unit = 0; 158 while (unit <= taplastunit) { 159 int s; 160 struct ifnet *ifp = NULL; 161 162 s = splimp(); 163 TAILQ_FOREACH(ifp, &ifnet, if_link) 164 if ((strcmp(ifp->if_name, TAP) == 0) || 165 (strcmp(ifp->if_name, VMNET) == 0)) 166 if (ifp->if_unit == unit) 167 break; 168 splx(s); 169 170 if (ifp != NULL) { 171 struct tap_softc *tp = ifp->if_softc; 172 173 TAPDEBUG("detaching %s%d. minor = %#x, " \ 174 "taplastunit = %d\n", 175 ifp->if_name, unit, minor(tp->tap_dev), 176 taplastunit); 177 178 s = splimp(); 179 ether_ifdetach(ifp, 1); 180 splx(s); 181 destroy_dev(tp->tap_dev); 182 FREE(tp, M_TAP); 183 } 184 else 185 unit ++; 186 } 187 188 attached = 0; 189 } break; 190 191 default: 192 return (EOPNOTSUPP); 193 } 194 195 return (0); 196} /* tapmodevent */ 197 198 199/* 200 * DEVFS handler 201 * 202 * We need to support two kind of devices - tap and vmnet 203 */ 204static void 205tapclone(arg, name, namelen, dev) 206 void *arg; 207 char *name; 208 int namelen; 209 dev_t *dev; 210{ 211 int unit, minor; 212 char *device_name = NULL; 213 214 if (*dev != NODEV) 215 return; 216 217 device_name = TAP; 218 if (dev_stdclone(name, NULL, device_name, &unit) != 1) { 219 device_name = VMNET; 220 221 if (dev_stdclone(name, NULL, device_name, &unit) != 1) 222 return; 223 224 minor = (unit | VMNET_DEV_MASK); 225 } 226 else 227 minor = unit; 228 229 *dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d", 230 device_name, unit); 231} /* tapclone */ 232 233 234/* 235 * tapcreate 236 * 237 * to create interface 238 */ 239static void 240tapcreate(dev) 241 dev_t dev; 242{ 243 struct ifnet *ifp = NULL; 244 struct tap_softc *tp = NULL; 245 unsigned short macaddr_hi; 246 int unit, s; 247 char *name = NULL; 248 249 /* allocate driver storage and create device */ 250 MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO); 251 252 /* select device: tap or vmnet */ 253 if (minor(dev) & VMNET_DEV_MASK) { 254 name = VMNET; 255 unit = dev2unit(dev) & 0xff; 256 tp->tap_flags |= TAP_VMNET; 257 } 258 else { 259 name = TAP; 260 unit = dev2unit(dev); 261 } 262 263 tp->tap_dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 264 0600, "%s%d", name, unit); 265 tp->tap_dev->si_drv1 = dev->si_drv1 = tp; 266 267 /* generate fake MAC address: 00 bd xx xx xx unit_no */ 268 macaddr_hi = htons(0x00bd); 269 bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 270 bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 271 tp->arpcom.ac_enaddr[5] = (u_char)unit; 272 273 /* fill the rest and attach interface */ 274 ifp = &tp->tap_if; 275 ifp->if_softc = tp; 276 277 ifp->if_unit = unit; 278 if (unit > taplastunit) 279 taplastunit = unit; 280 281 ifp->if_name = name; 282 ifp->if_init = tapifinit; 283 ifp->if_output = ether_output; 284 ifp->if_start = tapifstart; 285 ifp->if_ioctl = tapifioctl; 286 ifp->if_mtu = ETHERMTU; 287 ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 288 ifp->if_snd.ifq_maxlen = ifqmaxlen; 289 290 s = splimp(); 291 ether_ifattach(ifp, 1); 292 splx(s); 293 294 tp->tap_flags |= TAP_INITED; 295 296 TAPDEBUG("interface %s%d created. minor = %#x\n", 297 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 298} /* tapcreate */ 299 300 301/* 302 * tapopen 303 * 304 * to open tunnel. must be superuser 305 */ 306static int 307tapopen(dev, flag, mode, p) 308 dev_t dev; 309 int flag; 310 int mode; 311 struct proc *p; 312{ 313 struct tap_softc *tp = NULL; 314 int error; 315 316 if ((error = suser(p)) != 0) 317 return (error); 318 319 tp = dev->si_drv1; 320 if (tp == NULL) { 321 tapcreate(dev); 322 tp = dev->si_drv1; 323 } 324 325 if (tp->tap_flags & TAP_OPEN) 326 return (EBUSY); 327 328 bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr)); 329 330 tp->tap_pid = p->p_pid; 331 tp->tap_flags |= TAP_OPEN; 332 taprefcnt ++; 333 334 TAPDEBUG("%s%d is open. minor = %#x, refcnt = %d, taplastunit = %d\n", 335 tp->tap_if.if_name, tp->tap_if.if_unit, 336 minor(tp->tap_dev), taprefcnt, taplastunit); 337 338 return (0); 339} /* tapopen */ 340 341 342/* 343 * tapclose 344 * 345 * close the device - mark i/f down & delete routing info 346 */ 347static int 348tapclose(dev, foo, bar, p) 349 dev_t dev; 350 int foo; 351 int bar; 352 struct proc *p; 353{ 354 int s; 355 struct tap_softc *tp = dev->si_drv1; 356 struct ifnet *ifp = &tp->tap_if; 357 struct mbuf *m = NULL; 358 359 /* junk all pending output */ 360 361 s = splimp(); 362 do { 363 IF_DEQUEUE(&ifp->if_snd, m); 364 if (m != NULL) 365 m_freem(m); 366 } while (m != NULL); 367 splx(s); 368 369 /* 370 * do not bring the interface down, and do not anything with 371 * interface, if we are in VMnet mode. just close the device. 372 */ 373 374 if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 375 s = splimp(); 376 if_down(ifp); 377 if (ifp->if_flags & IFF_RUNNING) { 378 /* find internet addresses and delete routes */ 379 struct ifaddr *ifa = NULL; 380 381 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 382 if (ifa->ifa_addr->sa_family == AF_INET) { 383 rtinit(ifa, (int)RTM_DELETE, 0); 384 385 /* remove address from interface */ 386 bzero(ifa->ifa_addr, 387 sizeof(*(ifa->ifa_addr))); 388 bzero(ifa->ifa_dstaddr, 389 sizeof(*(ifa->ifa_dstaddr))); 390 bzero(ifa->ifa_netmask, 391 sizeof(*(ifa->ifa_netmask))); 392 } 393 } 394 395 ifp->if_flags &= ~IFF_RUNNING; 396 } 397 splx(s); 398 } 399 400 funsetown(tp->tap_sigio); 401 selwakeup(&tp->tap_rsel); 402 403 tp->tap_flags &= ~TAP_OPEN; 404 tp->tap_pid = 0; 405 406 taprefcnt --; 407 if (taprefcnt < 0) { 408 taprefcnt = 0; 409 printf("%s%d minor = %#x, refcnt = %d is out of sync. " \ 410 "set refcnt to 0\n", ifp->if_name, ifp->if_unit, 411 minor(tp->tap_dev), taprefcnt); 412 } 413 414 TAPDEBUG("%s%d is closed. minor = %#x, refcnt = %d, taplastunit = %d\n", 415 ifp->if_name, ifp->if_unit, minor(tp->tap_dev), 416 taprefcnt, taplastunit); 417 418 return (0); 419} /* tapclose */ 420 421 422/* 423 * tapifinit 424 * 425 * network interface initialization function 426 */ 427static void 428tapifinit(xtp) 429 void *xtp; 430{ 431 struct tap_softc *tp = (struct tap_softc *)xtp; 432 struct ifnet *ifp = &tp->tap_if; 433 434 TAPDEBUG("initializing %s%d, minor = %#x\n", 435 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 436 437 ifp->if_flags |= IFF_RUNNING; 438 ifp->if_flags &= ~IFF_OACTIVE; 439 440 /* attempt to start output */ 441 tapifstart(ifp); 442} /* tapifinit */ 443 444 445/* 446 * tapifioctl 447 * 448 * Process an ioctl request on network interface 449 */ 450int 451tapifioctl(ifp, cmd, data) 452 struct ifnet *ifp; 453 u_long cmd; 454 caddr_t data; 455{ 456 struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 457 struct ifstat *ifs = NULL; 458 int s, dummy; 459 460 switch (cmd) { 461 case SIOCSIFADDR: 462 case SIOCGIFADDR: 463 case SIOCSIFMTU: 464 s = splimp(); 465 dummy = ether_ioctl(ifp, cmd, data); 466 splx(s); 467 return (dummy); 468 469 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 470 case SIOCADDMULTI: 471 case SIOCDELMULTI: 472 break; 473 474 case SIOCGIFSTATUS: 475 s = splimp(); 476 ifs = (struct ifstat *)data; 477 dummy = strlen(ifs->ascii); 478 if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 479 snprintf(ifs->ascii + dummy, 480 sizeof(ifs->ascii) - dummy, 481 "\tOpened by PID %d\n", tp->tap_pid); 482 splx(s); 483 break; 484 485 default: 486 return (EINVAL); 487 } 488 489 return (0); 490} /* tapifioctl */ 491 492 493/* 494 * tapifstart 495 * 496 * queue packets from higher level ready to put out 497 */ 498static void 499tapifstart(ifp) 500 struct ifnet *ifp; 501{ 502 struct tap_softc *tp = ifp->if_softc; 503 int s; 504 505 TAPDEBUG("%s%d starting, minor = %#x\n", 506 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 507 508 /* 509 * do not junk pending output if we are in VMnet mode. 510 * XXX: can this do any harm because of queue overflow? 511 */ 512 513 if (((tp->tap_flags & TAP_VMNET) == 0) && 514 ((tp->tap_flags & TAP_READY) != TAP_READY)) { 515 struct mbuf *m = NULL; 516 517 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n", 518 ifp->if_name, ifp->if_unit, 519 minor(tp->tap_dev), tp->tap_flags); 520 521 s = splimp(); 522 do { 523 IF_DEQUEUE(&ifp->if_snd, m); 524 if (m != NULL) 525 m_freem(m); 526 ifp->if_oerrors ++; 527 } while (m != NULL); 528 splx(s); 529 530 return; 531 } 532 533 s = splimp(); 534 ifp->if_flags |= IFF_OACTIVE; 535 536 if (ifp->if_snd.ifq_len != 0) { 537 if (tp->tap_flags & TAP_RWAIT) { 538 tp->tap_flags &= ~TAP_RWAIT; 539 wakeup((caddr_t)tp); 540 } 541 542 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 543 pgsigio(tp->tap_sigio, SIGIO, 0); 544 545 selwakeup(&tp->tap_rsel); 546 ifp->if_opackets ++; /* obytes are counted in ether_output */ 547 } 548 549 ifp->if_flags &= ~IFF_OACTIVE; 550 splx(s); 551} /* tapifstart */ 552 553 554/* 555 * tapioctl 556 * 557 * the cdevsw interface is now pretty minimal 558 */ 559static int 560tapioctl(dev, cmd, data, flag, p) 561 dev_t dev; 562 u_long cmd; 563 caddr_t data; 564 int flag; 565 struct proc *p; 566{ 567 struct tap_softc *tp = dev->si_drv1; 568 struct ifnet *ifp = &tp->tap_if; 569 struct tapinfo *tapp = NULL; 570 int s; 571 572 switch (cmd) { 573 case TAPSIFINFO: 574 s = splimp(); 575 tapp = (struct tapinfo *)data; 576 ifp->if_mtu = tapp->mtu; 577 ifp->if_type = tapp->type; 578 ifp->if_baudrate = tapp->baudrate; 579 splx(s); 580 break; 581 582 case TAPGIFINFO: 583 tapp = (struct tapinfo *)data; 584 tapp->mtu = ifp->if_mtu; 585 tapp->type = ifp->if_type; 586 tapp->baudrate = ifp->if_baudrate; 587 break; 588 589 case TAPSDEBUG: 590 tapdebug = *(int *)data; 591 break; 592 593 case TAPGDEBUG: 594 *(int *)data = tapdebug; 595 break; 596 597 case FIONBIO: 598 break; 599 600 case FIOASYNC: 601 s = splimp(); 602 if (*(int *)data) 603 tp->tap_flags |= TAP_ASYNC; 604 else 605 tp->tap_flags &= ~TAP_ASYNC; 606 splx(s); 607 break; 608 609 case FIONREAD: 610 s = splimp(); 611 if (ifp->if_snd.ifq_head) { 612 struct mbuf *mb = ifp->if_snd.ifq_head; 613 614 for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 615 *(int *)data += mb->m_len; 616 } 617 else 618 *(int *)data = 0; 619 splx(s); 620 break; 621 622 case FIOSETOWN: 623 return (fsetown(*(int *)data, &tp->tap_sigio)); 624 625 case FIOGETOWN: 626 *(int *)data = fgetown(tp->tap_sigio); 627 return (0); 628 629 /* this is deprecated, FIOSETOWN should be used instead */ 630 case TIOCSPGRP: 631 return (fsetown(-(*(int *)data), &tp->tap_sigio)); 632 633 /* this is deprecated, FIOGETOWN should be used instead */ 634 case TIOCGPGRP: 635 *(int *)data = -fgetown(tp->tap_sigio); 636 return (0); 637 638 /* VMware/VMnet port ioctl's */ 639 640 case SIOCGIFFLAGS: /* get ifnet flags */ 641 bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 642 break; 643 644 case VMIO_SIOCSIFFLAGS: { /* VMware/VMnet SIOCSIFFLAGS */ 645 short f = *(short *)data; 646 647 f &= 0x0fff; 648 f &= ~IFF_CANTCHANGE; 649 f |= IFF_UP; 650 651 s = splimp(); 652 ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 653 splx(s); 654 } break; 655 656 case OSIOCGIFADDR: /* get MAC address of the remote side */ 657 case SIOCGIFADDR: 658 bcopy(tp->ether_addr, data, sizeof(tp->ether_addr)); 659 break; 660 661 case SIOCSIFADDR: /* set MAC address of the remote side */ 662 bcopy(data, tp->ether_addr, sizeof(tp->ether_addr)); 663 break; 664 665 default: 666 return (ENOTTY); 667 } 668 return (0); 669} /* tapioctl */ 670 671 672/* 673 * tapread 674 * 675 * the cdevsw read interface - reads a packet at a time, or at 676 * least as much of a packet as can be read 677 */ 678static int 679tapread(dev, uio, flag) 680 dev_t dev; 681 struct uio *uio; 682 int flag; 683{ 684 struct tap_softc *tp = dev->si_drv1; 685 struct ifnet *ifp = &tp->tap_if; 686 struct mbuf *m = NULL, *m0 = NULL; 687 int error = 0, len, s; 688 689 TAPDEBUG("%s%d reading, minor = %#x\n", 690 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 691 692 if ((tp->tap_flags & TAP_READY) != TAP_READY) { 693 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n", 694 ifp->if_name, ifp->if_unit, 695 minor(tp->tap_dev), tp->tap_flags); 696 697 return (EHOSTDOWN); 698 } 699 700 tp->tap_flags &= ~TAP_RWAIT; 701 702 /* sleep until we get a packet */ 703 do { 704 s = splimp(); 705 IF_DEQUEUE(&ifp->if_snd, m0); 706 splx(s); 707 708 if (m0 == NULL) { 709 if (flag & IO_NDELAY) 710 return (EWOULDBLOCK); 711 712 tp->tap_flags |= TAP_RWAIT; 713 error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0); 714 if (error) 715 return (error); 716 } 717 } while (m0 == NULL); 718 719 /* feed packet to bpf */ 720 if (ifp->if_bpf != NULL) 721 bpf_mtap(ifp, m0); 722 723 /* xfer packet to user space */ 724 while ((m0 != NULL) && (uio->uio_resid > 0) && (error == 0)) { 725 len = min(uio->uio_resid, m0->m_len); 726 if (len == 0) 727 break; 728 729 error = uiomove(mtod(m0, caddr_t), len, uio); 730 MFREE(m0, m); 731 m0 = m; 732 } 733 734 if (m0 != NULL) { 735 TAPDEBUG("%s%d dropping mbuf, minor = %#x\n", 736 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 737 m_freem(m0); 738 } 739 740 return (error); 741} /* tapread */ 742 743 744/* 745 * tapwrite 746 * 747 * the cdevsw write interface - an atomic write is a packet - or else! 748 */ 749static int 750tapwrite(dev, uio, flag) 751 dev_t dev; 752 struct uio *uio; 753 int flag; 754{ 755 struct tap_softc *tp = dev->si_drv1; 756 struct ifnet *ifp = &tp->tap_if; 757 struct mbuf *top = NULL, **mp = NULL, *m = NULL; 758 struct ether_header *eh = NULL; 759 int error = 0, tlen, mlen; 760 761 TAPDEBUG("%s%d writting, minor = %#x\n", 762 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 763 764 if (uio->uio_resid == 0) 765 return (0); 766 767 if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 768 TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n", 769 ifp->if_name, ifp->if_unit, 770 uio->uio_resid, minor(tp->tap_dev)); 771 772 return (EIO); 773 } 774 tlen = uio->uio_resid; 775 776 /* get a header mbuf */ 777 MGETHDR(m, M_DONTWAIT, MT_DATA); 778 if (m == NULL) 779 return (ENOBUFS); 780 mlen = MHLEN; 781 782 top = 0; 783 mp = ⊤ 784 while ((error == 0) && (uio->uio_resid > 0)) { 785 m->m_len = min(mlen, uio->uio_resid); 786 error = uiomove(mtod(m, caddr_t), m->m_len, uio); 787 *mp = m; 788 mp = &m->m_next; 789 if (uio->uio_resid > 0) { 790 MGET(m, M_DONTWAIT, MT_DATA); 791 if (m == NULL) { 792 error = ENOBUFS; 793 break; 794 } 795 mlen = MLEN; 796 } 797 } 798 if (error) { 799 ifp->if_ierrors ++; 800 if (top) 801 m_freem(top); 802 return (error); 803 } 804 805 top->m_pkthdr.len = tlen; 806 top->m_pkthdr.rcvif = ifp; 807 808 /* 809 * Ethernet bridge and bpf are handled in ether_input 810 * 811 * adjust mbuf and give packet to the ether_input 812 */ 813 814 eh = mtod(top, struct ether_header *); 815 m_adj(top, sizeof(struct ether_header)); 816 ether_input(ifp, eh, top); 817 ifp->if_ipackets ++; /* ibytes are counted in ether_input */ 818 819 return (0); 820} /* tapwrite */ 821 822 823/* 824 * tappoll 825 * 826 * the poll interface, this is only useful on reads 827 * really. the write detect always returns true, write never blocks 828 * anyway, it either accepts the packet or drops it 829 */ 830static int 831tappoll(dev, events, p) 832 dev_t dev; 833 int events; 834 struct proc *p; 835{ 836 struct tap_softc *tp = dev->si_drv1; 837 struct ifnet *ifp = &tp->tap_if; 838 int s, revents = 0; 839 840 TAPDEBUG("%s%d polling, minor = %#x\n", 841 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 842 843 s = splimp(); 844 if (events & (POLLIN | POLLRDNORM)) { 845 if (ifp->if_snd.ifq_len > 0) { 846 TAPDEBUG("%s%d have data in queue. len = %d, " \ 847 "minor = %#x\n", ifp->if_name, ifp->if_unit, 848 ifp->if_snd.ifq_len, minor(tp->tap_dev)); 849 850 revents |= (events & (POLLIN | POLLRDNORM)); 851 } 852 else { 853 TAPDEBUG("%s%d waiting for data, minor = %#x\n", 854 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 855 856 selrecord(p, &tp->tap_rsel); 857 } 858 } 859 860 if (events & (POLLOUT | POLLWRNORM)) 861 revents |= (events & (POLLOUT | POLLWRNORM)); 862 863 splx(s); 864 return (revents); 865} /* tappoll */ 866