revert between 56095 -> 55830 in arch
[AROS.git] / arch / all-unix / devs / networks / eth / init.c
blob7e2fb03691c1d6d1ea9bd44b8d407020583b7a29
1 /*
2 * eth - 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 "eth.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("[eth] 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("[eth] couldn't create unixio object\n");
33 return FALSE;
36 for (i = 0; i < MAX_ETH_UNITS; i ++)
37 LIBBASE->unit[i].num = i;
39 return TRUE;
42 static int GM_UNIQUENAME(expunge)(LIBBASETYPEPTR LIBBASE)
44 D(bug("[eth] 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 eth_iotask(struct eth_base *TAPBase, struct eth_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 eth_unit *unit;
73 struct eth_opener *opener = NULL;
74 int ioerr;
75 APTR pd;
77 D(bug("[eth] in open\n"));
79 D(bug("[eth] unit %ld, flags [0x%08x]%s%s\n", unitnum, flags,
80 flags & SANA2OPF_PROM ? " SANA2OPF_PROM" : "",
81 flags & SANA2OPF_MINE ? " SANA2OPF_MINE" : ""));
83 req->ios2_Req.io_Unit = NULL;
85 /* remember the callers buffer management functions */
86 tags = req->ios2_BufferManagement;
87 req->ios2_BufferManagement = NULL;
89 /* make sure the requested unit number is in range */
90 if (error == 0 && (unitnum < 0 || unitnum >= MAX_ETH_UNITS)) {
91 kprintf("[eth] request for unit %d, which is out of range (0..%d)\n", unitnum, MAX_ETH_UNITS-1);
92 error = IOERR_OPENFAIL;
94 unit = &(LIBBASE->unit[unitnum]);
96 /* allocate storage for opener state */
97 if (error == 0) {
98 opener = AllocVec(sizeof(struct eth_opener), MEMF_PUBLIC | MEMF_CLEAR);
99 req->ios2_BufferManagement = (APTR) opener;
101 if (opener == NULL) {
102 kprintf("[eth] [%d] couldn't allocate opener struct\n", unit->num);
103 error = IOERR_OPENFAIL;
107 /* prepare the opener port and buffer management functions */
108 if (error == 0) {
109 int i;
111 /* pending read requests get queued up in here */
112 NEWLIST(&(opener->read_pending.mp_MsgList));
113 opener->read_pending.mp_Flags = PA_IGNORE;
115 /* take the best rx/tx function from the ones offered by the caller */
116 for (i = 0; i < 2; i ++)
117 opener->rx = (APTR) GetTagData(rx_tags[i], (IPTR) opener->rx, tags);
118 for (i = 0; i < 3; i ++)
119 opener->tx = (APTR) GetTagData(tx_tags[i], (IPTR) opener->tx, tags);
121 /* the filter, if they have one */
122 opener->filter = (APTR) GetTagData(S2_PacketFilter, 0, tags);
124 D(bug("[eth] [%d] rx at 0x%08x, tx at 0x%08x, filter at 0x%08x\n", unit->num, opener->rx, opener->tx, opener->filter));
127 /* if the unit hasn't been setup previously, do that now */
128 if (error == 0 && unit->refcount == 0) {
129 char path[64];
131 snprintf(path, sizeof(path), ETH_IFACE_FORMAT, (long)unit->num);
132 path[sizeof(path)-1] = 0;
133 D(bug("[eth] [%d] refcount is 0, opening device %s\n", (int)unit->num, path));
135 /* open the tun/eth device */
136 pd = Hidd_UnixIO_OpenPacket(LIBBASE->unixio, path, &ioerr);
137 if (pd == NULL) {
138 kprintf("[eth] couldn't open '" ETH_IFACE_FORMAT "' (%d)\n", unit->num, ioerr);
139 error = IOERR_OPENFAIL;
142 /* and create the virtual network */
143 if (error == 0) {
144 snprintf(unit->name, sizeof(unit->name), ETH_IFACE_FORMAT, (long)unit->num);
145 unit->name[sizeof(unit->name)-1] = 0;
147 unit->pd = pd;
148 unit->fd = Hidd_UnixIO_PacketGetFileDescriptor(LIBBASE->unixio, unit->pd);
150 kprintf("[eth] unit %d attached to %s\n", unit->num, unit->name);
153 /* its good, time to create our unit */
154 if (error == 0)
156 char iotask_name[32];
158 Hidd_UnixIO_PacketGetMACAddress(LIBBASE->unixio, unit->pd, &unit->hwaddr[0]);
160 /* we're faking a 10Mbit ethernet card here */
161 unit->info.SizeAvailable = unit->info.SizeSupplied = sizeof(struct Sana2DeviceQuery);
162 unit->info.DevQueryFormat = 0;
163 unit->info.DeviceLevel = 0;
164 unit->info.AddrFieldSize = 48;
165 unit->info.MTU = 1500;
166 unit->info.BPS = 10000000;
167 unit->info.HardwareType = S2WireType_Ethernet;
169 kprintf("[eth] [%d] hardware address: %02x:%02x:%02x:%02x:%02x:%02x\n", unit->num,
170 unit->hwaddr[0], unit->hwaddr[1], unit->hwaddr[2],
171 unit->hwaddr[3], unit->hwaddr[4], unit->hwaddr[5]);
173 /* container for the openers */
174 NEWLIST(&(unit->openers));
176 /* and for the trackers */
177 NEWLIST(&(unit->trackers));
179 /* a port to sync actions with the iotask */
180 unit->iosyncport = CreateMsgPort();
182 /* make a unique name for this unit */
183 snprintf(iotask_name, sizeof(iotask_name), ETH_TASK_FORMAT, unit->num);
184 iotask_name[sizeof(iotask_name)-1] = 0;
186 /* make it fly */
187 unit->iotask = NewCreateTask(TASKTAG_PC , eth_iotask,
188 TASKTAG_NAME, iotask_name,
189 TASKTAG_PRI , 50,
190 TASKTAG_ARG1, LIBBASE,
191 TASKTAG_ARG2, unit,
192 TAG_DONE);
194 /* wait until its ready to go */
195 WaitPort(unit->iosyncport);
196 ReplyMsg(GetMsg(unit->iosyncport));
198 D(bug("[eth] [%d] unit created and running\n", unit->num));
202 /* at this point the unit is online, and the opener state is initialised.
203 * all that remains is to hook the two together */
204 if (error == 0) {
205 req->ios2_Req.io_Unit = (APTR) unit;
207 Disable();
208 AddTail((APTR) &(unit->openers), (APTR) opener);
209 Enable();
211 unit->refcount ++;
213 D(bug("[eth] [%d] refcount is now %d\n", unit->num, unit->refcount));
216 /* otoh, if it blew up, we've got some cleaning to do */
217 else {
219 /* shutdown the unit if there's noone using it */
220 if (unit->refcount == 0) {
221 D(bug("[eth] [%d] open failed, and there's no other users of this unit, killing it\n", unit->num));
223 /* kill the io task */
224 if (unit->iotask != NULL) {
225 Signal((struct Task *) unit->iotask, 1 << unit->abort_signal);
227 /* wait for it to die */
228 WaitPort(unit->iosyncport);
229 ReplyMsg(GetMsg(unit->iosyncport));
231 /* done with this */
232 DeleteMsgPort(unit->iosyncport);
235 /* close the nic */
236 if (unit->pd)
237 Hidd_UnixIO_ClosePacket(LIBBASE->unixio, unit->pd, NULL);
239 /* fastest way to kill it */
240 memset(unit, 0, sizeof(struct eth_unit));
241 unit->num = unitnum;
244 /* free the opener structure too */
245 FreeVec(opener);
248 req->ios2_Req.io_Error = error;
250 D(bug("[eth] open returning %d\n", error));
252 return (error == 0) ? TRUE : FALSE;
255 static int GM_UNIQUENAME(close)(LIBBASETYPEPTR LIBBASE, struct IOSana2Req *req) {
256 struct eth_unit *unit = (struct eth_unit *) req->ios2_Req.io_Unit;
257 struct eth_opener *opener = (struct eth_opener *) req->ios2_BufferManagement;
258 struct eth_tracker *tracker, *tracker_next;
259 ULONG unitnum = unit->num;
261 D(bug("[eth] in close\n"));
263 unit->refcount --;
265 D(bug("[eth] [%d] refcount is now %d\n", unit->num, unit->refcount));
267 if (unit->refcount == 0) {
268 D(bug("[eth] [%d] last user closed unit, stopping iotask\n", unit->num));
270 /* kill the io task */
271 Signal((struct Task *) unit->iotask, 1 << unit->abort_signal);
273 /* wait for it to die */
274 WaitPort(unit->iosyncport);
275 ReplyMsg(GetMsg(unit->iosyncport));
277 /* done with this */
278 DeleteMsgPort(unit->iosyncport);
280 /* close the nic */
281 if (unit->pd)
282 Hidd_UnixIO_ClosePacket(LIBBASE->unixio, unit->pd, NULL);
284 /* XXX return outstanding requests? */
286 /* kill trackers */
287 ForeachNodeSafe(&(unit->trackers), tracker, tracker_next)
288 FreeVec(tracker);
290 /* fastest way to kill it */
291 memset(unit, 0, sizeof(struct eth_unit));
292 unit->num = unitnum;
295 /* cleanup the opener structure too */
296 Disable();
297 Remove((APTR) opener);
298 Enable();
299 FreeVec(opener);
301 req->ios2_Req.io_Unit = NULL;
302 req->ios2_BufferManagement = NULL;
304 return TRUE;
307 ADD2INITLIB(GM_UNIQUENAME(init),0)
308 ADD2EXPUNGELIB(GM_UNIQUENAME(expunge),0)
309 ADD2OPENDEV(GM_UNIQUENAME(open),0)
310 ADD2CLOSEDEV(GM_UNIQUENAME(close),0)
311 ADD2LIBS("unixio.hidd", 0, static struct Library *, unixioBase);
313 AROS_LH1(void, begin_io, AROS_LHA(struct IOSana2Req *, req, A1), LIBBASETYPEPTR, LIBBASE, 5, eth_device) {
314 AROS_LIBFUNC_INIT
316 req->ios2_Req.io_Error = 0;
318 eth_handle_request(req);
320 AROS_LIBFUNC_EXIT
323 AROS_LH1(long, abort_io, AROS_LHA(struct IOSana2Req *, req, A1), LIBBASETYPEPTR, LIBBASE, 6, eth_device) {
324 AROS_LIBFUNC_INIT
326 /* XXX anything to do here? */
328 return 1;
330 AROS_LIBFUNC_EXIT
336 /* hexdumpery stoled from Dan Gudmundsson, stoled from Gordon Beaton, via Google Code Search */
338 #ifdef DEBUG
340 #define CHUNK 16
342 void eth_hexdump(unsigned char *buf, int bufsz)
344 int i,j;
345 int count;
347 /* do this in chunks of CHUNK bytes */
348 for (i=0; i<bufsz; i+=CHUNK) {
349 /* show the offset */
350 bug("0x%06x ", i);
352 /* max of CHUNK or remaining bytes */
353 count = ((bufsz-i) > CHUNK ? CHUNK : bufsz-i);
355 /* show the bytes */
356 for (j=0; j<count; j++) {
357 if (j==CHUNK/2) bug(" ");
358 bug("%02x ",buf[i+j]);
361 /* pad with spaces if less than CHUNK */
362 for (j=count; j<CHUNK; j++) {
363 if (j==CHUNK/2) bug(" ");
364 bug(" ");
367 /* divider between hex and ascii */
368 bug(" ");
371 for (j=0; j<count; j++)
372 bug("%c",(isprint(buf[i+j]) ? buf[i+j] : '.'));
375 bug("\n\r");
379 #endif