2 * tap - 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.
15 static const UWORD tap_supported_commands
[] = {
35 static BOOL
tap_device_query(struct IOSana2Req
*req
, struct tap_unit
*unit
) {
36 CopyMem(&(unit
->info
), req
->ios2_StatData
, sizeof(struct Sana2DeviceQuery
));
41 static BOOL
tap_get_station_address(struct IOSana2Req
*req
, struct tap_unit
*unit
) {
42 CopyMem(unit
->hwaddr
, &req
->ios2_SrcAddr
, ETH_ALEN
);
43 CopyMem(unit
->hwaddr
, &req
->ios2_DstAddr
, ETH_ALEN
);
48 static BOOL
tap_config_interface(struct IOSana2Req
*req
, struct tap_unit
*unit
) {
49 if (unit
->flags
& tu_CONFIGURED
) {
50 D(bug("[tap] [%d] already configured\n", unit
->num
));
52 req
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
53 req
->ios2_WireError
= S2WERR_IS_CONFIGURED
;
58 CopyMem(unit
->hwaddr
, &req
->ios2_SrcAddr
, ETH_ALEN
);
59 CopyMem(unit
->hwaddr
, &req
->ios2_DstAddr
, ETH_ALEN
);
61 unit
->flags
|= tu_CONFIGURED
;
66 static BOOL
tap_online(struct IOSana2Req
*req
, struct tap_unit
*unit
) {
67 if (unit
->flags
& tu_ONLINE
) {
68 D(bug("[tap] [%d] already online\n", unit
->num
));
70 req
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
71 req
->ios2_WireError
= S2WERR_UNIT_ONLINE
;
76 if (!(unit
->flags
& tu_CONFIGURED
)) {
77 D(bug("[tap] [%d] not configured\n", unit
->num
));
79 req
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
80 req
->ios2_WireError
= S2WERR_UNIT_ONLINE
;
85 unit
->flags
|= tu_ONLINE
;
87 D(bug("[tap] [%d] online\n", unit
->num
));
92 static BOOL
tap_offline(struct IOSana2Req
*req
, struct tap_unit
*unit
) {
93 if (!(unit
->flags
& tu_ONLINE
)) {
94 D(bug("[tap] [%d] already offline\n", unit
->num
));
96 req
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
97 req
->ios2_WireError
= S2WERR_UNIT_OFFLINE
;
102 unit
->flags
&= ~tu_ONLINE
;
104 D(bug("[tap] [%d] offline\n", unit
->num
));
109 static BOOL
tap_read(struct IOSana2Req
*req
, struct tap_unit
*unit
) {
110 struct tap_opener
*opener
;
112 if (!(unit
->flags
& tu_ONLINE
)) {
113 D(bug("[tap] [%d] not online\n", unit
->num
));
115 req
->ios2_Req
.io_Error
= S2ERR_OUTOFSERVICE
;
116 req
->ios2_WireError
= S2WERR_UNIT_OFFLINE
;
121 opener
= req
->ios2_BufferManagement
;
123 req
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
124 PutMsg(&(opener
->read_pending
), (struct Message
*) req
);
126 D(bug("[tap] [%d] queued read request\n", unit
->num
));
131 static BOOL
tap_write(struct IOSana2Req
*req
, struct tap_unit
*unit
) {
132 if (!(unit
->flags
& tu_ONLINE
)) {
133 DWRITE(bug("[tap] [%d] not online\n", unit
->num
));
135 req
->ios2_Req
.io_Error
= S2ERR_OUTOFSERVICE
;
136 req
->ios2_WireError
= S2WERR_UNIT_OFFLINE
;
141 req
->ios2_Req
.io_Flags
&= ~IOF_QUICK
;
142 PutMsg(unit
->write_queue
, (struct Message
*) req
);
144 DWRITE(bug("[tap] [%d] queued write request\n", unit
->num
));
149 static BOOL
tap_track_type(struct IOSana2Req
*req
, struct tap_unit
*unit
) {
150 struct tap_tracker
*tracker
, *tracker_next
;
151 WORD packet_type
= req
->ios2_PacketType
;
153 D(bug("[tap] [%d] track of packet type 0x%04x requested\n", unit
->num
, packet_type
));
155 ForeachNodeSafe(&(unit
->trackers
), tracker
, tracker_next
) {
156 if (tracker
->packet_type
== packet_type
) {
157 D(bug("[tap] [%d] already tracking, incrementing the refcount\n", unit
->num
));
158 tracker
->refcount
++;
163 tracker
= AllocVec(sizeof(struct tap_tracker
), MEMF_PUBLIC
| MEMF_CLEAR
);
164 tracker
->refcount
= 1;
165 tracker
->packet_type
= packet_type
;
168 AddTail((APTR
) &(unit
->trackers
), (APTR
) tracker
);
171 D(bug("[tap] [%d] now tracking\n", unit
->num
));
176 static BOOL
tap_untrack_type(struct IOSana2Req
*req
, struct tap_unit
*unit
) {
177 struct tap_tracker
*tracker
, *tracker_next
;
178 WORD packet_type
= req
->ios2_PacketType
;
180 D(bug("[tap] [%d] untrack of packet type 0x%04x requested\n", unit
->num
, packet_type
));
182 ForeachNodeSafe(&(unit
->trackers
), tracker
, tracker_next
) {
183 if (tracker
->packet_type
== packet_type
) {
184 D(bug("[tap] [%d] found it, decrementing the refcount\n", unit
->num
));
185 tracker
->refcount
--;
187 if (tracker
->refcount
== 0) {
188 D(bug("[tap] [%d] refcount is 0, not tracking any longer\n", unit
->num
));
191 Remove((APTR
) tracker
);
201 D(bug("[tap] [%d] no tracking, nothing to do\n", unit
->num
));
206 static BOOL
tap_get_type_stats(struct IOSana2Req
*req
, struct tap_unit
*unit
) {
207 struct tap_tracker
*tracker
, *tracker_next
;
208 WORD packet_type
= req
->ios2_PacketType
;
210 D(bug("[tap] [%d] get stats for packet type 0x%04x requested\n", unit
->num
, packet_type
));
212 ForeachNodeSafe(&(unit
->trackers
), tracker
, tracker_next
) {
213 if (tracker
->packet_type
== packet_type
) {
214 D(bug("[tap] [%d] found it, copying to caller\n", unit
->num
));
216 CopyMem(&(tracker
->stats
), req
->ios2_StatData
, sizeof(struct Sana2PacketTypeStats
));
222 D(bug("[tap] [%d] not tracking this type\n", unit
->num
));
224 req
->ios2_Req
.io_Error
= S2ERR_BAD_STATE
;
225 req
->ios2_WireError
= S2WERR_NOT_TRACKED
;
230 static BOOL
tap_get_global_stats(struct IOSana2Req
*req
, struct tap_unit
*unit
) {
231 D(bug("[tap] [%d] returning global stats\n", unit
->num
));
233 CopyMem(&(unit
->stats
), req
->ios2_StatData
, sizeof(struct Sana2DeviceStats
));
238 static BOOL
tap_broadcast(struct IOSana2Req
*req
, struct tap_unit
*unit
) {
239 /* just fill in the broadcast address as the dest, and write as normal */
240 char *addr
= req
->ios2_DstAddr
;
241 *((ULONG
*) addr
) = 0xffffffff;
242 *((UWORD
*) (addr
+ 4)) = 0xffff;
244 return tap_write(req
, unit
);
247 void tap_handle_request(struct IOSana2Req
*req
) {
248 struct tap_unit
*unit
= (struct tap_unit
*) req
->ios2_Req
.io_Unit
;
249 BOOL completed
= FALSE
;
251 switch (req
->ios2_Req
.io_Command
) {
253 case NSCMD_DEVICEQUERY
:
255 struct NSDeviceQueryResult
*d
;
257 struct IOStdReq
*iotd
;
258 iotd
= (struct IOStdReq
*)req
;
259 D(bug("[tap] [%d] NSCMD_DEVICEQUERY\n", unit
->num
));
260 if(iotd
->io_Length
>= sizeof(struct NSDeviceQueryResult
))
262 if((d
= (struct NSDeviceQueryResult
*)iotd
->io_Data
))
264 if ((d
->DevQueryFormat
== 0) && (d
->SizeAvailable
== 0))
266 d
->SizeAvailable
= sizeof(struct NSDeviceQueryResult
);
267 d
->DeviceType
= NSDEVTYPE_SANA2
;
268 d
->DeviceSubType
= 0;
269 d
->SupportedCommands
= (UWORD
*)tap_supported_commands
;
270 iotd
->io_Actual
= sizeof(struct NSDeviceQueryResult
);
271 } else error
= IOERR_BADLENGTH
;
272 } else error
= IOERR_BADADDRESS
;
273 } else error
= IOERR_BADLENGTH
;
274 iotd
->io_Error
= error
;
275 completed
= error
? FALSE
: TRUE
;
280 D(bug("[tap] [%d] S2_DEVICEQUERY\n", unit
->num
));
281 completed
= tap_device_query(req
, unit
);
284 case S2_GETSTATIONADDRESS
:
285 D(bug("[tap] [%d] S2_GETSTATIONADDRESS\n", unit
->num
));
286 completed
= tap_get_station_address(req
, unit
);
289 case S2_CONFIGINTERFACE
:
290 D(bug("[tap] [%d] S2_CONFIGINTERFACE\n", unit
->num
));
291 completed
= tap_config_interface(req
, unit
);
295 D(bug("[tap] [%d] S2_ONLINE\n", unit
->num
));
296 completed
= tap_online(req
, unit
);
300 D(bug("[tap] [%d] S2_OFFLINE\n", unit
->num
));
301 completed
= tap_offline(req
, unit
);
305 D(bug("[tap] [%d] CMD_READ\n", unit
->num
));
306 completed
= tap_read(req
, unit
);
310 D(bug("[tap] [%d] CMD_WRITE\n", unit
->num
));
311 completed
= tap_write(req
, unit
);
315 D(bug("[tap] [%d] CMD_FLUSH\n", unit
->num
));
319 D(bug("[tap] [%d] S2_BROADCAST\n", unit
->num
));
320 completed
= tap_broadcast(req
, unit
);
324 D(bug("[tap] [%d] S2_TRACKTYPE\n", unit
->num
));
325 completed
= tap_track_type(req
, unit
);
329 D(bug("[tap] [%d] S2_UNTRACKTYPE\n", unit
->num
));
330 completed
= tap_untrack_type(req
, unit
);
333 case S2_GETTYPESTATS
:
334 D(bug("[tap] [%d] S2_GETTYPESTATS\n", unit
->num
));
335 completed
= tap_get_type_stats(req
, unit
);
338 case S2_GETGLOBALSTATS
:
339 D(bug("[tap] [%d] S2_GETGLOBALSTATS\n", unit
->num
));
340 completed
= tap_get_global_stats(req
, unit
);
344 D(bug("[tap] [%d] unknown command (%d)\n", unit
->num
, req
->ios2_Req
.io_Command
));
345 req
->ios2_Req
.io_Error
= S2ERR_NOT_SUPPORTED
;
350 if (completed
&& ! (req
->ios2_Req
.io_Flags
& IOF_QUICK
))
351 ReplyMsg((APTR
) req
);