version 1.47, 2008/08/26 11:06:59 |
version 1.47.4.6, 2009/04/04 23:36:28 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
|
|
/* |
/* |
* Copyright (c) 2003, 2004, 2008 The NetBSD Foundation. |
* Copyright (c) 2003, 2004, 2008, 2009 The NetBSD Foundation. |
* All rights reserved. |
* All rights reserved. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
Line 37 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 37 __KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#if defined(_KERNEL_OPT) |
#if defined(_KERNEL_OPT) |
#include "bpfilter.h" |
#include "bpfilter.h" |
|
#include "opt_modular.h" |
|
#include "opt_compat_netbsd.h" |
#endif |
#endif |
|
|
#include <sys/param.h> |
#include <sys/param.h> |
Line 49 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 51 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/filedesc.h> |
#include <sys/filedesc.h> |
#include <sys/ksyms.h> |
#include <sys/ksyms.h> |
#include <sys/poll.h> |
#include <sys/poll.h> |
|
#include <sys/proc.h> |
#include <sys/select.h> |
#include <sys/select.h> |
#include <sys/sockio.h> |
#include <sys/sockio.h> |
|
#if defined(COMPAT_40) || defined(MODULAR) |
#include <sys/sysctl.h> |
#include <sys/sysctl.h> |
|
#endif |
#include <sys/kauth.h> |
#include <sys/kauth.h> |
#include <sys/mutex.h> |
#include <sys/mutex.h> |
#include <sys/simplelock.h> |
#include <sys/simplelock.h> |
Line 68 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 73 __KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#include <compat/sys/sockio.h> |
#include <compat/sys/sockio.h> |
|
|
|
#if defined(COMPAT_40) || defined(MODULAR) |
/* |
/* |
* sysctl node management |
* sysctl node management |
* |
* |
Line 85 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 91 __KERNEL_RCSID(0, "$NetBSD$"); |
|
static int tap_node; |
static int tap_node; |
static int tap_sysctl_handler(SYSCTLFN_PROTO); |
static int tap_sysctl_handler(SYSCTLFN_PROTO); |
SYSCTL_SETUP_PROTO(sysctl_tap_setup); |
SYSCTL_SETUP_PROTO(sysctl_tap_setup); |
|
#endif |
|
|
/* |
/* |
* Since we're an Ethernet device, we need the 3 following |
* Since we're an Ethernet device, we need the 3 following |
Line 141 static int tap_fops_poll(file_t *, int); |
|
Line 148 static int tap_fops_poll(file_t *, int); |
|
static int tap_fops_kqfilter(file_t *, struct knote *); |
static int tap_fops_kqfilter(file_t *, struct knote *); |
|
|
static const struct fileops tap_fileops = { |
static const struct fileops tap_fileops = { |
tap_fops_read, |
.fo_read = tap_fops_read, |
tap_fops_write, |
.fo_write = tap_fops_write, |
tap_fops_ioctl, |
.fo_ioctl = tap_fops_ioctl, |
fnullop_fcntl, |
.fo_fcntl = fnullop_fcntl, |
tap_fops_poll, |
.fo_poll = tap_fops_poll, |
fbadop_stat, |
.fo_stat = fbadop_stat, |
tap_fops_close, |
.fo_close = tap_fops_close, |
tap_fops_kqfilter, |
.fo_kqfilter = tap_fops_kqfilter, |
|
.fo_drain = fnullop_drain, |
}; |
}; |
|
|
/* Helper for cloning open() */ |
/* Helper for cloning open() */ |
Line 197 static int tap_init(struct ifnet *); |
|
Line 205 static int tap_init(struct ifnet *); |
|
static int tap_ioctl(struct ifnet *, u_long, void *); |
static int tap_ioctl(struct ifnet *, u_long, void *); |
|
|
/* Internal functions */ |
/* Internal functions */ |
|
#if defined(COMPAT_40) || defined(MODULAR) |
static int tap_lifaddr(struct ifnet *, u_long, struct ifaliasreq *); |
static int tap_lifaddr(struct ifnet *, u_long, struct ifaliasreq *); |
|
#endif |
static void tap_softintr(void *); |
static void tap_softintr(void *); |
|
|
/* |
/* |
Line 246 tap_attach(device_t parent, device_t sel |
|
Line 256 tap_attach(device_t parent, device_t sel |
|
{ |
{ |
struct tap_softc *sc = device_private(self); |
struct tap_softc *sc = device_private(self); |
struct ifnet *ifp; |
struct ifnet *ifp; |
|
#if defined(COMPAT_40) || defined(MODULAR) |
const struct sysctlnode *node; |
const struct sysctlnode *node; |
|
int error; |
|
#endif |
uint8_t enaddr[ETHER_ADDR_LEN] = |
uint8_t enaddr[ETHER_ADDR_LEN] = |
{ 0xf2, 0x0b, 0xa4, 0xff, 0xff, 0xff }; |
{ 0xf2, 0x0b, 0xa4, 0xff, 0xff, 0xff }; |
char enaddrstr[3 * ETHER_ADDR_LEN]; |
char enaddrstr[3 * ETHER_ADDR_LEN]; |
struct timeval tv; |
struct timeval tv; |
uint32_t ui; |
uint32_t ui; |
int error; |
|
|
|
sc->sc_dev = self; |
sc->sc_dev = self; |
sc->sc_sih = softint_establish(SOFTINT_CLOCK, tap_softintr, sc); |
sc->sc_sih = softint_establish(SOFTINT_CLOCK, tap_softintr, sc); |
|
|
|
if (!pmf_device_register(self, NULL, NULL)) |
|
aprint_error_dev(self, "couldn't establish power handler\n"); |
|
|
/* |
/* |
* In order to obtain unique initial Ethernet address on a host, |
* In order to obtain unique initial Ethernet address on a host, |
* do some randomisation using the current uptime. It's not meant |
* do some randomisation using the current uptime. It's not meant |
Line 309 tap_attach(device_t parent, device_t sel |
|
Line 324 tap_attach(device_t parent, device_t sel |
|
|
|
sc->sc_flags = 0; |
sc->sc_flags = 0; |
|
|
|
#if defined(COMPAT_40) || defined(MODULAR) |
/* |
/* |
* Add a sysctl node for that interface. |
* Add a sysctl node for that interface. |
* |
* |
Line 331 tap_attach(device_t parent, device_t sel |
|
Line 347 tap_attach(device_t parent, device_t sel |
|
CTL_EOL)) != 0) |
CTL_EOL)) != 0) |
aprint_error_dev(self, "sysctl_createv returned %d, ignoring\n", |
aprint_error_dev(self, "sysctl_createv returned %d, ignoring\n", |
error); |
error); |
|
#endif |
|
|
/* |
/* |
* Initialize the two locks for the device. |
* Initialize the two locks for the device. |
Line 362 tap_detach(device_t self, int flags) |
|
Line 379 tap_detach(device_t self, int flags) |
|
{ |
{ |
struct tap_softc *sc = device_private(self); |
struct tap_softc *sc = device_private(self); |
struct ifnet *ifp = &sc->sc_ec.ec_if; |
struct ifnet *ifp = &sc->sc_ec.ec_if; |
int error, s; |
#if defined(COMPAT_40) || defined(MODULAR) |
|
int error; |
|
#endif |
|
int s; |
|
|
sc->sc_flags |= TAP_GOING; |
sc->sc_flags |= TAP_GOING; |
s = splnet(); |
s = splnet(); |
Line 372 tap_detach(device_t self, int flags) |
|
Line 392 tap_detach(device_t self, int flags) |
|
|
|
softint_disestablish(sc->sc_sih); |
softint_disestablish(sc->sc_sih); |
|
|
|
#if defined(COMPAT_40) || defined(MODULAR) |
/* |
/* |
* Destroying a single leaf is a very straightforward operation using |
* Destroying a single leaf is a very straightforward operation using |
* sysctl_destroyv. One should be sure to always end the path with |
* sysctl_destroyv. One should be sure to always end the path with |
Line 381 tap_detach(device_t self, int flags) |
|
Line 402 tap_detach(device_t self, int flags) |
|
device_unit(sc->sc_dev), CTL_EOL)) != 0) |
device_unit(sc->sc_dev), CTL_EOL)) != 0) |
aprint_error_dev(self, |
aprint_error_dev(self, |
"sysctl_destroyv returned %d, ignoring\n", error); |
"sysctl_destroyv returned %d, ignoring\n", error); |
|
#endif |
ether_ifdetach(ifp); |
ether_ifdetach(ifp); |
if_detach(ifp); |
if_detach(ifp); |
ifmedia_delete_instance(&sc->sc_im, IFM_INST_ANY); |
ifmedia_delete_instance(&sc->sc_im, IFM_INST_ANY); |
seldestroy(&sc->sc_rsel); |
seldestroy(&sc->sc_rsel); |
mutex_destroy(&sc->sc_rdlock); |
mutex_destroy(&sc->sc_rdlock); |
|
|
|
pmf_device_deregister(self); |
|
|
return (0); |
return (0); |
} |
} |
|
|
Line 516 tap_ioctl(struct ifnet *ifp, u_long cmd, |
|
Line 540 tap_ioctl(struct ifnet *ifp, u_long cmd, |
|
case SIOCGIFMEDIA: |
case SIOCGIFMEDIA: |
error = ifmedia_ioctl(ifp, ifr, &sc->sc_im, cmd); |
error = ifmedia_ioctl(ifp, ifr, &sc->sc_im, cmd); |
break; |
break; |
|
#if defined(COMPAT_40) || defined(MODULAR) |
case SIOCSIFPHYADDR: |
case SIOCSIFPHYADDR: |
error = tap_lifaddr(ifp, cmd, (struct ifaliasreq *)data); |
error = tap_lifaddr(ifp, cmd, (struct ifaliasreq *)data); |
break; |
break; |
|
#endif |
default: |
default: |
error = ether_ioctl(ifp, cmd, data); |
error = ether_ioctl(ifp, cmd, data); |
if (error == ENETRESET) |
if (error == ENETRESET) |
Line 531 tap_ioctl(struct ifnet *ifp, u_long cmd, |
|
Line 557 tap_ioctl(struct ifnet *ifp, u_long cmd, |
|
return (error); |
return (error); |
} |
} |
|
|
|
#if defined(COMPAT_40) || defined(MODULAR) |
/* |
/* |
* Helper function to set Ethernet address. This shouldn't be done there, |
* Helper function to set Ethernet address. This has been replaced by |
* and should actually be available to all Ethernet drivers, real or not. |
* the generic SIOCALIFADDR ioctl on a PF_LINK socket. |
*/ |
*/ |
static int |
static int |
tap_lifaddr(struct ifnet *ifp, u_long cmd, struct ifaliasreq *ifra) |
tap_lifaddr(struct ifnet *ifp, u_long cmd, struct ifaliasreq *ifra) |
{ |
{ |
const struct sockaddr_dl *sdl = satosdl(&ifra->ifra_addr); |
const struct sockaddr *sa = &ifra->ifra_addr; |
|
|
if (sdl->sdl_family != AF_LINK) |
if (sa->sa_family != AF_LINK) |
return (EINVAL); |
return (EINVAL); |
|
|
if_set_sadl(ifp, CLLADDR(sdl), ETHER_ADDR_LEN); |
if_set_sadl(ifp, sa->sa_data, ETHER_ADDR_LEN); |
|
|
return (0); |
return (0); |
} |
} |
|
#endif |
|
|
/* |
/* |
* _init() would typically be called when an interface goes up, |
* _init() would typically be called when an interface goes up, |
Line 880 tap_dev_read(int unit, struct uio *uio, |
|
Line 908 tap_dev_read(int unit, struct uio *uio, |
|
s = splnet(); |
s = splnet(); |
if (IFQ_IS_EMPTY(&ifp->if_snd)) { |
if (IFQ_IS_EMPTY(&ifp->if_snd)) { |
ifp->if_flags &= ~IFF_OACTIVE; |
ifp->if_flags &= ~IFF_OACTIVE; |
splx(s); |
|
/* |
/* |
* We must release the lock before sleeping, and re-acquire it |
* We must release the lock before sleeping, and re-acquire it |
* after. |
* after. |
Line 890 tap_dev_read(int unit, struct uio *uio, |
|
Line 917 tap_dev_read(int unit, struct uio *uio, |
|
error = EWOULDBLOCK; |
error = EWOULDBLOCK; |
else |
else |
error = tsleep(sc, PSOCK|PCATCH, "tap", 0); |
error = tsleep(sc, PSOCK|PCATCH, "tap", 0); |
|
splx(s); |
|
|
if (error != 0) |
if (error != 0) |
return (error); |
return (error); |
/* The device might have been downed */ |
/* The device might have been downed */ |
Line 1212 tap_kqread(struct knote *kn, long hint) |
|
Line 1241 tap_kqread(struct knote *kn, long hint) |
|
return rv; |
return rv; |
} |
} |
|
|
|
#if defined(COMPAT_40) || defined(MODULAR) |
/* |
/* |
* sysctl management routines |
* sysctl management routines |
* You can set the address of an interface through: |
* You can set the address of an interface through: |
Line 1342 tap_sysctl_handler(SYSCTLFN_ARGS) |
|
Line 1372 tap_sysctl_handler(SYSCTLFN_ARGS) |
|
if_set_sadl(ifp, enaddr, ETHER_ADDR_LEN); |
if_set_sadl(ifp, enaddr, ETHER_ADDR_LEN); |
return (error); |
return (error); |
} |
} |
|
#endif |