2 * tap - TUN/TAP network driver for AROS
3 * Copyright (c) 2007 Robert Norris. All rights reserved.
4 * Copyright (c) 2010-2011 The AROS Development Team. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the same terms as AROS itself.
10 #include <hidd/unixio.h>
11 #include <proto/alib.h>
12 #include <proto/oop.h>
16 static int GM_UNIQUENAME(init
)(LIBBASETYPEPTR LIBBASE
)
20 LIBBASE
->UnixIOAttrBase
= OOP_ObtainAttrBase(IID_Hidd_UnixIO
);
21 if (!LIBBASE
->UnixIOAttrBase
)
24 D(bug("[tap] in init\n"));
26 LIBBASE
->unixio
= OOP_NewObjectTags(NULL
, CLID_Hidd_UnixIO
,
27 aHidd_UnixIO_Opener
, MOD_NAME_STRING
,
28 aHidd_UnixIO_Architecture
, AROS_ARCHITECTURE
,
30 if (LIBBASE
->unixio
== NULL
)
32 kprintf("[tap] couldn't create unixio object\n");
36 for (i
= 0; i
< MAX_TAP_UNITS
; i
++)
37 LIBBASE
->unit
[i
].num
= i
;
42 static int GM_UNIQUENAME(expunge
)(LIBBASETYPEPTR LIBBASE
)
44 D(bug("[tap] in expunge\n"));
46 /* XXX kill the tasks and free memory, just in case */
48 /* We don't need to dispose a unixio object, it's a singletone. */
50 if (LIBBASE
->UnixIOAttrBase
)
51 OOP_ReleaseAttrBase(IID_Hidd_UnixIO
);
56 static const ULONG rx_tags
[] = {
61 static const ULONG tx_tags
[] = {
67 extern void tap_iotask(struct tap_base
*TAPBase
, struct tap_unit
*unit
);
69 static int GM_UNIQUENAME(open
)(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*req
, ULONG unitnum
, ULONG flags
) {
72 struct tap_unit
*unit
;
73 struct tap_opener
*opener
= NULL
;
78 D(bug("[tap] in open\n"));
80 D(bug("[tap] unit %ld, flags [0x%08x]%s%s\n", unitnum
, flags
,
81 flags
& SANA2OPF_PROM
? " SANA2OPF_PROM" : "",
82 flags
& SANA2OPF_MINE
? " SANA2OPF_MINE" : ""));
84 req
->ios2_Req
.io_Unit
= NULL
;
86 /* remember the callers buffer management functions */
87 tags
= req
->ios2_BufferManagement
;
88 req
->ios2_BufferManagement
= NULL
;
90 /* make sure the requested unit number is in range */
91 if (error
== 0 && (unitnum
< 0 || unitnum
>= MAX_TAP_UNITS
)) {
92 kprintf("[tap] request for unit %d, which is out of range (0..%d)\n", unitnum
, MAX_TAP_UNITS
-1);
93 error
= IOERR_OPENFAIL
;
95 unit
= &(LIBBASE
->unit
[unitnum
]);
97 /* allocate storage for opener state */
99 opener
= AllocVec(sizeof(struct tap_opener
), MEMF_PUBLIC
| MEMF_CLEAR
);
100 req
->ios2_BufferManagement
= (APTR
) opener
;
102 if (opener
== NULL
) {
103 kprintf("[tap] [%d] couldn't allocate opener struct\n", unit
->num
);
104 error
= IOERR_OPENFAIL
;
108 /* prepare the opener port and buffer management functions */
112 /* pending read requests get queued up in here */
113 NEWLIST(&(opener
->read_pending
.mp_MsgList
));
114 opener
->read_pending
.mp_Flags
= PA_IGNORE
;
116 /* take the best rx/tx function from the ones offered by the caller */
117 for (i
= 0; i
< 2; i
++)
118 opener
->rx
= (APTR
) GetTagData(rx_tags
[i
], (IPTR
) opener
->rx
, tags
);
119 for (i
= 0; i
< 3; i
++)
120 opener
->tx
= (APTR
) GetTagData(tx_tags
[i
], (IPTR
) opener
->tx
, tags
);
122 /* the filter, if they have one */
123 opener
->filter
= (APTR
) GetTagData(S2_PacketFilter
, 0, tags
);
125 D(bug("[tap] [%d] rx at 0x%08x, tx at 0x%08x, filter at 0x%08x\n", unit
->num
, opener
->rx
, opener
->tx
, opener
->filter
));
128 /* if the unit hasn't been setup previously, do that now */
129 if (error
== 0 && unit
->refcount
== 0) {
130 D(bug("[tap] [%d] refcount is 0, opening device\n", unit
->num
));
132 /* open the tun/tap device */
133 fd
= Hidd_UnixIO_OpenFile(LIBBASE
->unixio
, TAP_DEV_NODE
, O_RDWR
, 0, &ioerr
);
135 kprintf("[tap] couldn't open '" TAP_DEV_NODE
"' (%d)\n", ioerr
);
136 error
= IOERR_OPENFAIL
;
139 /* and create the virtual network */
141 __sprintf(unit
->name
, TAP_IFACE_FORMAT
, unit
->num
);
143 memset(&ifr
, 0, sizeof(struct ifreq
));
144 ifr
.ifr_flags
= IFF_TAP
| IFF_NO_PI
;
145 strncpy(ifr
.ifr_name
, unit
->name
, IFNAMSIZ
);
147 if ((Hidd_UnixIO_IOControlFile(LIBBASE
->unixio
, fd
, TUNSETIFF
, &ifr
, &ioerr
)) < 0)
149 kprintf("[tap] couldn't perform TUNSETIFF on TAP device (%d)\n", ioerr
);
150 error
= IOERR_OPENFAIL
;
156 kprintf("[tap] unit %d attached to %s\n", unit
->num
, unit
->name
);
160 /* its good, time to create our unit */
163 char iotask_name
[32];
165 /* we're faking a 10Mbit ethernet card here */
166 unit
->info
.SizeAvailable
= unit
->info
.SizeSupplied
= sizeof(struct Sana2DeviceQuery
);
167 unit
->info
.DevQueryFormat
= 0;
168 unit
->info
.DeviceLevel
= 0;
169 unit
->info
.AddrFieldSize
= 48;
170 unit
->info
.MTU
= 1500;
171 unit
->info
.BPS
= 10000000;
172 unit
->info
.HardwareType
= S2WireType_Ethernet
;
174 /* create a random hardware address */
175 for (i
= 0; i
< ETH_ALEN
; i
++)
176 unit
->hwaddr
[i
] = (unsigned char) (rand() % 0xff);
178 unit
->hwaddr
[0] &= 0xfe; /* clear multicast bit */
179 unit
->hwaddr
[0] |= 0x02; /* set local assignment bit (IEEE802) */
181 kprintf("[tap] [%d] hardware address: %02x:%02x:%02x:%02x:%02x:%02x\n", unit
->num
,
182 unit
->hwaddr
[0], unit
->hwaddr
[1], unit
->hwaddr
[2],
183 unit
->hwaddr
[3], unit
->hwaddr
[4], unit
->hwaddr
[5]);
185 /* container for the openers */
186 NEWLIST(&(unit
->openers
));
188 /* and for the trackers */
189 NEWLIST(&(unit
->trackers
));
191 /* a port to sync actions with the iotask */
192 unit
->iosyncport
= CreateMsgPort();
194 /* make a unique name for this unit */
195 __sprintf(iotask_name
, TAP_TASK_FORMAT
, unit
->num
);
198 unit
->iotask
= NewCreateTask(TASKTAG_PC
, tap_iotask
,
199 TASKTAG_NAME
, iotask_name
,
201 TASKTAG_ARG1
, LIBBASE
,
205 /* wait until its ready to go */
206 WaitPort(unit
->iosyncport
);
207 ReplyMsg(GetMsg(unit
->iosyncport
));
209 D(bug("[tap] [%d] unit created and running\n", unit
->num
));
213 /* at this point the unit is online, and the opener state is initialised.
214 * all that remains is to hook the two together */
216 req
->ios2_Req
.io_Unit
= (APTR
) unit
;
219 AddTail((APTR
) &(unit
->openers
), (APTR
) opener
);
224 D(bug("[tap] [%d] refcount is now %d\n", unit
->num
, unit
->refcount
));
227 /* otoh, if it blew up, we've got some cleaning to do */
230 /* shutdown the unit if there's noone using it */
231 if (unit
->refcount
== 0) {
232 D(bug("[tap] [%d] open failed, and there's no other users of this unit, killing it\n", unit
->num
));
234 /* kill the io task */
235 if (unit
->iotask
!= NULL
) {
236 Signal((struct Task
*) unit
->iotask
, 1 << unit
->abort_signal
);
238 /* wait for it to die */
239 WaitPort(unit
->iosyncport
);
240 ReplyMsg(GetMsg(unit
->iosyncport
));
243 DeleteMsgPort(unit
->iosyncport
);
248 Hidd_UnixIO_CloseFile(LIBBASE
->unixio
, unit
->fd
, NULL
);
250 /* fastest way to kill it */
251 memset(unit
, 0, sizeof(struct tap_unit
));
255 /* free the opener structure too */
259 req
->ios2_Req
.io_Error
= error
;
261 D(bug("[tap] open returning %d\n", error
));
263 return (error
== 0) ? TRUE
: FALSE
;
266 static int GM_UNIQUENAME(close
)(LIBBASETYPEPTR LIBBASE
, struct IOSana2Req
*req
) {
267 struct tap_unit
*unit
= (struct tap_unit
*) req
->ios2_Req
.io_Unit
;
268 struct tap_opener
*opener
= (struct tap_opener
*) req
->ios2_BufferManagement
;
269 struct tap_tracker
*tracker
, *tracker_next
;
270 ULONG unitnum
= unit
->num
;
272 D(bug("[tap] in close\n"));
276 D(bug("[tap] [%d] refcount is now %d\n", unit
->num
, unit
->refcount
));
278 if (unit
->refcount
== 0) {
279 D(bug("[tap] [%d] last user closed unit, stopping iotask\n", unit
->num
));
281 /* kill the io task */
282 Signal((struct Task
*) unit
->iotask
, 1 << unit
->abort_signal
);
284 /* wait for it to die */
285 WaitPort(unit
->iosyncport
);
286 ReplyMsg(GetMsg(unit
->iosyncport
));
289 DeleteMsgPort(unit
->iosyncport
);
293 Hidd_UnixIO_CloseFile(LIBBASE
->unixio
, unit
->fd
, NULL
);
295 /* XXX return outstanding requests? */
298 ForeachNodeSafe(&(unit
->trackers
), tracker
, tracker_next
)
301 /* fastest way to kill it */
302 memset(unit
, 0, sizeof(struct tap_unit
));
306 /* cleanup the opener structure too */
308 Remove((APTR
) opener
);
312 req
->ios2_Req
.io_Unit
= NULL
;
313 req
->ios2_BufferManagement
= NULL
;
318 ADD2INITLIB(GM_UNIQUENAME(init
),0)
319 ADD2EXPUNGELIB(GM_UNIQUENAME(expunge
),0)
320 ADD2OPENDEV(GM_UNIQUENAME(open
),0)
321 ADD2CLOSEDEV(GM_UNIQUENAME(close
),0)
322 ADD2LIBS("unixio.hidd", 0, static struct Library
*, unixioBase
);
324 AROS_LH1(void, begin_io
, AROS_LHA(struct IOSana2Req
*, req
, A1
), LIBBASETYPEPTR
, LIBBASE
, 5, tap_device
) {
327 req
->ios2_Req
.io_Error
= 0;
329 tap_handle_request(req
);
334 AROS_LH1(long, abort_io
, AROS_LHA(struct IOSana2Req
*, req
, A1
), LIBBASETYPEPTR
, LIBBASE
, 6, tap_device
) {
337 /* XXX anything to do here? */
347 /* hexdumpery stoled from Dan Gudmundsson, stoled from Gordon Beaton, via Google Code Search */
353 void tap_hexdump(unsigned char *buf
, int bufsz
)
358 /* do this in chunks of CHUNK bytes */
359 for (i
=0; i
<bufsz
; i
+=CHUNK
) {
360 /* show the offset */
363 /* max of CHUNK or remaining bytes */
364 count
= ((bufsz
-i
) > CHUNK
? CHUNK
: bufsz
-i
);
367 for (j
=0; j
<count
; j
++) {
368 if (j
==CHUNK
/2) bug(" ");
369 bug("%02x ",buf
[i
+j
]);
372 /* pad with spaces if less than CHUNK */
373 for (j
=count
; j
<CHUNK
; j
++) {
374 if (j
==CHUNK
/2) bug(" ");
378 /* divider between hex and ascii */
382 for (j=0; j<count; j++)
383 bug("%c",(isprint(buf[i+j]) ? buf[i+j] : '.'));