unixio.hidd: Move to autogenerated interface includes
[AROS.git] / arch / all-unix / devs / networks / tap / init.c
blob31f1d95ae958a1dccb58001b76af3044035b13d8
1 /*
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.
8 */
10 #include <hidd/unixio.h>
11 #include <proto/alib.h>
12 #include <proto/oop.h>
14 #include "tap.h"
16 static int GM_UNIQUENAME(init)(LIBBASETYPEPTR LIBBASE)
18 int i;
20 LIBBASE->UnixIOAttrBase = OOP_ObtainAttrBase(IID_Hidd_UnixIO);
21 if (!LIBBASE->UnixIOAttrBase)
22 return FALSE;
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,
29 TAG_DONE);
30 if (LIBBASE->unixio == NULL)
32 kprintf("[tap] couldn't create unixio object\n");
33 return FALSE;
36 for (i = 0; i < MAX_TAP_UNITS; i ++)
37 LIBBASE->unit[i].num = i;
39 return TRUE;
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);
53 return TRUE;
56 static const ULONG rx_tags[] = {
57 S2_CopyToBuff,
58 S2_CopyToBuff16
61 static const ULONG tx_tags[] = {
62 S2_CopyFromBuff,
63 S2_CopyFromBuff16,
64 S2_CopyFromBuff32
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) {
70 struct TagItem *tags;
71 BYTE error = 0;
72 struct tap_unit *unit;
73 struct tap_opener *opener = NULL;
74 int fd, ioerr;
75 struct ifreq ifr;
76 int i;
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 */
98 if (error == 0) {
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 */
109 if (error == 0) {
110 int i;
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);
134 if (fd < 0) {
135 kprintf("[tap] couldn't open '" TAP_DEV_NODE "' (%d)\n", ioerr);
136 error = IOERR_OPENFAIL;
139 /* and create the virtual network */
140 if (error == 0) {
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;
153 else {
154 unit->fd = fd;
156 kprintf("[tap] unit %d attached to %s\n", unit->num, unit->name);
160 /* its good, time to create our unit */
161 if (error == 0)
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);
197 /* make it fly */
198 unit->iotask = NewCreateTask(TASKTAG_PC , tap_iotask,
199 TASKTAG_NAME, iotask_name,
200 TASKTAG_PRI , 50,
201 TASKTAG_ARG1, LIBBASE,
202 TASKTAG_ARG2, unit,
203 TAG_DONE);
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 */
215 if (error == 0) {
216 req->ios2_Req.io_Unit = (APTR) unit;
218 Disable();
219 AddTail((APTR) &(unit->openers), (APTR) opener);
220 Enable();
222 unit->refcount ++;
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 */
228 else {
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));
242 /* done with this */
243 DeleteMsgPort(unit->iosyncport);
246 /* close the nic */
247 if (unit->fd > 0)
248 Hidd_UnixIO_CloseFile(LIBBASE->unixio, unit->fd, NULL);
250 /* fastest way to kill it */
251 memset(unit, 0, sizeof(struct tap_unit));
252 unit->num = unitnum;
255 /* free the opener structure too */
256 FreeVec(opener);
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"));
274 unit->refcount --;
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));
288 /* done with this */
289 DeleteMsgPort(unit->iosyncport);
291 /* close the nic */
292 if (unit->fd > 0)
293 Hidd_UnixIO_CloseFile(LIBBASE->unixio, unit->fd, NULL);
295 /* XXX return outstanding requests? */
297 /* kill trackers */
298 ForeachNodeSafe(&(unit->trackers), tracker, tracker_next)
299 FreeVec(tracker);
301 /* fastest way to kill it */
302 memset(unit, 0, sizeof(struct tap_unit));
303 unit->num = unitnum;
306 /* cleanup the opener structure too */
307 Disable();
308 Remove((APTR) opener);
309 Enable();
310 FreeVec(opener);
312 req->ios2_Req.io_Unit = NULL;
313 req->ios2_BufferManagement = NULL;
315 return TRUE;
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) {
325 AROS_LIBFUNC_INIT
327 req->ios2_Req.io_Error = 0;
329 tap_handle_request(req);
331 AROS_LIBFUNC_EXIT
334 AROS_LH1(long, abort_io, AROS_LHA(struct IOSana2Req *, req, A1), LIBBASETYPEPTR, LIBBASE, 6, tap_device) {
335 AROS_LIBFUNC_INIT
337 /* XXX anything to do here? */
339 return 1;
341 AROS_LIBFUNC_EXIT
347 /* hexdumpery stoled from Dan Gudmundsson, stoled from Gordon Beaton, via Google Code Search */
349 #ifdef DEBUG
351 #define CHUNK 16
353 void tap_hexdump(unsigned char *buf, int bufsz)
355 int i,j;
356 int count;
358 /* do this in chunks of CHUNK bytes */
359 for (i=0; i<bufsz; i+=CHUNK) {
360 /* show the offset */
361 bug("0x%06x ", i);
363 /* max of CHUNK or remaining bytes */
364 count = ((bufsz-i) > CHUNK ? CHUNK : bufsz-i);
366 /* show the bytes */
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(" ");
375 bug(" ");
378 /* divider between hex and ascii */
379 bug(" ");
382 for (j=0; j<count; j++)
383 bug("%c",(isprint(buf[i+j]) ? buf[i+j] : '.'));
386 bug("\n\r");
390 #endif