2 * eth - TUN/TAP network driver for AROS
3 * Copyright (c) 2007 Robert Norris. All rights reserved.
4 * Copyright © 2010, 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.
14 static const UWORD eth_supported_commands
[] = {
34 static BOOL
eth_device_query(struct IOSana2Req
*req
, struct eth_unit
*unit
) {
35 CopyMem(&(unit
->info
), req
->ios2_StatData
, sizeof(struct Sana2DeviceQuery
));
40 static BOOL
eth_get_station_address(struct IOSana2Req
*req
, struct eth_unit
*unit
) {
41 CopyMem(unit
->hwaddr
, &req
->ios2_SrcAddr
, ETH_ALEN
);
42 CopyMem(unit
->hwaddr
, &req
->ios2_DstAddr
, ETH_ALEN
);
47 static BOOL
eth_config_interface(struct IOSana2Req
*req
, struct eth_unit
*unit
) {
48 if (unit
->flags
& eu_CONFIGURED
) {
49 D(bug("[eth] [%d] already configured\n", unit
->num
));
51 req
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
52 req
->ios2_WireError
= S2WERR_IS_CONFIGURED
;
57 CopyMem(unit
->hwaddr
, &req
->ios2_SrcAddr
, ETH_ALEN
);
58 CopyMem(unit
->hwaddr
, &req
->ios2_DstAddr
, ETH_ALEN
);
60 unit
->flags
|= eu_CONFIGURED
;
65 static BOOL
eth_online(struct IOSana2Req
*req
, struct eth_unit
*unit
) {
66 if (unit
->flags
& eu_ONLINE
) {
67 D(bug("[eth] [%d] already online\n", unit
->num
));
69 req
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
70 req
->ios2_WireError
= S2WERR_UNIT_ONLINE
;
75 if (!(unit
->flags
& eu_CONFIGURED
)) {
76 D(bug("[eth] [%d] not configured\n", unit
->num
));
78 req
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
79 req
->ios2_WireError
= S2WERR_UNIT_ONLINE
;
84 unit
->flags
|= eu_ONLINE
;
86 D(bug("[eth] [%d] online\n", unit
->num
));
91 static BOOL
eth_offline(struct IOSana2Req
*req
, struct eth_unit
*unit
) {
92 if (!(unit
->flags
& eu_ONLINE
)) {
93 D(bug("[eth] [%d] already offline\n", unit
->num
));
95 req
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
96 req
->ios2_WireError
= S2WERR_UNIT_OFFLINE
;
101 unit
->flags
&= ~eu_ONLINE
;
103 D(bug("[eth] [%d] offline\n", unit
->num
));
108 static BOOL
eth_read(struct IOSana2Req
*req
, struct eth_unit
*unit
) {
109 struct eth_opener
*opener
;
111 if (!(unit
->flags
& eu_ONLINE
)) {
112 D(bug("[eth] [%d] not online\n", unit
->num
));
114 req
->ios2_Req
.io_Error
= S2ERR_OUTOFSERVICE
;
115 req
->ios2_WireError
= S2WERR_UNIT_OFFLINE
;
120 opener
= req
->ios2_BufferManagement
;
122 req
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
123 PutMsg(&(opener
->read_pending
), (struct Message
*) req
);
125 D(bug("[eth] [%d] queued read request\n", unit
->num
));
130 static BOOL
eth_write(struct IOSana2Req
*req
, struct eth_unit
*unit
) {
131 if (!(unit
->flags
& eu_ONLINE
)) {
132 DWRITE(bug("[eth] [%d] not online\n", unit
->num
));
134 req
->ios2_Req
.io_Error
= S2ERR_OUTOFSERVICE
;
135 req
->ios2_WireError
= S2WERR_UNIT_OFFLINE
;
140 req
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
141 PutMsg(unit
->write_queue
, (struct Message
*) req
);
143 DWRITE(bug("[eth] [%d] queued write request\n", unit
->num
));
148 static BOOL
eth_track_type(struct IOSana2Req
*req
, struct eth_unit
*unit
) {
149 struct eth_tracker
*tracker
, *tracker_next
;
150 WORD packet_type
= req
->ios2_PacketType
;
152 D(bug("[eth] [%d] track of packet type 0x%04x requested\n", unit
->num
, packet_type
));
154 ForeachNodeSafe(&(unit
->trackers
), tracker
, tracker_next
) {
155 if (tracker
->packet_type
== packet_type
) {
156 D(bug("[eth] [%d] already tracking, incrementing the refcount\n", unit
->num
));
157 tracker
->refcount
++;
162 tracker
= AllocVec(sizeof(struct eth_tracker
), MEMF_PUBLIC
| MEMF_CLEAR
);
163 tracker
->refcount
= 1;
164 tracker
->packet_type
= packet_type
;
167 AddTail((APTR
) &(unit
->trackers
), (APTR
) tracker
);
170 D(bug("[eth] [%d] now tracking\n", unit
->num
));
175 static BOOL
eth_untrack_type(struct IOSana2Req
*req
, struct eth_unit
*unit
) {
176 struct eth_tracker
*tracker
, *tracker_next
;
177 WORD packet_type
= req
->ios2_PacketType
;
179 D(bug("[eth] [%d] untrack of packet type 0x%04x requested\n", unit
->num
, packet_type
));
181 ForeachNodeSafe(&(unit
->trackers
), tracker
, tracker_next
) {
182 if (tracker
->packet_type
== packet_type
) {
183 D(bug("[eth] [%d] found it, decrementing the refcount\n", unit
->num
));
184 tracker
->refcount
--;
186 if (tracker
->refcount
== 0) {
187 D(bug("[eth] [%d] refcount is 0, not tracking any longer\n", unit
->num
));
190 Remove((APTR
) tracker
);
200 D(bug("[eth] [%d] no tracking, nothing to do\n", unit
->num
));
205 static BOOL
eth_get_type_stats(struct IOSana2Req
*req
, struct eth_unit
*unit
) {
206 struct eth_tracker
*tracker
, *tracker_next
;
207 WORD packet_type
= req
->ios2_PacketType
;
209 D(bug("[eth] [%d] get stats for packet type 0x%04x requested\n", unit
->num
, packet_type
));
211 ForeachNodeSafe(&(unit
->trackers
), tracker
, tracker_next
) {
212 if (tracker
->packet_type
== packet_type
) {
213 D(bug("[eth] [%d] found it, copying to caller\n", unit
->num
));
215 CopyMem(&(tracker
->stats
), req
->ios2_StatData
, sizeof(struct Sana2PacketTypeStats
));
221 D(bug("[eth] [%d] not tracking this type\n", unit
->num
));
223 req
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
224 req
->ios2_WireError
= S2WERR_NOT_TRACKED
;
229 static BOOL
eth_get_global_stats(struct IOSana2Req
*req
, struct eth_unit
*unit
) {
230 D(bug("[eth] [%d] returning global stats\n", unit
->num
));
232 CopyMem(&(unit
->stats
), req
->ios2_StatData
, sizeof(struct Sana2DeviceStats
));
237 static BOOL
eth_broadcast(struct IOSana2Req
*req
, struct eth_unit
*unit
) {
238 /* just fill in the broadcast address as the dest, and write as normal */
239 char *addr
= req
->ios2_DstAddr
;
240 *((ULONG
*) addr
) = 0xffffffff;
241 *((UWORD
*) (addr
+ 4)) = 0xffff;
243 return eth_write(req
, unit
);
246 void eth_handle_request(struct IOSana2Req
*req
) {
247 struct eth_unit
*unit
= (struct eth_unit
*) req
->ios2_Req
.io_Unit
;
248 BOOL completed
= FALSE
;
250 switch (req
->ios2_Req
.io_Command
) {
252 case NSCMD_DEVICEQUERY
:
254 struct NSDeviceQueryResult
*d
;
256 struct IOStdReq
*iotd
;
257 iotd
= (struct IOStdReq
*)req
;
258 D(bug("[eth] [%d] NSCMD_DEVICEQUERY\n", unit
->num
));
259 if(iotd
->io_Length
>= sizeof(struct NSDeviceQueryResult
))
261 if((d
= (struct NSDeviceQueryResult
*)iotd
->io_Data
))
263 if ((d
->DevQueryFormat
== 0) && (d
->SizeAvailable
== 0))
265 d
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
266 d
->DeviceType
= NSDEVTYPE_SANA2
;
267 d
->DeviceSubType
= 0;
268 d
->SupportedCommands
= (UWORD
*)eth_supported_commands
;
269 iotd
->io_Actual
= sizeof(struct NSDeviceQueryResult
);
270 } else error
= IOERR_BADLENGTH
;
271 } else error
= IOERR_BADADDRESS
;
272 } else error
= IOERR_BADLENGTH
;
273 iotd
->io_Error
= error
;
274 completed
= error
? FALSE
: TRUE
;
279 D(bug("[eth] [%d] S2_DEVICEQUERY\n", unit
->num
));
280 completed
= eth_device_query(req
, unit
);
283 case S2_GETSTATIONADDRESS
:
284 D(bug("[eth] [%d] S2_GETSTATIONADDRESS\n", unit
->num
));
285 completed
= eth_get_station_address(req
, unit
);
288 case S2_CONFIGINTERFACE
:
289 D(bug("[eth] [%d] S2_CONFIGINTERFACE\n", unit
->num
));
290 completed
= eth_config_interface(req
, unit
);
294 D(bug("[eth] [%d] S2_ONLINE\n", unit
->num
));
295 completed
= eth_online(req
, unit
);
299 D(bug("[eth] [%d] S2_OFFLINE\n", unit
->num
));
300 completed
= eth_offline(req
, unit
);
304 D(bug("[eth] [%d] CMD_READ\n", unit
->num
));
305 completed
= eth_read(req
, unit
);
309 D(bug("[eth] [%d] CMD_WRITE\n", unit
->num
));
310 completed
= eth_write(req
, unit
);
314 D(bug("[eth] [%d] CMD_FLUSH\n", unit
->num
));
318 D(bug("[eth] [%d] S2_BROADCAST\n", unit
->num
));
319 completed
= eth_broadcast(req
, unit
);
323 D(bug("[eth] [%d] S2_TRACKTYPE\n", unit
->num
));
324 completed
= eth_track_type(req
, unit
);
328 D(bug("[eth] [%d] S2_UNTRACKTYPE\n", unit
->num
));
329 completed
= eth_untrack_type(req
, unit
);
332 case S2_GETTYPESTATS
:
333 D(bug("[eth] [%d] S2_GETTYPESTATS\n", unit
->num
));
334 completed
= eth_get_type_stats(req
, unit
);
337 case S2_GETGLOBALSTATS
:
338 D(bug("[eth] [%d] S2_GETGLOBALSTATS\n", unit
->num
));
339 completed
= eth_get_global_stats(req
, unit
);
343 D(bug("[eth] [%d] unknown command (%d)\n", unit
->num
, req
->ios2_Req
.io_Command
));
344 req
->ios2_Req
.io_Error
= S2ERR_NOT_SUPPORTED
;
349 if (completed
&& ! (req
->ios2_Req
.io_Flags
& IOF_QUICK
))
350 ReplyMsg((APTR
) req
);