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