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.
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("[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
,
30 if (LIBBASE
->unixio
== NULL
)
32 kprintf("[eth] couldn't create unixio object\n");
36 for (i
= 0; i
< MAX_ETH_UNITS
; i
++)
37 LIBBASE
->unit
[i
].num
= i
;
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
);
56 static const ULONG rx_tags
[] = {
61 static const ULONG tx_tags
[] = {
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
) {
72 struct eth_unit
*unit
;
73 struct eth_opener
*opener
= NULL
;
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 */
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 */
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) {
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
);
138 kprintf("[eth] couldn't open '" ETH_IFACE_FORMAT
"' (%d)\n", unit
->num
, ioerr
);
139 error
= IOERR_OPENFAIL
;
142 /* and create the virtual network */
144 snprintf(unit
->name
, sizeof(unit
->name
), ETH_IFACE_FORMAT
, (long)unit
->num
);
145 unit
->name
[sizeof(unit
->name
)-1] = 0;
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 */
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;
187 unit
->iotask
= NewCreateTask(TASKTAG_PC
, eth_iotask
,
188 TASKTAG_NAME
, iotask_name
,
190 TASKTAG_ARG1
, LIBBASE
,
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 */
205 req
->ios2_Req
.io_Unit
= (APTR
) unit
;
208 AddTail((APTR
) &(unit
->openers
), (APTR
) opener
);
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 */
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
));
232 DeleteMsgPort(unit
->iosyncport
);
237 Hidd_UnixIO_ClosePacket(LIBBASE
->unixio
, unit
->pd
, NULL
);
239 /* fastest way to kill it */
240 memset(unit
, 0, sizeof(struct eth_unit
));
244 /* free the opener structure too */
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"));
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
));
278 DeleteMsgPort(unit
->iosyncport
);
282 Hidd_UnixIO_ClosePacket(LIBBASE
->unixio
, unit
->pd
, NULL
);
284 /* XXX return outstanding requests? */
287 ForeachNodeSafe(&(unit
->trackers
), tracker
, tracker_next
)
290 /* fastest way to kill it */
291 memset(unit
, 0, sizeof(struct eth_unit
));
295 /* cleanup the opener structure too */
297 Remove((APTR
) opener
);
301 req
->ios2_Req
.io_Unit
= NULL
;
302 req
->ios2_BufferManagement
= NULL
;
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
) {
316 req
->ios2_Req
.io_Error
= 0;
318 eth_handle_request(req
);
323 AROS_LH1(long, abort_io
, AROS_LHA(struct IOSana2Req
*, req
, A1
), LIBBASETYPEPTR
, LIBBASE
, 6, eth_device
) {
326 /* XXX anything to do here? */
336 /* hexdumpery stoled from Dan Gudmundsson, stoled from Gordon Beaton, via Google Code Search */
342 void eth_hexdump(unsigned char *buf
, int bufsz
)
347 /* do this in chunks of CHUNK bytes */
348 for (i
=0; i
<bufsz
; i
+=CHUNK
) {
349 /* show the offset */
352 /* max of CHUNK or remaining bytes */
353 count
= ((bufsz
-i
) > CHUNK
? CHUNK
: bufsz
-i
);
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(" ");
367 /* divider between hex and ascii */
371 for (j=0; j<count; j++)
372 bug("%c",(isprint(buf[i+j]) ? buf[i+j] : '.'));