Deleted Added
full compact
if_tap.c (126188) if_tap.c (126796)
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 = &top;
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 = &top;
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 */