2 * eth - TUN/ETH 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>
16 /* this fires whenever data is waiting to be read on the eth descriptor */
17 static void eth_receive(struct eth_base
*ETHBase
, struct eth_unit
*unit
)
19 unsigned char buf
[ETH_FRAME_LEN
], *packet
;
24 struct eth_opener
*opener
, *opener_next
;
25 struct IOSana2Req
*req
, *req_next
;
26 BOOL bcast
= FALSE
, mcast
= FALSE
;
28 struct eth_tracker
*tracker
, *tracker_next
;
30 D(bug("[eth] [io:%d] got a packet\n", unit
->num
));
32 /* Try to read the packet */
33 nread
= Hidd_UnixIO_RecvPacket(ETHBase
->unixio
, unit
->pd
, buf
, ETH_FRAME_LEN
, &ioerr
);
36 D(bug("[eth] [io:%d] read failed (%d)\n", unit
->num
, ioerr
));
40 if (!(unit
->flags
& eu_ONLINE
)) {
41 D(bug("[eth] [io:%d] we're offline, dropping it\n", unit
->num
));
45 D(bug("[eth] [io:%d] packet dump (%d bytes):\n", unit
->num
, nread
));
46 D(eth_hexdump(buf
, nread
));
48 eth
= (struct ethhdr
*) buf
;
49 packet_type
= AROS_BE2WORD(eth
->h_proto
); /* AROS_BE2WORD === ntohs */
51 D(bug("[eth] [io:%d] source address: %02x:%02x:%02x:%02x:%02x:%02x\n", unit
->num
,
52 eth
->h_source
[0], eth
->h_source
[1], eth
->h_source
[2],
53 eth
->h_source
[3], eth
->h_source
[4], eth
->h_source
[5]));
54 D(bug("[eth] [io:%d] dest address: %02x:%02x:%02x:%02x:%02x:%02x\n", unit
->num
,
55 eth
->h_dest
[0], eth
->h_dest
[1], eth
->h_dest
[2],
56 eth
->h_dest
[3], eth
->h_dest
[4], eth
->h_dest
[5]));
57 D(bug("[eth] [io:%d] packet type: 0x%04x\n", unit
->num
, packet_type
));
59 /* broadcast packets have the top 40 bits (5 bytes) set */
61 if ((*((ULONG
*) (dest
)) == 0xffffffff) &&
62 (*((UWORD
*) (dest
+ 4)) == 0xffff)) {
63 D(bug("[eth] [io:%d] broadcast packet\n"));
67 /* multicasts have the top bit set */
68 else if ((eth
->h_dest
[0] & 0x1) != 0) {
69 D(bug("[eth] [io:%d] multicast packet\n"));
73 /* drop multicast packets (until we have support for them) */
75 D(bug("[eth] [io:%d] no support for multicast packets, dropping it\n", unit
->num
));
79 /* now we loop through our openers, seeing if anyone wants the packet */
80 ForeachNodeSafe(&(unit
->openers
), opener
, opener_next
) {
82 /* loop pending read requests */
83 ForeachNodeSafe(&(opener
->read_pending
.mp_MsgList
), req
, req_next
) {
85 if (req
->ios2_PacketType
== packet_type
) {
86 D(bug("[eth] [io:%d] found a request that wants this packet, sending it\n", unit
->num
));
88 /* record broadcast/multicast status */
89 req
->ios2_Req
.io_Flags
&= ~(SANA2IOF_BCAST
| SANA2IOF_MCAST
);
91 req
->ios2_Req
.io_Flags
|= SANA2IOF_BCAST
;
93 req
->ios2_Req
.io_Flags
|= SANA2IOF_MCAST
;
95 /* copy source, dest, type */
96 CopyMem(eth
->h_source
, req
->ios2_SrcAddr
, ETH_ALEN
);
97 CopyMem(eth
->h_dest
, req
->ios2_DstAddr
, ETH_ALEN
);
98 req
->ios2_PacketType
= packet_type
;
100 /* if they want the raw header, then use as-is */
101 if (req
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) {
102 req
->ios2_DataLength
= nread
;
106 /* otherwise rip the header off */
108 req
->ios2_DataLength
= nread
- ETH_HLEN
;
109 packet
= &(buf
[ETH_HLEN
]);
112 /* user filter. the packet gets blocked if
113 * - the request is CMD_READ, and
114 * - they provided a filter, and
115 * - the filter returns false
117 if (req
->ios2_Req
.io_Command
== CMD_READ
&&
118 opener
->filter
!= NULL
&&
119 ! CallHookPkt(opener
->filter
, req
, packet
)) {
120 D(bug("[eth] [io:%d] packet blocked by opener filter\n", unit
->num
));
125 /* hand it to the opener via the provided rx function */
126 if (! opener
->rx(req
->ios2_Data
, packet
, req
->ios2_DataLength
)) {
127 D(bug("[eth] [io:%d] opener signaled error during rx copy\n", unit
->num
));
129 req
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
130 req
->ios2_WireError
= S2WERR_BUFF_ERROR
;
134 D(bug("[eth] [io:%d] packet copied successfully\n", unit
->num
));
140 ReplyMsg((APTR
) req
);
154 D(bug("[eth] [io:%d] no one claimed the packet, orphaning\n", unit
->num
));
156 /* XXX handle orphans */
159 /* update tracked stats */
160 ForeachNodeSafe(&(unit
->trackers
), tracker
, tracker_next
) {
161 if (tracker
->packet_type
== packet_type
) {
162 tracker
->stats
.PacketsReceived
++;
163 tracker
->stats
.BytesReceived
+= nread
;
165 tracker
->stats
.PacketsDropped
++;
169 /* update global stats too */
170 unit
->stats
.PacketsReceived
++;
172 unit
->stats
.UnknownTypesReceived
++;
175 /* this fires whenever we can write to the eth descriptor */
176 static void eth_send(struct eth_base
*ETHBase
, struct eth_unit
*unit
)
178 struct IOSana2Req
*req
;
180 struct eth_opener
*opener
;
181 unsigned char buf
[ETH_FRAME_LEN
], *packet
;
183 int ioerr
, nwritten
= 0;
184 struct eth_tracker
*tracker
, *tracker_next
;
186 if (!unit
->write_queue
->mp_MsgList
.lh_Head
->ln_Succ
)
189 /* grab the first pending request */
190 req
= (struct IOSana2Req
*) unit
->write_queue
->mp_MsgList
.lh_Head
;
192 eth
= (struct ethhdr
*) buf
;
194 D(bug("[eth] [io:%d] buffer has %d bytes%s\n", unit
->num
, req
->ios2_DataLength
, req
->ios2_Req
.io_Flags
& SANA2IOF_RAW
? " (RAW is set)" : ""));
196 /* build a header if they didn't send us one */
197 if (! (req
->ios2_Req
.io_Flags
& SANA2IOF_RAW
)) {
198 D(bug("[eth] [io:%d] adding ethernet header\n", unit
->num
));
200 CopyMem(unit
->hwaddr
, eth
->h_source
, ETH_ALEN
);
201 CopyMem(req
->ios2_DstAddr
, eth
->h_dest
, ETH_ALEN
);
202 eth
->h_proto
= AROS_WORD2BE(req
->ios2_PacketType
); /* AROS_WORD2BE === htons */
204 packet
= &(buf
[ETH_HLEN
]);
205 packet_length
= ETH_HLEN
+ req
->ios2_DataLength
;
208 /* otherwise just use what they give us */
211 packet_length
= req
->ios2_DataLength
;
214 /* user magic functions */
215 opener
= (struct eth_opener
*) req
->ios2_BufferManagement
;
217 /* get the opener to magick into a buffer we can use */
218 if (! opener
->tx(packet
, req
->ios2_Data
, req
->ios2_DataLength
)) {
219 D(bug("[eth] [io:%d] opener signaled error during tx copy\n", unit
->num
));
221 req
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
222 req
->ios2_WireError
= S2WERR_BUFF_ERROR
;
226 D(bug("[eth] [io:%d] packet dump (%d bytes):\n", unit
->num
, packet_length
));
227 D(eth_hexdump(buf
, packet_length
));
229 D(bug("[eth] [io:%d] source address: %02x:%02x:%02x:%02x:%02x:%02x\n", unit
->num
,
230 eth
->h_source
[0], eth
->h_source
[1], eth
->h_source
[2],
231 eth
->h_source
[3], eth
->h_source
[4], eth
->h_source
[5]));
232 D(bug("[eth] [io:%d] dest address: %02x:%02x:%02x:%02x:%02x:%02x\n", unit
->num
,
233 eth
->h_dest
[0], eth
->h_dest
[1], eth
->h_dest
[2],
234 eth
->h_dest
[3], eth
->h_dest
[4], eth
->h_dest
[5]));
235 D(bug("[eth] [io:%d] packet type: 0x%04x\n", unit
->num
, AROS_BE2WORD(eth
->h_proto
)));
237 /* got a viable buffer, send it out */
238 nwritten
= Hidd_UnixIO_SendPacket(ETHBase
->unixio
, unit
->pd
, buf
, packet_length
, &ioerr
);
240 D(bug("[eth] [io:%d] write failed (%d)\n", unit
->num
, ioerr
));
241 req
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
243 else if (nwritten
< packet_length
) {
244 D(bug("[eth] [io:%d] short write, only %d bytes written, reporting error\n", unit
->num
, nwritten
));
245 req
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
248 D(bug("[eth] [io:%d] wrote %d bytes\n", unit
->num
, nwritten
));
252 if (req
->ios2_Req
.io_Error
== 0) {
255 ForeachNodeSafe(&(unit
->trackers
), tracker
, tracker_next
) {
256 if (tracker
->packet_type
== req
->ios2_PacketType
) {
257 tracker
->stats
.PacketsSent
++;
258 tracker
->stats
.BytesSent
+= nwritten
;
263 unit
->stats
.PacketsSent
++;
266 /* remove and reply to the request */
270 ReplyMsg((APTR
) req
);
273 static void IOHandler(int fd
, int mode
, void *data
)
275 struct eth_unit
*unit
= data
;
276 D(bug("[eth] IO interrupt received\n"));
277 Signal(unit
->iotask
, 1 << unit
->io_signal
);
281 void eth_iotask(struct eth_base
*ETHBase
, struct eth_unit
*unit
)
283 struct MsgPort
*reply_port
;
285 ULONG write_signal_mask
, abort_signal_mask
, io_signal_mask
, signal_mask
;
287 short write_flag
= 0;
289 D(bug("[eth] [io:%d] iotask starting up\n", unit
->num
));
291 /* Prepare write queue */
292 unit
->write_queue
= CreateMsgPort();
293 D(bug("[eth] Write port %p\n", unit
->write_queue
));
295 /* make some signals, one of them to shut us down, and one for I/O */
296 unit
->abort_signal
= AllocSignal(-1);
297 unit
->io_signal
= AllocSignal(-1);
298 write_signal_mask
= 1 << unit
->write_queue
->mp_SigBit
;
299 abort_signal_mask
= 1 << unit
->abort_signal
;
300 io_signal_mask
= 1 << unit
->io_signal
;
302 /* bundle all the signals together */
303 signal_mask
= write_signal_mask
| abort_signal_mask
| io_signal_mask
;
304 D(bug("[eth] signal mask 0x%08X\n", signal_mask
));
306 /* start waiting for read events */
307 unit
->irq
.fd
= unit
->fd
;
308 unit
->irq
.mode
= vHidd_UnixIO_RW
;
309 unit
->irq
.handler
= IOHandler
;
310 unit
->irq
.handlerData
= unit
;
311 Hidd_UnixIO_AddInterrupt(ETHBase
->unixio
, &unit
->irq
);
313 reply_port
= CreateMsgPort();
314 msg
= (struct Message
*) AllocVec(sizeof(struct Message
), MEMF_PUBLIC
| MEMF_CLEAR
);
315 msg
->mn_ReplyPort
= reply_port
;
316 msg
->mn_Length
= sizeof(struct Message
);
317 PutMsg(unit
->iosyncport
, msg
);
318 WaitPort(reply_port
);
321 DeleteMsgPort(reply_port
);
323 D(bug("[eth] [io:%d] iotask entering loop\n", unit
->num
));
331 events
= Hidd_UnixIO_Poll(ETHBase
->unixio
, unit
->fd
, vHidd_UnixIO_Read
| write_flag
, NULL
);
336 if (events
& vHidd_UnixIO_Read
)
338 D(bug("[eth] [io:%d] ready for read\n", unit
->num
));
339 eth_receive(ETHBase
, unit
);
342 if (events
& vHidd_UnixIO_Write
)
344 D(bug("[eth] [io:%d] ready for write\n", unit
->num
));
345 eth_send(ETHBase
, unit
);
347 if (IsMsgPortEmpty(unit
->write_queue
)) {
348 D(bug("[eth] [io:%d] all packets sent, will ignore future write events\n", unit
->num
));
354 D(bug("[eth] [io:%d] waiting for an event\n", unit
->num
));
356 signaled
= Wait(signal_mask
);
358 D(bug("[eth] [io:%d] iotask signaled\n", unit
->num
));
359 if (signaled
& write_signal_mask
)
361 D(bug("[eth] [io:%d] write requested, enabling\n", unit
->num
));
362 write_flag
= vHidd_UnixIO_Write
;
365 if (signaled
& abort_signal_mask
) {
366 D(bug("[eth] [io:%d] iotask received abort signal\n", unit
->num
));
370 D(bug("[eth] [io:%d] event processed, replying and looping\n", unit
->num
));
373 D(bug("[eth] [io:%d] iotask exiting\n", unit
->num
));
375 Hidd_UnixIO_RemInterrupt(ETHBase
->unixio
, &unit
->irq
);
377 FreeSignal(unit
->abort_signal
);
378 FreeSignal(unit
->io_signal
);
380 DeleteMsgPort(unit
->write_queue
);
382 msg
= (struct Message
*) AllocVec(sizeof(struct Message
), MEMF_PUBLIC
| MEMF_CLEAR
);
383 // FIXME: message may be freed before receiver gets it!
384 PutMsg(unit
->iosyncport
, msg
);