New WPA-capable version of prism2.device.
[AROS.git] / workbench / devs / networks / prism2 / unit.c
blob355324887a2ffde5d8a7135e6ed3bbb9dd0a12cf
1 /*
3 Copyright (C) 2001-2012 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>
27 #include <proto/exec.h>
28 #ifndef __amigaos4__
29 #include <proto/alib.h>
30 #else
31 #include <clib/alib_protos.h>
32 #endif
33 #include <proto/utility.h>
34 #include <proto/dos.h>
35 #include <proto/timer.h>
37 #include "device.h"
38 #include "prism2.h"
40 #include "unit_protos.h"
41 #include "request_protos.h"
42 #include "encryption_protos.h"
43 #include "timer_protos.h"
46 #define TASK_PRIORITY 0
47 #define STACK_SIZE 4096
48 #define INT_MASK \
49 (P2_EVENTF_INFO | P2_EVENTF_ALLOCMEM | P2_EVENTF_TXFAIL | P2_EVENTF_RX)
50 #define MAX_S_REC_SIZE 50
51 #define LUCENT_DBM_OFFSET 149
52 #define INTERSIL_DBM_OFFSET 100
53 #define SCAN_BUFFER_SIZE 2000
54 #define BEACON_BUFFER_SIZE 8000
55 #define SCAN_TAG_COUNT 8 +10
56 #define INFO_TAG_COUNT 4 +10
57 #define LUCENT_PDA_ADDRESS 0x390000
58 #define LUCENT_PDA_SIZE 1000
59 #define FRAME_BUFFER_SIZE (P2_H2FRM_ETHFRAME + ETH_HEADERSIZE \
60 + SNAP_HEADERSIZE + ETH_MTU + EIV_SIZE + ICV_SIZE + MIC_SIZE)
63 #ifndef AbsExecBase
64 #ifdef __AROS__
65 #define AbsExecBase sys_base
66 #else
67 #define AbsExecBase (*(struct ExecBase **)4)
68 #endif
69 #endif
71 static struct AddressRange *FindMulticastRange(struct DevUnit *unit,
72 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left,
73 UWORD upper_bound_right, struct DevBase *base);
74 static VOID SetMulticast(struct DevUnit *unit, struct DevBase *base);
75 static VOID RXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code));
76 static UBYTE *GetRXBuffer(struct DevUnit *unit, const UBYTE *address,
77 UWORD frag_no, UWORD *buffer_no, struct DevBase *base);
78 static VOID DistributeRXPacket(struct DevUnit *unit, UBYTE *frame,
79 struct DevBase *base);
80 static VOID CopyPacket(struct DevUnit *unit, struct IOSana2Req *request,
81 UWORD packet_size, UWORD packet_type, UBYTE *buffer,
82 struct DevBase *base);
83 static BOOL AddressFilter(struct DevUnit *unit, UBYTE *address,
84 struct DevBase *base);
85 static VOID SaveBeacon(struct DevUnit *unit, const UBYTE *frame,
86 struct DevBase *base);
87 static VOID TXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code));
88 static VOID InfoInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code));
89 static VOID ResetHandler(REG(a1, struct DevUnit *unit),
90 REG(a6, APTR int_code));
91 static VOID ReportEvents(struct DevUnit *unit, ULONG events,
92 struct DevBase *base);
93 static BOOL LoadFirmware(struct DevUnit *unit, struct DevBase *base);
94 static const TEXT *ParseNextSRecord(const TEXT *s, UBYTE *type, UBYTE *data,
95 UWORD *data_length, ULONG *location, struct DevBase *base);
96 static VOID P2DoCmd(struct DevUnit *unit, UWORD command, UWORD param,
97 struct DevBase *base);
98 static BOOL P2Seek(struct DevUnit *unit, UWORD path_no, UWORD rec_no,
99 UWORD offset, struct DevBase *base);
100 static VOID P2SetID(struct DevUnit *unit, UWORD rec_no, const UBYTE *id,
101 UWORD length, struct DevBase *base);
102 static VOID P2SetWord(struct DevUnit *unit, UWORD rec_no, UWORD value,
103 struct DevBase *base);
104 static UWORD P2GetWord(struct DevUnit *unit, UWORD rec_no,
105 struct DevBase *base);
106 static UWORD P2AllocMem(struct DevUnit *unit, UWORD size,
107 struct DevBase *base);
108 static VOID P2SetData(struct DevUnit *unit, UWORD rec_no, const UBYTE *data,
109 UWORD length, struct DevBase *base);
110 static BOOL P2ReadRec(struct DevUnit *unit, UWORD rec_no, APTR buffer,
111 UWORD max_length, struct DevBase *base);
112 static LONG ConvertLevel(struct DevUnit *unit, UWORD raw_level,
113 struct DevBase *base);
114 static LONG ConvertScanLevel(struct DevUnit *unit, UWORD raw_level,
115 struct DevBase *base);
116 static UBYTE *GetIE(UBYTE id, UBYTE *ies, UWORD ies_length,
117 struct DevBase *base);
118 static VOID UnitTask(struct ExecBase *sys_base);
119 static UPINT StrLen(const TEXT *s);
122 static const UBYTE snap_template[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
123 static const UBYTE scan_params[] = {0xff, 0x3f, 0x01, 0x00, 0x00, 0x00};
124 static const TEXT options_name[] = "Prism 2 options";
125 static const TEXT h1_firmware_file_name[] = "DEVS:Firmware/HermesI";
126 static const TEXT h2_firmware_file_name[] = "DEVS:Firmware/HermesII";
127 static const TEXT h25_firmware_file_name[] = "DEVS:Firmware/HermesII.5";
128 static const UBYTE h2_wpa_ie[] =
130 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00,
131 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50,
132 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02,
133 0x00, 0x00
137 #ifdef __amigaos4__
138 #undef AddTask
139 #define AddTask(task, initial_pc, final_pc) \
140 IExec->AddTask(task, initial_pc, final_pc, NULL)
141 #endif
142 #ifdef __MORPHOS__
143 static const struct EmulLibEntry mos_task_trap =
145 TRAP_LIB,
147 (APTR)UnitTask
149 #define UnitTask &mos_task_trap
150 #endif
151 #ifdef __AROS__
152 #undef AddTask
153 #define AddTask(task, initial_pc, final_pc) \
154 ({ \
155 struct TagItem _task_tags[] = \
156 {{TASKTAG_ARG1, (IPTR)SysBase}, {TAG_END, 0}}; \
157 NewAddTask(task, initial_pc, final_pc, _task_tags); \
159 #endif
163 /****i* prism2.device/CreateUnit *******************************************
165 * NAME
166 * CreateUnit -- Create a unit.
168 * SYNOPSIS
169 * unit = CreateUnit(index, card, io_tags, bus)
171 * struct DevUnit *CreateUnit(ULONG, APTR, struct TagItem *, UWORD);
173 * FUNCTION
174 * Creates a new unit.
176 ****************************************************************************
180 struct DevUnit *CreateUnit(ULONG index, APTR card,
181 const struct TagItem *io_tags, UWORD bus, struct DevBase *base)
183 BOOL success = TRUE;
184 struct DevUnit *unit;
185 struct Task *task;
186 struct MsgPort *port;
187 UBYTE i;
188 APTR stack;
190 unit = AllocMem(sizeof(struct DevUnit), MEMF_CLEAR | MEMF_PUBLIC);
191 if(unit == NULL)
192 success = FALSE;
194 if(success)
196 unit->index = index;
197 unit->device = base;
198 unit->card = card;
199 unit->bus = bus;
200 unit->WordsIn =
201 (APTR)GetTagData(IOTAG_WordsIn, (UPINT)NULL, io_tags);
202 unit->WordsOut =
203 (APTR)GetTagData(IOTAG_WordsOut, (UPINT)NULL, io_tags);
204 unit->BEWordOut =
205 (APTR)GetTagData(IOTAG_BEWordOut, (UPINT)NULL, io_tags);
206 unit->LEWordIn =
207 (APTR)GetTagData(IOTAG_LEWordIn, (UPINT)NULL, io_tags);
208 unit->LEWordOut =
209 (APTR)GetTagData(IOTAG_LEWordOut, (UPINT)NULL, io_tags);
210 if(unit->WordsIn == NULL || unit->WordsOut == NULL
211 || unit->BEWordOut == NULL || unit->LEWordIn == NULL
212 || unit->LEWordOut == NULL)
213 success = FALSE;
216 if(success)
218 InitSemaphore(&unit->access_lock);
219 success = InitialiseAdapter(unit, FALSE, base);
220 unit->flags |= UNITF_HAVEADAPTER;
222 /* Create the message ports for queuing requests */
224 for(i = 0; i < REQUEST_QUEUE_COUNT; i++)
226 unit->request_ports[i] = port = AllocMem(sizeof(struct MsgPort),
227 MEMF_PUBLIC | MEMF_CLEAR);
228 if(port == NULL)
229 success = FALSE;
231 if(success)
233 NewList(&port->mp_MsgList);
234 port->mp_Flags = PA_IGNORE;
235 port->mp_SigTask = &unit->tx_int;
239 /* Allocate buffers */
241 unit->rx_buffer = AllocVec(FRAME_BUFFER_SIZE, MEMF_PUBLIC);
242 unit->rx_buffers = AllocVec(FRAME_BUFFER_SIZE * RX_BUFFER_COUNT,
243 MEMF_PUBLIC);
244 for(i = 0; i < RX_BUFFER_COUNT; i++)
245 unit->rx_fragment_nos[i] = -1;
246 unit->tx_buffer = AllocVec(ETH_MAXPACKETSIZE, MEMF_PUBLIC);
247 unit->rx_descriptor = AllocVec(FRAME_BUFFER_SIZE,
248 MEMF_PUBLIC | MEMF_CLEAR);
249 unit->tx_descriptor = AllocVec(FRAME_BUFFER_SIZE,
250 MEMF_PUBLIC | MEMF_CLEAR);
251 unit->scan_results_rec = AllocVec(SCAN_BUFFER_SIZE, MEMF_PUBLIC);
252 unit->next_beacon = unit->beacons =
253 AllocVec(BEACON_BUFFER_SIZE, MEMF_PUBLIC);
254 if(unit->rx_buffer == NULL || unit->rx_buffers == NULL
255 || unit->tx_buffer == NULL || unit->rx_descriptor == NULL
256 || unit->tx_descriptor == NULL || unit->scan_results_rec == NULL
257 || unit->beacons == NULL)
258 success = FALSE;
261 if(success)
263 NewList((APTR)&unit->openers);
264 NewList((APTR)&unit->type_trackers);
265 NewList((APTR)&unit->multicast_ranges);
267 /* Record maximum speed in BPS */
269 unit->speed = 11000000;
271 /* Initialise status, transmit, receive and stats interrupts */
273 unit->status_int.is_Node.ln_Name =
274 base->device.dd_Library.lib_Node.ln_Name;
275 unit->status_int.is_Code = (APTR)StatusInt;
276 unit->status_int.is_Data = unit;
278 unit->rx_int.is_Node.ln_Name =
279 base->device.dd_Library.lib_Node.ln_Name;
280 unit->rx_int.is_Code = (APTR)RXInt;
281 unit->rx_int.is_Data = unit;
283 unit->tx_int.is_Node.ln_Name =
284 base->device.dd_Library.lib_Node.ln_Name;
285 unit->tx_int.is_Code = (APTR)TXInt;
286 unit->tx_int.is_Data = unit;
288 unit->info_int.is_Node.ln_Name =
289 base->device.dd_Library.lib_Node.ln_Name;
290 unit->info_int.is_Code = (APTR)InfoInt;
291 unit->info_int.is_Data = unit;
293 unit->reset_handler.is_Node.ln_Name =
294 base->device.dd_Library.lib_Node.ln_Name;
295 unit->reset_handler.is_Code = (APTR)ResetHandler;
296 unit->reset_handler.is_Data = unit;
298 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
301 if(success)
303 /* Create a new task */
305 unit->task = task =
306 AllocMem(sizeof(struct Task), MEMF_PUBLIC | MEMF_CLEAR);
307 if(task == NULL)
308 success = FALSE;
311 if(success)
313 stack = AllocMem(STACK_SIZE, MEMF_PUBLIC);
314 if(stack == NULL)
315 success = FALSE;
318 if(success)
320 /* Initialise and start task */
322 task->tc_Node.ln_Type = NT_TASK;
323 task->tc_Node.ln_Pri = TASK_PRIORITY;
324 task->tc_Node.ln_Name = base->device.dd_Library.lib_Node.ln_Name;
325 task->tc_SPUpper = stack + STACK_SIZE;
326 task->tc_SPLower = stack;
327 task->tc_SPReg = stack + STACK_SIZE;
328 NewList(&task->tc_MemEntry);
330 if(AddTask(task, UnitTask, NULL) == NULL)
331 success = FALSE;
334 if(success)
336 /* Send the unit to the new task */
338 task->tc_UserData = unit;
340 /* Set default wireless options */
342 unit->mode = S2PORT_MANAGED;
345 if(!success)
347 DeleteUnit(unit, base);
348 unit = NULL;
351 return unit;
356 /****i* prism2.device/DeleteUnit *******************************************
358 * NAME
359 * DeleteUnit -- Delete a unit.
361 * SYNOPSIS
362 * DeleteUnit(unit)
364 * VOID DeleteUnit(struct DevUnit *);
366 * FUNCTION
367 * Deletes a unit.
369 * INPUTS
370 * unit - Device unit (may be NULL).
372 * RESULT
373 * None.
375 ****************************************************************************
379 VOID DeleteUnit(struct DevUnit *unit, struct DevBase *base)
381 UBYTE i;
382 struct Task *task;
384 if(unit != NULL)
386 /* Remove task */
388 task = unit->task;
389 if(task != NULL)
391 if(task->tc_UserData != NULL)
393 RemTask(task);
394 FreeMem(task->tc_SPLower, STACK_SIZE);
396 FreeMem(task, sizeof(struct Task));
399 /* Free request queues */
401 for(i = 0; i < REQUEST_QUEUE_COUNT; i++)
403 if(unit->request_ports[i] != NULL)
404 FreeMem(unit->request_ports[i], sizeof(struct MsgPort));
407 /* Go offline */
409 if((unit->flags & UNITF_ONLINE) != 0) /* Needed! */
410 GoOffline(unit, base);
412 /* Clear target SSID */
414 P2SetID(unit, P2_REC_DESIREDSSID, unit->ssid, 0, base);
416 /* Free buffers and unit structure */
418 FreeVec(unit->scan_results_rec);
419 FreeVec(unit->tx_descriptor);
420 FreeVec(unit->rx_descriptor);
421 FreeVec(unit->tx_buffer);
422 FreeVec(unit->rx_buffers);
423 FreeVec(unit->rx_buffer);
425 FreeMem(unit, sizeof(struct DevUnit));
428 return;
433 /****i* prism2.device/InitialiseAdapter ************************************
435 * NAME
436 * InitialiseAdapter
438 * SYNOPSIS
439 * success = InitialiseAdapter(unit, reinsertion)
441 * BOOL InitialiseAdapter(struct DevUnit *, BOOL);
443 * FUNCTION
445 * INPUTS
446 * unit
447 * reinsertion
449 * RESULT
450 * success - Success indicator.
452 ****************************************************************************
456 BOOL InitialiseAdapter(struct DevUnit *unit, BOOL reinsertion,
457 struct DevBase *base)
459 UWORD id, version, revision, i;
460 BOOL success = TRUE, loaded;
461 UBYTE address[ETH_ADDRESSSIZE];
462 WORD length;
464 /* Wait for card to be ready following bus-specific reset, then start
465 it */
467 while((unit->LEWordIn(unit->card, P2_REG_COMMAND)
468 & P2_REG_COMMANDF_BUSY) != 0);
470 P2DoCmd(unit, P2_CMD_INIT, 0, base);
472 /* Determine firmware type */
474 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_NICIDENTITY, base);
475 P2Seek(unit, 1, P2_REC_NICIDENTITY, 4, base);
476 id = unit->LEWordIn(unit->card, P2_REG_DATA1);
477 unit->LEWordIn(unit->card, P2_REG_DATA1);
478 version = unit->LEWordIn(unit->card, P2_REG_DATA1);
479 revision = unit->LEWordIn(unit->card, P2_REG_DATA1);
481 if((id & 0x8000) != 0)
483 if(version == 0)
484 unit->firmware_type = SYMBOL_FIRMWARE;
485 else
486 unit->firmware_type = INTERSIL_FIRMWARE;
488 else
490 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_PRIIDENTITY, base);
491 P2Seek(unit, 1, P2_REC_PRIIDENTITY, 0, base);
492 length = unit->LEWordIn(unit->card, P2_REG_DATA1);
493 if(length == 5)
494 unit->firmware_type = LUCENT_FIRMWARE;
495 else
497 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_STAIDENTITY, base);
498 P2Seek(unit, 1, P2_REC_STAIDENTITY, 4, base);
499 id = unit->LEWordIn(unit->card, P2_REG_DATA1);
500 unit->LEWordIn(unit->card, P2_REG_DATA1);
501 version = unit->LEWordIn(unit->card, P2_REG_DATA1);
502 revision = unit->LEWordIn(unit->card, P2_REG_DATA1);
503 if(version > 1)
504 unit->firmware_type = HERMES2G_FIRMWARE;
505 else
506 unit->firmware_type = HERMES2_FIRMWARE;
510 /* Download firmware if necessary or available */
512 loaded = LoadFirmware(unit, base);
513 if(!loaded && unit->firmware_type >= HERMES2_FIRMWARE)
514 success = FALSE;
516 if(success)
518 /* Determine features, and get offsets of certain fields within frame
519 descriptors */
521 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_STAIDENTITY, base);
522 P2Seek(unit, 1, P2_REC_STAIDENTITY, 4, base);
523 unit->LEWordIn(unit->card, P2_REG_DATA1);
524 unit->LEWordIn(unit->card, P2_REG_DATA1);
525 version = unit->LEWordIn(unit->card, P2_REG_DATA1);
526 revision = unit->LEWordIn(unit->card, P2_REG_DATA1);
528 if(P2GetWord(unit, P2_REC_HASWEP, base) != 0)
529 unit->flags |= UNITF_HASWEP | UNITF_HARDWEP;
531 unit->ethernet_offset = P2_FRM_ETHFRAME;
532 unit->data_offset = P2_FRM_DATA;
533 unit->txcontrol_offset = P2_FRM_TXCONTROL;
534 unit->datalen_offset = P2_FRM_DATALEN;
536 if(unit->firmware_type == LUCENT_FIRMWARE)
538 if(version > 6 || version == 6 && revision >= 6)
539 unit->flags |= UNITF_HASADHOC;
540 if(version >= 9)
542 unit->flags |= UNITF_HASTKIP | UNITF_HARDTKIP;
543 unit->txcontrol_offset = P2_FRM_ALTTXCONTROL;
546 else if(unit->firmware_type >= HERMES2_FIRMWARE)
548 unit->flags |= UNITF_HASADHOC | UNITF_HASTKIP | UNITF_HARDTKIP;
549 unit->ethernet_offset = P2_H2FRM_ETHFRAME;
550 unit->data_offset = P2_H2FRM_DATA;
551 unit->txcontrol_offset = P2_H2FRM_TXCONTROL;
552 unit->datalen_offset = P2_H2FRM_DATALEN;
554 else if(unit->firmware_type == INTERSIL_FIRMWARE)
556 unit->flags |= UNITF_HASADHOC | UNITF_HASWEP;
557 if(version == 1 && revision >= 7)
558 unit->flags |= UNITF_HASTKIP | UNITF_HASCCMP;
561 /* Get default channel and MAC address */
563 unit->channel = P2GetWord(unit, P2_REC_OWNCHNL, base);
564 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_ADDRESS, base);
565 P2Seek(unit, 1, P2_REC_ADDRESS, 4, base);
566 unit->WordsIn(unit->card, P2_REG_DATA1, (UWORD *)address,
567 ETH_ADDRESSSIZE / 2);
569 /* If card has been re-inserted, check it has the same address as
570 before */
572 if(reinsertion)
574 for(i = 0; i < ETH_ADDRESSSIZE; i++)
575 if(address[i] != unit->default_address[i])
576 success = FALSE;
580 if(success)
582 CopyMem(address, unit->default_address, ETH_ADDRESSSIZE);
584 /* Get initial on-card TX buffer */
586 unit->tx_frame_id = P2AllocMem(unit, FRAME_BUFFER_SIZE, base);
588 /* Set IV sizes */
590 if((unit->flags & UNITF_HARDWEP) == 0)
591 unit->iv_sizes[S2ENC_WEP] = IV_SIZE;
592 if((unit->flags & UNITF_HARDTKIP) == 0)
593 unit->iv_sizes[S2ENC_TKIP] = EIV_SIZE;
594 unit->iv_sizes[S2ENC_CCMP] = EIV_SIZE;
596 /* Set encryption functions */
598 unit->fragment_encrypt_functions[S2ENC_NONE] = WriteClearFragment;
600 if((unit->flags & UNITF_HARDWEP) != 0)
601 unit->fragment_encrypt_functions[S2ENC_WEP] = WriteClearFragment;
602 else
603 unit->fragment_encrypt_functions[S2ENC_WEP] = EncryptWEPFragment;
605 if((unit->flags & UNITF_HARDTKIP) != 0)
606 unit->fragment_encrypt_functions[S2ENC_TKIP] = WriteClearFragment;
607 else
608 unit->fragment_encrypt_functions[S2ENC_TKIP] = EncryptTKIPFragment;
610 unit->fragment_encrypt_functions[S2ENC_CCMP] = EncryptCCMPFragment;
612 /* Set decryption functions */
614 unit->fragment_decrypt_functions[S2ENC_NONE] = ReadClearFragment;
616 if((unit->flags & UNITF_HARDWEP) != 0)
617 unit->fragment_decrypt_functions[S2ENC_WEP] = ReadClearFragment;
618 else
619 unit->fragment_decrypt_functions[S2ENC_WEP] = DecryptWEPFragment;
621 if((unit->flags & UNITF_HARDTKIP) != 0)
622 unit->fragment_decrypt_functions[S2ENC_TKIP] = ReadClearFragment;
623 else
624 unit->fragment_decrypt_functions[S2ENC_TKIP] = DecryptTKIPFragment;
626 unit->fragment_decrypt_functions[S2ENC_CCMP] = DecryptCCMPFragment;
629 /* Return */
631 return success;
636 /****i* prism2.device/ConfigureAdapter *************************************
638 * NAME
639 * ConfigureAdapter -- Set up card for transmission/reception.
641 * SYNOPSIS
642 * ConfigureAdapter(unit)
644 * VOID ConfigureAdapter(struct DevUnit *);
646 ****************************************************************************
650 VOID ConfigureAdapter(struct DevUnit *unit, struct DevBase *base)
652 UWORD i, key_length, port_type, lowest_enc = S2ENC_CCMP,
653 highest_enc = S2ENC_NONE, enc_flags, size, value;
654 const struct KeyUnion *keys;
656 /* Set MAC address */
658 P2SetData(unit, P2_REC_ADDRESS, unit->address, ETH_ADDRESSSIZE,
659 base);
661 /* Decide on promiscuous mode */
663 P2SetWord(unit, P2_REC_PROMISC, FALSE, base);
664 SetMulticast(unit, base);
666 /* Set wireless parameters */
668 if(unit->mode == S2PORT_ADHOC)
670 P2SetWord(unit, P2_REC_OWNCHNL, unit->channel, base);
671 P2SetID(unit, P2_REC_OWNSSID, unit->ssid, unit->ssid_length, base);
673 if(unit->mode == S2PORT_MANAGED)
674 port_type = 1;
675 else
676 port_type = 0;
677 if((unit->flags & UNITF_ONLINE) == 0)
678 P2SetWord(unit, P2_REC_PORTTYPE, port_type, base);
679 P2SetWord(unit, P2_REC_CREATEIBSS, unit->mode == S2PORT_ADHOC, base);
680 P2SetID(unit, P2_REC_DESIREDSSID, unit->ssid, unit->ssid_length, base);
682 /* Determine highest encryption type in use */
684 for(i = 0; i < WIFI_KEYCOUNT; i++)
686 if(unit->keys[i].type > highest_enc)
687 highest_enc = unit->keys[i].type;
688 if(unit->keys[i].type < lowest_enc)
689 lowest_enc = unit->keys[i].type;
692 if(unit->wpa_ie[1] != 0)
693 highest_enc = S2ENC_TKIP; // TO DO: Be more specific?
695 /* Allow reception of beacon/probe-response frames */
697 if(unit->firmware_type == INTERSIL_FIRMWARE)
698 P2SetWord(unit, P2_REC_RXMGMTFRAMES, 1, base);
700 /* Transmit at 11Mbps, with fallback */
702 if(unit->firmware_type == INTERSIL_FIRMWARE
703 || unit->firmware_type == SYMBOL_FIRMWARE)
704 P2SetWord(unit, P2_REC_TXRATE, 0xf, base);
706 /* Configure authentication and encryption */
708 if(unit->firmware_type >= LUCENT_FIRMWARE)
710 /* Set authentication and encryption modes */
712 P2SetWord(unit, P2_REC_ALTAUTHTYPE, unit->auth_types, base);
714 P2SetWord(unit, P2_REC_ALTENCRYPTION, highest_enc, base);
716 /* Set up firmware-based WEP encryption if appropriate */
718 if(highest_enc == S2ENC_WEP && (unit->flags & UNITF_HARDWEP) != 0)
720 P2SetWord(unit, P2_REC_ALTTXCRYPTKEY, unit->tx_key_no, base);
721 P2Seek(unit, 1, P2_REC_DEFLTCRYPTKEYS, 0, base);
722 unit->LEWordOut(unit->card, P2_REG_DATA1, P2_ALTWEPRECLEN);
723 unit->LEWordOut(unit->card, P2_REG_DATA1, P2_REC_DEFLTCRYPTKEYS);
724 keys = unit->keys;
725 for(i = 0; i < WIFI_KEYCOUNT; i++)
727 key_length = keys[i].u.wep.length;
728 if(key_length == 0)
729 key_length = WIFI_WEP128LEN;
730 unit->LEWordOut(unit->card, P2_REG_DATA1, key_length);
731 unit->WordsOut(unit->card, P2_REG_DATA1,
732 (UWORD *)keys[i].u.wep.key, (key_length + 1) / 2);
735 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE,
736 P2_REC_DEFLTCRYPTKEYS, base);
739 /* Set key management suite to PSK */
741 if(highest_enc > S2ENC_WEP)
743 value = (unit->firmware_type >= HERMES2_FIRMWARE) ? 4 : 2;
744 P2SetWord(unit, P2_REC_KEYMGMTSUITE, value, base);
747 else
749 /* Set authentication mode */
751 P2SetWord(unit, P2_REC_AUTHTYPE, unit->auth_types, base);
753 /* Set encryption flags */
755 if(highest_enc > S2ENC_NONE)
756 enc_flags = P2_REC_ENCRYPTIONF_ENABLE;
757 else
758 enc_flags = 0;
760 if(highest_enc > S2ENC_WEP
761 || highest_enc == S2ENC_WEP && (unit->flags & UNITF_HARDWEP) == 0)
762 enc_flags |= P2_REC_ENCRYPTIONF_HOSTDECRYPT
763 | P2_REC_ENCRYPTIONF_HOSTENCRYPT;
764 P2SetWord(unit, P2_REC_ENCRYPTION, enc_flags, base);
766 /* Set up firmware-based WEP encryption if appropriate */
768 if(highest_enc == S2ENC_WEP && (unit->flags & UNITF_HARDWEP) != 0)
770 P2SetWord(unit, P2_REC_TXCRYPTKEY, unit->tx_key_no, base);
772 keys = unit->keys;
773 for(i = 0; i < WIFI_KEYCOUNT; i++)
775 key_length = keys[i].u.wep.length;
776 if(key_length == 0)
777 key_length = keys[unit->tx_key_no].u.wep.length;
778 P2SetData(unit, P2_REC_CRYPTKEY0 + i, keys[i].u.wep.key,
779 key_length, base);
783 /* Set or clear WPA IE */
785 if(highest_enc > S2ENC_WEP)
786 size = unit->wpa_ie[1] + 2;
787 else
788 size = 0;
789 P2SetID(unit, P2_REC_WPAIE, unit->wpa_ie, size, base);
791 /* Let supplicant handle association and roaming */
793 P2SetWord(unit, P2_REC_ROAMINGMODE, 3, base);
796 /* Restart the transceiver if we're already online */
798 if((unit->flags & UNITF_ONLINE) != 0)
800 P2DoCmd(unit, P2_CMD_DISABLE, 0, base);
801 P2DoCmd(unit, P2_CMD_ENABLE, 0, base);
803 /* Attempt to join specified network */
805 if(unit->firmware_type == INTERSIL_FIRMWARE)
807 *(UWORD *)(unit->bssid + ETH_ADDRESSSIZE) =
808 MakeLEWord(unit->channel);
809 P2SetData(unit, P2_REC_JOIN, unit->bssid, ETH_ADDRESSSIZE + 2,
810 base);
814 /* Return */
816 return;
821 /****i* prism2.device/GoOnline *********************************************
823 * NAME
824 * GoOnline -- Enable transmission/reception.
826 * SYNOPSIS
827 * GoOnline(unit)
829 * VOID GoOnline(struct DevUnit *);
831 ****************************************************************************
835 VOID GoOnline(struct DevUnit *unit, struct DevBase *base)
837 /* Enable interrupts */
839 unit->flags |= UNITF_ONLINE;
840 unit->LEWordOut(unit->card, P2_REG_INTMASK, INT_MASK);
842 /* Enable the transceiver */
844 P2DoCmd(unit, P2_CMD_ENABLE, 0, base);
846 /* Record start time and report Online event */
848 GetSysTime(&unit->stats.LastStart);
849 ReportEvents(unit, S2EVENT_ONLINE, base);
851 return;
856 /****i* prism2.device/GoOffline ********************************************
858 * NAME
859 * GoOffline -- Disable transmission/reception.
861 * SYNOPSIS
862 * GoOffline(unit)
864 * VOID GoOffline(struct DevUnit *);
866 * FUNCTION
868 * INPUTS
869 * unit
871 * RESULT
872 * None.
874 ****************************************************************************
878 VOID GoOffline(struct DevUnit *unit, struct DevBase *base)
880 unit->flags &= ~UNITF_ONLINE;
881 if((unit->flags & UNITF_HAVEADAPTER) != 0)
883 /* Stop interrupts */
885 unit->LEWordOut(unit->card, P2_REG_INTMASK, 0);
886 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
888 /* Update statistics */
890 UpdateStats(unit, base);
892 /* Stop transmission and reception */
894 P2DoCmd(unit, P2_CMD_DISABLE, 0, base);
897 /* Flush pending read and write requests */
899 FlushUnit(unit, WRITE_QUEUE, S2ERR_OUTOFSERVICE, base);
901 /* Report Offline event and return */
903 ReportEvents(unit, S2EVENT_OFFLINE, base);
904 return;
909 /****i* prism2.device/SetOptions *******************************************
911 * NAME
912 * SetOptions -- Set and use interface options.
914 * SYNOPSIS
915 * SetOptions(unit, tag_list)
917 * VOID SetOptions(struct DevUnit *, struct TagItem *);
919 ****************************************************************************
923 VOID SetOptions(struct DevUnit *unit, const struct TagItem *tag_list,
924 struct DevBase *base)
926 struct TagItem *tag_item, *tlist = (struct TagItem *)tag_list;
927 const TEXT *id;
928 UPINT length;
929 const UBYTE *ie;
931 while((tag_item = NextTagItem(&tlist)) != NULL)
933 switch(tag_item->ti_Tag)
935 case S2INFO_SSID:
936 id = (const TEXT *)tag_item->ti_Data;
937 length = StrLen(id);
938 CopyMem(id, unit->ssid, length);
939 unit->ssid_length = length;
940 break;
942 case S2INFO_BSSID:
943 CopyMem((APTR)tag_item->ti_Data, unit->bssid, ETH_ADDRESSSIZE);
944 break;
946 case S2INFO_DefaultKeyNo:
947 unit->tx_key_no = tag_item->ti_Data;
948 break;
950 case S2INFO_PortType:
951 unit->mode = tag_item->ti_Data;
952 break;
954 case S2INFO_Channel:
955 if(tag_item->ti_Data != 0) // ???
956 unit->channel = tag_item->ti_Data;
957 break;
959 case S2INFO_WPAInfo:
960 if(tag_item->ti_Data != (UPINT)NULL)
962 /* Hermes-II uses an "unusual" WPA IE in its association
963 request. So we use a matching IE everywhere else too */
965 if(unit->firmware_type >= HERMES2_FIRMWARE)
966 ie = h2_wpa_ie;
967 else
968 ie = (const UBYTE *)tag_item->ti_Data;
969 CopyMem(ie, unit->wpa_ie, ie[1] + 2);
971 else
973 unit->wpa_ie[0] = 0;
974 unit->wpa_ie[1] = 0;
976 break;
978 case S2INFO_AuthTypes:
979 unit->auth_types = tag_item->ti_Data;
980 break;
984 return;
989 /****i* prism2.device/SetKey ***********************************************
991 * NAME
992 * SetKey -- Set an encryption key.
994 * SYNOPSIS
995 * SetKey(unit, index, type, key, key_length,
996 * rx_counter)
998 * VOID SetKey(struct DevUnit *, ULONG, ULONG, UBYTE *, ULONG,
999 * UBYTE *);
1001 ****************************************************************************
1005 VOID SetKey(struct DevUnit *unit, ULONG index, ULONG type, const UBYTE *key,
1006 ULONG key_length, const UBYTE *rx_counter, struct DevBase *base)
1008 struct KeyUnion *slot;
1009 const UBYTE tx_counter[8] = {0, 0, 0, 0, 0x10, 0, 0, 0};
1010 UWORD i;
1011 struct EClockVal eclock;
1013 Disable();
1014 slot = &unit->keys[index];
1015 switch(type)
1017 case S2ENC_WEP:
1018 CopyMem(key, slot->u.wep.key, key_length);
1019 slot->u.wep.length = key_length;
1021 if((unit->flags & UNITF_HARDWEP) == 0)
1023 /* Create a reasonably random IV */
1025 ReadEClock(&eclock);
1026 slot->u.wep.tx_iv = FastRand(eclock.ev_lo ^ eclock.ev_hi);
1029 break;
1031 case S2ENC_TKIP:
1032 CopyMem(key, slot->u.tkip.key, 16);
1033 CopyMem(key + 16, slot->u.tkip.tx_mic_key, MIC_SIZE);
1034 CopyMem(key + 24, slot->u.tkip.rx_mic_key, MIC_SIZE);
1035 slot->u.tkip.tx_iv_low = 0;
1036 slot->u.tkip.tx_iv_high = 0;
1037 slot->u.tkip.rx_iv_low = LEWord(*(UWORD *)rx_counter);
1038 slot->u.tkip.rx_iv_high = LELong(*(ULONG *)(rx_counter + 2));
1039 slot->u.tkip.tx_ttak_set = FALSE;
1040 slot->u.tkip.rx_ttak_set = FALSE;
1042 if((unit->flags & UNITF_HARDTKIP) != 0)
1044 /* For Hermes, load parameters for hardware encryption. The
1045 pairwise key is treated differently from group keys on
1046 Hermes-II, but not on Hermes-I */
1048 if(unit->firmware_type >= HERMES2_FIRMWARE && index == 0)
1050 P2Seek(unit, 1, P2_REC_ADDMAPPEDTKIPKEY, 0, base);
1051 unit->LEWordOut(unit->card, P2_REG_DATA1, 28);
1052 unit->LEWordOut(unit->card, P2_REG_DATA1,
1053 P2_REC_ADDMAPPEDTKIPKEY);
1054 unit->WordsOut(unit->card, P2_REG_DATA1,
1055 (UWORD *)unit->bssid, ETH_ADDRESSSIZE / 2);
1056 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)key,
1057 16 / 2);
1058 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)tx_counter,
1059 8 / 2);
1060 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)rx_counter,
1061 6 / 2);
1062 unit->LEWordOut(unit->card, P2_REG_DATA1, 0);
1063 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)key + 16,
1064 16 / 2);
1065 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE,
1066 P2_REC_ADDMAPPEDTKIPKEY, base);
1068 else
1070 P2Seek(unit, 1, P2_REC_ADDDEFAULTTKIPKEY, 0, base);
1071 unit->LEWordOut(unit->card, P2_REG_DATA1, 26);
1072 unit->LEWordOut(unit->card, P2_REG_DATA1,
1073 P2_REC_ADDDEFAULTTKIPKEY);
1074 if(index == unit->tx_key_no)
1075 index |= 0x8000;
1076 unit->LEWordOut(unit->card, P2_REG_DATA1, index);
1077 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)rx_counter,
1078 6 / 2);
1079 unit->LEWordOut(unit->card, P2_REG_DATA1, 0);
1080 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)key,
1081 32 / 2);
1082 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)tx_counter,
1083 8 / 2);
1084 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE,
1085 P2_REC_ADDDEFAULTTKIPKEY, base);
1088 else
1090 /* Convert key to native endianness */
1092 for(i = 0; i < 8; i++)
1093 slot->u.tkip.key[i] = LEWord(slot->u.tkip.key[i]);
1096 break;
1098 case S2ENC_CCMP:
1099 CopyMem(key, slot->u.ccmp.key, 16);
1100 slot->u.ccmp.tx_iv_low = 0;
1101 slot->u.ccmp.tx_iv_high = 0;
1102 slot->u.ccmp.rx_iv_low = LEWord(*(UWORD *)rx_counter);
1103 slot->u.ccmp.rx_iv_high = LELong(*(ULONG *)(rx_counter + 2));
1104 slot->u.ccmp.stream_set = FALSE;
1107 /* Clear TKIP key if necessary */
1109 if(slot->type == S2ENC_TKIP && type != S2ENC_TKIP)
1111 if(unit->firmware_type >= HERMES2_FIRMWARE && index == 0)
1112 P2SetData(unit, P2_REC_REMMAPPEDTKIPKEY, unit->bssid,
1113 ETH_ADDRESSSIZE, base);
1114 else if(unit->firmware_type >= LUCENT_FIRMWARE)
1115 P2SetWord(unit, P2_REC_REMDEFAULTTKIPKEY, index, base);
1118 /* Update type of key in selected slot */
1120 slot->type = type;
1121 Enable();
1123 return;
1128 /****i* prism2.device/AddMulticastRange ************************************
1130 * NAME
1131 * AddMulticastRange
1133 * SYNOPSIS
1134 * success = AddMulticastRange(unit, lower_bound, upper_bound)
1136 * BOOL AddMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1138 ****************************************************************************
1142 BOOL AddMulticastRange(struct DevUnit *unit, const UBYTE *lower_bound,
1143 const UBYTE *upper_bound, struct DevBase *base)
1145 struct AddressRange *range;
1146 ULONG lower_bound_left, upper_bound_left;
1147 UWORD lower_bound_right, upper_bound_right;
1149 lower_bound_left = BELong(*((ULONG *)lower_bound));
1150 lower_bound_right = BEWord(*((UWORD *)(lower_bound + 4)));
1151 upper_bound_left = BELong(*((ULONG *)upper_bound));
1152 upper_bound_right = BEWord(*((UWORD *)(upper_bound + 4)));
1154 range = FindMulticastRange(unit, lower_bound_left, lower_bound_right,
1155 upper_bound_left, upper_bound_right, base);
1157 if(range != NULL)
1158 range->add_count++;
1159 else
1161 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
1162 if(range != NULL)
1164 range->lower_bound_left = lower_bound_left;
1165 range->lower_bound_right = lower_bound_right;
1166 range->upper_bound_left = upper_bound_left;
1167 range->upper_bound_right = upper_bound_right;
1168 range->add_count = 1;
1170 Disable();
1171 AddTail((APTR)&unit->multicast_ranges, (APTR)range);
1172 unit->range_count++;
1173 SetMulticast(unit, base);
1174 Enable();
1178 return range != NULL;
1183 /****i* prism2.device/RemMulticastRange ************************************
1185 * NAME
1186 * RemMulticastRange
1188 * SYNOPSIS
1189 * found = RemMulticastRange(unit, lower_bound, upper_bound)
1191 * BOOL RemMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1193 ****************************************************************************
1197 BOOL RemMulticastRange(struct DevUnit *unit, const UBYTE *lower_bound,
1198 const UBYTE *upper_bound, struct DevBase *base)
1200 struct AddressRange *range;
1201 ULONG lower_bound_left, upper_bound_left;
1202 UWORD lower_bound_right, upper_bound_right;
1204 lower_bound_left = BELong(*((ULONG *)lower_bound));
1205 lower_bound_right = BEWord(*((UWORD *)(lower_bound + 4)));
1206 upper_bound_left = BELong(*((ULONG *)upper_bound));
1207 upper_bound_right = BEWord(*((UWORD *)(upper_bound + 4)));
1209 range = FindMulticastRange(unit, lower_bound_left, lower_bound_right,
1210 upper_bound_left, upper_bound_right, base);
1212 if(range != NULL)
1214 if(--range->add_count == 0)
1216 Disable();
1217 Remove((APTR)range);
1218 unit->range_count--;
1219 SetMulticast(unit, base);
1220 Enable();
1221 FreeMem(range, sizeof(struct AddressRange));
1225 return range != NULL;
1230 /****i* prism2.device/FindMulticastRange ***********************************
1232 * NAME
1233 * FindMulticastRange
1235 * SYNOPSIS
1236 * range = FindMulticastRange(unit, lower_bound_left,
1237 * lower_bound_right, upper_bound_left, upper_bound_right)
1239 * struct AddressRange *FindMulticastRange(struct DevUnit *, ULONG,
1240 * UWORD, ULONG, UWORD);
1242 ****************************************************************************
1246 static struct AddressRange *FindMulticastRange(struct DevUnit *unit,
1247 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left,
1248 UWORD upper_bound_right, struct DevBase *base)
1250 struct AddressRange *range, *tail;
1251 BOOL found = FALSE;
1253 range = (APTR)unit->multicast_ranges.mlh_Head;
1254 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
1256 while(range != tail && !found)
1258 if(lower_bound_left == range->lower_bound_left &&
1259 lower_bound_right == range->lower_bound_right &&
1260 upper_bound_left == range->upper_bound_left &&
1261 upper_bound_right == range->upper_bound_right)
1262 found = TRUE;
1263 else
1264 range = (APTR)range->node.mln_Succ;
1267 if(!found)
1268 range = NULL;
1270 return range;
1275 /****i* prism2.device/SetMulticast *****************************************
1277 * NAME
1278 * SetMulticast
1280 * SYNOPSIS
1281 * SetMulticast(unit)
1283 * VOID SetMulticast(struct DevUnit *);
1285 ****************************************************************************
1289 static VOID SetMulticast(struct DevUnit *unit, struct DevBase *base)
1291 ULONG address_left;
1292 UWORD address_right, i = 0;
1293 struct AddressRange *range, *tail;
1294 BOOL range_ended;
1296 /* Fill in multicast list */
1298 P2Seek(unit, 1, P2_REC_MCASTLIST, 4, base);
1300 range = (APTR)unit->multicast_ranges.mlh_Head;
1301 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
1303 while(range != tail && i < P2_MAXMCASTENTRIES)
1305 address_left = range->lower_bound_left;
1306 address_right = range->lower_bound_right;
1307 range_ended = FALSE;
1309 while(!range_ended && i++ < P2_MAXMCASTENTRIES)
1311 unit->BEWordOut(unit->card, P2_REG_DATA1,
1312 (UWORD)(address_left >> 16));
1313 unit->BEWordOut(unit->card, P2_REG_DATA1, (UWORD)address_left);
1314 unit->BEWordOut(unit->card, P2_REG_DATA1, (UWORD)address_right);
1316 if(address_left == range->upper_bound_left &&
1317 address_right == range->upper_bound_right)
1318 range_ended = TRUE;
1319 if(++address_right == 0)
1320 address_left++;
1323 if(range_ended)
1324 range = (APTR)range->node.mln_Succ;
1327 /* Turn promiscuous mode on or off depending on the previous state and
1328 whether we've overflowed the multicast list */
1330 if((unit->flags & UNITF_PROM) == 0)
1332 if(range != tail)
1334 if((unit->flags & UNITF_ALLMCAST) == 0)
1336 P2SetWord(unit, P2_REC_PROMISC, TRUE, base);
1337 unit->flags |= UNITF_ALLMCAST;
1340 else
1342 if((unit->flags & UNITF_ALLMCAST) != 0)
1344 P2SetWord(unit, P2_REC_PROMISC, FALSE, base);
1345 unit->flags &= ~UNITF_ALLMCAST;
1348 /* Only commit multicast list if promiscuity is off */
1350 P2Seek(unit, 1, P2_REC_MCASTLIST, 0, base);
1351 unit->LEWordOut(unit->card, P2_REG_DATA1,
1352 1 + ETH_ADDRESSSIZE / 2 * i);
1353 unit->LEWordOut(unit->card, P2_REG_DATA1, P2_REC_MCASTLIST);
1354 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, P2_REC_MCASTLIST,
1355 base);
1359 return;
1364 /****i* prism2.device/FindTypeStats ****************************************
1366 * NAME
1367 * FindTypeStats
1369 * SYNOPSIS
1370 * stats = FindTypeStats(unit, list,
1371 * packet_type)
1373 * struct TypeStats *FindTypeStats(struct DevUnit *, struct MinList *,
1374 * ULONG);
1376 ****************************************************************************
1380 struct TypeStats *FindTypeStats(struct DevUnit *unit, struct MinList *list,
1381 ULONG packet_type, struct DevBase *base)
1383 struct TypeStats *stats, *tail;
1384 BOOL found = FALSE;
1386 stats = (APTR)list->mlh_Head;
1387 tail = (APTR)&list->mlh_Tail;
1389 while(stats != tail && !found)
1391 if(stats->packet_type == packet_type)
1392 found = TRUE;
1393 else
1394 stats = (APTR)stats->node.mln_Succ;
1397 if(!found)
1398 stats = NULL;
1400 return stats;
1405 /****i* prism2.device/FlushUnit ********************************************
1407 * NAME
1408 * FlushUnit
1410 * SYNOPSIS
1411 * FlushUnit(unit, last_queue, error)
1413 * VOID FlushUnit(struct DevUnit *, UBYTE, BYTE);
1415 ****************************************************************************
1419 VOID FlushUnit(struct DevUnit *unit, UBYTE last_queue, BYTE error,
1420 struct DevBase *base)
1422 struct IORequest *request;
1423 UBYTE i;
1424 struct Opener *opener, *tail;
1426 /* Abort queued requests */
1428 for(i = 0; i <= last_queue; i++)
1430 while((request = (APTR)GetMsg(unit->request_ports[i])) != NULL)
1432 request->io_Error = error;
1433 ReplyMsg((APTR)request);
1437 #if 1
1438 opener = (APTR)unit->openers.mlh_Head;
1439 tail = (APTR)&unit->openers.mlh_Tail;
1441 /* Flush every opener's read queue */
1443 while(opener != tail)
1445 while((request = (APTR)GetMsg(&opener->read_port)) != NULL)
1447 request->io_Error = error;
1448 ReplyMsg((APTR)request);
1450 opener = (APTR)opener->node.mln_Succ;
1453 #else
1454 opener = request->ios2_BufferManagement;
1455 while((request = (APTR)GetMsg(&opener->read_port)) != NULL)
1457 request->io_Error = error;
1458 ReplyMsg((APTR)request);
1460 #endif
1462 /* Return */
1464 return;
1469 /****i* prism2.device/StatusInt ********************************************
1471 * NAME
1472 * StatusInt
1474 * SYNOPSIS
1475 * finished = StatusInt(unit)
1477 * BOOL StatusInt(struct DevUnit *);
1479 * FUNCTION
1481 * INPUTS
1482 * unit
1484 * RESULT
1485 * finished
1487 ****************************************************************************
1489 * int_code is really in A5, but GCC 2.95.3 doesn't seem able to handle that.
1490 * Since we don't use this parameter, we can lie.
1494 BOOL StatusInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
1496 struct DevBase *base;
1497 UWORD events, int_mask;
1499 base = unit->device;
1500 events = unit->LEWordIn(unit->card, P2_REG_EVENTS);
1502 /* Turning off ints acknowledges the request? */
1504 int_mask = unit->LEWordIn(unit->card, P2_REG_INTMASK);
1505 unit->LEWordOut(unit->card, P2_REG_INTMASK, 0);
1507 /* Handle events */
1509 if((events & P2_EVENTF_INFO) != 0)
1511 int_mask &= ~P2_EVENTF_INFO;
1512 Cause(&unit->info_int);
1514 if((events & P2_EVENTF_RX) != 0)
1516 int_mask &= ~P2_EVENTF_RX;
1517 Cause(&unit->rx_int);
1519 if((events & P2_EVENTF_ALLOCMEM) != 0)
1521 unit->tx_frame_id = unit->LEWordIn(unit->card, P2_REG_ALLOCFID);
1522 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_ALLOCMEM);
1523 Cause(&unit->tx_int);
1525 if((events & P2_EVENTF_TXFAIL) != 0)
1527 ReportEvents(unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX,
1528 base);
1529 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_TXFAIL);
1532 #ifdef __MORPHOS__
1533 int_mask = INT_MASK;
1534 #endif
1535 unit->LEWordOut(unit->card, P2_REG_INTMASK, int_mask);
1537 return FALSE;
1542 /****i* prism2.device/RXInt ************************************************
1544 * NAME
1545 * RXInt -- Soft interrupt for packet reception.
1547 * SYNOPSIS
1548 * RXInt(unit)
1550 * VOID RXInt(struct DevUnit *);
1552 * FUNCTION
1554 * INPUTS
1555 * unit - A unit of this device.
1557 * RESULT
1558 * None.
1560 ****************************************************************************
1564 static VOID RXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
1566 UWORD frame_status, frame_id, ieee_length, frame_control, frame_type,
1567 frame_subtype, encryption, key_no, buffer_no, old_length;
1568 struct DevBase *base;
1569 BOOL is_good;
1570 LONG frag_no;
1571 UBYTE *buffer, *p, *frame, *data;
1573 base = unit->device;
1575 while((unit->LEWordIn(unit->card, P2_REG_EVENTS) & P2_EVENTF_RX) != 0)
1577 is_good = TRUE;
1578 frame_id = unit->LEWordIn(unit->card, P2_REG_RXFID);
1579 P2Seek(unit, 1, frame_id, P2_FRM_STATUS, base);
1580 frame_status = unit->LEWordIn(unit->card, P2_REG_DATA1);
1582 if((frame_status & (P2_FRM_STATUSF_BADCRYPT | P2_FRM_STATUSF_BADCRC))
1583 == 0)
1585 /* Read frame descriptor from card */
1587 P2Seek(unit, 1, frame_id, 0, base);
1588 unit->WordsIn(unit->card, P2_REG_DATA1,
1589 (UWORD *)unit->rx_descriptor,
1590 (unit->ethernet_offset + ETH_HEADERSIZE) / 2);
1591 frame = unit->rx_descriptor + unit->ethernet_offset;
1592 ieee_length = BEWord(*(UWORD *)(frame + ETH_PACKET_IEEELEN));
1593 data = frame + ETH_PACKET_DATA;
1594 unit->WordsIn(unit->card, P2_REG_DATA1, (UWORD *)data,
1595 (ieee_length + MIC_SIZE + 1) / 2);
1596 frame_control =
1597 LEWord(*(UWORD *)(unit->rx_descriptor + P2_FRM_HEADER));
1599 /* Get buffer to store fragment in */
1601 frag_no = LEWord(*(UWORD *)(unit->rx_descriptor + P2_FRM_HEADER
1602 + WIFI_FRM_SEQCONTROL));
1603 buffer = GetRXBuffer(unit, frame + ETH_PACKET_SOURCE, frag_no,
1604 &buffer_no, base);
1606 /* Get location to put new data */
1608 if(buffer != NULL)
1610 if((frag_no & 0xf ) > 0)
1611 old_length = BEWord(*(UWORD *)(buffer + ETH_PACKET_IEEELEN));
1612 else
1614 /* Copy header to new frame */
1616 CopyMem(frame, buffer, ETH_HEADERSIZE);
1617 old_length = 0;
1619 p = buffer + ETH_HEADERSIZE + old_length;
1621 /* Get encryption type and key index */
1623 if((frame_control & WIFI_FRM_CONTROLF_WEP) != 0)
1625 key_no = data[3] >> 6 & 0x3;
1626 encryption = unit->keys[key_no].type;
1628 else
1629 encryption = S2ENC_NONE;
1631 /* Append fragment to frame, decrypting/checking fragment if
1632 necessary */
1634 is_good = unit->fragment_decrypt_functions[encryption](unit,
1635 unit->rx_descriptor + P2_FRM_HEADER, data, &ieee_length, p,
1636 base);
1638 /* Update length in frame being built with current fragment, or
1639 increment bad frame counter if fragment is bad */
1641 if(is_good)
1643 ieee_length += old_length;
1644 *(UWORD *)(buffer + ETH_PACKET_IEEELEN) =
1645 MakeBEWord(ieee_length);
1647 else
1648 unit->stats.BadData++;
1650 /* If all fragments have arrived, process the complete frame */
1652 if((frame_control & WIFI_FRM_CONTROLF_MOREFRAGS) == 0)
1654 if(is_good)
1656 /* Decrypt complete frame if necessary */
1658 data = buffer + ETH_HEADERSIZE;
1659 if(encryption == S2ENC_TKIP)
1661 /* Hermes cards don't include MIC in frame length, so
1662 we need to grab the MIC from the original RX
1663 descriptor here */
1665 if(unit->firmware_type >= LUCENT_FIRMWARE)
1667 CopyMem(frame + ETH_PACKET_DATA + ieee_length,
1668 data + ieee_length, MIC_SIZE);
1669 ieee_length += MIC_SIZE;
1672 /* Check Michael MIC */
1674 #ifndef __mc68000
1675 is_good = TKIPDecryptFrame(unit, buffer, data,
1676 ieee_length, data, key_no, base);
1677 #endif
1678 ieee_length -= MIC_SIZE;
1679 *(UWORD *)(buffer + ETH_PACKET_IEEELEN) =
1680 MakeBEWord(ieee_length);
1681 if(!is_good)
1682 unit->stats.BadData++;
1686 if(is_good)
1688 /* Get frame's 802.11 type and subtype */
1690 frame_type = (frame_control & WIFI_FRM_CONTROLF_TYPE)
1691 >> WIFI_FRM_CONTROLB_TYPE;
1692 frame_subtype =
1693 (frame_control & WIFI_FRM_CONTROLF_SUBTYPE)
1694 >> WIFI_FRM_CONTROLB_SUBTYPE;
1696 /* If it's a management frame, process it internally;
1697 otherwise distribute it to clients after filtering */
1699 if(frame_type == WIFI_FRMTYPE_MGMT)
1701 if(frame_subtype == 0x5)
1703 CopyMem(unit->rx_descriptor + P2_FRM_HEADER
1704 + WIFI_FRM_ADDRESS3, buffer + ETH_PACKET_SOURCE,
1705 ETH_ADDRESSSIZE);
1706 SaveBeacon(unit, buffer, base);
1709 else if(AddressFilter(unit, buffer + ETH_PACKET_DEST,
1710 base))
1712 unit->stats.PacketsReceived++;
1713 DistributeRXPacket(unit, buffer, base);
1718 /* Mark fragment buffer as unused for next time */
1720 unit->rx_fragment_nos[buffer_no] = -1;
1722 else
1723 ReportEvents(unit, S2EVENT_ERROR | S2EVENT_RX, base);
1725 else
1727 is_good = FALSE;
1730 if(!is_good)
1732 ReportEvents(unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX,
1733 base);
1736 /* Discard packet */
1738 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_RX);
1741 /* Re-enable RX interrupts */
1743 Disable();
1744 unit->LEWordOut(unit->card, P2_REG_INTMASK,
1745 unit->LEWordIn(unit->card, P2_REG_INTMASK) | P2_EVENTF_RX);
1746 Enable();
1748 return;
1753 /****i* prism2.device/GetRXBuffer ******************************************
1755 * NAME
1756 * GetRXBuffer -- Find an appropriate RX buffer to use.
1758 * SYNOPSIS
1759 * buffer = GetRXBuffer(unit, address, frag_no)
1761 * UBYTE *GetRXBuffer(struct DevUnit *, UBYTE *, UWORD);
1763 ****************************************************************************
1767 static UBYTE *GetRXBuffer(struct DevUnit *unit, const UBYTE *address,
1768 UWORD frag_no, UWORD *buffer_no, struct DevBase *base)
1770 UWORD i;
1771 UBYTE *buffer;
1772 LONG n;
1773 BOOL found;
1775 buffer = unit->rx_buffers;
1776 for(i = 0, found = FALSE; i < RX_BUFFER_COUNT * 2 && !found; i++)
1778 /* Throw away old buffer contents if we didn't find a free slot the
1779 first time around */
1781 if(i >= RX_BUFFER_COUNT)
1782 unit->rx_fragment_nos[i % RX_BUFFER_COUNT] = -1;
1784 /* For a frame's first fragment, find an empty slot; for subsequent
1785 fragments, find a slot with matching source address */
1787 n = unit->rx_fragment_nos[i % RX_BUFFER_COUNT];
1788 if(n == -1 && (frag_no & 0xf) == 0
1789 || *((ULONG *)(buffer + ETH_PACKET_SOURCE))
1790 == *((ULONG *)(address))
1791 && *((UWORD *)(buffer + ETH_PACKET_SOURCE + 4))
1792 == *((UWORD *)(address + 4)))
1794 found = TRUE;
1795 if(n == -1)
1796 unit->rx_fragment_nos[i % RX_BUFFER_COUNT] = frag_no;
1797 *buffer_no = i;
1799 else
1800 buffer += FRAME_BUFFER_SIZE;
1803 if(!found)
1804 buffer = NULL;
1806 return buffer;
1811 /****i* prism2.device/DistributeRXPacket ***********************************
1813 * NAME
1814 * DistributeRXPacket -- Send a packet to all appropriate destinations.
1816 * SYNOPSIS
1817 * DistributeRXPacket(unit, frame)
1819 * VOID DistributeRXPacket(struct DevUnit *, UBYTE *);
1821 ****************************************************************************
1825 static VOID DistributeRXPacket(struct DevUnit *unit, UBYTE *frame,
1826 struct DevBase *base)
1828 UWORD packet_size, ieee_length;
1829 BOOL is_orphan = TRUE, accepted, is_snap = FALSE;
1830 ULONG packet_type;
1831 UBYTE *buffer;
1832 const UBYTE *template = snap_template;
1833 struct IOSana2Req *request, *request_tail;
1834 struct Opener *opener, *opener_tail;
1835 struct TypeStats *tracker;
1837 ieee_length = BEWord(*(UWORD *)(frame + ETH_PACKET_IEEELEN));
1838 packet_size = ETH_HEADERSIZE + ieee_length;
1839 if(ieee_length >= SNAP_HEADERSIZE)
1840 is_snap = *(const ULONG *)(frame + ETH_PACKET_DATA)
1841 == *(const ULONG *)template;
1843 /* De-encapsulate SNAP packets and get packet type */
1845 if(is_snap)
1847 buffer = unit->rx_buffer;
1848 packet_size -= SNAP_HEADERSIZE;
1849 CopyMem(frame, buffer, ETH_PACKET_TYPE);
1850 CopyMem(frame + ETH_HEADERSIZE + SNAP_FRM_TYPE,
1851 buffer + ETH_PACKET_TYPE, packet_size - ETH_PACKET_TYPE);
1853 else
1854 buffer = frame;
1856 packet_type = BEWord(*((UWORD *)(buffer + ETH_PACKET_TYPE)));
1858 if(packet_size <= ETH_MAXPACKETSIZE)
1860 /* Offer packet to every opener */
1862 opener = (APTR)unit->openers.mlh_Head;
1863 opener_tail = (APTR)&unit->openers.mlh_Tail;
1865 while(opener != opener_tail)
1867 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
1868 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
1869 accepted = FALSE;
1871 /* Offer packet to each request until it's accepted */
1873 while(request != request_tail && !accepted)
1875 if(request->ios2_PacketType == packet_type)
1877 CopyPacket(unit, request, packet_size, packet_type,
1878 buffer, base);
1879 accepted = TRUE;
1881 request =
1882 (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
1885 if(accepted)
1886 is_orphan = FALSE;
1887 opener = (APTR)opener->node.mln_Succ;
1890 /* If packet was unwanted, give it to S2_READORPHAN request */
1892 if(is_orphan)
1894 unit->stats.UnknownTypesReceived++;
1895 if(!IsMsgPortEmpty(unit->request_ports[ADOPT_QUEUE]))
1897 CopyPacket(unit,
1898 (APTR)unit->request_ports[ADOPT_QUEUE]->
1899 mp_MsgList.lh_Head, packet_size, packet_type, buffer,
1900 base);
1904 /* Update remaining statistics */
1906 if(packet_type <= ETH_MTU)
1907 packet_type = ETH_MTU;
1908 tracker =
1909 FindTypeStats(unit, &unit->type_trackers, packet_type, base);
1910 if(tracker != NULL)
1912 tracker->stats.PacketsReceived++;
1913 tracker->stats.BytesReceived += packet_size;
1916 else
1917 unit->stats.BadData++;
1919 return;
1924 /****i* prism2.device/CopyPacket *******************************************
1926 * NAME
1927 * CopyPacket -- Copy packet to client's buffer.
1929 * SYNOPSIS
1930 * CopyPacket(unit, request, packet_size, packet_type,
1931 * buffer)
1933 * VOID CopyPacket(struct DevUnit *, struct IOSana2Req *, UWORD, UWORD,
1934 * UBYTE *);
1936 ****************************************************************************
1940 static VOID CopyPacket(struct DevUnit *unit, struct IOSana2Req *request,
1941 UWORD packet_size, UWORD packet_type, UBYTE *buffer,
1942 struct DevBase *base)
1944 struct Opener *opener;
1945 BOOL filtered = FALSE;
1947 /* Set multicast and broadcast flags */
1949 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
1950 if((*((ULONG *)(buffer + ETH_PACKET_DEST)) == 0xffffffff) &&
1951 (*((UWORD *)(buffer + ETH_PACKET_DEST + 4)) == 0xffff))
1952 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
1953 else if((buffer[ETH_PACKET_DEST] & 0x1) != 0)
1954 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
1956 /* Set source and destination addresses and packet type */
1958 CopyMem(buffer + ETH_PACKET_SOURCE, request->ios2_SrcAddr,
1959 ETH_ADDRESSSIZE);
1960 CopyMem(buffer + ETH_PACKET_DEST, request->ios2_DstAddr,
1961 ETH_ADDRESSSIZE);
1962 request->ios2_PacketType = packet_type;
1964 /* Adjust for cooked packet request */
1966 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
1968 packet_size -= ETH_PACKET_DATA;
1969 buffer += ETH_PACKET_DATA;
1971 #ifdef USE_HACKS
1972 else
1973 packet_size += 4; /* Needed for Shapeshifter & Fusion */
1974 #endif
1975 request->ios2_DataLength = packet_size;
1977 /* Filter packet */
1979 opener = request->ios2_BufferManagement;
1980 if(request->ios2_Req.io_Command == CMD_READ &&
1981 opener->filter_hook != NULL)
1982 if(!CallHookPkt(opener->filter_hook, request, buffer))
1983 filtered = TRUE;
1985 if(!filtered)
1987 /* Copy packet into opener's buffer and reply packet */
1989 if(!opener->rx_function(request->ios2_Data, buffer, packet_size))
1991 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
1992 request->ios2_WireError = S2WERR_BUFF_ERROR;
1993 ReportEvents(unit,
1994 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX,
1995 base);
1997 Remove((APTR)request);
1998 ReplyMsg((APTR)request);
2001 return;
2006 /****i* prism2.device/AddressFilter ****************************************
2008 * NAME
2009 * AddressFilter -- Determine if an RX packet should be accepted.
2011 * SYNOPSIS
2012 * accept = AddressFilter(unit, address)
2014 * BOOL AddressFilter(struct DevUnit *, UBYTE *);
2016 ****************************************************************************
2020 static BOOL AddressFilter(struct DevUnit *unit, UBYTE *address,
2021 struct DevBase *base)
2023 struct AddressRange *range, *tail;
2024 BOOL accept = TRUE;
2025 ULONG address_left;
2026 UWORD address_right;
2028 /* Check whether address is unicast/broadcast or multicast */
2030 address_left = BELong(*((ULONG *)address));
2031 address_right = BEWord(*((UWORD *)(address + 4)));
2033 if(((address_left & 0x01000000) != 0) &&
2034 !((address_left == 0xffffffff) && (address_right == 0xffff)))
2036 /* Check if this multicast address is wanted */
2038 range = (APTR)unit->multicast_ranges.mlh_Head;
2039 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
2040 accept = FALSE;
2042 while((range != tail) && !accept)
2044 if((address_left > range->lower_bound_left ||
2045 address_left == range->lower_bound_left &&
2046 address_right >= range->lower_bound_right) &&
2047 (address_left < range->upper_bound_left ||
2048 address_left == range->upper_bound_left &&
2049 address_right <= range->upper_bound_right))
2050 accept = TRUE;
2051 range = (APTR)range->node.mln_Succ;
2054 if(!accept)
2055 unit->special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
2058 return accept;
2063 /****i* prism2.device/SaveBeacon *******************************************
2065 * NAME
2066 * SaveBeacon -- Save beacon frame for later examination.
2068 * SYNOPSIS
2069 * SaveBeacon(unit, frame)
2071 * VOID SaveBeacon(struct DevUnit *, UBYTE *);
2073 ****************************************************************************
2077 static VOID SaveBeacon(struct DevUnit *unit, const UBYTE *frame,
2078 struct DevBase *base)
2080 UWORD size;
2082 /* Store frame for later matching with scan results */
2084 size = ETH_HEADERSIZE + BEWord(*(UWORD *)(frame + ETH_PACKET_IEEELEN));
2085 if(unit->next_beacon + size < unit->beacons + BEACON_BUFFER_SIZE)
2087 CopyMem(frame, unit->next_beacon, size);
2088 unit->beacon_count++;
2089 unit->next_beacon += size + sizeof(ULONG) & ~3;
2092 return;
2097 /****i* prism2.device/TXInt ************************************************
2099 * NAME
2100 * TXInt -- Soft interrupt for packet transmission.
2102 * SYNOPSIS
2103 * TXInt(unit)
2105 * VOID TXInt(struct DevUnit *);
2107 * FUNCTION
2109 * INPUTS
2110 * unit - A unit of this device.
2112 * RESULT
2113 * None.
2115 ****************************************************************************
2119 static VOID TXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
2121 UWORD i, packet_size, send_size, packet_type, data_size, body_size = 0,
2122 frame_id, encryption, control_value, subtype;
2123 UBYTE *buffer, *desc = unit->tx_descriptor, *plaintext, *ciphertext,
2124 *header, mic_header[ETH_ADDRESSSIZE * 2], *q;
2125 const UBYTE *p, *dest, *source;
2126 struct DevBase *base;
2127 struct IOSana2Req *request;
2128 BOOL is_ieee;
2129 struct Opener *opener;
2130 ULONG wire_error;
2131 UBYTE *(*dma_tx_function)(REG(a0, APTR));
2132 BYTE error = 0;
2133 struct MsgPort *port;
2134 struct TypeStats *tracker;
2136 base = unit->device;
2137 port = unit->request_ports[WRITE_QUEUE];
2139 if(unit->tx_frame_id != 0 && !IsMsgPortEmpty(port))
2141 /* Get next request and full packet size */
2143 request = (APTR)port->mp_MsgList.lh_Head;
2144 packet_size = request->ios2_DataLength;
2145 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
2146 packet_size += ETH_PACKET_DATA;
2148 /* Determine encryption type and frame subtype */
2150 if(packet_size > ETH_HEADERSIZE)
2152 encryption = unit->keys[unit->tx_key_no].type;
2153 subtype = 0;
2155 else
2157 encryption = S2ENC_NONE;
2158 subtype = 4;
2161 /* Get packet data */
2163 opener = request->ios2_BufferManagement;
2164 dma_tx_function = opener->dma_tx_function;
2165 if(dma_tx_function != NULL)
2166 buffer = dma_tx_function(request->ios2_Data);
2167 else
2168 buffer = NULL;
2170 if(buffer == NULL)
2172 buffer = unit->tx_buffer;
2173 if(!opener->tx_function(buffer, request->ios2_Data,
2174 request->ios2_DataLength))
2176 error = S2ERR_NO_RESOURCES;
2177 wire_error = S2WERR_BUFF_ERROR;
2178 ReportEvents(unit,
2179 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_TX,
2180 base);
2184 if(error == 0)
2186 /* Get packet type and/or length */
2188 data_size = request->ios2_DataLength;
2189 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) != 0)
2191 data_size -= ETH_PACKET_DATA;
2192 packet_type = BEWord(*(UWORD *)(buffer + ETH_PACKET_TYPE));
2194 else
2195 packet_type = request->ios2_PacketType;
2196 is_ieee = packet_type <= ETH_MTU;
2198 /* Get source and destination addresses */
2200 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) != 0)
2202 dest = buffer;
2203 source = buffer + ETH_ADDRESSSIZE;
2204 buffer += ETH_ADDRESSSIZE * 2 + 2;
2206 else
2208 dest = request->ios2_DstAddr;
2209 source = unit->address;
2212 /* Clear frame descriptor as far as start of 802.11 header */
2214 q = desc;
2215 for(i = 0; i < P2_FRM_HEADER; i++)
2216 *q++ = 0;
2217 header = q;
2219 /* Set TX control field */
2221 control_value = P2_FRM_TXCONTROLF_NATIVE;
2222 if(encryption == S2ENC_TKIP && (unit->flags & UNITF_HARDTKIP) != 0)
2223 control_value |= unit->tx_key_no << P2_FRM_TXCONTROLB_MICKEYID
2224 | P2_FRM_TXCONTROLF_MIC;
2225 else if(encryption == S2ENC_NONE
2226 && unit->firmware_type < LUCENT_FIRMWARE)
2227 control_value |= P2_FRM_TXCONTROLF_NOENC;
2229 *(UWORD *)(desc + unit->txcontrol_offset) =
2230 MakeLEWord(control_value);
2232 /* Write 802.11 header */
2234 *(UWORD *)q = MakeLEWord(
2235 (encryption == S2ENC_NONE ? 0 : WIFI_FRM_CONTROLF_WEP)
2236 | (unit->mode == S2PORT_ADHOC ? 0 : WIFI_FRM_CONTROLF_TODS)
2237 | subtype << WIFI_FRM_CONTROLB_SUBTYPE
2238 | WIFI_FRMTYPE_DATA << WIFI_FRM_CONTROLB_TYPE);
2239 q += 2;
2241 *(UWORD *)q = 0;
2242 q += 2;
2244 if(unit->mode == S2PORT_ADHOC)
2245 p = dest;
2246 else
2247 p = unit->bssid;
2248 for(i = 0; i < ETH_ADDRESSSIZE; i++)
2249 *q++ = *p++;
2251 for(i = 0, p = source; i < ETH_ADDRESSSIZE; i++)
2252 *q++ = *p++;
2254 if(unit->mode == S2PORT_ADHOC)
2255 p = unit->bssid;
2256 else
2257 p = dest;
2258 for(i = 0; i < ETH_ADDRESSSIZE; i++)
2259 *q++ = *p++;
2260 *(UWORD *)q = 0;
2262 /* Clear 802.3 header */
2264 q = desc + unit->ethernet_offset;
2265 for(i = 0; i < ETH_HEADERSIZE; i++)
2266 *q++ = 0;
2268 /* Leave room for encryption overhead */
2270 q = desc + unit->data_offset;
2271 ciphertext = q;
2272 q += unit->iv_sizes[encryption];
2273 plaintext = q;
2275 /* Write SNAP header */
2277 if(!is_ieee)
2279 for(i = 0, p = snap_template; i < SNAP_FRM_TYPE; i++)
2280 *q++ = *p++;
2281 *(UWORD *)q = MakeBEWord(packet_type);
2282 q += 2;
2283 body_size += SNAP_HEADERSIZE;
2286 /* Copy data into frame */
2288 CopyMem(buffer, q, data_size);
2289 body_size += data_size;
2291 /* Append MIC to frame for TKIP */
2293 if(encryption == S2ENC_TKIP)
2295 q = mic_header;
2296 for(i = 0, p = dest; i < ETH_ADDRESSSIZE; i++)
2297 *q++ = *p++;
2298 for(i = 0, p = source; i < ETH_ADDRESSSIZE; i++)
2299 *q++ = *p++;
2300 TKIPEncryptFrame(unit, mic_header, plaintext, body_size,
2301 plaintext, base);
2302 body_size += MIC_SIZE;
2305 /* Encrypt fragment if applicable */
2307 unit->fragment_encrypt_functions[encryption](unit, header,
2308 plaintext, &body_size, ciphertext, base);
2310 /* Calculate total length of data to send to adapter */
2312 send_size = unit->data_offset + body_size;
2314 /* Fill in length field, adjusting for Hermes peculiarities */
2316 if(unit->firmware_type >= LUCENT_FIRMWARE
2317 && encryption == S2ENC_TKIP)
2318 body_size -= MIC_SIZE;
2320 if(unit->firmware_type == LUCENT_FIRMWARE
2321 && (unit->flags & UNITF_HARDTKIP) != 0)
2322 *(UWORD *)(desc + unit->ethernet_offset + ETH_PACKET_IEEELEN) =
2323 MakeBEWord(body_size);
2324 else
2325 *(UWORD *)(desc + unit->datalen_offset) = MakeLEWord(body_size);
2327 /* Write packet to adapter and send */
2329 frame_id = unit->tx_frame_id;
2330 P2Seek(unit, 0, frame_id, 0, base);
2331 unit->WordsOut(unit->card, P2_REG_DATA0, (UWORD *)desc,
2332 (send_size + 1) / 2);
2333 unit->tx_frame_id = 0;
2334 P2DoCmd(unit, P2_CMD_TX | P2_CMDF_RECLAIM, frame_id, base);
2337 /* Reply request */
2339 request->ios2_Req.io_Error = error;
2340 request->ios2_WireError = wire_error;
2341 Remove((APTR)request);
2342 ReplyMsg((APTR)request);
2344 /* Update statistics */
2346 if(error == 0)
2348 unit->stats.PacketsSent++;
2350 tracker = FindTypeStats(unit, &unit->type_trackers,
2351 request->ios2_PacketType, base);
2352 if(tracker != NULL)
2354 tracker->stats.PacketsSent++;
2355 tracker->stats.BytesSent += packet_size;
2360 /* Don't try to keep sending packets if there's no space left */
2362 if(unit->tx_frame_id != 0)
2363 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
2364 else
2365 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
2367 return;
2372 /****i* prism2.device/UpdateStats ******************************************
2374 * NAME
2375 * UpdateStats
2377 * SYNOPSIS
2378 * UpdateStats(unit)
2380 * VOID UpdateStats(struct DevUnit *);
2382 * FUNCTION
2384 * INPUTS
2385 * unit - A unit of this device.
2387 * RESULT
2388 * None.
2390 ****************************************************************************
2394 VOID UpdateStats(struct DevUnit *unit, struct DevBase *base)
2396 /* Ask for and wait for stats */
2398 if((unit->flags & UNITF_ONLINE) != 0)
2400 Disable();
2401 unit->LEWordOut(unit->card, P2_REG_INTMASK,
2402 unit->LEWordIn(unit->card, P2_REG_INTMASK) & ~P2_EVENTF_INFO);
2403 Enable();
2404 P2DoCmd(unit, P2_CMD_INQUIRE, P2_INFO_COUNTERS, base);
2405 while((unit->LEWordIn(unit->card, P2_REG_EVENTS) & P2_EVENTF_INFO)
2406 == 0);
2407 Cause(&unit->info_int);
2410 return;
2415 /****i* prism2.device/InfoInt **********************************************
2417 * NAME
2418 * InfoInt
2420 * SYNOPSIS
2421 * InfoInt(unit)
2423 * VOID InfoInt(struct DevUnit *);
2425 * FUNCTION
2427 * INPUTS
2428 * unit - A unit of this device.
2430 * RESULT
2431 * None.
2433 * NOTES
2434 * The only reason this is a (soft) interrupt is so that it won't
2435 * interfere with RXInt() by interrupting it. This would be dangerous
2436 * because they use the same data channel.
2438 ****************************************************************************
2442 static VOID InfoInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
2444 struct DevBase *base;
2445 UWORD id, length, rec_length, status, ies_length, data_length,
2446 ssid_length, *ap_rec;
2447 UBYTE *ie, *ssid, *descriptor, *frame, *data, *bssid = unit->bssid;
2448 BOOL associated;
2450 base = unit->device;
2451 id = unit->LEWordIn(unit->card, P2_REG_INFOFID);
2453 P2Seek(unit, 1, id, 0, base);
2454 length = (unit->LEWordIn(unit->card, P2_REG_DATA1) + 1) * 2;
2456 switch(unit->LEWordIn(unit->card, P2_REG_DATA1))
2458 case P2_INFO_COUNTERS:
2460 /* Read useful stats and skip others */
2462 unit->LEWordIn(unit->card, P2_REG_DATA1);
2463 unit->LEWordIn(unit->card, P2_REG_DATA1);
2465 unit->LEWordIn(unit->card, P2_REG_DATA1);
2466 unit->LEWordIn(unit->card, P2_REG_DATA1);
2467 unit->LEWordIn(unit->card, P2_REG_DATA1);
2468 unit->LEWordIn(unit->card, P2_REG_DATA1);
2470 unit->special_stats[S2SS_ETHERNET_RETRIES & 0xffff] +=
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->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);
2481 unit->LEWordIn(unit->card, P2_REG_DATA1);
2482 unit->LEWordIn(unit->card, P2_REG_DATA1);
2484 unit->stats.BadData += unit->LEWordIn(unit->card, P2_REG_DATA1);
2485 unit->stats.Overruns += 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);
2491 break;
2493 case P2_INFO_SCANRESULTS:
2494 case P2_INFO_HOSTSCANRESULTS:
2496 P2ReadRec(unit, id, unit->scan_results_rec, SCAN_BUFFER_SIZE, base);
2497 Signal(unit->task, unit->scan_complete_signal);
2498 break;
2500 case P2_INFO_SCANRESULT:
2502 descriptor = unit->rx_descriptor;
2503 P2ReadRec(unit, id, descriptor, FRAME_BUFFER_SIZE, base);
2504 if(length > 4)
2506 /* Save IEEE 802.3 portion of scan result */
2508 frame = descriptor + unit->ethernet_offset;
2509 data = frame + ETH_PACKET_DATA;
2510 CopyMem(descriptor + P2_FRM_HEADER + WIFI_FRM_ADDRESS3,
2511 frame + ETH_PACKET_SOURCE, ETH_ADDRESSSIZE);
2512 data_length =
2513 LEWord(*(UWORD *)(descriptor + unit->datalen_offset));
2514 ies_length = data_length - WIFI_BEACON_IES;
2515 *(UWORD *)(frame + ETH_PACKET_IEEELEN) = MakeBEWord(data_length);
2516 SaveBeacon(unit, frame, base);
2518 /* Append a fake old-style scan record on to fake record list */
2520 rec_length = LEWord(unit->scan_results_rec[0]);
2522 if(2 + rec_length * 2 + P2_APRECLEN < SCAN_BUFFER_SIZE)
2524 ap_rec = unit->scan_results_rec + 1 + rec_length;
2525 CopyMem(frame + ETH_PACKET_SOURCE, ap_rec + P2_APREC_BSSID / 2,
2526 ETH_ADDRESSSIZE);
2528 ap_rec[P2_APREC_SIGNAL / 2] =
2529 MakeLEWord(descriptor[P2_FRM_SIGNAL]);
2531 ap_rec[P2_APREC_NOISE / 2] =
2532 MakeLEWord(descriptor[P2_FRM_NOISE]);
2534 ap_rec[P2_APREC_CHANNEL / 2] = MakeLEWord(GetIE(WIFI_IE_CHANNEL,
2535 data + WIFI_BEACON_IES, ies_length, base)[2]);
2537 ap_rec[P2_APREC_INTERVAL / 2] =
2538 *(UWORD *)(data + WIFI_BEACON_INTERVAL);
2540 ap_rec[P2_APREC_CAPABILITIES / 2] =
2541 *(UWORD *)(data + WIFI_BEACON_CAPABILITIES);
2543 ie = GetIE(WIFI_IE_SSID, data + WIFI_BEACON_IES, ies_length,
2544 base);
2545 ssid_length = ie[1];
2546 ssid = ie + 2;
2547 ap_rec[P2_APREC_NAMELEN / 2] = MakeLEWord(ssid_length);
2548 CopyMem(ssid, ap_rec + P2_APREC_NAME / 2, ssid_length);
2550 unit->scan_results_rec[0] =
2551 MakeLEWord(rec_length + P2_APRECLEN / 2);
2554 else
2555 Signal(unit->task, unit->scan_complete_signal);
2556 break;
2558 case P2_INFO_LINKSTATUS:
2560 /* Only report an event if association status has really changed */
2562 status = unit->LEWordIn(unit->card, P2_REG_DATA1);
2564 if(status == 1 || unit->firmware_type < LUCENT_FIRMWARE
2565 && status == 3)
2566 associated = TRUE;
2567 else //if(unit->firmware_type < LUCENT_FIRMWARE || status == 3)
2568 associated = FALSE;
2570 if(!(*(ULONG *)bssid == 0 && *(UWORD *)(bssid + 4) == 0))
2572 if(associated && (unit->flags & UNITF_ASSOCIATED) == 0)
2574 unit->flags |= UNITF_ASSOCIATED;
2575 ReportEvents(unit, S2EVENT_CONNECT, base);
2577 else if(!associated && (unit->flags & UNITF_ASSOCIATED) != 0)
2579 unit->flags &= ~UNITF_ASSOCIATED;
2580 ReportEvents(unit, S2EVENT_DISCONNECT, base);
2585 /* Acknowledge event and re-enable info interrupts */
2587 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_INFO);
2588 Disable();
2589 if((unit->flags & UNITF_ONLINE) != 0)
2590 unit->LEWordOut(unit->card, P2_REG_INTMASK,
2591 unit->LEWordIn(unit->card, P2_REG_INTMASK) | P2_EVENTF_INFO);
2592 Enable();
2594 return;
2599 /****i* prism2.device/ResetHandler *****************************************
2601 * NAME
2602 * ResetHandler -- Disable hardware before a reboot.
2604 * SYNOPSIS
2605 * ResetHandler(unit, int_code)
2607 * VOID ResetHandler(struct DevUnit *, APTR);
2609 ****************************************************************************
2613 static VOID ResetHandler(REG(a1, struct DevUnit *unit),
2614 REG(a6, APTR int_code))
2616 if((unit->flags & UNITF_HAVEADAPTER) != 0)
2618 /* Stop interrupts */
2620 unit->LEWordOut(unit->card, P2_REG_INTMASK, 0);
2622 /* Stop transmission and reception */
2624 unit->LEWordOut(unit->card, P2_REG_PARAM0, 0);
2625 unit->LEWordOut(unit->card, P2_REG_COMMAND, P2_CMD_DISABLE);
2628 return;
2633 /****i* prism2.device/ReportEvents *****************************************
2635 * NAME
2636 * ReportEvents
2638 * SYNOPSIS
2639 * ReportEvents(unit, events)
2641 * VOID ReportEvents(struct DevUnit *, ULONG);
2643 * FUNCTION
2645 * INPUTS
2646 * unit - A unit of this device.
2647 * events - A mask of events to report.
2649 * RESULT
2650 * None.
2652 ****************************************************************************
2656 static VOID ReportEvents(struct DevUnit *unit, ULONG events,
2657 struct DevBase *base)
2659 struct IOSana2Req *request, *tail, *next_request;
2660 struct List *list;
2662 list = &unit->request_ports[EVENT_QUEUE]->mp_MsgList;
2663 next_request = (APTR)list->lh_Head;
2664 tail = (APTR)&list->lh_Tail;
2666 Disable();
2667 while(next_request != tail)
2669 request = next_request;
2670 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
2672 if((request->ios2_WireError & events) != 0)
2674 request->ios2_WireError = events;
2675 Remove((APTR)request);
2676 ReplyMsg((APTR)request);
2679 Enable();
2681 return;
2686 /****i* prism2.device/SendScanResults **************************************
2688 * NAME
2689 * SendScanResults -- Reply to all outstanding scan requests.
2691 * SYNOPSIS
2692 * SendScanResults(unit)
2694 * VOID SendScanResults(struct DevUnit *);
2696 * FUNCTION
2698 * INPUTS
2699 * unit - A unit of this device.
2701 * RESULT
2702 * None.
2704 ****************************************************************************
2708 static VOID SendScanResults(struct DevUnit *unit, struct DevBase *base)
2710 BYTE error = 0;
2711 struct IOSana2Req *request, *tail, *next_request;
2712 struct List *list;
2713 APTR pool;
2714 UWORD count, i, j, ssid_length, length, entry_length, *ap_rec,
2715 data_length, frame_length, ies_length;
2716 struct TagItem **tag_lists, *tag;
2717 UBYTE *bssid, *ies;
2718 const UBYTE *beacon, *ie_bssid;
2719 TEXT *ssid;
2721 list = &unit->request_ports[SCAN_QUEUE]->mp_MsgList;
2722 next_request = (APTR)list->lh_Head;
2723 tail = (APTR)&list->lh_Tail;
2725 while(next_request != tail)
2727 request = next_request;
2728 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
2730 pool = request->ios2_Data;
2732 length = LEWord(unit->scan_results_rec[0]);
2733 ap_rec = unit->scan_results_rec + 2;
2735 if(unit->firmware_type == INTERSIL_FIRMWARE)
2737 entry_length = LEWord(unit->scan_results_rec[2]);
2738 ap_rec += 2;
2739 count = (length - 3) * 2 / entry_length;
2741 else
2743 entry_length = P2_APRECLEN;
2744 count = (length - 1) * 2 / entry_length;
2747 /* Allocate array of tag lists, one for each AP */
2749 if(count > 0)
2751 tag_lists = AllocPooled(pool, count * sizeof(APTR));
2752 if(tag_lists == NULL)
2753 error = S2ERR_NO_RESOURCES;
2755 else
2756 tag_lists = NULL;
2758 for(i = 0; i < count && error == 0; i++, ap_rec += entry_length / 2)
2760 tag_lists[i] =
2761 AllocPooled(pool, SCAN_TAG_COUNT * sizeof(struct TagItem));
2762 if(tag_lists[i] == NULL)
2763 error = S2ERR_NO_RESOURCES;
2765 if(error == 0)
2767 tag = tag_lists[i];
2769 tag->ti_Tag = S2INFO_BSSID;
2770 tag->ti_Data = (UPINT)(bssid =
2771 AllocPooled(pool, ETH_ADDRESSSIZE));
2772 if(bssid != NULL)
2773 CopyMem(ap_rec + P2_APREC_BSSID / 2, bssid,
2774 ETH_ADDRESSSIZE);
2775 else
2776 error = S2ERR_NO_RESOURCES;
2777 tag++;
2779 tag->ti_Tag = TAG_IGNORE;
2780 tag++;
2782 tag->ti_Tag = S2INFO_Channel;
2783 tag->ti_Data = LEWord(ap_rec[P2_APREC_CHANNEL / 2]);
2784 tag++;
2786 tag->ti_Tag = S2INFO_BeaconInterval;
2787 tag->ti_Data = LEWord(ap_rec[P2_APREC_INTERVAL / 2]);
2788 tag++;
2790 tag->ti_Tag = S2INFO_Capabilities;
2791 tag->ti_Data = LEWord(ap_rec[P2_APREC_CAPABILITIES / 2]);
2792 tag++;
2794 tag->ti_Tag = S2INFO_Signal;
2795 tag->ti_Data = ConvertScanLevel(unit,
2796 LEWord(ap_rec[P2_APREC_SIGNAL / 2]), base);
2797 tag++;
2799 tag->ti_Tag = S2INFO_Noise;
2800 tag->ti_Data = ConvertScanLevel(unit,
2801 LEWord(ap_rec[P2_APREC_NOISE / 2]), base);
2802 tag++;
2805 ssid_length = LEWord(ap_rec[P2_APREC_NAMELEN / 2]);
2806 tag->ti_Tag = S2INFO_SSID;
2807 tag->ti_Data = (UPINT)(ssid =
2808 AllocPooled(pool, 31 + 1));
2809 if(ssid != NULL)
2811 CopyMem(ap_rec + P2_APREC_NAME / 2, ssid, ssid_length);
2812 ssid[ssid_length] = '\0';
2814 else
2815 error = S2ERR_NO_RESOURCES;
2816 tag++;
2818 tag->ti_Tag = TAG_END;
2822 /* Find IEs for each BSS and insert them into the BSS's tag list */
2824 for(beacon = unit->beacons, i = 0; i < unit->beacon_count; i++)
2826 /* Extract IEs from beacon descriptor */
2828 data_length = BEWord(*(UWORD *)(beacon + ETH_PACKET_IEEELEN));
2829 ies_length = data_length - 12;
2830 frame_length = ETH_HEADERSIZE + data_length;
2831 ies = AllocPooled(pool, sizeof(UWORD) + ies_length);
2832 if(ies != NULL)
2834 *(UWORD *)ies = ies_length;
2835 CopyMem(beacon + ETH_PACKET_DATA + WIFI_BEACON_IES,
2836 ies + sizeof(UWORD), ies_length);
2838 else
2839 error = S2ERR_NO_RESOURCES;
2841 /* Find matching tag list and add IEs to it */
2843 ie_bssid = beacon + ETH_PACKET_SOURCE;
2844 for(j = 0; j < count; j++)
2846 tag = tag_lists[j];
2847 bssid = (UBYTE *)tag->ti_Data;
2848 if(*(ULONG *)bssid == *(ULONG *)ie_bssid
2849 && *(UWORD *)(bssid + 4) == *(UWORD *)(ie_bssid + 4))
2851 tag++;
2852 tag->ti_Tag = S2INFO_InfoElements;
2853 tag->ti_Data = (PINT)ies;
2857 beacon += frame_length + sizeof(ULONG) & ~3;
2860 /* Return results */
2862 if(error == 0)
2864 request->ios2_StatData = tag_lists;
2865 request->ios2_DataLength = count;
2867 else
2869 request->ios2_Req.io_Error = error;
2870 request->ios2_WireError = S2WERR_GENERIC_ERROR;
2872 Remove((APTR)request);
2873 ReplyMsg((APTR)request);
2876 /* Discard collected beacon frames */
2878 Disable();
2879 unit->next_beacon = unit->beacons;
2880 unit->beacon_count = 0;
2881 Enable();
2883 return;
2888 /****i* prism2.device/GetNetworkInfo ***************************************
2890 * NAME
2891 * GetNetworkInfo -- Get information on current network.
2893 * SYNOPSIS
2894 * tag_list = GetNetworkInfo(unit, pool)
2896 * struct TagItem *GetNetworkInfo(struct DevUnit *, APTR);
2898 * FUNCTION
2900 * INPUTS
2901 * unit - A unit of this device.
2902 * pool - A memory pool.
2904 * RESULT
2905 * None.
2907 ****************************************************************************
2911 struct TagItem *GetNetworkInfo(struct DevUnit *unit, APTR pool,
2912 struct DevBase *base)
2914 BYTE error = 0;
2915 struct TagItem *tag_list, *tag;
2916 UBYTE *bssid, *ie;
2918 tag_list =
2919 AllocPooled(pool, INFO_TAG_COUNT * sizeof(struct TagItem));
2920 if(tag_list == NULL)
2921 error = S2ERR_NO_RESOURCES;
2923 if(error == 0)
2925 tag = tag_list;
2927 tag->ti_Tag = S2INFO_BSSID;
2928 tag->ti_Data = (UPINT)(bssid =
2929 AllocPooled(pool, ETH_ADDRESSSIZE));
2930 if(bssid != NULL)
2931 CopyMem(unit->bssid, bssid, ETH_ADDRESSSIZE);
2932 else
2933 error = S2ERR_NO_RESOURCES;
2934 tag++;
2936 tag->ti_Tag = TAG_IGNORE;
2937 tag++;
2939 tag->ti_Tag = S2INFO_WPAInfo;
2940 tag->ti_Data = (UPINT)(ie =
2941 AllocPooled(pool, unit->wpa_ie[1] + 2));
2942 if(ie != NULL)
2943 CopyMem(unit->wpa_ie, ie, unit->wpa_ie[1] + 2);
2944 else
2945 error = S2ERR_NO_RESOURCES;
2946 tag++;
2948 tag->ti_Tag = TAG_END;
2951 if(error != 0)
2952 tag_list = NULL;
2954 return tag_list;
2959 /****i* prism2.device/UpdateSignalQuality **********************************
2961 * NAME
2962 * UpdateSignalQuality -- Read signal quality from card.
2964 * SYNOPSIS
2965 * UpdateSignalQuality(unit)
2967 * VOID UpdateSignalQuality(struct DevUnit *);
2969 * FUNCTION
2971 * INPUTS
2972 * unit - A unit of this device.
2974 * RESULT
2975 * None.
2977 ****************************************************************************
2981 VOID UpdateSignalQuality(struct DevUnit *unit, struct DevBase *base)
2983 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_LINKQUALITY, base);
2984 P2Seek(unit, 1, P2_REC_LINKQUALITY, 6, base);
2986 unit->signal_quality.SignalLevel =
2987 ConvertLevel(unit, unit->LEWordIn(unit->card, P2_REG_DATA1), base);
2988 unit->signal_quality.NoiseLevel =
2989 ConvertLevel(unit, unit->LEWordIn(unit->card, P2_REG_DATA1), base);
2991 return;
2996 /****i* prism2.device/StartScan ********************************************
2998 * NAME
2999 * StartScan -- Start a scan for available networks.
3001 * SYNOPSIS
3002 * StartScan(unit)
3004 * VOID StartScan(struct DevUnit *);
3006 * FUNCTION
3008 * INPUTS
3009 * unit - A unit of this device.
3011 * RESULT
3012 * None.
3014 ****************************************************************************
3018 VOID StartScan(struct DevUnit *unit, const TEXT *ssid, struct DevBase *base)
3020 UBYTE *params;
3021 UWORD ssid_length = 0;
3023 /* Ask for a scan */
3025 if((unit->flags & UNITF_ONLINE) != 0)
3027 if(ssid != NULL)
3028 ssid_length = StrLen(ssid);
3029 if(unit->firmware_type == INTERSIL_FIRMWARE)
3031 params = AllocVec(sizeof(scan_params) + ssid_length, MEMF_PUBLIC);
3032 if(params != NULL)
3034 CopyMem(scan_params, params, sizeof(scan_params));
3035 if(ssid != NULL)
3036 CopyMem(ssid, params + sizeof(scan_params), ssid_length);
3037 params[4] = ssid_length;
3038 P2SetData(unit, P2_REC_HOSTSCAN, params,
3039 sizeof(scan_params) + ssid_length, base);
3040 FreeVec(params);
3043 else if(unit->firmware_type == SYMBOL_FIRMWARE)
3044 P2SetWord(unit, P2_REC_ALTHOSTSCAN, 0x82, base);
3045 else if(unit->firmware_type >= LUCENT_FIRMWARE
3046 && (unit->flags & UNITF_HARDTKIP) != 0)
3048 /* Initialise fake scan results and ask for a series of raw beacon
3049 descriptors */
3051 unit->scan_results_rec[0] = MakeLEWord(1);
3053 P2SetID(unit, P2_REC_SCANSSID, ssid, ssid_length, base);
3054 P2SetWord(unit, P2_REC_SCANCHANNELS, 0x7fff, base);
3055 unit->LEWordOut(unit->card, P2_REG_PARAM1, 0x3fff);
3056 P2DoCmd(unit, P2_CMD_INQUIRE, P2_INFO_SCANRESULT, base);
3058 else
3060 P2SetID(unit, P2_REC_SCANSSID, ssid, ssid_length, base);
3061 P2DoCmd(unit, P2_CMD_INQUIRE, P2_INFO_SCANRESULTS, base);
3065 return;
3070 /****i* prism2.device/LoadFirmware *****************************************
3072 * NAME
3073 * LoadFirmware
3075 * SYNOPSIS
3076 * success = LoadFirmware(unit)
3078 * BOOL LoadFirmware(struct DevUnit *);
3080 * FUNCTION
3082 * INPUTS
3083 * unit - A unit of this device.
3085 * RESULT
3086 * success - Success indicator.
3088 ****************************************************************************
3092 static BOOL LoadFirmware(struct DevUnit *unit, struct DevBase *base)
3094 BOOL success = TRUE;
3095 const TEXT *file_name;
3096 struct FileInfoBlock *info = NULL;
3097 UWORD control_reg, pdr_no, *pda = NULL, *pdr, *prod_data, length;
3098 ULONG location, start_address;
3099 BPTR file = (BPTR)NULL;
3100 UBYTE *data = NULL;
3101 TEXT *buffer = NULL;
3102 const TEXT *p;
3103 UBYTE type;
3105 /* Read firmware file */
3107 switch(unit->firmware_type)
3109 case LUCENT_FIRMWARE:
3110 file_name = h1_firmware_file_name;
3111 break;
3112 case HERMES2_FIRMWARE:
3113 file_name = h2_firmware_file_name;
3114 break;
3115 case HERMES2G_FIRMWARE:
3116 file_name = h25_firmware_file_name;
3117 break;
3118 default:
3119 file_name = NULL;
3122 if(file_name == NULL)
3123 success = FALSE;
3125 if(success)
3127 file = Open(file_name, MODE_OLDFILE);
3128 if(file == (BPTR)NULL)
3129 success = FALSE;
3132 if(success)
3134 info = AllocDosObject(DOS_FIB, NULL);
3135 if(info == NULL)
3136 success = FALSE;
3139 if(success)
3141 if(!ExamineFH(file, info))
3142 success = FALSE;
3145 if(success)
3147 buffer = AllocVec(info->fib_Size + 1, MEMF_ANY);
3148 data = AllocVec(MAX_S_REC_SIZE, MEMF_ANY);
3149 pda = AllocVec(LUCENT_PDA_SIZE, MEMF_ANY);
3150 if(buffer == NULL || data == NULL || pda == NULL)
3151 success = FALSE;
3154 if(success)
3156 if(Read(file, buffer, info->fib_Size) == -1)
3157 success = FALSE;
3158 buffer[info->fib_Size] = '\0';
3161 if(success)
3163 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3164 P2DoCmd(unit, P2_CMD_INIT | 0x100, 0, base);
3165 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3166 P2DoCmd(unit, P2_CMD_INIT | 0x0, 0, base);
3167 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3169 /* Enable auxiliary ports */
3171 unit->LEWordOut(unit->card, P2_REG_PARAM0, 0xfe01);
3172 unit->LEWordOut(unit->card, P2_REG_PARAM1, 0xdc23);
3173 unit->LEWordOut(unit->card, P2_REG_PARAM2, 0xba45);
3175 control_reg = unit->LEWordIn(unit->card, P2_REG_CONTROL);
3176 control_reg =
3177 control_reg & ~P2_REG_CONTROLF_AUX | P2_REG_CONTROL_ENABLEAUX;
3178 unit->LEWordOut(unit->card, P2_REG_CONTROL, control_reg);
3180 BusyMilliDelay(5, base);
3181 while(
3182 (unit->LEWordIn(unit->card, P2_REG_CONTROL) & P2_REG_CONTROLF_AUX)
3183 != P2_REG_CONTROL_AUXENABLED);
3185 /* Read Production Data Area from card */
3187 if(unit->firmware_type < HERMES2_FIRMWARE)
3189 location = LUCENT_PDA_ADDRESS;
3190 unit->LEWordOut(unit->card, P2_REG_AUXPAGE, location >> 7);
3191 unit->LEWordOut(unit->card, P2_REG_AUXOFFSET,
3192 location & (1 << 7) - 1);
3194 unit->WordsIn(unit->card, P2_REG_AUXDATA,
3195 (UWORD *)pda, LUCENT_PDA_SIZE >> 1);
3198 /* Allow writing to card's RAM */
3200 BusyMilliDelay(100, base);
3201 start_address = 0xf8000;
3202 unit->LEWordOut(unit->card, P2_REG_PARAM1, start_address >> 16);
3203 P2DoCmd(unit, P2_CMD_PROGRAM | P2_CMDF_WRITE, start_address, base);
3205 /* Parse firmware image data and write it to card */
3207 p = buffer;
3208 while(p != NULL)
3210 p = ParseNextSRecord(p, &type, data, &length, &location, base);
3211 if(p != NULL)
3213 switch(type)
3215 case '3':
3217 /* Check that this is not a "special" record */
3219 if(location < 0xff000000)
3221 /* Write data to card */
3223 if(unit->firmware_type < LUCENT_FIRMWARE)
3225 unit->LEWordOut(unit->card, P2_REG_PARAM1,
3226 location >> 16);
3227 P2DoCmd(unit, P2_CMD_PROGRAM | P2_CMDF_WRITE, location,
3228 base);
3231 unit->LEWordOut(unit->card, P2_REG_AUXPAGE,
3232 location >> 7);
3233 unit->LEWordOut(unit->card, P2_REG_AUXOFFSET,
3234 location & (1 << 7) - 1);
3236 unit->WordsOut(unit->card, P2_REG_AUXDATA,
3237 (UWORD *)data, length >> 1);
3239 break;
3241 case '7':
3243 /* Get location in card memory to begin execution of new
3244 firmware at */
3246 start_address = location;
3251 /* Parse PDA plug records and patch firmware */
3253 p = buffer;
3254 while(p != NULL)
3256 p = ParseNextSRecord(p, &type, data, &length, &location, base);
3258 if(p != NULL && type == '3' && location == 0xff000000)
3260 /* Get PDR number and the location where it should be patched
3261 into firmware */
3263 pdr_no = LELong(*(ULONG *)data);
3264 location = LELong(*(ULONG *)(data + 4));
3265 length = LELong(*(ULONG *)(data + 8));
3267 /* Find PDR to copy data from */
3269 prod_data = NULL;
3270 for(pdr = pda; pdr[1] != 0; pdr += LEWord(pdr[0]) + 1)
3272 if(LEWord(pdr[1]) == pdr_no)
3273 prod_data = pdr + 2;
3276 /* Write production data to card if it was found */
3278 if(prod_data != NULL)
3280 if(unit->firmware_type < LUCENT_FIRMWARE)
3282 unit->LEWordOut(unit->card, P2_REG_PARAM1,
3283 location >> 16);
3284 P2DoCmd(unit, P2_CMD_PROGRAM | P2_CMDF_WRITE, location,
3285 base);
3288 unit->LEWordOut(unit->card, P2_REG_AUXPAGE, location >> 7);
3289 unit->LEWordOut(unit->card, P2_REG_AUXOFFSET,
3290 location & (1 << 7) - 1);
3292 unit->WordsOut(unit->card, P2_REG_AUXDATA, prod_data,
3293 length >> 1);
3298 /* Disable auxiliary ports */
3300 control_reg = unit->LEWordIn(unit->card, P2_REG_CONTROL);
3301 control_reg =
3302 control_reg & ~P2_REG_CONTROLF_AUX | P2_REG_CONTROL_DISABLEAUX;
3303 unit->LEWordOut(unit->card, P2_REG_CONTROL, control_reg);
3305 /* Execute downloaded firmware */
3307 if(unit->firmware_type >= HERMES2_FIRMWARE)
3309 unit->LEWordOut(unit->card, P2_REG_PARAM1, start_address >> 16);
3310 P2DoCmd(unit, P2_CMD_EXECUTE, start_address, base);
3312 else if(unit->firmware_type >= LUCENT_FIRMWARE)
3314 P2DoCmd(unit, P2_CMD_PROGRAM, 0, base);
3315 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3316 P2DoCmd(unit, P2_CMD_INIT, 0, base);
3317 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3319 else
3321 unit->LEWordOut(unit->card, P2_REG_PARAM1, start_address >> 16);
3322 P2DoCmd(unit, P2_CMD_PROGRAM, start_address, base);
3323 P2DoCmd(unit, P2_CMD_INIT, 0, base);
3327 /* Free Resources */
3329 FreeVec(pda);
3330 FreeVec(buffer);
3331 FreeVec(data);
3332 FreeDosObject(DOS_FIB, info);
3333 if(file != (BPTR)NULL)
3334 Close(file);
3336 return success;
3341 /****i* prism2.device/ParseNextSRecord *************************************
3343 * NAME
3344 * ParseNextSRecord
3346 ****************************************************************************
3350 static const TEXT *ParseNextSRecord(const TEXT *s, UBYTE *type, UBYTE *data,
3351 UWORD *data_length, ULONG *location, struct DevBase *base)
3353 LONG ch;
3354 ULONG n = 0;
3355 UWORD i;
3356 BOOL found = FALSE;
3358 /* Find start of next record, if any */
3360 while(!found)
3362 ch = *s++;
3363 if(ch == 'S' || ch == '\0')
3364 found = TRUE;
3367 if(ch == 'S')
3369 /* Get record type */
3371 *type = *s++;
3373 /* Skip length field to keep alignment easy */
3375 s += 2;
3377 /* Parse hexadecimal portion of record */
3379 for(i = 0; (ch = *s++) >= '0'; i++)
3381 n <<= 4;
3383 if(ch >= 'A')
3384 n |= ch - 'A' + 10;
3385 else
3386 n |= ch - '0';
3388 if(i >= 8 && (i & 0x1) != 0)
3390 *data++ = n;
3391 n = 0;
3393 else if(i == 7)
3395 *location = n;
3396 n = 0;
3399 *data_length = (i >> 1) - 5;
3401 else
3402 s = NULL;
3404 /* Return updated text pointer */
3406 return s;
3411 /****i* prism2.device/P2DoCmd **********************************************
3413 * NAME
3414 * P2DoCmd
3416 ****************************************************************************
3418 * Commands can't fail without software/firmware bug?
3422 static VOID P2DoCmd(struct DevUnit *unit, UWORD command, UWORD param,
3423 struct DevBase *base)
3425 if(unit->firmware_type < LUCENT_FIRMWARE && command == P2_CMD_INIT)
3426 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3428 unit->LEWordOut(unit->card, P2_REG_PARAM0, param);
3429 unit->LEWordOut(unit->card, P2_REG_COMMAND, command);
3430 while((unit->LEWordIn(unit->card, P2_REG_EVENTS)
3431 & P2_EVENTF_CMD) == 0);
3432 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_CMD);
3434 if(unit->firmware_type < LUCENT_FIRMWARE && command == P2_CMD_INIT)
3435 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3440 /****i* prism2.device/P2Seek ***********************************************
3442 * NAME
3443 * P2Seek
3445 ****************************************************************************
3449 static BOOL P2Seek(struct DevUnit *unit, UWORD path_no, UWORD rec_no,
3450 UWORD offset, struct DevBase *base)
3452 UPINT offset_reg;
3454 path_no <<= 1;
3455 offset_reg = P2_REG_OFFSET0 + path_no;
3456 while((unit->LEWordIn(unit->card, offset_reg) & P2_REG_OFFSETF_BUSY)
3457 != 0);
3458 unit->LEWordOut(unit->card, P2_REG_SELECT0 + path_no, rec_no);
3459 unit->LEWordOut(unit->card, offset_reg, offset);
3460 while((unit->LEWordIn(unit->card, offset_reg) & P2_REG_OFFSETF_BUSY)
3461 != 0);
3463 return (unit->LEWordIn(unit->card, offset_reg) & P2_REG_OFFSETF_ERROR)
3464 == 0;
3469 /****i* prism2.device/P2SetID **********************************************
3471 * NAME
3472 * P2SetID
3474 * NOTES
3475 * id may be NULL as long as length is zero.
3477 ****************************************************************************
3481 static VOID P2SetID(struct DevUnit *unit, UWORD rec_no, const UBYTE *id,
3482 UWORD length, struct DevBase *base)
3484 P2Seek(unit, 1, rec_no, 0, base);
3486 unit->LEWordOut(unit->card, P2_REG_DATA1, length / 2 + 3);
3487 unit->LEWordOut(unit->card, P2_REG_DATA1, rec_no);
3488 unit->LEWordOut(unit->card, P2_REG_DATA1, length);
3489 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)id, (length + 1) / 2);
3491 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, rec_no, base);
3493 return;
3498 /****i* prism2.device/P2SetWord ********************************************
3500 * NAME
3501 * P2SetWord
3503 ****************************************************************************
3507 static VOID P2SetWord(struct DevUnit *unit, UWORD rec_no, UWORD value,
3508 struct DevBase *base)
3510 P2Seek(unit, 1, rec_no, 0, base);
3512 unit->LEWordOut(unit->card, P2_REG_DATA1, 2);
3513 unit->LEWordOut(unit->card, P2_REG_DATA1, rec_no);
3514 unit->LEWordOut(unit->card, P2_REG_DATA1, value);
3516 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, rec_no, base);
3518 return;
3523 /****i* prism2.device/P2GetWord ********************************************
3525 * NAME
3526 * P2GetWord
3528 ****************************************************************************
3532 static UWORD P2GetWord(struct DevUnit *unit, UWORD rec_no,
3533 struct DevBase *base)
3535 P2DoCmd(unit, P2_CMD_ACCESS, rec_no, base);
3536 P2Seek(unit, 1, rec_no, 4, base);
3538 return unit->LEWordIn(unit->card, P2_REG_DATA1);
3543 /****i* prism2.device/P2AllocMem *******************************************
3545 * NAME
3546 * P2AllocMem
3548 ****************************************************************************
3552 static UWORD P2AllocMem(struct DevUnit *unit, UWORD size,
3553 struct DevBase *base)
3555 UWORD id;
3556 P2DoCmd(unit, P2_CMD_ALLOCMEM, size, base);
3557 while((unit->LEWordIn(unit->card, P2_REG_EVENTS) & P2_EVENTF_ALLOCMEM)
3558 == 0);
3559 id = unit->LEWordIn(unit->card, P2_REG_ALLOCFID);
3560 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_ALLOCMEM);
3561 return id;
3566 /****i* prism2.device/P2SetData ********************************************
3568 * NAME
3569 * P2SetData
3571 ****************************************************************************
3575 static VOID P2SetData(struct DevUnit *unit, UWORD rec_no, const UBYTE *data,
3576 UWORD length, struct DevBase *base)
3578 length = (length + 1) / 2;
3579 P2Seek(unit, 1, rec_no, 0, base);
3581 unit->LEWordOut(unit->card, P2_REG_DATA1, 1 + length);
3582 unit->LEWordOut(unit->card, P2_REG_DATA1, rec_no);
3583 unit->WordsOut(unit->card, P2_REG_DATA1, (const UWORD *)data, length);
3585 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, rec_no, base);
3587 return;
3592 /****i* prism2.device/P2ReadRec ********************************************
3594 * NAME
3595 * P2ReadRec -- Load and read an entire record.
3597 * SYNOPSIS
3598 * success = P2ReadRec(unit, rec_no, buffer, max_length)
3600 * BOOL P2ReadRec(struct DevUnit *, UWORD, APTR, UWORD);
3602 * FUNCTION
3604 * INPUTS
3605 * unit - A unit of this device.
3606 * rec_no - Record number to read.
3607 * buffer - Buffer to store data in.
3608 * max_length - Maximum number of bytes to store in buffer.
3610 * RESULT
3611 * success - Success indicator.
3613 ****************************************************************************
3617 static BOOL P2ReadRec(struct DevUnit *unit, UWORD rec_no, APTR buffer,
3618 UWORD max_length, struct DevBase *base)
3620 BOOL success = TRUE;
3621 WORD length;
3623 P2DoCmd(unit, P2_CMD_ACCESS, rec_no, base);
3624 P2Seek(unit, 1, rec_no, 0, base);
3626 length = (unit->LEWordIn(unit->card, P2_REG_DATA1) + 1) * 2;
3627 P2Seek(unit, 1, rec_no, 0, base);
3628 if(length <= max_length)
3629 unit->WordsIn(unit->card, P2_REG_DATA1, (UWORD *)buffer,
3630 length / 2);
3631 else
3632 success = FALSE;
3633 return success;
3638 /****i* prism2.device/ConvertLevel *****************************************
3640 * NAME
3641 * ConvertLevel -- Convert a signal or noise level to dBm.
3643 * SYNOPSIS
3644 * dbm_level = ConvertLevel(unit, raw_level)
3646 * LONG ConvertLevel(struct DevUnit *, UWORD);
3648 * FUNCTION
3650 * INPUTS
3651 * unit - A unit of this device.
3652 * raw_level - The value returned from the hardware.
3654 * RESULT
3655 * dbm_level - The value in dBm.
3657 ****************************************************************************
3661 static LONG ConvertLevel(struct DevUnit *unit, UWORD raw_level,
3662 struct DevBase *base)
3664 LONG dbm_level;
3666 if(unit->firmware_type >= LUCENT_FIRMWARE)
3667 dbm_level = raw_level - LUCENT_DBM_OFFSET;
3668 else
3669 dbm_level = raw_level / 3 - INTERSIL_DBM_OFFSET;
3671 return dbm_level;
3676 /****i* prism2.device/ConvertScanLevel *************************************
3678 * NAME
3679 * ConvertScanLevel -- Convert a signal or noise level to dBm.
3681 * SYNOPSIS
3682 * dbm_level = ConvertScanLevel(unit, raw_level)
3684 * LONG ConvertScanLevel(struct DevUnit *, UWORD);
3686 * FUNCTION
3688 * INPUTS
3689 * unit - A unit of this device.
3690 * raw_level - The value returned from the hardware.
3692 * RESULT
3693 * dbm_level - The value in dBm.
3695 ****************************************************************************
3699 static LONG ConvertScanLevel(struct DevUnit *unit, UWORD raw_level,
3700 struct DevBase *base)
3702 LONG dbm_level;
3704 if(unit->firmware_type >= LUCENT_FIRMWARE)
3705 dbm_level = raw_level - LUCENT_DBM_OFFSET;
3706 else
3707 dbm_level = (WORD)raw_level;
3709 return dbm_level;
3714 /****i* prism2.device/GetIE ************************************************
3716 * NAME
3717 * GetIE
3719 * SYNOPSIS
3720 * ie = GetIE(id, ies, ies_length)
3722 * UBYTE *GetIE(UBYTE, UBYTE *, UWORD);
3724 * FUNCTION
3726 * INPUTS
3727 * id - ID of IE to find.
3728 * ies - A series of IEs.
3729 * ies_length - Length of IE block.
3731 * RESULT
3732 * ie - Pointer to start of IE within block, or NULL if not found.
3734 ****************************************************************************
3738 #if 0
3739 static UBYTE *GetIE(UBYTE id, UBYTE *ies, UWORD ies_length,
3740 struct DevBase *base)
3742 BOOL found = FALSE;
3743 UBYTE *ie, *end;
3745 // for(ie = ies; ie < end && ie + ie[1] < end; ie += length + 2)
3746 end = ies + ies_length;
3747 while(ie < end && !found)
3749 if(ie[0] == id)
3750 found = TRUE;
3751 else
3752 ie += ie[1] + 2;
3754 if(!found)
3755 ie = NULL;
3757 return ie;
3759 #else
3760 static UBYTE *GetIE(UBYTE id, UBYTE *ies, UWORD ies_length,
3761 struct DevBase *base)
3763 UBYTE *ie;
3765 for(ie = ies; ie < ies + ies_length && ie[0] != id; ie += ie[1] + 2);
3766 // for(ie = ies, end = ies + ies_length; ie < end && ie[0] != id; ie += ie[1] + 2);
3767 if(ie >= ies + ies_length)
3768 ie = NULL;
3770 return ie;
3772 #endif
3775 /****i* prism2.device/UnitTask *********************************************
3777 * NAME
3778 * UnitTask
3780 * SYNOPSIS
3781 * UnitTask(sys_base)
3783 * VOID UnitTask(struct ExecBase *);
3785 * FUNCTION
3786 * Completes deferred requests, and handles card insertion and removal
3787 * in conjunction with the relevant interrupts.
3789 ****************************************************************************
3793 #ifdef __MORPHOS__
3794 #undef UnitTask
3795 #endif
3797 static VOID UnitTask(struct ExecBase *sys_base)
3799 struct Task *task;
3800 struct IORequest *request;
3801 struct DevUnit *unit;
3802 struct DevBase *base;
3803 struct MsgPort *general_port;
3804 ULONG signals = 0, wait_signals, card_removed_signal,
3805 card_inserted_signal, scan_complete_signal, general_port_signal;
3807 /* Get parameters */
3809 task = AbsExecBase->ThisTask;
3810 unit = task->tc_UserData;
3811 base = unit->device;
3813 /* Activate general request port */
3815 general_port = unit->request_ports[GENERAL_QUEUE];
3816 general_port->mp_SigTask = task;
3817 general_port->mp_SigBit = AllocSignal(-1);
3818 general_port_signal = 1 << general_port->mp_SigBit;
3819 general_port->mp_Flags = PA_SIGNAL;
3821 /* Allocate signals for notification of card removal and insertion */
3823 card_removed_signal = unit->card_removed_signal = 1 << AllocSignal(-1);
3824 card_inserted_signal = unit->card_inserted_signal = 1 << AllocSignal(-1);
3825 scan_complete_signal = unit->scan_complete_signal = 1 << AllocSignal(-1);
3826 wait_signals = (1 << general_port->mp_SigBit) | card_removed_signal
3827 | card_inserted_signal | scan_complete_signal | SIGBREAKF_CTRL_C;
3829 /* Tell ourselves to check port for old messages */
3831 Signal(task, general_port_signal);
3833 /* Infinite loop to service requests and signals */
3835 while((signals & SIGBREAKF_CTRL_C) == 0)
3837 signals = Wait(wait_signals);
3839 if((signals & card_inserted_signal) != 0)
3841 if(unit->insertion_function(unit->card, base))
3843 unit->flags |= UNITF_HAVEADAPTER;
3844 if((unit->flags & UNITF_CONFIGURED) != 0)
3845 ConfigureAdapter(unit, base);
3846 if((unit->flags & UNITF_WASONLINE) != 0)
3848 GoOnline(unit, base);
3849 unit->flags &= ~UNITF_WASONLINE;
3854 if((signals & card_removed_signal) != 0)
3856 unit->removal_function(unit->card, base);
3857 if((unit->flags & UNITF_WASONLINE) != 0)
3858 GoOffline(unit, base);
3861 if((signals & scan_complete_signal) != 0)
3862 SendScanResults(unit, base);
3864 if((signals & general_port_signal) != 0)
3866 while((request = (APTR)GetMsg(general_port)) != NULL)
3868 /* Service the request as soon as the unit is free */
3870 ObtainSemaphore(&unit->access_lock);
3871 ServiceRequest((APTR)request, base);
3876 FreeMem(task->tc_SPLower, STACK_SIZE);
3881 /****i* prism2.device/StrLen ***********************************************
3883 * NAME
3884 * StrLen
3886 * SYNOPSIS
3887 * length = StrLen(s)
3889 * UPINT StrLen(TEXT *);
3891 ****************************************************************************
3895 static UPINT StrLen(const TEXT *s)
3897 const TEXT *p;
3899 for(p = s; *p != '\0'; p++);
3900 return p - s;