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