make.tmpl: add missing compiler attribute to build_progs
[AROS.git] / arch / all-unix / devs / networks / eth / command.c
blob6b7da80201a56eb3d79cc019094a3ac3ae292cfb
1 /*
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.
8 */
10 #define DWRITE(x)
12 #include "eth.h"
14 static const UWORD eth_supported_commands[] = {
15 S2_DEVICEQUERY,
16 S2_GETSTATIONADDRESS,
17 S2_CONFIGINTERFACE,
18 S2_ONLINE,
19 S2_OFFLINE,
20 S2_BROADCAST,
21 CMD_READ,
22 CMD_WRITE,
23 CMD_FLUSH,
24 S2_TRACKTYPE,
25 S2_UNTRACKTYPE,
26 S2_GETTYPESTATS,
27 S2_GETGLOBALSTATS,
28 #if NEWSTYLE_DEVICE
29 NSCMD_DEVICEQUERY,
30 #endif
34 static BOOL eth_device_query(struct IOSana2Req *req, struct eth_unit *unit) {
35 CopyMem(&(unit->info), req->ios2_StatData, sizeof(struct Sana2DeviceQuery));
37 return TRUE;
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);
44 return TRUE;
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;
54 return TRUE;
57 CopyMem(unit->hwaddr, &req->ios2_SrcAddr, ETH_ALEN);
58 CopyMem(unit->hwaddr, &req->ios2_DstAddr, ETH_ALEN);
60 unit->flags |= eu_CONFIGURED;
62 return TRUE;
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;
72 return TRUE;
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;
81 return TRUE;
84 unit->flags |= eu_ONLINE;
86 D(bug("[eth] [%d] online\n", unit->num));
88 return TRUE;
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;
98 return TRUE;
101 unit->flags &= ~eu_ONLINE;
103 D(bug("[eth] [%d] offline\n", unit->num));
105 return TRUE;
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;
117 return TRUE;
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));
127 return FALSE;
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;
137 return TRUE;
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));
145 return FALSE;
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 ++;
158 return TRUE;
162 tracker = AllocVec(sizeof(struct eth_tracker), MEMF_PUBLIC | MEMF_CLEAR);
163 tracker->refcount = 1;
164 tracker->packet_type = packet_type;
166 Disable();
167 AddTail((APTR) &(unit->trackers), (APTR) tracker);
168 Enable();
170 D(bug("[eth] [%d] now tracking\n", unit->num));
172 return TRUE;
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));
189 Disable();
190 Remove((APTR) tracker);
191 Enable();
193 FreeVec(tracker);
196 return TRUE;
200 D(bug("[eth] [%d] no tracking, nothing to do\n", unit->num));
202 return TRUE;
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));
217 return TRUE;
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;
226 return TRUE;
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));
234 return TRUE;
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) {
251 #if NEWSTYLE_DEVICE
252 case NSCMD_DEVICEQUERY:
254 struct NSDeviceQueryResult *d;
255 LONG error = 0;
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;
275 break;
277 #endif
278 case S2_DEVICEQUERY:
279 D(bug("[eth] [%d] S2_DEVICEQUERY\n", unit->num));
280 completed = eth_device_query(req, unit);
281 break;
283 case S2_GETSTATIONADDRESS:
284 D(bug("[eth] [%d] S2_GETSTATIONADDRESS\n", unit->num));
285 completed = eth_get_station_address(req, unit);
286 break;
288 case S2_CONFIGINTERFACE:
289 D(bug("[eth] [%d] S2_CONFIGINTERFACE\n", unit->num));
290 completed = eth_config_interface(req, unit);
291 break;
293 case S2_ONLINE:
294 D(bug("[eth] [%d] S2_ONLINE\n", unit->num));
295 completed = eth_online(req, unit);
296 break;
298 case S2_OFFLINE:
299 D(bug("[eth] [%d] S2_OFFLINE\n", unit->num));
300 completed = eth_offline(req, unit);
301 break;
303 case CMD_READ:
304 D(bug("[eth] [%d] CMD_READ\n", unit->num));
305 completed = eth_read(req, unit);
306 break;
308 case CMD_WRITE:
309 D(bug("[eth] [%d] CMD_WRITE\n", unit->num));
310 completed = eth_write(req, unit);
311 break;
313 case CMD_FLUSH:
314 D(bug("[eth] [%d] CMD_FLUSH\n", unit->num));
315 break;
317 case S2_BROADCAST:
318 D(bug("[eth] [%d] S2_BROADCAST\n", unit->num));
319 completed = eth_broadcast(req, unit);
320 break;
322 case S2_TRACKTYPE:
323 D(bug("[eth] [%d] S2_TRACKTYPE\n", unit->num));
324 completed = eth_track_type(req, unit);
325 break;
327 case S2_UNTRACKTYPE:
328 D(bug("[eth] [%d] S2_UNTRACKTYPE\n", unit->num));
329 completed = eth_untrack_type(req, unit);
330 break;
332 case S2_GETTYPESTATS:
333 D(bug("[eth] [%d] S2_GETTYPESTATS\n", unit->num));
334 completed = eth_get_type_stats(req, unit);
335 break;
337 case S2_GETGLOBALSTATS:
338 D(bug("[eth] [%d] S2_GETGLOBALSTATS\n", unit->num));
339 completed = eth_get_global_stats(req, unit);
340 break;
342 default:
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;
345 completed = TRUE;
346 break;
349 if (completed && ! (req->ios2_Req.io_Flags & IOF_QUICK))
350 ReplyMsg((APTR) req);