revert between 56095 -> 55830 in arch
[AROS.git] / workbench / devs / networks / prism2 / unit.c
blob9ea3b6b61bd8e10a12587c7aed63de138c3ef950
1 /*
3 Copyright (C) 2001-2017 Neil Cafferkey
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 MA 02111-1307, USA.
23 #include <exec/memory.h>
24 #include <exec/execbase.h>
25 #include <exec/errors.h>
26 #include <exec/tasks.h>
28 #include <proto/exec.h>
29 #ifndef __amigaos4__
30 #include <proto/alib.h>
31 #else
32 #include <clib/alib_protos.h>
33 #endif
34 #include <proto/utility.h>
35 #include <proto/dos.h>
36 #include <proto/timer.h>
38 #include "device.h"
39 #include "prism2.h"
41 #include "unit_protos.h"
42 #include "request_protos.h"
43 #include "encryption_protos.h"
44 #include "timer_protos.h"
47 #define TASK_PRIORITY 0
48 #define STACK_SIZE 4096
49 #define INT_MASK \
50 (P2_EVENTF_INFO | P2_EVENTF_ALLOCMEM | P2_EVENTF_TXFAIL | P2_EVENTF_RX)
51 #define MAX_S_REC_SIZE 50
52 #define LUCENT_DBM_OFFSET 149
53 #define INTERSIL_DBM_OFFSET 100
54 #define SCAN_BUFFER_SIZE 2000
55 #define BEACON_BUFFER_SIZE 8000
56 #define SCAN_TAG_COUNT 8 +10
57 #define INFO_TAG_COUNT 4 +10
58 #define LUCENT_PDA_ADDRESS 0x390000
59 #define LUCENT_PDA_SIZE 1000
60 #define FRAME_BUFFER_SIZE (P2_H2FRM_ETHFRAME + ETH_HEADERSIZE \
61 + SNAP_HEADERSIZE + ETH_MTU + EIV_SIZE + ICV_SIZE + MIC_SIZE)
64 static struct AddressRange *FindMulticastRange(struct DevUnit *unit,
65 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left,
66 UWORD upper_bound_right, struct DevBase *base);
67 static VOID SetMulticast(struct DevUnit *unit, struct DevBase *base);
68 static VOID RXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code));
69 static UBYTE *GetRXBuffer(struct DevUnit *unit, const UBYTE *address,
70 UWORD frag_no, UWORD *buffer_no, struct DevBase *base);
71 static VOID DistributeRXPacket(struct DevUnit *unit, UBYTE *frame,
72 struct DevBase *base);
73 static VOID CopyPacket(struct DevUnit *unit, struct IOSana2Req *request,
74 UWORD packet_size, UWORD packet_type, UBYTE *buffer,
75 struct DevBase *base);
76 static BOOL AddressFilter(struct DevUnit *unit, UBYTE *address,
77 struct DevBase *base);
78 static VOID SaveBeacon(struct DevUnit *unit, const UBYTE *frame,
79 struct DevBase *base);
80 static VOID TXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code));
81 static VOID InfoInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code));
82 static VOID ResetHandler(REG(a1, struct DevUnit *unit),
83 REG(a6, APTR int_code));
84 static VOID ReportEvents(struct DevUnit *unit, ULONG events,
85 struct DevBase *base);
86 static BOOL LoadFirmware(struct DevUnit *unit, struct DevBase *base);
87 static const TEXT *ParseNextSRecord(const TEXT *s, UBYTE *type, UBYTE *data,
88 UWORD *data_length, ULONG *location, struct DevBase *base);
89 static VOID P2DoCmd(struct DevUnit *unit, UWORD command, UWORD param,
90 struct DevBase *base);
91 static BOOL P2Seek(struct DevUnit *unit, UWORD path_no, UWORD rec_no,
92 UWORD offset, struct DevBase *base);
93 static VOID P2SetID(struct DevUnit *unit, UWORD rec_no, const UBYTE *id,
94 UWORD length, struct DevBase *base);
95 static VOID P2SetWord(struct DevUnit *unit, UWORD rec_no, UWORD value,
96 struct DevBase *base);
97 static UWORD P2GetWord(struct DevUnit *unit, UWORD rec_no,
98 struct DevBase *base);
99 static UWORD P2AllocMem(struct DevUnit *unit, UWORD size,
100 struct DevBase *base);
101 static VOID P2SetData(struct DevUnit *unit, UWORD rec_no, const UBYTE *data,
102 UWORD length, struct DevBase *base);
103 static BOOL P2ReadRec(struct DevUnit *unit, UWORD rec_no, APTR buffer,
104 UWORD max_length, struct DevBase *base);
105 static LONG ConvertLevel(struct DevUnit *unit, UWORD raw_level,
106 struct DevBase *base);
107 static LONG ConvertScanLevel(struct DevUnit *unit, UWORD raw_level,
108 struct DevBase *base);
109 static UBYTE *GetIE(UBYTE id, UBYTE *ies, UWORD ies_length,
110 struct DevBase *base);
111 static BOOL CompareMACAddresses(APTR mac1, APTR mac2);
112 static VOID UnitTask(struct DevUnit *unit);
113 static UPINT StrLen(const TEXT *s);
116 static const UBYTE snap_template[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
117 static const UBYTE scan_params[] = {0xff, 0x3f, 0x01, 0x00, 0x00, 0x00};
118 static const TEXT h1_firmware_file_name[] = "DEVS:Firmware/HermesI";
119 static const TEXT h2_firmware_file_name[] = "DEVS:Firmware/HermesII";
120 static const TEXT h25_firmware_file_name[] = "DEVS:Firmware/HermesII.5";
121 static const UBYTE h2_wpa_ie[] =
123 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00,
124 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50,
125 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02,
126 0x00, 0x00
130 #if defined(__mc68000) && !defined(__AROS__)
131 #define AddUnitTask(task, initial_pc, unit) \
132 ({ \
133 task->tc_SPReg -= sizeof(APTR); \
134 *((APTR *)task->tc_SPReg) = unit; \
135 AddTask(task, initial_pc, NULL); \
137 #endif
138 #ifdef __amigaos4__
139 #define AddUnitTask(task, initial_pc, unit) \
140 ({ \
141 struct TagItem _task_tags[] = \
142 {{AT_Param1, (UPINT)unit}, {TAG_END, 0}}; \
143 AddTask(task, initial_pc, NULL, _task_tags); \
145 #endif
146 #ifdef __MORPHOS__
147 #define AddUnitTask(task, initial_pc, unit) \
148 ({ \
149 struct TagItem _task_tags[] = \
151 {TASKTAG_CODETYPE, CODETYPE_PPC}, \
152 {TASKTAG_PC, (UPINT)initial_pc}, \
153 {TASKTAG_PPC_ARG1, (UPINT)unit}, \
154 {TAG_END, 1} \
155 }; \
156 struct TaskInitExtension _task_init = {0xfff0, 0, _task_tags}; \
157 AddTask(task, &_task_init, NULL); \
159 #endif
160 #ifdef __AROS__
161 #define AddUnitTask(task, initial_pc, unit) \
162 ({ \
163 struct TagItem _task_tags[] = \
164 {{TASKTAG_ARG1, (UPINT)unit}, {TAG_END, 0}}; \
165 NewAddTask(task, initial_pc, NULL, _task_tags); \
167 #endif
171 /****i* prism2.device/CreateUnit *******************************************
173 * NAME
174 * CreateUnit -- Create a unit.
176 * SYNOPSIS
177 * unit = CreateUnit(index, card, io_tags, bus)
179 * struct DevUnit *CreateUnit(ULONG, APTR, struct TagItem *, UWORD);
181 * FUNCTION
182 * Creates a new unit.
184 ****************************************************************************
188 struct DevUnit *CreateUnit(ULONG index, APTR card,
189 const struct TagItem *io_tags, UWORD bus, struct DevBase *base)
191 BOOL success = TRUE;
192 struct DevUnit *unit;
193 struct Task *task;
194 struct MsgPort *port;
195 UBYTE i;
196 APTR stack;
198 unit = AllocMem(sizeof(struct DevUnit), MEMF_CLEAR | MEMF_PUBLIC);
199 if(unit == NULL)
200 success = FALSE;
202 if(success)
204 unit->index = index;
205 unit->device = base;
206 unit->card = card;
207 unit->bus = bus;
208 unit->WordsIn =
209 (APTR)GetTagData(IOTAG_WordsIn, (UPINT)NULL, io_tags);
210 unit->WordsOut =
211 (APTR)GetTagData(IOTAG_WordsOut, (UPINT)NULL, io_tags);
212 unit->BEWordOut =
213 (APTR)GetTagData(IOTAG_BEWordOut, (UPINT)NULL, io_tags);
214 unit->LEWordIn =
215 (APTR)GetTagData(IOTAG_LEWordIn, (UPINT)NULL, io_tags);
216 unit->LEWordOut =
217 (APTR)GetTagData(IOTAG_LEWordOut, (UPINT)NULL, io_tags);
218 if(unit->WordsIn == NULL || unit->WordsOut == NULL
219 || unit->BEWordOut == NULL || unit->LEWordIn == NULL
220 || unit->LEWordOut == NULL)
221 success = FALSE;
224 if(success)
226 InitSemaphore(&unit->access_lock);
227 success = InitialiseAdapter(unit, FALSE, base);
228 unit->flags |= UNITF_HAVEADAPTER;
230 /* Create the message ports for queuing requests */
232 for(i = 0; i < REQUEST_QUEUE_COUNT; i++)
234 unit->request_ports[i] = port = AllocMem(sizeof(struct MsgPort),
235 MEMF_PUBLIC | MEMF_CLEAR);
236 if(port == NULL)
237 success = FALSE;
239 if(success)
241 NewList(&port->mp_MsgList);
242 port->mp_Flags = PA_IGNORE;
243 port->mp_SigTask = &unit->tx_int;
247 /* Allocate buffers */
249 unit->rx_buffer = AllocVec(FRAME_BUFFER_SIZE, MEMF_PUBLIC);
250 unit->rx_buffers = AllocVec(FRAME_BUFFER_SIZE * RX_BUFFER_COUNT,
251 MEMF_PUBLIC);
252 for(i = 0; i < RX_BUFFER_COUNT; i++)
253 unit->rx_fragment_nos[i] = -1;
254 unit->tx_buffer = AllocVec(ETH_MAXPACKETSIZE, MEMF_PUBLIC);
255 unit->rx_descriptor = AllocVec(FRAME_BUFFER_SIZE,
256 MEMF_PUBLIC | MEMF_CLEAR);
257 unit->tx_descriptor = AllocVec(FRAME_BUFFER_SIZE,
258 MEMF_PUBLIC | MEMF_CLEAR);
259 unit->scan_results_rec = AllocVec(SCAN_BUFFER_SIZE, MEMF_PUBLIC);
260 unit->next_beacon = unit->beacons =
261 AllocVec(BEACON_BUFFER_SIZE, MEMF_PUBLIC);
262 if(unit->rx_buffer == NULL || unit->rx_buffers == NULL
263 || unit->tx_buffer == NULL || unit->rx_descriptor == NULL
264 || unit->tx_descriptor == NULL || unit->scan_results_rec == NULL
265 || unit->beacons == NULL)
266 success = FALSE;
269 if(success)
271 NewList((APTR)&unit->openers);
272 NewList((APTR)&unit->type_trackers);
273 NewList((APTR)&unit->multicast_ranges);
275 /* Record maximum speed in BPS */
277 unit->speed = 11000000;
279 /* Initialise status, transmit, receive and stats interrupts */
281 unit->status_int.is_Node.ln_Name =
282 base->device.dd_Library.lib_Node.ln_Name;
283 unit->status_int.is_Code = (APTR)StatusInt;
284 unit->status_int.is_Data = unit;
286 unit->rx_int.is_Node.ln_Name =
287 base->device.dd_Library.lib_Node.ln_Name;
288 unit->rx_int.is_Code = (APTR)RXInt;
289 unit->rx_int.is_Data = unit;
291 unit->tx_int.is_Node.ln_Name =
292 base->device.dd_Library.lib_Node.ln_Name;
293 unit->tx_int.is_Code = (APTR)TXInt;
294 unit->tx_int.is_Data = unit;
296 unit->info_int.is_Node.ln_Name =
297 base->device.dd_Library.lib_Node.ln_Name;
298 unit->info_int.is_Code = (APTR)InfoInt;
299 unit->info_int.is_Data = unit;
301 unit->reset_handler.is_Node.ln_Name =
302 base->device.dd_Library.lib_Node.ln_Name;
303 unit->reset_handler.is_Code = (APTR)ResetHandler;
304 unit->reset_handler.is_Data = unit;
306 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
309 if(success)
311 /* Create a new task */
313 unit->task = task =
314 AllocMem(sizeof(struct Task), MEMF_PUBLIC | MEMF_CLEAR);
315 if(task == NULL)
316 success = FALSE;
319 if(success)
321 stack = AllocMem(STACK_SIZE, MEMF_PUBLIC);
322 if(stack == NULL)
323 success = FALSE;
326 if(success)
328 /* Initialise and start task */
330 task->tc_Node.ln_Type = NT_TASK;
331 task->tc_Node.ln_Pri = TASK_PRIORITY;
332 task->tc_Node.ln_Name = base->device.dd_Library.lib_Node.ln_Name;
333 task->tc_SPUpper = stack + STACK_SIZE;
334 task->tc_SPLower = stack;
335 task->tc_SPReg = task->tc_SPUpper;
336 NewList(&task->tc_MemEntry);
338 if(AddUnitTask(task, UnitTask, unit) != NULL)
339 unit->flags |= UNITF_TASKADDED;
340 else
341 success = FALSE;
344 if(success)
346 /* Set default wireless options */
348 unit->mode = S2PORT_MANAGED;
351 if(!success)
353 DeleteUnit(unit, base);
354 unit = NULL;
357 return unit;
362 /****i* prism2.device/DeleteUnit *******************************************
364 * NAME
365 * DeleteUnit -- Delete a unit.
367 * SYNOPSIS
368 * DeleteUnit(unit)
370 * VOID DeleteUnit(struct DevUnit *);
372 * FUNCTION
373 * Deletes a unit.
375 * INPUTS
376 * unit - Device unit (may be NULL).
378 * RESULT
379 * None.
381 ****************************************************************************
385 VOID DeleteUnit(struct DevUnit *unit, struct DevBase *base)
387 UBYTE i;
388 struct Task *task;
390 if(unit != NULL)
392 /* Remove task */
394 task = unit->task;
395 if(task != NULL)
397 if((unit->flags & UNITF_TASKADDED) != 0)
399 RemTask(task);
400 FreeMem(task->tc_SPLower, STACK_SIZE);
402 FreeMem(task, sizeof(struct Task));
405 /* Free request queues */
407 for(i = 0; i < REQUEST_QUEUE_COUNT; i++)
409 if(unit->request_ports[i] != NULL)
410 FreeMem(unit->request_ports[i], sizeof(struct MsgPort));
413 /* Go offline */
415 if((unit->flags & UNITF_ONLINE) != 0) /* Needed! */
416 GoOffline(unit, base);
418 /* Clear target SSID */
420 P2SetID(unit, P2_REC_DESIREDSSID, unit->ssid, 0, base);
422 /* Free buffers and unit structure */
424 FreeVec(unit->beacons);
425 FreeVec(unit->scan_results_rec);
426 FreeVec(unit->tx_descriptor);
427 FreeVec(unit->rx_descriptor);
428 FreeVec(unit->tx_buffer);
429 FreeVec(unit->rx_buffers);
430 FreeVec(unit->rx_buffer);
432 FreeMem(unit, sizeof(struct DevUnit));
435 return;
440 /****i* prism2.device/InitialiseAdapter ************************************
442 * NAME
443 * InitialiseAdapter
445 * SYNOPSIS
446 * success = InitialiseAdapter(unit, reinsertion)
448 * BOOL InitialiseAdapter(struct DevUnit *, BOOL);
450 * FUNCTION
452 * INPUTS
453 * unit
454 * reinsertion
456 * RESULT
457 * success - Success indicator.
459 ****************************************************************************
463 BOOL InitialiseAdapter(struct DevUnit *unit, BOOL reinsertion,
464 struct DevBase *base)
466 UWORD id, version, revision, i;
467 BOOL success = TRUE, loaded;
468 UBYTE address[ETH_ADDRESSSIZE];
469 WORD length;
471 /* Wait for card to be ready following bus-specific reset, then start
472 it */
474 while((unit->LEWordIn(unit->card, P2_REG_COMMAND)
475 & P2_REG_COMMANDF_BUSY) != 0);
477 P2DoCmd(unit, P2_CMD_INIT, 0, base);
479 /* Determine firmware type */
481 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_NICIDENTITY, base);
482 P2Seek(unit, 1, P2_REC_NICIDENTITY, 4, base);
483 id = unit->LEWordIn(unit->card, P2_REG_DATA1);
484 unit->LEWordIn(unit->card, P2_REG_DATA1);
485 version = unit->LEWordIn(unit->card, P2_REG_DATA1);
486 revision = unit->LEWordIn(unit->card, P2_REG_DATA1);
488 if((id & 0x8000) != 0)
490 if(version == 0)
491 unit->firmware_type = SYMBOL_FIRMWARE;
492 else
493 unit->firmware_type = INTERSIL_FIRMWARE;
495 else
497 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_PRIIDENTITY, base);
498 P2Seek(unit, 1, P2_REC_PRIIDENTITY, 0, base);
499 length = unit->LEWordIn(unit->card, P2_REG_DATA1);
500 if(length == 5)
501 unit->firmware_type = LUCENT_FIRMWARE;
502 else
504 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_STAIDENTITY, base);
505 P2Seek(unit, 1, P2_REC_STAIDENTITY, 4, base);
506 id = unit->LEWordIn(unit->card, P2_REG_DATA1);
507 unit->LEWordIn(unit->card, P2_REG_DATA1);
508 version = unit->LEWordIn(unit->card, P2_REG_DATA1);
509 revision = unit->LEWordIn(unit->card, P2_REG_DATA1);
510 if(version > 1)
511 unit->firmware_type = HERMES2G_FIRMWARE;
512 else
513 unit->firmware_type = HERMES2_FIRMWARE;
517 /* Download firmware if necessary or available */
519 loaded = LoadFirmware(unit, base);
520 if(!loaded && unit->firmware_type >= HERMES2_FIRMWARE)
521 success = FALSE;
523 if(success)
525 /* Determine features, and get offsets of certain fields within frame
526 descriptors */
528 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_STAIDENTITY, base);
529 P2Seek(unit, 1, P2_REC_STAIDENTITY, 4, base);
530 unit->LEWordIn(unit->card, P2_REG_DATA1);
531 unit->LEWordIn(unit->card, P2_REG_DATA1);
532 version = unit->LEWordIn(unit->card, P2_REG_DATA1);
533 revision = unit->LEWordIn(unit->card, P2_REG_DATA1);
535 if(P2GetWord(unit, P2_REC_HASWEP, base) != 0)
536 unit->flags |= UNITF_HASWEP | UNITF_HARDWEP;
538 unit->ethernet_offset = P2_FRM_ETHFRAME;
539 unit->data_offset = P2_FRM_DATA;
540 unit->txcontrol_offset = P2_FRM_TXCONTROL;
541 unit->datalen_offset = P2_FRM_DATALEN;
543 if(unit->firmware_type == LUCENT_FIRMWARE)
545 if(version > 6 || version == 6 && revision >= 6)
546 unit->flags |= UNITF_HASADHOC;
547 if(version >= 9)
549 unit->flags |= UNITF_HASTKIP | UNITF_HARDTKIP;
550 unit->txcontrol_offset = P2_FRM_ALTTXCONTROL;
553 else if(unit->firmware_type >= HERMES2_FIRMWARE)
555 unit->flags |= UNITF_HASADHOC | UNITF_HASTKIP | UNITF_HARDTKIP;
556 unit->ethernet_offset = P2_H2FRM_ETHFRAME;
557 unit->data_offset = P2_H2FRM_DATA;
558 unit->txcontrol_offset = P2_H2FRM_TXCONTROL;
559 unit->datalen_offset = P2_H2FRM_DATALEN;
561 else if(unit->firmware_type == INTERSIL_FIRMWARE)
563 unit->flags |= UNITF_HASADHOC | UNITF_HASWEP;
564 if(version == 1 && revision >= 7)
565 unit->flags |= UNITF_HASTKIP | UNITF_HASCCMP;
568 /* Get default channel and MAC address */
570 unit->channel = P2GetWord(unit, P2_REC_OWNCHNL, base);
571 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_ADDRESS, base);
572 P2Seek(unit, 1, P2_REC_ADDRESS, 4, base);
573 unit->WordsIn(unit->card, P2_REG_DATA1, (UWORD *)address,
574 ETH_ADDRESSSIZE / 2);
576 /* If card has been re-inserted, check it has the same address as
577 before */
579 if(reinsertion)
581 for(i = 0; i < ETH_ADDRESSSIZE; i++)
582 if(address[i] != unit->default_address[i])
583 success = FALSE;
587 if(success)
589 CopyMem(address, unit->default_address, ETH_ADDRESSSIZE);
591 /* Get initial on-card TX buffer */
593 unit->tx_frame_id = P2AllocMem(unit, FRAME_BUFFER_SIZE, base);
595 /* Set IV sizes */
597 if((unit->flags & UNITF_HARDWEP) == 0)
598 unit->iv_sizes[S2ENC_WEP] = IV_SIZE;
599 if((unit->flags & UNITF_HARDTKIP) == 0)
600 unit->iv_sizes[S2ENC_TKIP] = EIV_SIZE;
601 unit->iv_sizes[S2ENC_CCMP] = EIV_SIZE;
603 /* Set encryption functions */
605 unit->fragment_encrypt_functions[S2ENC_NONE] = WriteClearFragment;
607 if((unit->flags & UNITF_HARDWEP) != 0)
608 unit->fragment_encrypt_functions[S2ENC_WEP] = WriteClearFragment;
609 else
610 unit->fragment_encrypt_functions[S2ENC_WEP] = EncryptWEPFragment;
612 if((unit->flags & UNITF_HARDTKIP) != 0)
613 unit->fragment_encrypt_functions[S2ENC_TKIP] = WriteClearFragment;
614 else
615 unit->fragment_encrypt_functions[S2ENC_TKIP] = EncryptTKIPFragment;
617 unit->fragment_encrypt_functions[S2ENC_CCMP] = EncryptCCMPFragment;
619 /* Set decryption functions */
621 unit->fragment_decrypt_functions[S2ENC_NONE] = ReadClearFragment;
623 if((unit->flags & UNITF_HARDWEP) != 0)
624 unit->fragment_decrypt_functions[S2ENC_WEP] = ReadClearFragment;
625 else
626 unit->fragment_decrypt_functions[S2ENC_WEP] = DecryptWEPFragment;
628 if((unit->flags & UNITF_HARDTKIP) != 0)
629 unit->fragment_decrypt_functions[S2ENC_TKIP] = ReadClearFragment;
630 else
631 unit->fragment_decrypt_functions[S2ENC_TKIP] = DecryptTKIPFragment;
633 unit->fragment_decrypt_functions[S2ENC_CCMP] = DecryptCCMPFragment;
636 /* Return */
638 return success;
643 /****i* prism2.device/ConfigureAdapter *************************************
645 * NAME
646 * ConfigureAdapter -- Set up card for transmission/reception.
648 * SYNOPSIS
649 * ConfigureAdapter(unit)
651 * VOID ConfigureAdapter(struct DevUnit *);
653 ****************************************************************************
657 VOID ConfigureAdapter(struct DevUnit *unit, struct DevBase *base)
659 UWORD i, key_length, port_type, lowest_enc = S2ENC_CCMP,
660 highest_enc = S2ENC_NONE, enc_flags, size, value;
661 const struct KeyUnion *keys;
663 /* Set MAC address */
665 P2SetData(unit, P2_REC_ADDRESS, unit->address, ETH_ADDRESSSIZE,
666 base);
668 /* Decide on promiscuous mode */
670 P2SetWord(unit, P2_REC_PROMISC, FALSE, base);
671 SetMulticast(unit, base);
673 /* Set wireless parameters */
675 if(unit->mode == S2PORT_ADHOC)
677 P2SetWord(unit, P2_REC_OWNCHNL, unit->channel, base);
678 P2SetID(unit, P2_REC_OWNSSID, unit->ssid, unit->ssid_length, base);
680 if(unit->mode == S2PORT_MANAGED)
681 port_type = 1;
682 else
683 port_type = 0;
684 if((unit->flags & UNITF_ONLINE) == 0)
685 P2SetWord(unit, P2_REC_PORTTYPE, port_type, base);
686 P2SetWord(unit, P2_REC_CREATEIBSS, unit->mode == S2PORT_ADHOC, base);
687 P2SetID(unit, P2_REC_DESIREDSSID, unit->ssid, unit->ssid_length, base);
689 /* Determine highest encryption type in use */
691 for(i = 0; i < WIFI_KEYCOUNT; i++)
693 if(unit->keys[i].type > highest_enc)
694 highest_enc = unit->keys[i].type;
695 if(unit->keys[i].type < lowest_enc)
696 lowest_enc = unit->keys[i].type;
699 if(unit->wpa_ie[1] != 0)
700 highest_enc = S2ENC_TKIP;
702 /* Allow reception of beacon/probe-response frames */
704 if(unit->firmware_type == INTERSIL_FIRMWARE)
705 P2SetWord(unit, P2_REC_RXMGMTFRAMES, 1, base);
707 /* Transmit at 11Mbps, with fallback */
709 if(unit->firmware_type == INTERSIL_FIRMWARE
710 || unit->firmware_type == SYMBOL_FIRMWARE)
711 P2SetWord(unit, P2_REC_TXRATE, 0xf, base);
713 /* Configure authentication and encryption */
715 if(unit->firmware_type >= LUCENT_FIRMWARE)
717 /* Set authentication and encryption modes */
719 P2SetWord(unit, P2_REC_ALTAUTHTYPE, unit->auth_types, base);
721 P2SetWord(unit, P2_REC_ALTENCRYPTION, highest_enc, base);
723 /* Set up firmware-based WEP encryption if appropriate */
725 if(highest_enc == S2ENC_WEP && (unit->flags & UNITF_HARDWEP) != 0)
727 P2SetWord(unit, P2_REC_ALTTXCRYPTKEY, unit->tx_key_no, base);
728 P2Seek(unit, 1, P2_REC_DEFLTCRYPTKEYS, 0, base);
729 unit->LEWordOut(unit->card, P2_REG_DATA1, P2_ALTWEPRECLEN);
730 unit->LEWordOut(unit->card, P2_REG_DATA1, P2_REC_DEFLTCRYPTKEYS);
731 keys = unit->keys;
732 for(i = 0; i < WIFI_KEYCOUNT; i++)
734 key_length = keys[i].u.wep.length;
735 if(key_length == 0)
736 key_length = WIFI_WEP128LEN;
737 unit->LEWordOut(unit->card, P2_REG_DATA1, key_length);
738 unit->WordsOut(unit->card, P2_REG_DATA1,
739 (UWORD *)keys[i].u.wep.key, (key_length + 1) / 2);
742 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE,
743 P2_REC_DEFLTCRYPTKEYS, base);
746 /* Set key management suite to PSK */
748 if(highest_enc > S2ENC_WEP)
750 value = (unit->firmware_type >= HERMES2_FIRMWARE) ? 4 : 2;
751 P2SetWord(unit, P2_REC_KEYMGMTSUITE, value, base);
754 else
756 /* Set authentication mode */
758 P2SetWord(unit, P2_REC_AUTHTYPE, unit->auth_types, base);
760 /* Set encryption flags */
762 if(highest_enc > S2ENC_NONE)
763 enc_flags = P2_REC_ENCRYPTIONF_ENABLE;
764 else
765 enc_flags = 0;
767 if(highest_enc > S2ENC_WEP
768 || highest_enc == S2ENC_WEP && (unit->flags & UNITF_HARDWEP) == 0)
769 enc_flags |= P2_REC_ENCRYPTIONF_HOSTDECRYPT
770 | P2_REC_ENCRYPTIONF_HOSTENCRYPT;
771 P2SetWord(unit, P2_REC_ENCRYPTION, enc_flags, base);
773 /* Set up firmware-based WEP encryption if appropriate */
775 if(highest_enc == S2ENC_WEP && (unit->flags & UNITF_HARDWEP) != 0)
777 P2SetWord(unit, P2_REC_TXCRYPTKEY, unit->tx_key_no, base);
779 keys = unit->keys;
780 for(i = 0; i < WIFI_KEYCOUNT; i++)
782 key_length = keys[i].u.wep.length;
783 if(key_length == 0)
784 key_length = keys[unit->tx_key_no].u.wep.length;
785 P2SetData(unit, P2_REC_CRYPTKEY0 + i, keys[i].u.wep.key,
786 key_length, base);
790 /* Set or clear WPA IE */
792 if(highest_enc > S2ENC_WEP)
793 size = unit->wpa_ie[1] + 2;
794 else
795 size = 0;
796 P2SetID(unit, P2_REC_WPAIE, unit->wpa_ie, size, base);
798 /* Let supplicant handle association and roaming */
800 P2SetWord(unit, P2_REC_ROAMINGMODE, 3, base);
803 /* Restart the transceiver if we're already online */
805 if((unit->flags & UNITF_ONLINE) != 0)
807 P2DoCmd(unit, P2_CMD_DISABLE, 0, base);
808 P2DoCmd(unit, P2_CMD_ENABLE, 0, base);
810 /* Attempt to join specified network */
812 if(unit->firmware_type == INTERSIL_FIRMWARE)
814 unit->bssid[ETH_ADDRESSSIZE] = unit->channel;
815 P2SetData(unit, P2_REC_JOIN, unit->bssid, ETH_ADDRESSSIZE + 2,
816 base);
820 /* Return */
822 return;
827 /****i* prism2.device/GoOnline *********************************************
829 * NAME
830 * GoOnline -- Enable transmission/reception.
832 * SYNOPSIS
833 * GoOnline(unit)
835 * VOID GoOnline(struct DevUnit *);
837 ****************************************************************************
841 VOID GoOnline(struct DevUnit *unit, struct DevBase *base)
843 /* Enable interrupts */
845 unit->flags |= UNITF_ONLINE;
846 unit->LEWordOut(unit->card, P2_REG_INTMASK, INT_MASK);
848 /* Enable the transceiver */
850 P2DoCmd(unit, P2_CMD_ENABLE, 0, base);
852 /* Record start time and report Online event */
854 GetSysTime(&unit->stats.LastStart);
855 ReportEvents(unit, S2EVENT_ONLINE, base);
857 return;
862 /****i* prism2.device/GoOffline ********************************************
864 * NAME
865 * GoOffline -- Disable transmission/reception.
867 * SYNOPSIS
868 * GoOffline(unit)
870 * VOID GoOffline(struct DevUnit *);
872 * FUNCTION
874 * INPUTS
875 * unit
877 * RESULT
878 * None.
880 ****************************************************************************
884 VOID GoOffline(struct DevUnit *unit, struct DevBase *base)
886 unit->flags &= ~UNITF_ONLINE;
887 if((unit->flags & UNITF_HAVEADAPTER) != 0)
889 /* Stop interrupts */
891 unit->LEWordOut(unit->card, P2_REG_INTMASK, 0);
892 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
894 /* Update statistics */
896 UpdateStats(unit, base);
898 /* Stop transmission and reception */
900 P2DoCmd(unit, P2_CMD_DISABLE, 0, base);
903 /* Flush pending read and write requests */
905 FlushUnit(unit, WRITE_QUEUE, S2ERR_OUTOFSERVICE, base);
907 /* Report Offline event and return */
909 ReportEvents(unit, S2EVENT_OFFLINE, base);
910 return;
915 /****i* prism2.device/SetOptions *******************************************
917 * NAME
918 * SetOptions -- Set and use interface options.
920 * SYNOPSIS
921 * SetOptions(unit, tag_list)
923 * VOID SetOptions(struct DevUnit *, struct TagItem *);
925 ****************************************************************************
929 VOID SetOptions(struct DevUnit *unit, const struct TagItem *tag_list,
930 struct DevBase *base)
932 struct TagItem *tag_item, *tlist = (struct TagItem *)tag_list;
933 const TEXT *id;
934 UPINT length;
935 const UBYTE *ie;
937 while((tag_item = NextTagItem(&tlist)) != NULL)
939 switch(tag_item->ti_Tag)
941 case S2INFO_SSID:
942 id = (const TEXT *)tag_item->ti_Data;
943 length = StrLen(id);
944 CopyMem(id, unit->ssid, length);
945 unit->ssid_length = length;
946 break;
948 case S2INFO_BSSID:
949 CopyMem((APTR)tag_item->ti_Data, unit->bssid, ETH_ADDRESSSIZE);
950 break;
952 case S2INFO_DefaultKeyNo:
953 unit->tx_key_no = tag_item->ti_Data;
954 break;
956 case S2INFO_PortType:
957 unit->mode = tag_item->ti_Data;
958 break;
960 case S2INFO_Channel:
961 unit->channel = tag_item->ti_Data;
962 break;
964 case S2INFO_WPAInfo:
965 if(tag_item->ti_Data != (UPINT)NULL)
967 /* Hermes-II uses an "unusual" WPA IE in its association
968 request. So we use a matching IE everywhere else too */
970 if(unit->firmware_type >= HERMES2_FIRMWARE)
971 ie = h2_wpa_ie;
972 else
973 ie = (const UBYTE *)tag_item->ti_Data;
974 CopyMem(ie, unit->wpa_ie, ie[1] + 2);
976 else
978 unit->wpa_ie[0] = 0;
979 unit->wpa_ie[1] = 0;
981 break;
983 case S2INFO_AuthTypes:
984 unit->auth_types = tag_item->ti_Data;
985 break;
989 return;
994 /****i* prism2.device/SetKey ***********************************************
996 * NAME
997 * SetKey -- Set an encryption key.
999 * SYNOPSIS
1000 * SetKey(unit, index, type, key, key_length,
1001 * rx_counter)
1003 * VOID SetKey(struct DevUnit *, ULONG, ULONG, UBYTE *, ULONG,
1004 * UBYTE *);
1006 ****************************************************************************
1010 VOID SetKey(struct DevUnit *unit, ULONG index, ULONG type, const UBYTE *key,
1011 ULONG key_length, const UBYTE *rx_counter, struct DevBase *base)
1013 struct KeyUnion *slot;
1014 const UBYTE tx_counter[8] = {0, 0, 0, 0, 0x10, 0, 0, 0};
1015 UWORD i;
1016 struct EClockVal eclock;
1018 Disable();
1019 slot = &unit->keys[index];
1020 switch(type)
1022 case S2ENC_WEP:
1023 CopyMem(key, slot->u.wep.key, key_length);
1024 slot->u.wep.length = key_length;
1026 if((unit->flags & UNITF_HARDWEP) == 0)
1028 /* Create a reasonably random IV */
1030 ReadEClock(&eclock);
1031 slot->u.wep.tx_iv = FastRand(eclock.ev_lo ^ eclock.ev_hi);
1034 break;
1036 case S2ENC_TKIP:
1037 CopyMem(key, slot->u.tkip.key, 16);
1038 CopyMem(key + 16, slot->u.tkip.tx_mic_key, MIC_SIZE);
1039 CopyMem(key + 24, slot->u.tkip.rx_mic_key, MIC_SIZE);
1040 slot->u.tkip.tx_iv_low = 0;
1041 slot->u.tkip.tx_iv_high = 0;
1042 slot->u.tkip.rx_iv_low = LEWord(*(UWORD *)rx_counter);
1043 slot->u.tkip.rx_iv_high = LELong(*(ULONG *)(rx_counter + 2));
1044 slot->u.tkip.tx_ttak_set = FALSE;
1045 slot->u.tkip.rx_ttak_set = FALSE;
1047 if((unit->flags & UNITF_HARDTKIP) != 0)
1049 /* For Hermes, load parameters for hardware encryption. The
1050 pairwise key is treated differently from group keys on
1051 Hermes-II, but not on Hermes-I */
1053 if(unit->firmware_type >= HERMES2_FIRMWARE && index == 0)
1055 P2Seek(unit, 1, P2_REC_ADDMAPPEDTKIPKEY, 0, base);
1056 unit->LEWordOut(unit->card, P2_REG_DATA1, 28);
1057 unit->LEWordOut(unit->card, P2_REG_DATA1,
1058 P2_REC_ADDMAPPEDTKIPKEY);
1059 unit->WordsOut(unit->card, P2_REG_DATA1,
1060 (UWORD *)unit->bssid, ETH_ADDRESSSIZE / 2);
1061 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)key,
1062 16 / 2);
1063 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)tx_counter,
1064 8 / 2);
1065 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)rx_counter,
1066 6 / 2);
1067 unit->LEWordOut(unit->card, P2_REG_DATA1, 0);
1068 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)key + 16,
1069 16 / 2);
1070 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE,
1071 P2_REC_ADDMAPPEDTKIPKEY, base);
1073 else
1075 P2Seek(unit, 1, P2_REC_ADDDEFAULTTKIPKEY, 0, base);
1076 unit->LEWordOut(unit->card, P2_REG_DATA1, 26);
1077 unit->LEWordOut(unit->card, P2_REG_DATA1,
1078 P2_REC_ADDDEFAULTTKIPKEY);
1079 if(index == unit->tx_key_no)
1080 index |= 0x8000;
1081 unit->LEWordOut(unit->card, P2_REG_DATA1, index);
1082 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)rx_counter,
1083 6 / 2);
1084 unit->LEWordOut(unit->card, P2_REG_DATA1, 0);
1085 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)key,
1086 32 / 2);
1087 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)tx_counter,
1088 8 / 2);
1089 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE,
1090 P2_REC_ADDDEFAULTTKIPKEY, base);
1093 else
1095 /* Convert key to native endianness */
1097 for(i = 0; i < 8; i++)
1098 slot->u.tkip.key[i] = LEWord(slot->u.tkip.key[i]);
1101 break;
1103 case S2ENC_CCMP:
1104 CopyMem(key, slot->u.ccmp.key, 16);
1105 slot->u.ccmp.tx_iv_low = 0;
1106 slot->u.ccmp.tx_iv_high = 0;
1107 slot->u.ccmp.rx_iv_low = LEWord(*(UWORD *)rx_counter);
1108 slot->u.ccmp.rx_iv_high = LELong(*(ULONG *)(rx_counter + 2));
1109 slot->u.ccmp.stream_set = FALSE;
1112 /* Clear TKIP key if necessary */
1114 if(slot->type == S2ENC_TKIP && type != S2ENC_TKIP)
1116 if(unit->firmware_type >= HERMES2_FIRMWARE && index == 0)
1117 P2SetData(unit, P2_REC_REMMAPPEDTKIPKEY, unit->bssid,
1118 ETH_ADDRESSSIZE, base);
1119 else if(unit->firmware_type >= LUCENT_FIRMWARE)
1120 P2SetWord(unit, P2_REC_REMDEFAULTTKIPKEY, index, base);
1123 /* Update type of key in selected slot */
1125 slot->type = type;
1126 Enable();
1128 return;
1133 /****i* prism2.device/AddMulticastRange ************************************
1135 * NAME
1136 * AddMulticastRange
1138 * SYNOPSIS
1139 * success = AddMulticastRange(unit, lower_bound, upper_bound)
1141 * BOOL AddMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1143 ****************************************************************************
1147 BOOL AddMulticastRange(struct DevUnit *unit, const UBYTE *lower_bound,
1148 const UBYTE *upper_bound, struct DevBase *base)
1150 struct AddressRange *range;
1151 ULONG lower_bound_left, upper_bound_left;
1152 UWORD lower_bound_right, upper_bound_right;
1154 lower_bound_left = BELong(*((ULONG *)lower_bound));
1155 lower_bound_right = BEWord(*((UWORD *)(lower_bound + 4)));
1156 upper_bound_left = BELong(*((ULONG *)upper_bound));
1157 upper_bound_right = BEWord(*((UWORD *)(upper_bound + 4)));
1159 range = FindMulticastRange(unit, lower_bound_left, lower_bound_right,
1160 upper_bound_left, upper_bound_right, base);
1162 if(range != NULL)
1163 range->add_count++;
1164 else
1166 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
1167 if(range != NULL)
1169 range->lower_bound_left = lower_bound_left;
1170 range->lower_bound_right = lower_bound_right;
1171 range->upper_bound_left = upper_bound_left;
1172 range->upper_bound_right = upper_bound_right;
1173 range->add_count = 1;
1175 Disable();
1176 AddTail((APTR)&unit->multicast_ranges, (APTR)range);
1177 unit->range_count++;
1178 SetMulticast(unit, base);
1179 Enable();
1183 return range != NULL;
1188 /****i* prism2.device/RemMulticastRange ************************************
1190 * NAME
1191 * RemMulticastRange
1193 * SYNOPSIS
1194 * found = RemMulticastRange(unit, lower_bound, upper_bound)
1196 * BOOL RemMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1198 ****************************************************************************
1202 BOOL RemMulticastRange(struct DevUnit *unit, const UBYTE *lower_bound,
1203 const UBYTE *upper_bound, struct DevBase *base)
1205 struct AddressRange *range;
1206 ULONG lower_bound_left, upper_bound_left;
1207 UWORD lower_bound_right, upper_bound_right;
1209 lower_bound_left = BELong(*((ULONG *)lower_bound));
1210 lower_bound_right = BEWord(*((UWORD *)(lower_bound + 4)));
1211 upper_bound_left = BELong(*((ULONG *)upper_bound));
1212 upper_bound_right = BEWord(*((UWORD *)(upper_bound + 4)));
1214 range = FindMulticastRange(unit, lower_bound_left, lower_bound_right,
1215 upper_bound_left, upper_bound_right, base);
1217 if(range != NULL)
1219 if(--range->add_count == 0)
1221 Disable();
1222 Remove((APTR)range);
1223 unit->range_count--;
1224 SetMulticast(unit, base);
1225 Enable();
1226 FreeMem(range, sizeof(struct AddressRange));
1230 return range != NULL;
1235 /****i* prism2.device/FindMulticastRange ***********************************
1237 * NAME
1238 * FindMulticastRange
1240 * SYNOPSIS
1241 * range = FindMulticastRange(unit, lower_bound_left,
1242 * lower_bound_right, upper_bound_left, upper_bound_right)
1244 * struct AddressRange *FindMulticastRange(struct DevUnit *, ULONG,
1245 * UWORD, ULONG, UWORD);
1247 ****************************************************************************
1251 static struct AddressRange *FindMulticastRange(struct DevUnit *unit,
1252 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left,
1253 UWORD upper_bound_right, struct DevBase *base)
1255 struct AddressRange *range, *tail;
1256 BOOL found = FALSE;
1258 range = (APTR)unit->multicast_ranges.mlh_Head;
1259 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
1261 while(range != tail && !found)
1263 if(lower_bound_left == range->lower_bound_left &&
1264 lower_bound_right == range->lower_bound_right &&
1265 upper_bound_left == range->upper_bound_left &&
1266 upper_bound_right == range->upper_bound_right)
1267 found = TRUE;
1268 else
1269 range = (APTR)range->node.mln_Succ;
1272 if(!found)
1273 range = NULL;
1275 return range;
1280 /****i* prism2.device/SetMulticast *****************************************
1282 * NAME
1283 * SetMulticast
1285 * SYNOPSIS
1286 * SetMulticast(unit)
1288 * VOID SetMulticast(struct DevUnit *);
1290 ****************************************************************************
1294 static VOID SetMulticast(struct DevUnit *unit, struct DevBase *base)
1296 ULONG address_left;
1297 UWORD address_right, i = 0;
1298 struct AddressRange *range, *tail;
1299 BOOL range_ended;
1301 /* Fill in multicast list */
1303 P2Seek(unit, 1, P2_REC_MCASTLIST, 4, base);
1305 range = (APTR)unit->multicast_ranges.mlh_Head;
1306 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
1308 while(range != tail && i < P2_MAXMCASTENTRIES)
1310 address_left = range->lower_bound_left;
1311 address_right = range->lower_bound_right;
1312 range_ended = FALSE;
1314 while(!range_ended && i++ < P2_MAXMCASTENTRIES)
1316 unit->BEWordOut(unit->card, P2_REG_DATA1,
1317 (UWORD)(address_left >> 16));
1318 unit->BEWordOut(unit->card, P2_REG_DATA1, (UWORD)address_left);
1319 unit->BEWordOut(unit->card, P2_REG_DATA1, (UWORD)address_right);
1321 if(address_left == range->upper_bound_left &&
1322 address_right == range->upper_bound_right)
1323 range_ended = TRUE;
1324 if(++address_right == 0)
1325 address_left++;
1328 if(range_ended)
1329 range = (APTR)range->node.mln_Succ;
1332 /* Turn promiscuous mode on or off depending on the previous state and
1333 whether we've overflowed the multicast list */
1335 if((unit->flags & UNITF_PROM) == 0)
1337 if(range != tail)
1339 if((unit->flags & UNITF_ALLMCAST) == 0)
1341 P2SetWord(unit, P2_REC_PROMISC, TRUE, base);
1342 unit->flags |= UNITF_ALLMCAST;
1345 else
1347 if((unit->flags & UNITF_ALLMCAST) != 0)
1349 P2SetWord(unit, P2_REC_PROMISC, FALSE, base);
1350 unit->flags &= ~UNITF_ALLMCAST;
1353 /* Only commit multicast list if promiscuity is off */
1355 P2Seek(unit, 1, P2_REC_MCASTLIST, 0, base);
1356 unit->LEWordOut(unit->card, P2_REG_DATA1,
1357 1 + ETH_ADDRESSSIZE / 2 * i);
1358 unit->LEWordOut(unit->card, P2_REG_DATA1, P2_REC_MCASTLIST);
1359 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, P2_REC_MCASTLIST,
1360 base);
1364 return;
1369 /****i* prism2.device/FindTypeStats ****************************************
1371 * NAME
1372 * FindTypeStats
1374 * SYNOPSIS
1375 * stats = FindTypeStats(unit, list,
1376 * packet_type)
1378 * struct TypeStats *FindTypeStats(struct DevUnit *, struct MinList *,
1379 * ULONG);
1381 ****************************************************************************
1385 struct TypeStats *FindTypeStats(struct DevUnit *unit, struct MinList *list,
1386 ULONG packet_type, struct DevBase *base)
1388 struct TypeStats *stats, *tail;
1389 BOOL found = FALSE;
1391 stats = (APTR)list->mlh_Head;
1392 tail = (APTR)&list->mlh_Tail;
1394 while(stats != tail && !found)
1396 if(stats->packet_type == packet_type)
1397 found = TRUE;
1398 else
1399 stats = (APTR)stats->node.mln_Succ;
1402 if(!found)
1403 stats = NULL;
1405 return stats;
1410 /****i* prism2.device/FlushUnit ********************************************
1412 * NAME
1413 * FlushUnit
1415 * SYNOPSIS
1416 * FlushUnit(unit, last_queue, error)
1418 * VOID FlushUnit(struct DevUnit *, UBYTE, BYTE);
1420 ****************************************************************************
1424 VOID FlushUnit(struct DevUnit *unit, UBYTE last_queue, BYTE error,
1425 struct DevBase *base)
1427 struct IORequest *request;
1428 UBYTE i;
1429 struct Opener *opener, *tail;
1431 /* Abort queued requests */
1433 for(i = 0; i <= last_queue; i++)
1435 while((request = (APTR)GetMsg(unit->request_ports[i])) != NULL)
1437 request->io_Error = error;
1438 ReplyMsg((APTR)request);
1442 #if 1
1443 opener = (APTR)unit->openers.mlh_Head;
1444 tail = (APTR)&unit->openers.mlh_Tail;
1446 /* Flush every opener's read queue */
1448 while(opener != tail)
1450 while((request = (APTR)GetMsg(&opener->read_port)) != NULL)
1452 request->io_Error = error;
1453 ReplyMsg((APTR)request);
1455 opener = (APTR)opener->node.mln_Succ;
1458 #else
1459 opener = request->ios2_BufferManagement;
1460 while((request = (APTR)GetMsg(&opener->read_port)) != NULL)
1462 request->io_Error = error;
1463 ReplyMsg((APTR)request);
1465 #endif
1467 /* Return */
1469 return;
1474 /****i* prism2.device/StatusInt ********************************************
1476 * NAME
1477 * StatusInt
1479 * SYNOPSIS
1480 * finished = StatusInt(unit)
1482 * BOOL StatusInt(struct DevUnit *);
1484 * FUNCTION
1486 * INPUTS
1487 * unit
1489 * RESULT
1490 * finished
1492 ****************************************************************************
1494 * int_code is really in A5, but GCC 2.95.3 doesn't seem able to handle that.
1495 * Since we don't use this parameter, we can lie.
1499 BOOL StatusInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
1501 struct DevBase *base;
1502 UWORD events, int_mask;
1504 base = unit->device;
1505 events = unit->LEWordIn(unit->card, P2_REG_EVENTS);
1507 /* Turning off ints acknowledges the request? */
1509 int_mask = unit->LEWordIn(unit->card, P2_REG_INTMASK);
1510 unit->LEWordOut(unit->card, P2_REG_INTMASK, 0);
1512 /* Handle events */
1514 if((events & P2_EVENTF_INFO) != 0)
1516 int_mask &= ~P2_EVENTF_INFO;
1517 Cause(&unit->info_int);
1519 if((events & P2_EVENTF_RX) != 0)
1521 int_mask &= ~P2_EVENTF_RX;
1522 Cause(&unit->rx_int);
1524 if((events & P2_EVENTF_ALLOCMEM) != 0)
1526 unit->tx_frame_id = unit->LEWordIn(unit->card, P2_REG_ALLOCFID);
1527 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_ALLOCMEM);
1528 Cause(&unit->tx_int);
1530 if((events & P2_EVENTF_TXFAIL) != 0)
1532 ReportEvents(unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX,
1533 base);
1534 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_TXFAIL);
1537 #ifdef __MORPHOS__
1538 int_mask = INT_MASK;
1539 #endif
1540 unit->LEWordOut(unit->card, P2_REG_INTMASK, int_mask);
1542 return FALSE;
1547 /****i* prism2.device/RXInt ************************************************
1549 * NAME
1550 * RXInt -- Soft interrupt for packet reception.
1552 * SYNOPSIS
1553 * RXInt(unit)
1555 * VOID RXInt(struct DevUnit *);
1557 * FUNCTION
1559 * INPUTS
1560 * unit - A unit of this device.
1562 * RESULT
1563 * None.
1565 ****************************************************************************
1569 static VOID RXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
1571 UWORD frame_status, frame_id, ieee_length, frame_control, frame_type,
1572 frame_subtype, encryption, key_no, buffer_no, old_length;
1573 struct DevBase *base;
1574 BOOL is_good;
1575 LONG frag_no;
1576 UBYTE *buffer, *p, *frame, *data;
1578 base = unit->device;
1580 while((unit->LEWordIn(unit->card, P2_REG_EVENTS) & P2_EVENTF_RX) != 0)
1582 is_good = TRUE;
1583 frame_id = unit->LEWordIn(unit->card, P2_REG_RXFID);
1584 P2Seek(unit, 1, frame_id, P2_FRM_STATUS, base);
1585 frame_status = unit->LEWordIn(unit->card, P2_REG_DATA1);
1587 if((frame_status & (P2_FRM_STATUSF_BADCRYPT | P2_FRM_STATUSF_BADCRC))
1588 == 0)
1590 /* Read frame descriptor from card */
1592 P2Seek(unit, 1, frame_id, 0, base);
1593 unit->WordsIn(unit->card, P2_REG_DATA1,
1594 (UWORD *)unit->rx_descriptor,
1595 (unit->ethernet_offset + ETH_HEADERSIZE) / 2);
1596 frame = unit->rx_descriptor + unit->ethernet_offset;
1597 ieee_length = BEWord(*(UWORD *)(frame + ETH_PACKET_IEEELEN));
1598 data = frame + ETH_PACKET_DATA;
1599 unit->WordsIn(unit->card, P2_REG_DATA1, (UWORD *)data,
1600 (ieee_length + MIC_SIZE + 1) / 2);
1601 frame_control =
1602 LEWord(*(UWORD *)(unit->rx_descriptor + P2_FRM_HEADER));
1604 /* Get buffer to store fragment in */
1606 frag_no = LEWord(*(UWORD *)(unit->rx_descriptor + P2_FRM_HEADER
1607 + WIFI_FRM_SEQCONTROL));
1608 buffer = GetRXBuffer(unit, frame + ETH_PACKET_SOURCE, frag_no,
1609 &buffer_no, base);
1611 /* Get location to put new data */
1613 if(buffer != NULL)
1615 if((frag_no & 0xf ) > 0)
1616 old_length = BEWord(*(UWORD *)(buffer + ETH_PACKET_IEEELEN));
1617 else
1619 /* Copy header to new frame */
1621 CopyMem(frame, buffer, ETH_HEADERSIZE);
1622 old_length = 0;
1624 p = buffer + ETH_HEADERSIZE + old_length;
1626 /* Get encryption type and key index */
1628 if((frame_control & WIFI_FRM_CONTROLF_WEP) != 0)
1630 key_no = data[3] >> 6 & 0x3;
1631 encryption = unit->keys[key_no].type;
1633 else
1634 encryption = S2ENC_NONE;
1636 /* Append fragment to frame, decrypting/checking fragment if
1637 necessary */
1639 is_good = unit->fragment_decrypt_functions[encryption](unit,
1640 unit->rx_descriptor + P2_FRM_HEADER, data, &ieee_length, p,
1641 base);
1643 /* Update length in frame being built with current fragment, or
1644 increment bad frame counter if fragment is bad */
1646 if(is_good)
1648 ieee_length += old_length;
1649 *(UWORD *)(buffer + ETH_PACKET_IEEELEN) =
1650 MakeBEWord(ieee_length);
1652 else
1653 unit->stats.BadData++;
1655 /* If all fragments have arrived, process the complete frame */
1657 if((frame_control & WIFI_FRM_CONTROLF_MOREFRAGS) == 0)
1659 if(is_good)
1661 /* Decrypt complete frame if necessary */
1663 data = buffer + ETH_HEADERSIZE;
1664 if(encryption == S2ENC_TKIP)
1666 /* Hermes cards don't include MIC in frame length, so
1667 we need to grab the MIC from the original RX
1668 descriptor here */
1670 if(unit->firmware_type >= LUCENT_FIRMWARE)
1672 CopyMem(frame + ETH_PACKET_DATA + ieee_length,
1673 data + ieee_length, MIC_SIZE);
1674 ieee_length += MIC_SIZE;
1677 /* Check Michael MIC */
1679 #ifndef __mc68000
1680 is_good = TKIPDecryptFrame(unit, buffer, data,
1681 ieee_length, data, key_no, base);
1682 #endif
1683 ieee_length -= MIC_SIZE;
1684 *(UWORD *)(buffer + ETH_PACKET_IEEELEN) =
1685 MakeBEWord(ieee_length);
1686 if(!is_good)
1687 unit->stats.BadData++;
1691 if(is_good)
1693 /* Get frame's 802.11 type and subtype */
1695 frame_type = (frame_control & WIFI_FRM_CONTROLF_TYPE)
1696 >> WIFI_FRM_CONTROLB_TYPE;
1697 frame_subtype =
1698 (frame_control & WIFI_FRM_CONTROLF_SUBTYPE)
1699 >> WIFI_FRM_CONTROLB_SUBTYPE;
1701 /* If it's a management frame, process it internally;
1702 otherwise distribute it to clients after filtering */
1704 if(frame_type == WIFI_FRMTYPE_MGMT)
1706 if(frame_subtype == 0x5)
1708 CopyMem(unit->rx_descriptor + P2_FRM_HEADER
1709 + WIFI_FRM_ADDRESS3, buffer + ETH_PACKET_SOURCE,
1710 ETH_ADDRESSSIZE);
1711 SaveBeacon(unit, buffer, base);
1714 else if(AddressFilter(unit, buffer + ETH_PACKET_DEST,
1715 base))
1717 unit->stats.PacketsReceived++;
1718 DistributeRXPacket(unit, buffer, base);
1723 /* Mark fragment buffer as unused for next time */
1725 unit->rx_fragment_nos[buffer_no] = -1;
1727 else
1728 ReportEvents(unit, S2EVENT_ERROR | S2EVENT_RX, base);
1730 else
1732 is_good = FALSE;
1735 if(!is_good)
1737 ReportEvents(unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX,
1738 base);
1741 /* Discard packet */
1743 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_RX);
1746 /* Re-enable RX interrupts */
1748 Disable();
1749 unit->LEWordOut(unit->card, P2_REG_INTMASK,
1750 unit->LEWordIn(unit->card, P2_REG_INTMASK) | P2_EVENTF_RX);
1751 Enable();
1753 return;
1758 /****i* prism2.device/GetRXBuffer ******************************************
1760 * NAME
1761 * GetRXBuffer -- Find an appropriate RX buffer to use.
1763 * SYNOPSIS
1764 * buffer = GetRXBuffer(unit, address, frag_no)
1766 * UBYTE *GetRXBuffer(struct DevUnit *, UBYTE *, UWORD);
1768 ****************************************************************************
1772 static UBYTE *GetRXBuffer(struct DevUnit *unit, const UBYTE *address,
1773 UWORD frag_no, UWORD *buffer_no, struct DevBase *base)
1775 UWORD i;
1776 UBYTE *buffer;
1777 LONG n;
1778 BOOL found;
1780 buffer = unit->rx_buffers;
1781 for(i = 0, found = FALSE; i < RX_BUFFER_COUNT * 2 && !found; i++)
1783 /* Throw away old buffer contents if we didn't find a free slot the
1784 first time around */
1786 if(i >= RX_BUFFER_COUNT)
1787 unit->rx_fragment_nos[i % RX_BUFFER_COUNT] = -1;
1789 /* For a frame's first fragment, find an empty slot; for subsequent
1790 fragments, find a slot with matching source address */
1792 n = unit->rx_fragment_nos[i % RX_BUFFER_COUNT];
1793 if(n == -1 && (frag_no & 0xf) == 0
1794 || *((ULONG *)(buffer + ETH_PACKET_SOURCE))
1795 == *((ULONG *)(address))
1796 && *((UWORD *)(buffer + ETH_PACKET_SOURCE + 4))
1797 == *((UWORD *)(address + 4)))
1799 found = TRUE;
1800 if(n == -1)
1801 unit->rx_fragment_nos[i % RX_BUFFER_COUNT] = frag_no;
1802 *buffer_no = i;
1804 else
1805 buffer += FRAME_BUFFER_SIZE;
1808 if(!found)
1809 buffer = NULL;
1811 return buffer;
1816 /****i* prism2.device/DistributeRXPacket ***********************************
1818 * NAME
1819 * DistributeRXPacket -- Send a packet to all appropriate destinations.
1821 * SYNOPSIS
1822 * DistributeRXPacket(unit, frame)
1824 * VOID DistributeRXPacket(struct DevUnit *, UBYTE *);
1826 ****************************************************************************
1830 static VOID DistributeRXPacket(struct DevUnit *unit, UBYTE *frame,
1831 struct DevBase *base)
1833 UWORD packet_size, ieee_length;
1834 BOOL is_orphan = TRUE, accepted, is_snap = FALSE;
1835 ULONG packet_type;
1836 UBYTE *buffer;
1837 const UBYTE *template = snap_template;
1838 struct IOSana2Req *request, *request_tail;
1839 struct Opener *opener, *opener_tail;
1840 struct TypeStats *tracker;
1842 ieee_length = BEWord(*(UWORD *)(frame + ETH_PACKET_IEEELEN));
1843 packet_size = ETH_HEADERSIZE + ieee_length;
1844 if(ieee_length >= SNAP_HEADERSIZE)
1845 is_snap = *(const ULONG *)(frame + ETH_PACKET_DATA)
1846 == *(const ULONG *)template;
1848 /* De-encapsulate SNAP packets and get packet type */
1850 if(is_snap)
1852 buffer = unit->rx_buffer;
1853 packet_size -= SNAP_HEADERSIZE;
1854 CopyMem(frame, buffer, ETH_PACKET_TYPE);
1855 CopyMem(frame + ETH_HEADERSIZE + SNAP_FRM_TYPE,
1856 buffer + ETH_PACKET_TYPE, packet_size - ETH_PACKET_TYPE);
1858 else
1859 buffer = frame;
1861 packet_type = BEWord(*((UWORD *)(buffer + ETH_PACKET_TYPE)));
1863 if(packet_size <= ETH_MAXPACKETSIZE)
1865 /* Offer packet to every opener */
1867 opener = (APTR)unit->openers.mlh_Head;
1868 opener_tail = (APTR)&unit->openers.mlh_Tail;
1870 while(opener != opener_tail)
1872 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
1873 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
1874 accepted = FALSE;
1876 /* Offer packet to each request until it's accepted */
1878 while(request != request_tail && !accepted)
1880 if(request->ios2_PacketType == packet_type)
1882 CopyPacket(unit, request, packet_size, packet_type,
1883 buffer, base);
1884 accepted = TRUE;
1886 request =
1887 (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
1890 if(accepted)
1891 is_orphan = FALSE;
1892 opener = (APTR)opener->node.mln_Succ;
1895 /* If packet was unwanted, give it to S2_READORPHAN request */
1897 if(is_orphan)
1899 unit->stats.UnknownTypesReceived++;
1900 if(!IsMsgPortEmpty(unit->request_ports[ADOPT_QUEUE]))
1902 CopyPacket(unit,
1903 (APTR)unit->request_ports[ADOPT_QUEUE]->
1904 mp_MsgList.lh_Head, packet_size, packet_type, buffer,
1905 base);
1909 /* Update remaining statistics */
1911 if(packet_type <= ETH_MTU)
1912 packet_type = ETH_MTU;
1913 tracker =
1914 FindTypeStats(unit, &unit->type_trackers, packet_type, base);
1915 if(tracker != NULL)
1917 tracker->stats.PacketsReceived++;
1918 tracker->stats.BytesReceived += packet_size;
1921 else
1922 unit->stats.BadData++;
1924 return;
1929 /****i* prism2.device/CopyPacket *******************************************
1931 * NAME
1932 * CopyPacket -- Copy packet to client's buffer.
1934 * SYNOPSIS
1935 * CopyPacket(unit, request, packet_size, packet_type,
1936 * buffer)
1938 * VOID CopyPacket(struct DevUnit *, struct IOSana2Req *, UWORD, UWORD,
1939 * UBYTE *);
1941 ****************************************************************************
1945 static VOID CopyPacket(struct DevUnit *unit, struct IOSana2Req *request,
1946 UWORD packet_size, UWORD packet_type, UBYTE *buffer,
1947 struct DevBase *base)
1949 struct Opener *opener;
1950 BOOL filtered = FALSE;
1952 /* Set multicast and broadcast flags */
1954 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
1955 if((*((ULONG *)(buffer + ETH_PACKET_DEST)) == 0xffffffff) &&
1956 (*((UWORD *)(buffer + ETH_PACKET_DEST + 4)) == 0xffff))
1957 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
1958 else if((buffer[ETH_PACKET_DEST] & 0x1) != 0)
1959 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
1961 /* Set source and destination addresses and packet type */
1963 CopyMem(buffer + ETH_PACKET_SOURCE, request->ios2_SrcAddr,
1964 ETH_ADDRESSSIZE);
1965 CopyMem(buffer + ETH_PACKET_DEST, request->ios2_DstAddr,
1966 ETH_ADDRESSSIZE);
1967 request->ios2_PacketType = packet_type;
1969 /* Adjust for cooked packet request */
1971 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
1973 packet_size -= ETH_PACKET_DATA;
1974 buffer += ETH_PACKET_DATA;
1976 #ifdef USE_HACKS
1977 else
1978 packet_size += 4; /* Needed for Shapeshifter & Fusion */
1979 #endif
1980 request->ios2_DataLength = packet_size;
1982 /* Filter packet */
1984 opener = request->ios2_BufferManagement;
1985 if(request->ios2_Req.io_Command == CMD_READ &&
1986 opener->filter_hook != NULL)
1987 if(!CallHookPkt(opener->filter_hook, request, buffer))
1988 filtered = TRUE;
1990 if(!filtered)
1992 /* Copy packet into opener's buffer and reply packet */
1994 if(!opener->rx_function(request->ios2_Data, buffer, packet_size))
1996 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
1997 request->ios2_WireError = S2WERR_BUFF_ERROR;
1998 ReportEvents(unit,
1999 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX,
2000 base);
2002 Remove((APTR)request);
2003 ReplyMsg((APTR)request);
2006 return;
2011 /****i* prism2.device/AddressFilter ****************************************
2013 * NAME
2014 * AddressFilter -- Determine if an RX packet should be accepted.
2016 * SYNOPSIS
2017 * accept = AddressFilter(unit, address)
2019 * BOOL AddressFilter(struct DevUnit *, UBYTE *);
2021 ****************************************************************************
2025 static BOOL AddressFilter(struct DevUnit *unit, UBYTE *address,
2026 struct DevBase *base)
2028 struct AddressRange *range, *tail;
2029 BOOL accept = TRUE;
2030 ULONG address_left;
2031 UWORD address_right;
2033 /* Check whether address is unicast/broadcast or multicast */
2035 address_left = BELong(*((ULONG *)address));
2036 address_right = BEWord(*((UWORD *)(address + 4)));
2038 if(((address_left & 0x01000000) != 0) &&
2039 !((address_left == 0xffffffff) && (address_right == 0xffff)))
2041 /* Check if this multicast address is wanted */
2043 range = (APTR)unit->multicast_ranges.mlh_Head;
2044 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
2045 accept = FALSE;
2047 while((range != tail) && !accept)
2049 if((address_left > range->lower_bound_left ||
2050 address_left == range->lower_bound_left &&
2051 address_right >= range->lower_bound_right) &&
2052 (address_left < range->upper_bound_left ||
2053 address_left == range->upper_bound_left &&
2054 address_right <= range->upper_bound_right))
2055 accept = TRUE;
2056 range = (APTR)range->node.mln_Succ;
2059 if(!accept)
2060 unit->special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
2063 return accept;
2068 /****i* prism2.device/SaveBeacon *******************************************
2070 * NAME
2071 * SaveBeacon -- Save beacon frame for later examination.
2073 * SYNOPSIS
2074 * SaveBeacon(unit, frame)
2076 * VOID SaveBeacon(struct DevUnit *, UBYTE *);
2078 ****************************************************************************
2082 static VOID SaveBeacon(struct DevUnit *unit, const UBYTE *frame,
2083 struct DevBase *base)
2085 UWORD size;
2087 /* Store frame for later matching with scan results */
2089 size = ETH_HEADERSIZE + BEWord(*(UWORD *)(frame + ETH_PACKET_IEEELEN));
2090 if(unit->next_beacon + size < unit->beacons + BEACON_BUFFER_SIZE)
2092 CopyMem(frame, unit->next_beacon, size);
2093 unit->beacon_count++;
2094 unit->next_beacon += size + sizeof(ULONG) & ~3;
2097 return;
2102 /****i* prism2.device/TXInt ************************************************
2104 * NAME
2105 * TXInt -- Soft interrupt for packet transmission.
2107 * SYNOPSIS
2108 * TXInt(unit)
2110 * VOID TXInt(struct DevUnit *);
2112 * FUNCTION
2114 * INPUTS
2115 * unit - A unit of this device.
2117 * RESULT
2118 * None.
2120 ****************************************************************************
2124 static VOID TXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
2126 UWORD i, packet_size, send_size, packet_type, data_size, body_size = 0,
2127 frame_id, encryption, control_value, subtype;
2128 UBYTE *buffer, *desc = unit->tx_descriptor, *plaintext, *ciphertext,
2129 *header, mic_header[ETH_ADDRESSSIZE * 2], *q;
2130 const UBYTE *p, *dest, *source;
2131 struct DevBase *base;
2132 struct IOSana2Req *request;
2133 BOOL is_ieee;
2134 struct Opener *opener;
2135 ULONG wire_error;
2136 UBYTE *(*dma_tx_function)(REG(a0, APTR));
2137 BYTE error = 0;
2138 struct MsgPort *port;
2139 struct TypeStats *tracker;
2141 base = unit->device;
2142 port = unit->request_ports[WRITE_QUEUE];
2144 if(unit->tx_frame_id != 0 && !IsMsgPortEmpty(port))
2146 /* Get next request and full packet size */
2148 request = (APTR)port->mp_MsgList.lh_Head;
2149 packet_size = request->ios2_DataLength;
2150 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
2151 packet_size += ETH_PACKET_DATA;
2153 /* Determine encryption type and frame subtype */
2155 if(packet_size > ETH_HEADERSIZE)
2157 encryption = unit->keys[unit->tx_key_no].type;
2158 subtype = 0;
2160 else
2162 encryption = S2ENC_NONE;
2163 subtype = 4;
2166 /* Get packet data */
2168 opener = request->ios2_BufferManagement;
2169 dma_tx_function = opener->dma_tx_function;
2170 if(dma_tx_function != NULL)
2171 buffer = dma_tx_function(request->ios2_Data);
2172 else
2173 buffer = NULL;
2175 if(buffer == NULL)
2177 buffer = unit->tx_buffer;
2178 if(!opener->tx_function(buffer, request->ios2_Data,
2179 request->ios2_DataLength))
2181 error = S2ERR_NO_RESOURCES;
2182 wire_error = S2WERR_BUFF_ERROR;
2183 ReportEvents(unit,
2184 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_TX,
2185 base);
2189 if(error == 0)
2191 /* Get packet type and/or length */
2193 data_size = request->ios2_DataLength;
2194 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) != 0)
2196 data_size -= ETH_PACKET_DATA;
2197 packet_type = BEWord(*(UWORD *)(buffer + ETH_PACKET_TYPE));
2199 else
2200 packet_type = request->ios2_PacketType;
2201 is_ieee = packet_type <= ETH_MTU;
2203 /* Get source and destination addresses */
2205 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) != 0)
2207 dest = buffer;
2208 source = buffer + ETH_ADDRESSSIZE;
2209 buffer += ETH_ADDRESSSIZE * 2 + 2;
2211 else
2213 dest = request->ios2_DstAddr;
2214 source = unit->address;
2217 /* Clear frame descriptor as far as start of 802.11 header */
2219 q = desc;
2220 for(i = 0; i < P2_FRM_HEADER; i++)
2221 *q++ = 0;
2222 header = q;
2224 /* Set TX control field */
2226 control_value = P2_FRM_TXCONTROLF_NATIVE;
2227 if(encryption == S2ENC_TKIP && (unit->flags & UNITF_HARDTKIP) != 0)
2228 control_value |= unit->tx_key_no << P2_FRM_TXCONTROLB_MICKEYID
2229 | P2_FRM_TXCONTROLF_MIC;
2230 else if(encryption == S2ENC_NONE
2231 && unit->firmware_type < LUCENT_FIRMWARE)
2232 control_value |= P2_FRM_TXCONTROLF_NOENC;
2234 *(UWORD *)(desc + unit->txcontrol_offset) =
2235 MakeLEWord(control_value);
2237 /* Write 802.11 header */
2239 *(UWORD *)q = MakeLEWord(
2240 (encryption == S2ENC_NONE ? 0 : WIFI_FRM_CONTROLF_WEP)
2241 | (unit->mode == S2PORT_ADHOC ? 0 : WIFI_FRM_CONTROLF_TODS)
2242 | subtype << WIFI_FRM_CONTROLB_SUBTYPE
2243 | WIFI_FRMTYPE_DATA << WIFI_FRM_CONTROLB_TYPE);
2244 q += 2;
2246 *(UWORD *)q = 0;
2247 q += 2;
2249 if(unit->mode == S2PORT_ADHOC)
2250 p = dest;
2251 else
2252 p = unit->bssid;
2253 for(i = 0; i < ETH_ADDRESSSIZE; i++)
2254 *q++ = *p++;
2256 for(i = 0, p = source; i < ETH_ADDRESSSIZE; i++)
2257 *q++ = *p++;
2259 if(unit->mode == S2PORT_ADHOC)
2260 p = unit->bssid;
2261 else
2262 p = dest;
2263 for(i = 0; i < ETH_ADDRESSSIZE; i++)
2264 *q++ = *p++;
2265 *(UWORD *)q = 0;
2267 /* Clear 802.3 header */
2269 q = desc + unit->ethernet_offset;
2270 for(i = 0; i < ETH_HEADERSIZE; i++)
2271 *q++ = 0;
2273 /* Leave room for encryption overhead */
2275 q = desc + unit->data_offset;
2276 ciphertext = q;
2277 q += unit->iv_sizes[encryption];
2278 plaintext = q;
2280 /* Write SNAP header */
2282 if(!is_ieee)
2284 for(i = 0, p = snap_template; i < SNAP_FRM_TYPE; i++)
2285 *q++ = *p++;
2286 *(UWORD *)q = MakeBEWord(packet_type);
2287 q += 2;
2288 body_size += SNAP_HEADERSIZE;
2291 /* Copy data into frame */
2293 CopyMem(buffer, q, data_size);
2294 body_size += data_size;
2296 /* Append MIC to frame for TKIP */
2298 if(encryption == S2ENC_TKIP)
2300 q = mic_header;
2301 for(i = 0, p = dest; i < ETH_ADDRESSSIZE; i++)
2302 *q++ = *p++;
2303 for(i = 0, p = source; i < ETH_ADDRESSSIZE; i++)
2304 *q++ = *p++;
2305 TKIPEncryptFrame(unit, mic_header, plaintext, body_size,
2306 plaintext, base);
2307 body_size += MIC_SIZE;
2310 /* Encrypt fragment if applicable */
2312 unit->fragment_encrypt_functions[encryption](unit, header,
2313 plaintext, &body_size, ciphertext, base);
2315 /* Calculate total length of data to send to adapter */
2317 send_size = unit->data_offset + body_size;
2319 /* Fill in length field, adjusting for Hermes peculiarities */
2321 if(unit->firmware_type >= LUCENT_FIRMWARE
2322 && encryption == S2ENC_TKIP)
2323 body_size -= MIC_SIZE;
2325 if(unit->firmware_type == LUCENT_FIRMWARE
2326 && (unit->flags & UNITF_HARDTKIP) != 0)
2327 *(UWORD *)(desc + unit->ethernet_offset + ETH_PACKET_IEEELEN) =
2328 MakeBEWord(body_size);
2329 else
2330 *(UWORD *)(desc + unit->datalen_offset) = MakeLEWord(body_size);
2332 /* Write packet to adapter and send */
2334 frame_id = unit->tx_frame_id;
2335 P2Seek(unit, 0, frame_id, 0, base);
2336 unit->WordsOut(unit->card, P2_REG_DATA0, (UWORD *)desc,
2337 (send_size + 1) / 2);
2338 unit->tx_frame_id = 0;
2339 P2DoCmd(unit, P2_CMD_TX | P2_CMDF_RECLAIM, frame_id, base);
2342 /* Reply request */
2344 request->ios2_Req.io_Error = error;
2345 request->ios2_WireError = wire_error;
2346 Remove((APTR)request);
2347 ReplyMsg((APTR)request);
2349 /* Update statistics */
2351 if(error == 0)
2353 unit->stats.PacketsSent++;
2355 tracker = FindTypeStats(unit, &unit->type_trackers,
2356 request->ios2_PacketType, base);
2357 if(tracker != NULL)
2359 tracker->stats.PacketsSent++;
2360 tracker->stats.BytesSent += packet_size;
2365 /* Don't try to keep sending packets if there's no space left */
2367 if(unit->tx_frame_id != 0)
2368 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
2369 else
2370 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
2372 return;
2377 /****i* prism2.device/UpdateStats ******************************************
2379 * NAME
2380 * UpdateStats
2382 * SYNOPSIS
2383 * UpdateStats(unit)
2385 * VOID UpdateStats(struct DevUnit *);
2387 * FUNCTION
2389 * INPUTS
2390 * unit - A unit of this device.
2392 * RESULT
2393 * None.
2395 ****************************************************************************
2399 VOID UpdateStats(struct DevUnit *unit, struct DevBase *base)
2401 /* Ask for and wait for stats */
2403 if((unit->flags & UNITF_ONLINE) != 0)
2405 Disable();
2406 unit->LEWordOut(unit->card, P2_REG_INTMASK,
2407 unit->LEWordIn(unit->card, P2_REG_INTMASK) & ~P2_EVENTF_INFO);
2408 Enable();
2409 P2DoCmd(unit, P2_CMD_INQUIRE, P2_INFO_COUNTERS, base);
2410 while((unit->LEWordIn(unit->card, P2_REG_EVENTS) & P2_EVENTF_INFO)
2411 == 0);
2412 Cause(&unit->info_int);
2415 return;
2420 /****i* prism2.device/InfoInt **********************************************
2422 * NAME
2423 * InfoInt
2425 * SYNOPSIS
2426 * InfoInt(unit)
2428 * VOID InfoInt(struct DevUnit *);
2430 * FUNCTION
2432 * INPUTS
2433 * unit - A unit of this device.
2435 * RESULT
2436 * None.
2438 * NOTES
2439 * The only reason this is a (soft) interrupt is so that it won't
2440 * interfere with RXInt() by interrupting it. This would be dangerous
2441 * because they use the same data channel.
2443 ****************************************************************************
2447 static VOID InfoInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
2449 struct DevBase *base;
2450 UWORD id, length, rec_length, status, ies_length, data_length,
2451 ssid_length, *ap_rec, *rec, count, i;
2452 UBYTE *ie, *ssid, *descriptor, *frame, *data, *bssid = unit->bssid;
2453 BOOL associated, is_duplicate = FALSE;
2455 base = unit->device;
2456 id = unit->LEWordIn(unit->card, P2_REG_INFOFID);
2458 P2Seek(unit, 1, id, 0, base);
2459 length = (unit->LEWordIn(unit->card, P2_REG_DATA1) + 1) * 2;
2461 switch(unit->LEWordIn(unit->card, P2_REG_DATA1))
2463 case P2_INFO_COUNTERS:
2465 /* Read useful stats and skip others */
2467 unit->LEWordIn(unit->card, P2_REG_DATA1);
2468 unit->LEWordIn(unit->card, P2_REG_DATA1);
2470 unit->LEWordIn(unit->card, P2_REG_DATA1);
2471 unit->LEWordIn(unit->card, P2_REG_DATA1);
2472 unit->LEWordIn(unit->card, P2_REG_DATA1);
2473 unit->LEWordIn(unit->card, P2_REG_DATA1);
2475 unit->special_stats[S2SS_ETHERNET_RETRIES & 0xffff] +=
2476 unit->LEWordIn(unit->card, P2_REG_DATA1) +
2477 unit->LEWordIn(unit->card, P2_REG_DATA1) +
2478 unit->LEWordIn(unit->card, P2_REG_DATA1);
2480 unit->LEWordIn(unit->card, P2_REG_DATA1);
2482 unit->LEWordIn(unit->card, P2_REG_DATA1);
2483 unit->LEWordIn(unit->card, P2_REG_DATA1);
2485 unit->LEWordIn(unit->card, P2_REG_DATA1);
2486 unit->LEWordIn(unit->card, P2_REG_DATA1);
2487 unit->LEWordIn(unit->card, P2_REG_DATA1);
2489 unit->stats.BadData += unit->LEWordIn(unit->card, P2_REG_DATA1);
2490 unit->stats.Overruns += unit->LEWordIn(unit->card, P2_REG_DATA1);
2492 unit->LEWordIn(unit->card, P2_REG_DATA1);
2494 unit->stats.BadData += unit->LEWordIn(unit->card, P2_REG_DATA1);
2496 break;
2498 case P2_INFO_SCANRESULTS:
2499 case P2_INFO_HOSTSCANRESULTS:
2501 P2ReadRec(unit, id, unit->scan_results_rec, SCAN_BUFFER_SIZE, base);
2502 Signal(unit->task, unit->scan_complete_signal);
2503 break;
2505 case P2_INFO_SCANRESULT:
2507 descriptor = unit->rx_descriptor;
2508 P2ReadRec(unit, id, descriptor, FRAME_BUFFER_SIZE, base);
2509 if(length > 4)
2511 /* Save IEEE 802.3 portion of scan result */
2513 frame = descriptor + unit->ethernet_offset;
2514 data = frame + ETH_PACKET_DATA;
2515 CopyMem(descriptor + P2_FRM_HEADER + WIFI_FRM_ADDRESS3,
2516 frame + ETH_PACKET_SOURCE, ETH_ADDRESSSIZE);
2517 data_length =
2518 LEWord(*(UWORD *)(descriptor + unit->datalen_offset));
2519 ies_length = data_length - WIFI_BEACON_IES;
2520 *(UWORD *)(frame + ETH_PACKET_IEEELEN) = MakeBEWord(data_length);
2522 /* Append a fake old-style scan record on to fake record list */
2524 rec_length = LEWord(unit->scan_results_rec[0]);
2525 ap_rec = unit->scan_results_rec + 1 + rec_length;
2527 /* Check for duplicate scan results */
2529 rec = unit->scan_results_rec + 2;
2530 count = (rec_length - 1) * 2 / P2_APRECLEN;
2531 for(i = 0; i < count && !is_duplicate; i++, rec += P2_APRECLEN / 2)
2532 if(CompareMACAddresses(frame + ETH_PACKET_SOURCE,
2533 rec + P2_APREC_BSSID / 2))
2534 is_duplicate = TRUE;
2536 /* Only add new record if there's space and its BSSID hasn't
2537 already been seen */
2539 if(2 + rec_length * 2 + P2_APRECLEN < SCAN_BUFFER_SIZE
2540 && !is_duplicate)
2542 SaveBeacon(unit, frame, base);
2544 CopyMem(frame + ETH_PACKET_SOURCE, ap_rec + P2_APREC_BSSID / 2,
2545 ETH_ADDRESSSIZE);
2547 ap_rec[P2_APREC_SIGNAL / 2] =
2548 MakeLEWord(descriptor[P2_FRM_SIGNAL]);
2550 ap_rec[P2_APREC_NOISE / 2] =
2551 MakeLEWord(descriptor[P2_FRM_NOISE]);
2553 ap_rec[P2_APREC_CHANNEL / 2] = MakeLEWord(GetIE(WIFI_IE_CHANNEL,
2554 data + WIFI_BEACON_IES, ies_length, base)[2]);
2556 ap_rec[P2_APREC_INTERVAL / 2] =
2557 *(UWORD *)(data + WIFI_BEACON_INTERVAL);
2559 ap_rec[P2_APREC_CAPABILITIES / 2] =
2560 *(UWORD *)(data + WIFI_BEACON_CAPABILITIES);
2562 ie = GetIE(WIFI_IE_SSID, data + WIFI_BEACON_IES, ies_length,
2563 base);
2564 ssid_length = ie[1];
2565 ssid = ie + 2;
2566 ap_rec[P2_APREC_NAMELEN / 2] = MakeLEWord(ssid_length);
2567 CopyMem(ssid, ap_rec + P2_APREC_NAME / 2, ssid_length);
2569 unit->scan_results_rec[0] =
2570 MakeLEWord(rec_length + P2_APRECLEN / 2);
2573 else
2574 Signal(unit->task, unit->scan_complete_signal);
2575 break;
2577 case P2_INFO_LINKSTATUS:
2579 /* Only report an event if association status has really changed */
2581 status = unit->LEWordIn(unit->card, P2_REG_DATA1);
2583 if(status == 1 || unit->firmware_type < LUCENT_FIRMWARE
2584 && status == 3)
2585 associated = TRUE;
2586 else
2587 associated = FALSE;
2589 if(!(*(ULONG *)bssid == 0 && *(UWORD *)(bssid + 4) == 0))
2591 if(associated && (unit->flags & UNITF_ASSOCIATED) == 0)
2593 unit->flags |= UNITF_ASSOCIATED;
2594 ReportEvents(unit, S2EVENT_CONNECT, base);
2596 else if(!associated && (unit->flags & UNITF_ASSOCIATED) != 0)
2598 unit->flags &= ~UNITF_ASSOCIATED;
2599 ReportEvents(unit, S2EVENT_DISCONNECT, base);
2604 /* Acknowledge event and re-enable info interrupts */
2606 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_INFO);
2607 Disable();
2608 if((unit->flags & UNITF_ONLINE) != 0)
2609 unit->LEWordOut(unit->card, P2_REG_INTMASK,
2610 unit->LEWordIn(unit->card, P2_REG_INTMASK) | P2_EVENTF_INFO);
2611 Enable();
2613 return;
2618 /****i* prism2.device/ResetHandler *****************************************
2620 * NAME
2621 * ResetHandler -- Disable hardware before a reboot.
2623 * SYNOPSIS
2624 * ResetHandler(unit, int_code)
2626 * VOID ResetHandler(struct DevUnit *, APTR);
2628 ****************************************************************************
2632 static VOID ResetHandler(REG(a1, struct DevUnit *unit),
2633 REG(a6, APTR int_code))
2635 if((unit->flags & UNITF_HAVEADAPTER) != 0)
2637 /* Stop interrupts */
2639 unit->LEWordOut(unit->card, P2_REG_INTMASK, 0);
2641 /* Stop transmission and reception */
2643 unit->LEWordOut(unit->card, P2_REG_PARAM0, 0);
2644 unit->LEWordOut(unit->card, P2_REG_COMMAND, P2_CMD_DISABLE);
2647 return;
2652 /****i* prism2.device/ReportEvents *****************************************
2654 * NAME
2655 * ReportEvents
2657 * SYNOPSIS
2658 * ReportEvents(unit, events)
2660 * VOID ReportEvents(struct DevUnit *, ULONG);
2662 * FUNCTION
2664 * INPUTS
2665 * unit - A unit of this device.
2666 * events - A mask of events to report.
2668 * RESULT
2669 * None.
2671 ****************************************************************************
2675 static VOID ReportEvents(struct DevUnit *unit, ULONG events,
2676 struct DevBase *base)
2678 struct IOSana2Req *request, *tail, *next_request;
2679 struct List *list;
2681 list = &unit->request_ports[EVENT_QUEUE]->mp_MsgList;
2682 next_request = (APTR)list->lh_Head;
2683 tail = (APTR)&list->lh_Tail;
2685 Disable();
2686 while(next_request != tail)
2688 request = next_request;
2689 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
2691 if((request->ios2_WireError & events) != 0)
2693 request->ios2_WireError = events;
2694 Remove((APTR)request);
2695 ReplyMsg((APTR)request);
2698 Enable();
2700 return;
2705 /****i* prism2.device/SendScanResults **************************************
2707 * NAME
2708 * SendScanResults -- Reply to all outstanding scan requests.
2710 * SYNOPSIS
2711 * SendScanResults(unit)
2713 * VOID SendScanResults(struct DevUnit *);
2715 * FUNCTION
2717 * INPUTS
2718 * unit - A unit of this device.
2720 * RESULT
2721 * None.
2723 ****************************************************************************
2727 static VOID SendScanResults(struct DevUnit *unit, struct DevBase *base)
2729 BYTE error = 0;
2730 struct IOSana2Req *request, *tail, *next_request;
2731 struct List *list;
2732 APTR pool;
2733 UWORD count, i, j, ssid_length, length, entry_length, *ap_rec,
2734 data_length, frame_length, ies_length;
2735 struct TagItem **tag_lists, *tag;
2736 UBYTE *bssid, *ies;
2737 const UBYTE *beacon, *ie_bssid;
2738 TEXT *ssid;
2740 list = &unit->request_ports[SCAN_QUEUE]->mp_MsgList;
2741 next_request = (APTR)list->lh_Head;
2742 tail = (APTR)&list->lh_Tail;
2744 while(next_request != tail)
2746 request = next_request;
2747 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
2749 pool = request->ios2_Data;
2751 length = LEWord(unit->scan_results_rec[0]);
2752 ap_rec = unit->scan_results_rec + 2;
2754 if(unit->firmware_type == INTERSIL_FIRMWARE)
2756 entry_length = LEWord(unit->scan_results_rec[2]);
2757 ap_rec += 2;
2758 count = (length - 3) * 2 / entry_length;
2760 else
2762 entry_length = P2_APRECLEN;
2763 count = (length - 1) * 2 / entry_length;
2766 /* Allocate array of tag lists, one for each AP */
2768 if(count > 0)
2770 tag_lists = AllocPooled(pool, count * sizeof(APTR));
2771 if(tag_lists == NULL)
2772 error = S2ERR_NO_RESOURCES;
2774 else
2775 tag_lists = NULL;
2777 for(i = 0; i < count && error == 0; i++, ap_rec += entry_length / 2)
2779 tag_lists[i] =
2780 AllocPooled(pool, SCAN_TAG_COUNT * sizeof(struct TagItem));
2781 if(tag_lists[i] == NULL)
2782 error = S2ERR_NO_RESOURCES;
2784 if(error == 0)
2786 tag = tag_lists[i];
2788 tag->ti_Tag = S2INFO_BSSID;
2789 tag->ti_Data = (UPINT)(bssid =
2790 AllocPooled(pool, ETH_ADDRESSSIZE));
2791 if(bssid != NULL)
2792 CopyMem(ap_rec + P2_APREC_BSSID / 2, bssid,
2793 ETH_ADDRESSSIZE);
2794 else
2795 error = S2ERR_NO_RESOURCES;
2796 tag++;
2798 tag->ti_Tag = TAG_IGNORE;
2799 tag++;
2801 tag->ti_Tag = S2INFO_Channel;
2802 tag->ti_Data = LEWord(ap_rec[P2_APREC_CHANNEL / 2]);
2803 tag++;
2805 tag->ti_Tag = S2INFO_BeaconInterval;
2806 tag->ti_Data = LEWord(ap_rec[P2_APREC_INTERVAL / 2]);
2807 tag++;
2809 tag->ti_Tag = S2INFO_Capabilities;
2810 tag->ti_Data = LEWord(ap_rec[P2_APREC_CAPABILITIES / 2]);
2811 tag++;
2813 tag->ti_Tag = S2INFO_Signal;
2814 tag->ti_Data = ConvertScanLevel(unit,
2815 LEWord(ap_rec[P2_APREC_SIGNAL / 2]), base);
2816 tag++;
2818 tag->ti_Tag = S2INFO_Noise;
2819 tag->ti_Data = ConvertScanLevel(unit,
2820 LEWord(ap_rec[P2_APREC_NOISE / 2]), base);
2821 tag++;
2824 ssid_length = LEWord(ap_rec[P2_APREC_NAMELEN / 2]);
2825 tag->ti_Tag = S2INFO_SSID;
2826 tag->ti_Data = (UPINT)(ssid =
2827 AllocPooled(pool, 31 + 1));
2828 if(ssid != NULL)
2830 CopyMem(ap_rec + P2_APREC_NAME / 2, ssid, ssid_length);
2831 ssid[ssid_length] = '\0';
2833 else
2834 error = S2ERR_NO_RESOURCES;
2835 tag++;
2837 tag->ti_Tag = TAG_END;
2841 /* Find IEs for each BSS and insert them into the BSS's tag list */
2843 for(beacon = unit->beacons, i = 0; i < unit->beacon_count; i++)
2845 /* Extract IEs from beacon descriptor */
2847 data_length = BEWord(*(UWORD *)(beacon + ETH_PACKET_IEEELEN));
2848 ies_length = data_length - 12;
2849 frame_length = ETH_HEADERSIZE + data_length;
2850 ies = AllocPooled(pool, sizeof(UWORD) + ies_length);
2851 if(ies != NULL)
2853 *(UWORD *)ies = ies_length;
2854 CopyMem(beacon + ETH_PACKET_DATA + WIFI_BEACON_IES,
2855 ies + sizeof(UWORD), ies_length);
2857 else
2858 error = S2ERR_NO_RESOURCES;
2860 /* Find matching tag list and add IEs to it */
2862 ie_bssid = beacon + ETH_PACKET_SOURCE;
2863 for(j = 0; j < count; j++)
2865 tag = tag_lists[j];
2866 bssid = (UBYTE *)tag->ti_Data;
2867 if(*(ULONG *)bssid == *(ULONG *)ie_bssid
2868 && *(UWORD *)(bssid + 4) == *(UWORD *)(ie_bssid + 4))
2870 tag++;
2871 tag->ti_Tag = S2INFO_InfoElements;
2872 tag->ti_Data = (PINT)ies;
2876 beacon += frame_length + sizeof(ULONG) & ~3;
2879 /* Return results */
2881 if(error == 0)
2883 request->ios2_StatData = tag_lists;
2884 request->ios2_DataLength = count;
2886 else
2888 request->ios2_Req.io_Error = error;
2889 request->ios2_WireError = S2WERR_GENERIC_ERROR;
2891 Remove((APTR)request);
2892 ReplyMsg((APTR)request);
2895 /* Discard collected beacon frames */
2897 Disable();
2898 unit->next_beacon = unit->beacons;
2899 unit->beacon_count = 0;
2900 Enable();
2902 return;
2907 /****i* prism2.device/GetNetworkInfo ***************************************
2909 * NAME
2910 * GetNetworkInfo -- Get information on current network.
2912 * SYNOPSIS
2913 * tag_list = GetNetworkInfo(unit, pool)
2915 * struct TagItem *GetNetworkInfo(struct DevUnit *, APTR);
2917 * FUNCTION
2919 * INPUTS
2920 * unit - A unit of this device.
2921 * pool - A memory pool.
2923 * RESULT
2924 * None.
2926 ****************************************************************************
2930 struct TagItem *GetNetworkInfo(struct DevUnit *unit, APTR pool,
2931 struct DevBase *base)
2933 BYTE error = 0;
2934 struct TagItem *tag_list, *tag;
2935 UBYTE *bssid, *ie;
2937 tag_list =
2938 AllocPooled(pool, INFO_TAG_COUNT * sizeof(struct TagItem));
2939 if(tag_list == NULL)
2940 error = S2ERR_NO_RESOURCES;
2942 if(error == 0)
2944 tag = tag_list;
2946 tag->ti_Tag = S2INFO_BSSID;
2947 tag->ti_Data = (UPINT)(bssid =
2948 AllocPooled(pool, ETH_ADDRESSSIZE));
2949 if(bssid != NULL)
2950 CopyMem(unit->bssid, bssid, ETH_ADDRESSSIZE);
2951 else
2952 error = S2ERR_NO_RESOURCES;
2953 tag++;
2955 tag->ti_Tag = TAG_IGNORE;
2956 tag++;
2958 tag->ti_Tag = S2INFO_WPAInfo;
2959 tag->ti_Data = (UPINT)(ie =
2960 AllocPooled(pool, unit->wpa_ie[1] + 2));
2961 if(ie != NULL)
2962 CopyMem(unit->wpa_ie, ie, unit->wpa_ie[1] + 2);
2963 else
2964 error = S2ERR_NO_RESOURCES;
2965 tag++;
2967 tag->ti_Tag = TAG_END;
2970 if(error != 0)
2971 tag_list = NULL;
2973 return tag_list;
2978 /****i* prism2.device/UpdateSignalQuality **********************************
2980 * NAME
2981 * UpdateSignalQuality -- Read signal quality from card.
2983 * SYNOPSIS
2984 * UpdateSignalQuality(unit)
2986 * VOID UpdateSignalQuality(struct DevUnit *);
2988 * FUNCTION
2990 * INPUTS
2991 * unit - A unit of this device.
2993 * RESULT
2994 * None.
2996 ****************************************************************************
3000 VOID UpdateSignalQuality(struct DevUnit *unit, struct DevBase *base)
3002 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_LINKQUALITY, base);
3003 P2Seek(unit, 1, P2_REC_LINKQUALITY, 6, base);
3005 unit->signal_quality.SignalLevel =
3006 ConvertLevel(unit, unit->LEWordIn(unit->card, P2_REG_DATA1), base);
3007 unit->signal_quality.NoiseLevel =
3008 ConvertLevel(unit, unit->LEWordIn(unit->card, P2_REG_DATA1), base);
3010 return;
3015 /****i* prism2.device/StartScan ********************************************
3017 * NAME
3018 * StartScan -- Start a scan for available networks.
3020 * SYNOPSIS
3021 * StartScan(unit)
3023 * VOID StartScan(struct DevUnit *);
3025 * FUNCTION
3027 * INPUTS
3028 * unit - A unit of this device.
3030 * RESULT
3031 * None.
3033 ****************************************************************************
3037 VOID StartScan(struct DevUnit *unit, const TEXT *ssid, struct DevBase *base)
3039 UBYTE *params;
3040 UWORD ssid_length = 0;
3042 /* Ask for a scan */
3044 if((unit->flags & UNITF_ONLINE) != 0)
3046 if(ssid != NULL)
3047 ssid_length = StrLen(ssid);
3048 if(unit->firmware_type == INTERSIL_FIRMWARE)
3050 params = AllocVec(sizeof(scan_params) + ssid_length, MEMF_PUBLIC);
3051 if(params != NULL)
3053 CopyMem(scan_params, params, sizeof(scan_params));
3054 if(ssid != NULL)
3055 CopyMem(ssid, params + sizeof(scan_params), ssid_length);
3056 params[4] = ssid_length;
3057 P2SetData(unit, P2_REC_HOSTSCAN, params,
3058 sizeof(scan_params) + ssid_length, base);
3059 FreeVec(params);
3062 else if(unit->firmware_type == SYMBOL_FIRMWARE)
3063 P2SetWord(unit, P2_REC_ALTHOSTSCAN, 0x82, base);
3064 else if(unit->firmware_type >= LUCENT_FIRMWARE
3065 && (unit->flags & UNITF_HARDTKIP) != 0)
3067 /* Initialise fake scan results and ask for a series of raw beacon
3068 descriptors */
3070 unit->scan_results_rec[0] = MakeLEWord(1);
3072 P2SetID(unit, P2_REC_SCANSSID, ssid, ssid_length, base);
3073 P2SetWord(unit, P2_REC_SCANCHANNELS, 0x7fff, base);
3074 unit->LEWordOut(unit->card, P2_REG_PARAM1, 0x3fff);
3075 P2DoCmd(unit, P2_CMD_INQUIRE, P2_INFO_SCANRESULT, base);
3077 else
3079 P2SetID(unit, P2_REC_SCANSSID, ssid, ssid_length, base);
3080 P2DoCmd(unit, P2_CMD_INQUIRE, P2_INFO_SCANRESULTS, base);
3084 return;
3089 /****i* prism2.device/LoadFirmware *****************************************
3091 * NAME
3092 * LoadFirmware
3094 * SYNOPSIS
3095 * success = LoadFirmware(unit)
3097 * BOOL LoadFirmware(struct DevUnit *);
3099 * FUNCTION
3101 * INPUTS
3102 * unit - A unit of this device.
3104 * RESULT
3105 * success - Success indicator.
3107 ****************************************************************************
3111 static BOOL LoadFirmware(struct DevUnit *unit, struct DevBase *base)
3113 BOOL success = TRUE;
3114 const TEXT *file_name;
3115 struct FileInfoBlock *info = NULL;
3116 UWORD control_reg, pdr_no, *pda = NULL, *pdr, *prod_data, length;
3117 ULONG location, start_address;
3118 BPTR file = (BPTR)NULL;
3119 UBYTE *data = NULL;
3120 TEXT *buffer = NULL;
3121 const TEXT *p;
3122 UBYTE type;
3124 /* Read firmware file */
3126 switch(unit->firmware_type)
3128 case LUCENT_FIRMWARE:
3129 file_name = h1_firmware_file_name;
3130 break;
3131 case HERMES2_FIRMWARE:
3132 file_name = h2_firmware_file_name;
3133 break;
3134 case HERMES2G_FIRMWARE:
3135 file_name = h25_firmware_file_name;
3136 break;
3137 default:
3138 file_name = NULL;
3141 if(file_name == NULL)
3142 success = FALSE;
3144 if(success)
3146 file = Open(file_name, MODE_OLDFILE);
3147 if(file == (BPTR)NULL)
3148 success = FALSE;
3151 if(success)
3153 info = AllocDosObject(DOS_FIB, NULL);
3154 if(info == NULL)
3155 success = FALSE;
3158 if(success)
3160 if(!ExamineFH(file, info))
3161 success = FALSE;
3164 if(success)
3166 buffer = AllocVec(info->fib_Size + 1, MEMF_ANY);
3167 data = AllocVec(MAX_S_REC_SIZE, MEMF_ANY);
3168 pda = AllocVec(LUCENT_PDA_SIZE, MEMF_ANY);
3169 if(buffer == NULL || data == NULL || pda == NULL)
3170 success = FALSE;
3173 if(success)
3175 if(Read(file, buffer, info->fib_Size) == -1)
3176 success = FALSE;
3177 buffer[info->fib_Size] = '\0';
3180 if(success)
3182 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3183 P2DoCmd(unit, P2_CMD_INIT | 0x100, 0, base);
3184 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3185 P2DoCmd(unit, P2_CMD_INIT | 0x0, 0, base);
3186 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3188 /* Enable auxiliary ports */
3190 unit->LEWordOut(unit->card, P2_REG_PARAM0, 0xfe01);
3191 unit->LEWordOut(unit->card, P2_REG_PARAM1, 0xdc23);
3192 unit->LEWordOut(unit->card, P2_REG_PARAM2, 0xba45);
3194 control_reg = unit->LEWordIn(unit->card, P2_REG_CONTROL);
3195 control_reg =
3196 control_reg & ~P2_REG_CONTROLF_AUX | P2_REG_CONTROL_ENABLEAUX;
3197 unit->LEWordOut(unit->card, P2_REG_CONTROL, control_reg);
3199 BusyMilliDelay(5, base);
3200 while(
3201 (unit->LEWordIn(unit->card, P2_REG_CONTROL) & P2_REG_CONTROLF_AUX)
3202 != P2_REG_CONTROL_AUXENABLED);
3204 /* Read Production Data Area from card */
3206 if(unit->firmware_type < HERMES2_FIRMWARE)
3208 location = LUCENT_PDA_ADDRESS;
3209 unit->LEWordOut(unit->card, P2_REG_AUXPAGE, location >> 7);
3210 unit->LEWordOut(unit->card, P2_REG_AUXOFFSET,
3211 location & (1 << 7) - 1);
3213 unit->WordsIn(unit->card, P2_REG_AUXDATA,
3214 (UWORD *)pda, LUCENT_PDA_SIZE >> 1);
3217 /* Allow writing to card's RAM */
3219 BusyMilliDelay(100, base);
3220 start_address = 0xf8000;
3221 unit->LEWordOut(unit->card, P2_REG_PARAM1, start_address >> 16);
3222 P2DoCmd(unit, P2_CMD_PROGRAM | P2_CMDF_WRITE, start_address, base);
3224 /* Parse firmware image data and write it to card */
3226 p = buffer;
3227 while(p != NULL)
3229 p = ParseNextSRecord(p, &type, data, &length, &location, base);
3230 if(p != NULL)
3232 switch(type)
3234 case '3':
3236 /* Check that this is not a "special" record */
3238 if(location < 0xff000000)
3240 /* Write data to card */
3242 if(unit->firmware_type < LUCENT_FIRMWARE)
3244 unit->LEWordOut(unit->card, P2_REG_PARAM1,
3245 location >> 16);
3246 P2DoCmd(unit, P2_CMD_PROGRAM | P2_CMDF_WRITE, location,
3247 base);
3250 unit->LEWordOut(unit->card, P2_REG_AUXPAGE,
3251 location >> 7);
3252 unit->LEWordOut(unit->card, P2_REG_AUXOFFSET,
3253 location & (1 << 7) - 1);
3255 unit->WordsOut(unit->card, P2_REG_AUXDATA,
3256 (UWORD *)data, length >> 1);
3258 break;
3260 case '7':
3262 /* Get location in card memory to begin execution of new
3263 firmware at */
3265 start_address = location;
3270 /* Parse PDA plug records and patch firmware */
3272 p = buffer;
3273 while(p != NULL)
3275 p = ParseNextSRecord(p, &type, data, &length, &location, base);
3277 if(p != NULL && type == '3' && location == 0xff000000)
3279 /* Get PDR number and the location where it should be patched
3280 into firmware */
3282 pdr_no = LELong(*(ULONG *)data);
3283 location = LELong(*(ULONG *)(data + 4));
3284 length = LELong(*(ULONG *)(data + 8));
3286 /* Find PDR to copy data from */
3288 prod_data = NULL;
3289 for(pdr = pda; pdr[1] != 0; pdr += LEWord(pdr[0]) + 1)
3291 if(LEWord(pdr[1]) == pdr_no)
3292 prod_data = pdr + 2;
3295 /* Write production data to card if it was found */
3297 if(prod_data != NULL)
3299 if(unit->firmware_type < LUCENT_FIRMWARE)
3301 unit->LEWordOut(unit->card, P2_REG_PARAM1,
3302 location >> 16);
3303 P2DoCmd(unit, P2_CMD_PROGRAM | P2_CMDF_WRITE, location,
3304 base);
3307 unit->LEWordOut(unit->card, P2_REG_AUXPAGE, location >> 7);
3308 unit->LEWordOut(unit->card, P2_REG_AUXOFFSET,
3309 location & (1 << 7) - 1);
3311 unit->WordsOut(unit->card, P2_REG_AUXDATA, prod_data,
3312 length >> 1);
3317 /* Disable auxiliary ports */
3319 control_reg = unit->LEWordIn(unit->card, P2_REG_CONTROL);
3320 control_reg =
3321 control_reg & ~P2_REG_CONTROLF_AUX | P2_REG_CONTROL_DISABLEAUX;
3322 unit->LEWordOut(unit->card, P2_REG_CONTROL, control_reg);
3324 /* Execute downloaded firmware */
3326 if(unit->firmware_type >= HERMES2_FIRMWARE)
3328 unit->LEWordOut(unit->card, P2_REG_PARAM1, start_address >> 16);
3329 P2DoCmd(unit, P2_CMD_EXECUTE, start_address, base);
3331 else if(unit->firmware_type >= LUCENT_FIRMWARE)
3333 P2DoCmd(unit, P2_CMD_PROGRAM, 0, base);
3334 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3335 P2DoCmd(unit, P2_CMD_INIT, 0, base);
3336 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3338 else
3340 unit->LEWordOut(unit->card, P2_REG_PARAM1, start_address >> 16);
3341 P2DoCmd(unit, P2_CMD_PROGRAM, start_address, base);
3342 P2DoCmd(unit, P2_CMD_INIT, 0, base);
3346 /* Free Resources */
3348 FreeVec(pda);
3349 FreeVec(buffer);
3350 FreeVec(data);
3351 FreeDosObject(DOS_FIB, info);
3352 if(file != (BPTR)NULL)
3353 Close(file);
3355 return success;
3360 /****i* prism2.device/ParseNextSRecord *************************************
3362 * NAME
3363 * ParseNextSRecord
3365 ****************************************************************************
3369 static const TEXT *ParseNextSRecord(const TEXT *s, UBYTE *type, UBYTE *data,
3370 UWORD *data_length, ULONG *location, struct DevBase *base)
3372 LONG ch;
3373 ULONG n = 0;
3374 UWORD i;
3375 BOOL found = FALSE;
3377 /* Find start of next record, if any */
3379 while(!found)
3381 ch = *s++;
3382 if(ch == 'S' || ch == '\0')
3383 found = TRUE;
3386 if(ch == 'S')
3388 /* Get record type */
3390 *type = *s++;
3392 /* Skip length field to keep alignment easy */
3394 s += 2;
3396 /* Parse hexadecimal portion of record */
3398 for(i = 0; (ch = *s++) >= '0'; i++)
3400 n <<= 4;
3402 if(ch >= 'A')
3403 n |= ch - 'A' + 10;
3404 else
3405 n |= ch - '0';
3407 if(i >= 8 && (i & 0x1) != 0)
3409 *data++ = n;
3410 n = 0;
3412 else if(i == 7)
3414 *location = n;
3415 n = 0;
3418 *data_length = (i >> 1) - 5;
3420 else
3421 s = NULL;
3423 /* Return updated text pointer */
3425 return s;
3430 /****i* prism2.device/P2DoCmd **********************************************
3432 * NAME
3433 * P2DoCmd
3435 ****************************************************************************
3437 * Commands can't fail without software/firmware bug?
3441 static VOID P2DoCmd(struct DevUnit *unit, UWORD command, UWORD param,
3442 struct DevBase *base)
3444 if(unit->firmware_type < LUCENT_FIRMWARE && command == P2_CMD_INIT)
3445 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3447 unit->LEWordOut(unit->card, P2_REG_PARAM0, param);
3448 unit->LEWordOut(unit->card, P2_REG_COMMAND, command);
3449 while((unit->LEWordIn(unit->card, P2_REG_EVENTS)
3450 & P2_EVENTF_CMD) == 0);
3451 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_CMD);
3453 if(unit->firmware_type < LUCENT_FIRMWARE && command == P2_CMD_INIT)
3454 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3459 /****i* prism2.device/P2Seek ***********************************************
3461 * NAME
3462 * P2Seek
3464 ****************************************************************************
3468 static BOOL P2Seek(struct DevUnit *unit, UWORD path_no, UWORD rec_no,
3469 UWORD offset, struct DevBase *base)
3471 UPINT offset_reg;
3473 path_no <<= 1;
3474 offset_reg = P2_REG_OFFSET0 + path_no;
3475 while((unit->LEWordIn(unit->card, offset_reg) & P2_REG_OFFSETF_BUSY)
3476 != 0);
3477 unit->LEWordOut(unit->card, P2_REG_SELECT0 + path_no, rec_no);
3478 unit->LEWordOut(unit->card, offset_reg, offset);
3479 while((unit->LEWordIn(unit->card, offset_reg) & P2_REG_OFFSETF_BUSY)
3480 != 0);
3482 return (unit->LEWordIn(unit->card, offset_reg) & P2_REG_OFFSETF_ERROR)
3483 == 0;
3488 /****i* prism2.device/P2SetID **********************************************
3490 * NAME
3491 * P2SetID
3493 * NOTES
3494 * id may be NULL as long as length is zero.
3496 ****************************************************************************
3500 static VOID P2SetID(struct DevUnit *unit, UWORD rec_no, const UBYTE *id,
3501 UWORD length, struct DevBase *base)
3503 P2Seek(unit, 1, rec_no, 0, base);
3505 unit->LEWordOut(unit->card, P2_REG_DATA1, length / 2 + 3);
3506 unit->LEWordOut(unit->card, P2_REG_DATA1, rec_no);
3507 unit->LEWordOut(unit->card, P2_REG_DATA1, length);
3508 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)id, (length + 1) / 2);
3510 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, rec_no, base);
3512 return;
3517 /****i* prism2.device/P2SetWord ********************************************
3519 * NAME
3520 * P2SetWord
3522 ****************************************************************************
3526 static VOID P2SetWord(struct DevUnit *unit, UWORD rec_no, UWORD value,
3527 struct DevBase *base)
3529 P2Seek(unit, 1, rec_no, 0, base);
3531 unit->LEWordOut(unit->card, P2_REG_DATA1, 2);
3532 unit->LEWordOut(unit->card, P2_REG_DATA1, rec_no);
3533 unit->LEWordOut(unit->card, P2_REG_DATA1, value);
3535 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, rec_no, base);
3537 return;
3542 /****i* prism2.device/P2GetWord ********************************************
3544 * NAME
3545 * P2GetWord
3547 ****************************************************************************
3551 static UWORD P2GetWord(struct DevUnit *unit, UWORD rec_no,
3552 struct DevBase *base)
3554 P2DoCmd(unit, P2_CMD_ACCESS, rec_no, base);
3555 P2Seek(unit, 1, rec_no, 4, base);
3557 return unit->LEWordIn(unit->card, P2_REG_DATA1);
3562 /****i* prism2.device/P2AllocMem *******************************************
3564 * NAME
3565 * P2AllocMem
3567 ****************************************************************************
3571 static UWORD P2AllocMem(struct DevUnit *unit, UWORD size,
3572 struct DevBase *base)
3574 UWORD id;
3575 P2DoCmd(unit, P2_CMD_ALLOCMEM, size, base);
3576 while((unit->LEWordIn(unit->card, P2_REG_EVENTS) & P2_EVENTF_ALLOCMEM)
3577 == 0);
3578 id = unit->LEWordIn(unit->card, P2_REG_ALLOCFID);
3579 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_ALLOCMEM);
3580 return id;
3585 /****i* prism2.device/P2SetData ********************************************
3587 * NAME
3588 * P2SetData
3590 ****************************************************************************
3594 static VOID P2SetData(struct DevUnit *unit, UWORD rec_no, const UBYTE *data,
3595 UWORD length, struct DevBase *base)
3597 length = (length + 1) / 2;
3598 P2Seek(unit, 1, rec_no, 0, base);
3600 unit->LEWordOut(unit->card, P2_REG_DATA1, 1 + length);
3601 unit->LEWordOut(unit->card, P2_REG_DATA1, rec_no);
3602 unit->WordsOut(unit->card, P2_REG_DATA1, (const UWORD *)data, length);
3604 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, rec_no, base);
3606 return;
3611 /****i* prism2.device/P2ReadRec ********************************************
3613 * NAME
3614 * P2ReadRec -- Load and read an entire record.
3616 * SYNOPSIS
3617 * success = P2ReadRec(unit, rec_no, buffer, max_length)
3619 * BOOL P2ReadRec(struct DevUnit *, UWORD, APTR, UWORD);
3621 * FUNCTION
3623 * INPUTS
3624 * unit - A unit of this device.
3625 * rec_no - Record number to read.
3626 * buffer - Buffer to store data in.
3627 * max_length - Maximum number of bytes to store in buffer.
3629 * RESULT
3630 * success - Success indicator.
3632 ****************************************************************************
3636 static BOOL P2ReadRec(struct DevUnit *unit, UWORD rec_no, APTR buffer,
3637 UWORD max_length, struct DevBase *base)
3639 BOOL success = TRUE;
3640 WORD length;
3642 P2DoCmd(unit, P2_CMD_ACCESS, rec_no, base);
3643 P2Seek(unit, 1, rec_no, 0, base);
3645 length = (unit->LEWordIn(unit->card, P2_REG_DATA1) + 1) * 2;
3646 P2Seek(unit, 1, rec_no, 0, base);
3647 if(length <= max_length)
3648 unit->WordsIn(unit->card, P2_REG_DATA1, (UWORD *)buffer,
3649 length / 2);
3650 else
3651 success = FALSE;
3652 return success;
3657 /****i* prism2.device/ConvertLevel *****************************************
3659 * NAME
3660 * ConvertLevel -- Convert a signal or noise level to dBm.
3662 * SYNOPSIS
3663 * dbm_level = ConvertLevel(unit, raw_level)
3665 * LONG ConvertLevel(struct DevUnit *, UWORD);
3667 * FUNCTION
3669 * INPUTS
3670 * unit - A unit of this device.
3671 * raw_level - The value returned from the hardware.
3673 * RESULT
3674 * dbm_level - The value in dBm.
3676 ****************************************************************************
3680 static LONG ConvertLevel(struct DevUnit *unit, UWORD raw_level,
3681 struct DevBase *base)
3683 LONG dbm_level;
3685 if(unit->firmware_type >= LUCENT_FIRMWARE)
3686 dbm_level = raw_level - LUCENT_DBM_OFFSET;
3687 else
3688 dbm_level = raw_level / 3 - INTERSIL_DBM_OFFSET;
3690 return dbm_level;
3695 /****i* prism2.device/ConvertScanLevel *************************************
3697 * NAME
3698 * ConvertScanLevel -- Convert a signal or noise level to dBm.
3700 * SYNOPSIS
3701 * dbm_level = ConvertScanLevel(unit, raw_level)
3703 * LONG ConvertScanLevel(struct DevUnit *, UWORD);
3705 * FUNCTION
3707 * INPUTS
3708 * unit - A unit of this device.
3709 * raw_level - The value returned from the hardware.
3711 * RESULT
3712 * dbm_level - The value in dBm.
3714 ****************************************************************************
3718 static LONG ConvertScanLevel(struct DevUnit *unit, UWORD raw_level,
3719 struct DevBase *base)
3721 LONG dbm_level;
3723 if(unit->firmware_type >= LUCENT_FIRMWARE)
3724 dbm_level = raw_level - LUCENT_DBM_OFFSET;
3725 else
3726 dbm_level = (WORD)raw_level;
3728 return dbm_level;
3733 /****i* prism2.device/GetIE ************************************************
3735 * NAME
3736 * GetIE
3738 * SYNOPSIS
3739 * ie = GetIE(id, ies, ies_length)
3741 * UBYTE *GetIE(UBYTE, UBYTE *, UWORD);
3743 * FUNCTION
3745 * INPUTS
3746 * id - ID of IE to find.
3747 * ies - A series of IEs.
3748 * ies_length - Length of IE block.
3750 * RESULT
3751 * ie - Pointer to start of IE within block, or NULL if not found.
3753 ****************************************************************************
3757 static UBYTE *GetIE(UBYTE id, UBYTE *ies, UWORD ies_length,
3758 struct DevBase *base)
3760 UBYTE *ie;
3762 for(ie = ies; ie < ies + ies_length && ie[0] != id; ie += ie[1] + 2);
3763 if(ie >= ies + ies_length)
3764 ie = NULL;
3766 return ie;
3771 /****i* prism2.device/CompareMACAddresses **********************************
3773 * NAME
3774 * CompareMACAddresses -- Compare two MAC addresses for equality.
3776 * SYNOPSIS
3777 * same = CompareMACAddresses(mac1, mac2)
3779 * UBYTE *CompareMACAddresses(UBYTE *, UBYTE *);
3781 * INPUTS
3782 * mac1 - first MAC address.
3783 * mac2 - second MAC address.
3785 * RESULT
3786 * same - TRUE if MAC addresses are equal.
3788 ****************************************************************************
3792 static BOOL CompareMACAddresses(APTR mac1, APTR mac2)
3794 return *(ULONG *)mac1 == *(ULONG *)mac2
3795 && *((UWORD *)mac1 + 2) == *((UWORD *)mac2 + 2);
3800 /****i* prism2.device/UnitTask *********************************************
3802 * NAME
3803 * UnitTask
3805 * SYNOPSIS
3806 * UnitTask(unit)
3808 * VOID UnitTask(struct DevUnit *);
3810 * FUNCTION
3811 * Completes deferred requests, and handles card insertion and removal
3812 * in conjunction with the relevant interrupts.
3814 ****************************************************************************
3818 static VOID UnitTask(struct DevUnit *unit)
3820 struct DevBase *base;
3821 struct IORequest *request;
3822 struct MsgPort *general_port;
3823 ULONG signals = 0, wait_signals, card_removed_signal,
3824 card_inserted_signal, scan_complete_signal, general_port_signal;
3826 base = unit->device;
3828 /* Activate general request port */
3830 general_port = unit->request_ports[GENERAL_QUEUE];
3831 general_port->mp_SigTask = unit->task;
3832 general_port->mp_SigBit = AllocSignal(-1);
3833 general_port_signal = 1 << general_port->mp_SigBit;
3834 general_port->mp_Flags = PA_SIGNAL;
3836 /* Allocate signals for notification of card removal and insertion */
3838 card_removed_signal = unit->card_removed_signal = 1 << AllocSignal(-1);
3839 card_inserted_signal = unit->card_inserted_signal = 1 << AllocSignal(-1);
3840 scan_complete_signal = unit->scan_complete_signal = 1 << AllocSignal(-1);
3841 wait_signals = (1 << general_port->mp_SigBit) | card_removed_signal
3842 | card_inserted_signal | scan_complete_signal | SIGBREAKF_CTRL_C;
3844 /* Tell ourselves to check port for old messages */
3846 Signal(unit->task, general_port_signal);
3848 /* Infinite loop to service requests and signals */
3850 while((signals & SIGBREAKF_CTRL_C) == 0)
3852 signals = Wait(wait_signals);
3854 if((signals & card_inserted_signal) != 0)
3856 if(unit->insertion_function(unit->card, base))
3858 unit->flags |= UNITF_HAVEADAPTER;
3859 if((unit->flags & UNITF_CONFIGURED) != 0)
3860 ConfigureAdapter(unit, base);
3861 if((unit->flags & UNITF_WASONLINE) != 0)
3863 GoOnline(unit, base);
3864 unit->flags &= ~UNITF_WASONLINE;
3869 if((signals & card_removed_signal) != 0)
3871 unit->removal_function(unit->card, base);
3872 if((unit->flags & UNITF_WASONLINE) != 0)
3873 GoOffline(unit, base);
3876 if((signals & scan_complete_signal) != 0)
3877 SendScanResults(unit, base);
3879 if((signals & general_port_signal) != 0)
3881 while((request = (APTR)GetMsg(general_port)) != NULL)
3883 /* Service the request as soon as the unit is free */
3885 ObtainSemaphore(&unit->access_lock);
3886 ServiceRequest((APTR)request, base);
3894 /****i* prism2.device/StrLen ***********************************************
3896 * NAME
3897 * StrLen
3899 * SYNOPSIS
3900 * length = StrLen(s)
3902 * UPINT StrLen(TEXT *);
3904 ****************************************************************************
3908 static UPINT StrLen(const TEXT *s)
3910 const TEXT *p;
3912 for(p = s; *p != '\0'; p++);
3913 return p - s;