if_tap.c revision 63803
12966Swollman/* 241035Sdima * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com> 31590Srgrimes * All rights reserved. 44699Sjkh * 534706Sbde * Redistribution and use in source and binary forms, with or without 65766Sbde * modification, are permitted provided that the following conditions 71930Swollman * are met: 81930Swollman * 1. Redistributions of source code must retain the above copyright 938653Sgpalmer * notice, this list of conditions and the following disclaimer. 1038653Sgpalmer * 2. Redistributions in binary form must reproduce the above copyright 1138653Sgpalmer * notice, this list of conditions and the following disclaimer in the 1238653Sgpalmer * documentation and/or other materials provided with the distribution. 1338653Sgpalmer * 1438653Sgpalmer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1538653Sgpalmer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1638653Sgpalmer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1738653Sgpalmer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1838653Sgpalmer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1938653Sgpalmer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2039614Sbde * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2138653Sgpalmer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2238653Sgpalmer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2338653Sgpalmer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2438653Sgpalmer * SUCH DAMAGE. 2538653Sgpalmer * 2638653Sgpalmer * BASED ON: 2738653Sgpalmer * ------------------------------------------------------------------------- 2838653Sgpalmer * 2938653Sgpalmer * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk> 3038653Sgpalmer * Nottingham University 1987. 3138653Sgpalmer */ 3238653Sgpalmer 3338653Sgpalmer/* 3438653Sgpalmer * $FreeBSD: head/sys/net/if_tap.c 63803 2000-07-24 15:32:26Z nsayer $ 3541003Sgpalmer * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $ 3638653Sgpalmer */ 3741003Sgpalmer 3838653Sgpalmer#include "opt_inet.h" 3938653Sgpalmer 4040826Sjoerg#include <sys/param.h> 4138653Sgpalmer#include <sys/conf.h> 4238653Sgpalmer#include <sys/filedesc.h> 4338653Sgpalmer#include <sys/filio.h> 4438653Sgpalmer#include <sys/kernel.h> 4538653Sgpalmer#include <sys/malloc.h> 4638653Sgpalmer#include <sys/mbuf.h> 4738653Sgpalmer#include <sys/poll.h> 4838653Sgpalmer#include <sys/proc.h> 4938653Sgpalmer#include <sys/signalvar.h> 5038653Sgpalmer#include <sys/socket.h> 5138653Sgpalmer#include <sys/sockio.h> 5238653Sgpalmer#include <sys/sysctl.h> 5338653Sgpalmer#include <sys/systm.h> 5438653Sgpalmer#include <sys/ttycom.h> 5538653Sgpalmer#include <sys/uio.h> 5638653Sgpalmer#include <sys/vnode.h> 5738653Sgpalmer 5840334Speter#include <net/bpf.h> 5938653Sgpalmer#include <net/ethernet.h> 6038653Sgpalmer#include <net/if.h> 6138653Sgpalmer#include <net/if_arp.h> 6238653Sgpalmer#include <net/route.h> 6341003Sgpalmer 6438653Sgpalmer#include <netinet/in.h> 6538653Sgpalmer 6638653Sgpalmer#include <net/if_tapvar.h> 6738653Sgpalmer#include <net/if_tap.h> 6838653Sgpalmer 6938653Sgpalmer 7038653Sgpalmer#define CDEV_NAME "tap" 7138653Sgpalmer#define CDEV_MAJOR 149 7238653Sgpalmer#define TAPDEBUG if (tapdebug) printf 7338653Sgpalmer 7438653Sgpalmer#define TAP "tap" 7538653Sgpalmer#define VMNET "vmnet" 7638653Sgpalmer#define VMNET_DEV_MASK 0x00010000 7738653Sgpalmer 7838653Sgpalmer/* module */ 7938653Sgpalmerstatic int tapmodevent __P((module_t, int, void *)); 8038653Sgpalmer 8138653Sgpalmer/* device */ 8239614Sbdestatic void tapcreate __P((dev_t)); 8338653Sgpalmer 8438653Sgpalmer/* network interface */ 8538653Sgpalmerstatic void tapifstart __P((struct ifnet *)); 8638653Sgpalmerstatic int tapifioctl __P((struct ifnet *, u_long, caddr_t)); 8738653Sgpalmerstatic void tapifinit __P((void *)); 8838653Sgpalmer 8938653Sgpalmer/* character device */ 9038653Sgpalmerstatic d_open_t tapopen; 9138653Sgpalmerstatic d_close_t tapclose; 9238653Sgpalmerstatic d_read_t tapread; 9338653Sgpalmerstatic d_write_t tapwrite; 9438653Sgpalmerstatic d_ioctl_t tapioctl; 9538653Sgpalmerstatic d_poll_t tappoll; 9638653Sgpalmer 9738653Sgpalmerstatic struct cdevsw tap_cdevsw = { 9838653Sgpalmer /* open */ tapopen, 9939614Sbde /* close */ tapclose, 10039614Sbde /* read */ tapread, 10138653Sgpalmer /* write */ tapwrite, 10238653Sgpalmer /* ioctl */ tapioctl, 10338653Sgpalmer /* poll */ tappoll, 10438653Sgpalmer /* mmap */ nommap, 10538653Sgpalmer /* startegy */ nostrategy, 10638653Sgpalmer /* dev name */ CDEV_NAME, 10738653Sgpalmer /* dev major */ CDEV_MAJOR, 10839914Sdfr /* dump */ nodump, 10938653Sgpalmer /* psize */ nopsize, 11038653Sgpalmer /* flags */ 0, 11138653Sgpalmer /* bmaj */ -1 11238653Sgpalmer}; 11338653Sgpalmer 11438653Sgpalmerstatic int taprefcnt = 0; /* module ref. counter */ 11538653Sgpalmerstatic int taplastunit = -1; /* max. open unit number */ 11638653Sgpalmerstatic int tapdebug = 0; /* debug flag */ 11738653Sgpalmer 11838653SgpalmerMALLOC_DECLARE(M_TAP); 11938653SgpalmerMALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface"); 12038653SgpalmerSYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, ""); 12138653SgpalmerDEV_MODULE(if_tap, tapmodevent, NULL); 12238653Sgpalmer 12338653Sgpalmer/* 12438653Sgpalmer * tapmodevent 12538653Sgpalmer * 12638653Sgpalmer * module event handler 12738653Sgpalmer */ 12838653Sgpalmerstatic int 12938653Sgpalmertapmodevent(mod, type, data) 13038653Sgpalmer module_t mod; 13138653Sgpalmer int type; 13238653Sgpalmer void *data; 13338653Sgpalmer{ 13438653Sgpalmer static int attached = 0; 13538653Sgpalmer struct ifnet *ifp = NULL; 13638653Sgpalmer int unit, s; 13738653Sgpalmer 13838653Sgpalmer switch (type) { 13938653Sgpalmer case MOD_LOAD: 14038653Sgpalmer if (attached) 14138653Sgpalmer return (EEXIST); 14238653Sgpalmer 14338653Sgpalmer cdevsw_add(&tap_cdevsw); 14438653Sgpalmer attached = 1; 14538653Sgpalmer break; 14638653Sgpalmer 14741035Sdima case MOD_UNLOAD: 14838653Sgpalmer if (taprefcnt > 0) 14938653Sgpalmer return (EBUSY); 15038653Sgpalmer 15138653Sgpalmer cdevsw_remove(&tap_cdevsw); 15238653Sgpalmer 15338653Sgpalmer unit = 0; 15438653Sgpalmer while (unit <= taplastunit) { 15538653Sgpalmer s = splimp(); 15638653Sgpalmer TAILQ_FOREACH(ifp, &ifnet, if_link) 15738653Sgpalmer if ((strcmp(ifp->if_name, TAP) == 0) || 15838653Sgpalmer (strcmp(ifp->if_name, VMNET) == 0)) 15938653Sgpalmer if (ifp->if_unit == unit) 16038653Sgpalmer break; 16138653Sgpalmer splx(s); 16239928Ssef 16338653Sgpalmer if (ifp != NULL) { 16438653Sgpalmer struct tap_softc *tp = ifp->if_softc; 16538653Sgpalmer 16638653Sgpalmer TAPDEBUG("detaching %s%d. minor = %#x, " \ 16738653Sgpalmer "taplastunit = %d\n", 16838653Sgpalmer ifp->if_name, unit, minor(tp->tap_dev), 16938653Sgpalmer taplastunit); 17038653Sgpalmer 17138653Sgpalmer s = splimp(); 17238653Sgpalmer ether_ifdetach(ifp, 1); 17338653Sgpalmer splx(s); 17438653Sgpalmer destroy_dev(tp->tap_dev); 17538653Sgpalmer FREE(tp, M_TAP); 17638653Sgpalmer } 17738653Sgpalmer else 17841035Sdima unit ++; 17938653Sgpalmer } 18038653Sgpalmer 18138653Sgpalmer attached = 0; 18238653Sgpalmer break; 18338653Sgpalmer 18438653Sgpalmer default: 18538653Sgpalmer return (EOPNOTSUPP); 18638653Sgpalmer } 18738653Sgpalmer 18838653Sgpalmer return (0); 18938653Sgpalmer} /* tapmodevent */ 19038653Sgpalmer 19138653Sgpalmer 19238653Sgpalmer/* 19338653Sgpalmer * tapcreate 19438653Sgpalmer * 19538653Sgpalmer * to create interface 19638653Sgpalmer */ 19738653Sgpalmerstatic void 19838653Sgpalmertapcreate(dev) 19938653Sgpalmer dev_t dev; 2001590Srgrimes{ 20139614Sbde struct ifnet *ifp = NULL; 20239614Sbde struct tap_softc *tp = NULL; 20339614Sbde unsigned short macaddr_hi; 20434554Sjb int unit, s; 20534554Sjb char *name = NULL; 20634554Sjb 20734554Sjb /* allocate driver storage and create device */ 20836064Sjb MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK); 20938653Sgpalmer bzero(tp, sizeof(*tp)); 21038653Sgpalmer 21138653Sgpalmer /* select device: tap or vmnet */ 21238653Sgpalmer if (minor(dev) & VMNET_DEV_MASK) { 21338653Sgpalmer name = VMNET; 21438653Sgpalmer unit = lminor(dev) & 0xff; 21538653Sgpalmer tp->tap_flags |= TAP_VMNET; 21638653Sgpalmer } 21738653Sgpalmer else { 21838653Sgpalmer name = TAP; 21938653Sgpalmer unit = lminor(dev); 22038653Sgpalmer } 22141035Sdima 22236064Sjb tp->tap_dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 22334554Sjb 0600, "%s%d", name, unit); 2241590Srgrimes tp->tap_dev->si_drv1 = dev->si_drv1 = tp; 225 226 /* generate fake MAC address: 00 bd xx xx xx unit_no */ 227 macaddr_hi = htons(0x00bd); 228 bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short)); 229 bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long)); 230 tp->arpcom.ac_enaddr[5] = (u_char)unit; 231 232 /* fill the rest and attach interface */ 233 ifp = &tp->tap_if; 234 ifp->if_softc = tp; 235 236 ifp->if_unit = unit; 237 if (unit > taplastunit) 238 taplastunit = unit; 239 240 ifp->if_name = name; 241 ifp->if_init = tapifinit; 242 ifp->if_output = ether_output; 243 ifp->if_start = tapifstart; 244 ifp->if_ioctl = tapifioctl; 245 ifp->if_mtu = ETHERMTU; 246 ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST); 247 ifp->if_snd.ifq_maxlen = ifqmaxlen; 248 249 s = splimp(); 250 ether_ifattach(ifp, 1); 251 splx(s); 252 253 tp->tap_flags |= TAP_INITED; 254 255 TAPDEBUG("interface %s%d created. minor = %#x\n", 256 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 257} /* tapcreate */ 258 259 260/* 261 * tapopen 262 * 263 * to open tunnel. must be superuser 264 */ 265static int 266tapopen(dev, flag, mode, p) 267 dev_t dev; 268 int flag; 269 int mode; 270 struct proc *p; 271{ 272 struct tap_softc *tp = NULL; 273 int error; 274 275 if ((error = suser(p)) != 0) 276 return (error); 277 278 tp = dev->si_drv1; 279 if (tp == NULL) { 280 tapcreate(dev); 281 tp = dev->si_drv1; 282 } 283 284 if (tp->tap_flags & TAP_OPEN) 285 return (EBUSY); 286 287 tp->tap_pid = p->p_pid; 288 tp->tap_flags |= TAP_OPEN; 289 taprefcnt ++; 290 291 TAPDEBUG("%s%d is open. minor = %#x, refcnt = %d, taplastunit = %d\n", 292 tp->tap_if.if_name, tp->tap_if.if_unit, 293 minor(tp->tap_dev), taprefcnt, taplastunit); 294 295 return (0); 296} /* tapopen */ 297 298 299/* 300 * tapclose 301 * 302 * close the device - mark i/f down & delete routing info 303 */ 304static int 305tapclose(dev, foo, bar, p) 306 dev_t dev; 307 int foo; 308 int bar; 309 struct proc *p; 310{ 311 int s; 312 struct tap_softc *tp = dev->si_drv1; 313 struct ifnet *ifp = &tp->tap_if; 314 struct mbuf *m = NULL; 315 316 /* junk all pending output */ 317 318 s = splimp(); 319 do { 320 IF_DEQUEUE(&ifp->if_snd, m); 321 if (m != NULL) 322 m_freem(m); 323 } while (m != NULL); 324 splx(s); 325 326 /* 327 * do not bring the interface down, and do not anything with 328 * interface, if we are in VMnet mode. just close the device. 329 */ 330 331 if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) { 332 s = splimp(); 333 if_down(ifp); 334 if (ifp->if_flags & IFF_RUNNING) { 335 /* find internet addresses and delete routes */ 336 struct ifaddr *ifa = NULL; 337 338 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 339 if (ifa->ifa_addr->sa_family == AF_INET) { 340 rtinit(ifa, (int)RTM_DELETE, 0); 341 342 /* remove address from interface */ 343 bzero(ifa->ifa_addr, 344 sizeof(*(ifa->ifa_addr))); 345 bzero(ifa->ifa_dstaddr, 346 sizeof(*(ifa->ifa_dstaddr))); 347 bzero(ifa->ifa_netmask, 348 sizeof(*(ifa->ifa_netmask))); 349 } 350 } 351 352 ifp->if_flags &= ~IFF_RUNNING; 353 } 354 splx(s); 355 } 356 357 funsetown(tp->tap_sigio); 358 selwakeup(&tp->tap_rsel); 359 360 tp->tap_flags &= ~TAP_OPEN; 361 tp->tap_pid = 0; 362 363 taprefcnt --; 364 if (taprefcnt < 0) { 365 taprefcnt = 0; 366 printf("%s%d minor = %#x, refcnt = %d is out of sync. " \ 367 "set refcnt to 0\n", ifp->if_name, ifp->if_unit, 368 minor(tp->tap_dev), taprefcnt); 369 } 370 371 TAPDEBUG("%s%d is closed. minor = %#x, refcnt = %d, taplastunit = %d\n", 372 ifp->if_name, ifp->if_unit, minor(tp->tap_dev), 373 taprefcnt, taplastunit); 374 375 return (0); 376} /* tapclose */ 377 378 379/* 380 * tapifinit 381 * 382 * network interface initialization function 383 */ 384static void 385tapifinit(xtp) 386 void *xtp; 387{ 388 struct tap_softc *tp = (struct tap_softc *)xtp; 389 struct ifnet *ifp = &tp->tap_if; 390 391 TAPDEBUG("initializing %s%d, minor = %#x\n", 392 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 393 394 ifp->if_flags |= IFF_RUNNING; 395 ifp->if_flags &= ~IFF_OACTIVE; 396 397 /* attempt to start output */ 398 tapifstart(ifp); 399} /* tapifinit */ 400 401 402/* 403 * tapifioctl 404 * 405 * Process an ioctl request on network interface 406 */ 407int 408tapifioctl(ifp, cmd, data) 409 struct ifnet *ifp; 410 u_long cmd; 411 caddr_t data; 412{ 413 struct tap_softc *tp = (struct tap_softc *)(ifp->if_softc); 414 struct ifstat *ifs = NULL; 415 int s, dummy; 416 417 switch (cmd) { 418 case SIOCSIFADDR: 419 case SIOCGIFADDR: 420 case SIOCSIFMTU: 421 s = splimp(); 422 dummy = ether_ioctl(ifp, cmd, data); 423 splx(s); 424 return (dummy); 425 426 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */ 427 case SIOCADDMULTI: 428 case SIOCDELMULTI: 429 break; 430 431 case SIOCGIFSTATUS: 432 s = splimp(); 433 ifs = (struct ifstat *)data; 434 dummy = strlen(ifs->ascii); 435 if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii)) 436 snprintf(ifs->ascii + dummy, 437 sizeof(ifs->ascii) - dummy, 438 "\tOpened by PID %d\n", tp->tap_pid); 439 splx(s); 440 break; 441 442 default: 443 return (EINVAL); 444 } 445 446 return (0); 447} /* tapifioctl */ 448 449 450/* 451 * tapifstart 452 * 453 * queue packets from higher level ready to put out 454 */ 455static void 456tapifstart(ifp) 457 struct ifnet *ifp; 458{ 459 struct tap_softc *tp = ifp->if_softc; 460 int s; 461 462 TAPDEBUG("%s%d starting, minor = %#x\n", 463 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 464 465 /* 466 * do not junk pending output if we are in VMnet mode. 467 * XXX: can this do any harm because of queue overflow? 468 */ 469 470 if (((tp->tap_flags & TAP_VMNET) == 0) && 471 ((tp->tap_flags & TAP_READY) != TAP_READY)) { 472 struct mbuf *m = NULL; 473 474 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n", 475 ifp->if_name, ifp->if_unit, 476 minor(tp->tap_dev), tp->tap_flags); 477 478 s = splimp(); 479 do { 480 IF_DEQUEUE(&ifp->if_snd, m); 481 if (m != NULL) 482 m_freem(m); 483 ifp->if_oerrors ++; 484 } while (m != NULL); 485 splx(s); 486 487 return; 488 } 489 490 s = splimp(); 491 ifp->if_flags |= IFF_OACTIVE; 492 493 if (ifp->if_snd.ifq_len != 0) { 494 if (tp->tap_flags & TAP_RWAIT) { 495 tp->tap_flags &= ~TAP_RWAIT; 496 wakeup((caddr_t)tp); 497 } 498 499 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) 500 pgsigio(tp->tap_sigio, SIGIO, 0); 501 502 selwakeup(&tp->tap_rsel); 503 ifp->if_opackets ++; /* obytes are counted in ether_output */ 504 } 505 506 ifp->if_flags &= ~IFF_OACTIVE; 507 splx(s); 508} /* tapifstart */ 509 510 511/* 512 * tapioctl 513 * 514 * the cdevsw interface is now pretty minimal 515 */ 516static int 517tapioctl(dev, cmd, data, flag, p) 518 dev_t dev; 519 u_long cmd; 520 caddr_t data; 521 int flag; 522 struct proc *p; 523{ 524 struct tap_softc *tp = dev->si_drv1; 525 struct ifnet *ifp = &tp->tap_if; 526 struct tapinfo *tapp = NULL; 527 int s; 528 529 switch (cmd) { 530 case TAPSIFINFO: 531 s = splimp(); 532 tapp = (struct tapinfo *)data; 533 ifp->if_mtu = tapp->mtu; 534 ifp->if_type = tapp->type; 535 ifp->if_baudrate = tapp->baudrate; 536 splx(s); 537 break; 538 539 case TAPGIFINFO: 540 tapp = (struct tapinfo *)data; 541 tapp->mtu = ifp->if_mtu; 542 tapp->type = ifp->if_type; 543 tapp->baudrate = ifp->if_baudrate; 544 break; 545 546 case TAPSDEBUG: 547 tapdebug = *(int *)data; 548 break; 549 550 case TAPGDEBUG: 551 *(int *)data = tapdebug; 552 break; 553 554 case FIONBIO: 555 break; 556 557 case FIOASYNC: 558 s = splimp(); 559 if (*(int *)data) 560 tp->tap_flags |= TAP_ASYNC; 561 else 562 tp->tap_flags &= ~TAP_ASYNC; 563 splx(s); 564 break; 565 566 case FIONREAD: 567 s = splimp(); 568 if (ifp->if_snd.ifq_head) { 569 struct mbuf *mb = ifp->if_snd.ifq_head; 570 571 for(*(int *)data = 0;mb != NULL;mb = mb->m_next) 572 *(int *)data += mb->m_len; 573 } 574 else 575 *(int *)data = 0; 576 splx(s); 577 break; 578 579 case FIOSETOWN: 580 return (fsetown(*(int *)data, &tp->tap_sigio)); 581 582 case FIOGETOWN: 583 *(int *)data = fgetown(tp->tap_sigio); 584 return (0); 585 586 /* this is deprecated, FIOSETOWN should be used instead */ 587 case TIOCSPGRP: 588 return (fsetown(-(*(int *)data), &tp->tap_sigio)); 589 590 /* this is deprecated, FIOGETOWN should be used instead */ 591 case TIOCGPGRP: 592 *(int *)data = -fgetown(tp->tap_sigio); 593 return (0); 594 595 /* VMware/VMnet port ioctl's */ 596 597 case SIOCGIFFLAGS: /* get ifnet flags */ 598 bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags)); 599 break; 600 601 case VMIO_SIOCSIFFLAGS: { /* VMware/VMnet SIOCSIFFLAGS */ 602 short f = *(short *)data; 603 604 f &= 0x0fff; 605 f &= ~IFF_CANTCHANGE; 606 f |= IFF_UP; 607 608 s = splimp(); 609 ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE); 610 splx(s); 611 } break; 612 613 case OSIOCGIFADDR: /* get MAC address */ 614 case SIOCGIFADDR: 615 bcopy(tp->arpcom.ac_enaddr, data, ETHER_ADDR_LEN); 616 break; 617 618 case SIOCSIFADDR: /* set MAC address */ 619 s = splimp(); 620 bcopy(data, tp->arpcom.ac_enaddr, ETHER_ADDR_LEN); 621 splx(s); 622 break; 623 624 default: 625 return (ENOTTY); 626 } 627 return (0); 628} /* tapioctl */ 629 630 631/* 632 * tapread 633 * 634 * the cdevsw read interface - reads a packet at a time, or at 635 * least as much of a packet as can be read 636 */ 637static int 638tapread(dev, uio, flag) 639 dev_t dev; 640 struct uio *uio; 641 int flag; 642{ 643 struct tap_softc *tp = dev->si_drv1; 644 struct ifnet *ifp = &tp->tap_if; 645 struct mbuf *m = NULL, *m0 = NULL; 646 int error = 0, len, s; 647 648 TAPDEBUG("%s%d reading, minor = %#x\n", 649 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 650 651 if ((tp->tap_flags & TAP_READY) != TAP_READY) { 652 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n", 653 ifp->if_name, ifp->if_unit, 654 minor(tp->tap_dev), tp->tap_flags); 655 656 return (EHOSTDOWN); 657 } 658 659 tp->tap_flags &= ~TAP_RWAIT; 660 661 /* sleep until we get a packet */ 662 do { 663 s = splimp(); 664 IF_DEQUEUE(&ifp->if_snd, m0); 665 splx(s); 666 667 if (m0 == NULL) { 668 if (flag & IO_NDELAY) 669 return (EWOULDBLOCK); 670 671 tp->tap_flags |= TAP_RWAIT; 672 error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0); 673 if (error) 674 return (error); 675 } 676 } while (m0 == NULL); 677 678 /* feed packet to bpf */ 679 if (ifp->if_bpf != NULL) 680 bpf_mtap(ifp, m0); 681 682 /* xfer packet to user space */ 683 while ((m0 != NULL) && (uio->uio_resid > 0) && (error == 0)) { 684 len = min(uio->uio_resid, m0->m_len); 685 if (len == 0) 686 break; 687 688 error = uiomove(mtod(m0, caddr_t), len, uio); 689 MFREE(m0, m); 690 m0 = m; 691 } 692 693 if (m0 != NULL) { 694 TAPDEBUG("%s%d dropping mbuf, minor = %#x\n", 695 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 696 m_freem(m0); 697 } 698 699 return (error); 700} /* tapread */ 701 702 703/* 704 * tapwrite 705 * 706 * the cdevsw write interface - an atomic write is a packet - or else! 707 */ 708static int 709tapwrite(dev, uio, flag) 710 dev_t dev; 711 struct uio *uio; 712 int flag; 713{ 714 struct tap_softc *tp = dev->si_drv1; 715 struct ifnet *ifp = &tp->tap_if; 716 struct mbuf *top = NULL, **mp = NULL, *m = NULL; 717 struct ether_header *eh = NULL; 718 int error = 0, tlen, mlen; 719 720 TAPDEBUG("%s%d writting, minor = %#x\n", 721 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 722 723 if (uio->uio_resid == 0) 724 return (0); 725 726 if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) { 727 TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n", 728 ifp->if_name, ifp->if_unit, 729 uio->uio_resid, minor(tp->tap_dev)); 730 731 return (EIO); 732 } 733 tlen = uio->uio_resid; 734 735 /* get a header mbuf */ 736 MGETHDR(m, M_DONTWAIT, MT_DATA); 737 if (m == NULL) 738 return (ENOBUFS); 739 mlen = MHLEN; 740 741 top = 0; 742 mp = ⊤ 743 while ((error == 0) && (uio->uio_resid > 0)) { 744 m->m_len = min(mlen, uio->uio_resid); 745 error = uiomove(mtod(m, caddr_t), m->m_len, uio); 746 *mp = m; 747 mp = &m->m_next; 748 if (uio->uio_resid > 0) { 749 MGET(m, M_DONTWAIT, MT_DATA); 750 if (m == NULL) { 751 error = ENOBUFS; 752 break; 753 } 754 mlen = MLEN; 755 } 756 } 757 if (error) { 758 ifp->if_ierrors ++; 759 if (top) 760 m_freem(top); 761 return (error); 762 } 763 764 top->m_pkthdr.len = tlen; 765 top->m_pkthdr.rcvif = ifp; 766 767 /* 768 * Ethernet bridge and bpf are handled in ether_input 769 * 770 * adjust mbuf and give packet to the ether_input 771 */ 772 773 eh = mtod(top, struct ether_header *); 774 m_adj(top, sizeof(struct ether_header)); 775 ether_input(ifp, eh, top); 776 ifp->if_ipackets ++; /* ibytes are counted in ether_input */ 777 778 return (0); 779} /* tapwrite */ 780 781 782/* 783 * tappoll 784 * 785 * the poll interface, this is only useful on reads 786 * really. the write detect always returns true, write never blocks 787 * anyway, it either accepts the packet or drops it 788 */ 789static int 790tappoll(dev, events, p) 791 dev_t dev; 792 int events; 793 struct proc *p; 794{ 795 struct tap_softc *tp = dev->si_drv1; 796 struct ifnet *ifp = &tp->tap_if; 797 int s, revents = 0; 798 799 TAPDEBUG("%s%d polling, minor = %#x\n", 800 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 801 802 s = splimp(); 803 if (events & (POLLIN | POLLRDNORM)) { 804 if (ifp->if_snd.ifq_len > 0) { 805 TAPDEBUG("%s%d have data in queue. len = %d, " \ 806 "minor = %#x\n", ifp->if_name, ifp->if_unit, 807 ifp->if_snd.ifq_len, minor(tp->tap_dev)); 808 809 revents |= (events & (POLLIN | POLLRDNORM)); 810 } 811 else { 812 TAPDEBUG("%s%d waiting for data, minor = %#x\n", 813 ifp->if_name, ifp->if_unit, minor(tp->tap_dev)); 814 815 selrecord(p, &tp->tap_rsel); 816 } 817 } 818 819 if (events & (POLLOUT | POLLWRNORM)) 820 revents |= (events & (POLLOUT | POLLWRNORM)); 821 822 splx(s); 823 return (revents); 824} /* tappoll */ 825