Reverted removal of 'const' from TagItem arrays/pointers in r50146
[AROS.git] / workbench / devs / networks / prism2 / unit.c
blob116735c33c8acd537ddd8d8d287485932ba88af2
1 /*
3 Copyright (C) 2012-2017 The AROS Dev Team
4 Copyright (C) 2001-2012 Neil Cafferkey
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
19 MA 02111-1307, USA.
24 #include <exec/memory.h>
25 #include <exec/execbase.h>
26 #include <exec/errors.h>
28 #include <proto/exec.h>
29 #ifndef __amigaos4__
30 #include <proto/alib.h>
31 #else
32 #include <clib/alib_protos.h>
33 #endif
34 #include <proto/utility.h>
35 #include <proto/dos.h>
36 #include <proto/timer.h>
38 #include "device.h"
39 #include "prism2.h"
41 #include "unit_protos.h"
42 #include "request_protos.h"
43 #include "encryption_protos.h"
44 #include "timer_protos.h"
47 #define TASK_PRIORITY 0
48 #define STACK_SIZE 4096
49 #define INT_MASK \
50 (P2_EVENTF_INFO | P2_EVENTF_ALLOCMEM | P2_EVENTF_TXFAIL | P2_EVENTF_RX)
51 #define MAX_S_REC_SIZE 50
52 #define LUCENT_DBM_OFFSET 149
53 #define INTERSIL_DBM_OFFSET 100
54 #define SCAN_BUFFER_SIZE 2000
55 #define BEACON_BUFFER_SIZE 8000
56 #define SCAN_TAG_COUNT 8 +10
57 #define INFO_TAG_COUNT 4 +10
58 #define LUCENT_PDA_ADDRESS 0x390000
59 #define LUCENT_PDA_SIZE 1000
60 #define FRAME_BUFFER_SIZE (P2_H2FRM_ETHFRAME + ETH_HEADERSIZE \
61 + SNAP_HEADERSIZE + ETH_MTU + EIV_SIZE + ICV_SIZE + MIC_SIZE)
64 #ifndef AbsExecBase
65 #ifdef __AROS__
66 #define AbsExecBase sys_base
67 #else
68 #define AbsExecBase (*(struct ExecBase **)4)
69 #endif
70 #endif
72 static struct AddressRange *FindMulticastRange(struct DevUnit *unit,
73 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left,
74 UWORD upper_bound_right, struct DevBase *base);
75 static VOID SetMulticast(struct DevUnit *unit, struct DevBase *base);
76 static VOID RXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code));
77 static UBYTE *GetRXBuffer(struct DevUnit *unit, const UBYTE *address,
78 UWORD frag_no, UWORD *buffer_no, struct DevBase *base);
79 static VOID DistributeRXPacket(struct DevUnit *unit, UBYTE *frame,
80 struct DevBase *base);
81 static VOID CopyPacket(struct DevUnit *unit, struct IOSana2Req *request,
82 UWORD packet_size, UWORD packet_type, UBYTE *buffer,
83 struct DevBase *base);
84 static BOOL AddressFilter(struct DevUnit *unit, UBYTE *address,
85 struct DevBase *base);
86 static VOID SaveBeacon(struct DevUnit *unit, const UBYTE *frame,
87 struct DevBase *base);
88 static VOID TXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code));
89 static VOID InfoInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code));
90 static VOID ResetHandler(REG(a1, struct DevUnit *unit),
91 REG(a6, APTR int_code));
92 static VOID ReportEvents(struct DevUnit *unit, ULONG events,
93 struct DevBase *base);
94 static BOOL LoadFirmware(struct DevUnit *unit, struct DevBase *base);
95 static const TEXT *ParseNextSRecord(const TEXT *s, UBYTE *type, UBYTE *data,
96 UWORD *data_length, ULONG *location, struct DevBase *base);
97 static VOID P2DoCmd(struct DevUnit *unit, UWORD command, UWORD param,
98 struct DevBase *base);
99 static BOOL P2Seek(struct DevUnit *unit, UWORD path_no, UWORD rec_no,
100 UWORD offset, struct DevBase *base);
101 static VOID P2SetID(struct DevUnit *unit, UWORD rec_no, const UBYTE *id,
102 UWORD length, struct DevBase *base);
103 static VOID P2SetWord(struct DevUnit *unit, UWORD rec_no, UWORD value,
104 struct DevBase *base);
105 static UWORD P2GetWord(struct DevUnit *unit, UWORD rec_no,
106 struct DevBase *base);
107 static UWORD P2AllocMem(struct DevUnit *unit, UWORD size,
108 struct DevBase *base);
109 static VOID P2SetData(struct DevUnit *unit, UWORD rec_no, const UBYTE *data,
110 UWORD length, struct DevBase *base);
111 static BOOL P2ReadRec(struct DevUnit *unit, UWORD rec_no, APTR buffer,
112 UWORD max_length, struct DevBase *base);
113 static LONG ConvertLevel(struct DevUnit *unit, UWORD raw_level,
114 struct DevBase *base);
115 static LONG ConvertScanLevel(struct DevUnit *unit, UWORD raw_level,
116 struct DevBase *base);
117 static UBYTE *GetIE(UBYTE id, UBYTE *ies, UWORD ies_length,
118 struct DevBase *base);
119 static VOID UnitTask(struct ExecBase *sys_base);
120 static UPINT StrLen(const TEXT *s);
123 static const UBYTE snap_template[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
124 static const UBYTE scan_params[] = {0xff, 0x3f, 0x01, 0x00, 0x00, 0x00};
125 #if !defined(__AROS__)
126 static const TEXT options_name[] = "Prism 2 options";
127 #endif
128 static const TEXT h1_firmware_file_name[] = "DEVS:Firmware/HermesI";
129 static const TEXT h2_firmware_file_name[] = "DEVS:Firmware/HermesII";
130 static const TEXT h25_firmware_file_name[] = "DEVS:Firmware/HermesII.5";
131 static const UBYTE h2_wpa_ie[] =
133 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00,
134 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50,
135 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02,
136 0x00, 0x00
140 #ifdef __amigaos4__
141 #undef AddTask
142 #define AddTask(task, initial_pc, final_pc) \
143 IExec->AddTask(task, initial_pc, final_pc, NULL)
144 #endif
145 #ifdef __MORPHOS__
146 static const struct EmulLibEntry mos_task_trap =
148 TRAP_LIB,
150 (APTR)UnitTask
152 #define UnitTask &mos_task_trap
153 #endif
154 #ifdef __AROS__
155 #undef AddTask
156 #define AddTask(task, initial_pc, final_pc) \
157 ({ \
158 struct TagItem _task_tags[] = \
159 {{TASKTAG_ARG1, (IPTR)SysBase}, {TAG_END, 0}}; \
160 NewAddTask(task, initial_pc, final_pc, _task_tags); \
162 #endif
166 /****i* prism2.device/CreateUnit *******************************************
168 * NAME
169 * CreateUnit -- Create a unit.
171 * SYNOPSIS
172 * unit = CreateUnit(index, card, io_tags, bus)
174 * struct DevUnit *CreateUnit(ULONG, APTR, struct TagItem *, UWORD);
176 * FUNCTION
177 * Creates a new unit.
179 ****************************************************************************
183 struct DevUnit *CreateUnit(ULONG index, APTR card,
184 const struct TagItem *io_tags, UWORD bus, struct DevBase *base)
186 BOOL success = TRUE;
187 struct DevUnit *unit;
188 struct Task *task;
189 struct MsgPort *port;
190 UBYTE i;
191 APTR stack;
193 unit = AllocMem(sizeof(struct DevUnit), MEMF_CLEAR | MEMF_PUBLIC);
194 if(unit == NULL)
195 success = FALSE;
197 if(success)
199 unit->index = index;
200 unit->device = base;
201 unit->card = card;
202 unit->bus = bus;
203 unit->WordsIn =
204 (APTR)GetTagData(IOTAG_WordsIn, (UPINT)NULL, io_tags);
205 unit->WordsOut =
206 (APTR)GetTagData(IOTAG_WordsOut, (UPINT)NULL, io_tags);
207 unit->BEWordOut =
208 (APTR)GetTagData(IOTAG_BEWordOut, (UPINT)NULL, io_tags);
209 unit->LEWordIn =
210 (APTR)GetTagData(IOTAG_LEWordIn, (UPINT)NULL, io_tags);
211 unit->LEWordOut =
212 (APTR)GetTagData(IOTAG_LEWordOut, (UPINT)NULL, io_tags);
213 if(unit->WordsIn == NULL || unit->WordsOut == NULL
214 || unit->BEWordOut == NULL || unit->LEWordIn == NULL
215 || unit->LEWordOut == NULL)
216 success = FALSE;
219 if(success)
221 InitSemaphore(&unit->access_lock);
222 success = InitialiseAdapter(unit, FALSE, base);
223 unit->flags |= UNITF_HAVEADAPTER;
225 /* Create the message ports for queuing requests */
227 for(i = 0; i < REQUEST_QUEUE_COUNT; i++)
229 unit->request_ports[i] = port = AllocMem(sizeof(struct MsgPort),
230 MEMF_PUBLIC | MEMF_CLEAR);
231 if(port == NULL)
232 success = FALSE;
234 if(success)
236 NewList(&port->mp_MsgList);
237 port->mp_Flags = PA_IGNORE;
238 port->mp_SigTask = &unit->tx_int;
242 /* Allocate buffers */
244 unit->rx_buffer = AllocVec(FRAME_BUFFER_SIZE, MEMF_PUBLIC);
245 unit->rx_buffers = AllocVec(FRAME_BUFFER_SIZE * RX_BUFFER_COUNT,
246 MEMF_PUBLIC);
247 for(i = 0; i < RX_BUFFER_COUNT; i++)
248 unit->rx_fragment_nos[i] = -1;
249 unit->tx_buffer = AllocVec(ETH_MAXPACKETSIZE, MEMF_PUBLIC);
250 unit->rx_descriptor = AllocVec(FRAME_BUFFER_SIZE,
251 MEMF_PUBLIC | MEMF_CLEAR);
252 unit->tx_descriptor = AllocVec(FRAME_BUFFER_SIZE,
253 MEMF_PUBLIC | MEMF_CLEAR);
254 unit->scan_results_rec = AllocVec(SCAN_BUFFER_SIZE, MEMF_PUBLIC);
255 unit->next_beacon = unit->beacons =
256 AllocVec(BEACON_BUFFER_SIZE, MEMF_PUBLIC);
257 if(unit->rx_buffer == NULL || unit->rx_buffers == NULL
258 || unit->tx_buffer == NULL || unit->rx_descriptor == NULL
259 || unit->tx_descriptor == NULL || unit->scan_results_rec == NULL
260 || unit->beacons == NULL)
261 success = FALSE;
264 if(success)
266 NewList((APTR)&unit->openers);
267 NewList((APTR)&unit->type_trackers);
268 NewList((APTR)&unit->multicast_ranges);
270 /* Record maximum speed in BPS */
272 unit->speed = 11000000;
274 /* Initialise status, transmit, receive and stats interrupts */
276 unit->status_int.is_Node.ln_Name =
277 base->device.dd_Library.lib_Node.ln_Name;
278 unit->status_int.is_Code = (APTR)StatusInt;
279 unit->status_int.is_Data = unit;
281 unit->rx_int.is_Node.ln_Name =
282 base->device.dd_Library.lib_Node.ln_Name;
283 unit->rx_int.is_Code = (APTR)RXInt;
284 unit->rx_int.is_Data = unit;
286 unit->tx_int.is_Node.ln_Name =
287 base->device.dd_Library.lib_Node.ln_Name;
288 unit->tx_int.is_Code = (APTR)TXInt;
289 unit->tx_int.is_Data = unit;
291 unit->info_int.is_Node.ln_Name =
292 base->device.dd_Library.lib_Node.ln_Name;
293 unit->info_int.is_Code = (APTR)InfoInt;
294 unit->info_int.is_Data = unit;
296 unit->reset_handler.is_Node.ln_Name =
297 base->device.dd_Library.lib_Node.ln_Name;
298 unit->reset_handler.is_Code = (APTR)ResetHandler;
299 unit->reset_handler.is_Data = unit;
301 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
304 if(success)
306 /* Create a new task */
308 unit->task = task =
309 AllocMem(sizeof(struct Task), MEMF_PUBLIC | MEMF_CLEAR);
310 if(task == NULL)
311 success = FALSE;
314 if(success)
316 stack = AllocMem(STACK_SIZE, MEMF_PUBLIC);
317 if(stack == NULL)
318 success = FALSE;
321 if(success)
323 /* Initialise and start task */
325 task->tc_Node.ln_Type = NT_TASK;
326 task->tc_Node.ln_Pri = TASK_PRIORITY;
327 task->tc_Node.ln_Name = base->device.dd_Library.lib_Node.ln_Name;
328 task->tc_SPUpper = stack + STACK_SIZE;
329 task->tc_SPLower = stack;
330 task->tc_SPReg = stack + STACK_SIZE;
331 NewList(&task->tc_MemEntry);
333 if(AddTask(task, UnitTask, NULL) == NULL)
334 success = FALSE;
337 if(success)
339 /* Send the unit to the new task */
341 task->tc_UserData = unit;
343 /* Set default wireless options */
345 unit->mode = S2PORT_MANAGED;
348 if(!success)
350 DeleteUnit(unit, base);
351 unit = NULL;
354 return unit;
359 /****i* prism2.device/DeleteUnit *******************************************
361 * NAME
362 * DeleteUnit -- Delete a unit.
364 * SYNOPSIS
365 * DeleteUnit(unit)
367 * VOID DeleteUnit(struct DevUnit *);
369 * FUNCTION
370 * Deletes a unit.
372 * INPUTS
373 * unit - Device unit (may be NULL).
375 * RESULT
376 * None.
378 ****************************************************************************
382 VOID DeleteUnit(struct DevUnit *unit, struct DevBase *base)
384 UBYTE i;
385 struct Task *task;
387 if(unit != NULL)
389 /* Remove task */
391 task = unit->task;
392 if(task != NULL)
394 if(task->tc_UserData != NULL)
396 RemTask(task);
397 FreeMem(task->tc_SPLower, STACK_SIZE);
399 FreeMem(task, sizeof(struct Task));
402 /* Free request queues */
404 for(i = 0; i < REQUEST_QUEUE_COUNT; i++)
406 if(unit->request_ports[i] != NULL)
407 FreeMem(unit->request_ports[i], sizeof(struct MsgPort));
410 /* Go offline */
412 if((unit->flags & UNITF_ONLINE) != 0) /* Needed! */
413 GoOffline(unit, base);
415 /* Clear target SSID */
417 P2SetID(unit, P2_REC_DESIREDSSID, unit->ssid, 0, base);
419 /* Free buffers and unit structure */
421 FreeVec(unit->scan_results_rec);
422 FreeVec(unit->tx_descriptor);
423 FreeVec(unit->rx_descriptor);
424 FreeVec(unit->tx_buffer);
425 FreeVec(unit->rx_buffers);
426 FreeVec(unit->rx_buffer);
428 FreeMem(unit, sizeof(struct DevUnit));
431 return;
436 /****i* prism2.device/InitialiseAdapter ************************************
438 * NAME
439 * InitialiseAdapter
441 * SYNOPSIS
442 * success = InitialiseAdapter(unit, reinsertion)
444 * BOOL InitialiseAdapter(struct DevUnit *, BOOL);
446 * FUNCTION
448 * INPUTS
449 * unit
450 * reinsertion
452 * RESULT
453 * success - Success indicator.
455 ****************************************************************************
459 BOOL InitialiseAdapter(struct DevUnit *unit, BOOL reinsertion,
460 struct DevBase *base)
462 UWORD id, version, revision, i;
463 BOOL success = TRUE, loaded;
464 UBYTE address[ETH_ADDRESSSIZE];
465 WORD length;
467 /* Wait for card to be ready following bus-specific reset, then start
468 it */
470 while((unit->LEWordIn(unit->card, P2_REG_COMMAND)
471 & P2_REG_COMMANDF_BUSY) != 0);
473 P2DoCmd(unit, P2_CMD_INIT, 0, base);
475 /* Determine firmware type */
477 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_NICIDENTITY, base);
478 P2Seek(unit, 1, P2_REC_NICIDENTITY, 4, base);
479 id = unit->LEWordIn(unit->card, P2_REG_DATA1);
480 unit->LEWordIn(unit->card, P2_REG_DATA1);
481 version = unit->LEWordIn(unit->card, P2_REG_DATA1);
482 revision = unit->LEWordIn(unit->card, P2_REG_DATA1);
484 if((id & 0x8000) != 0)
486 if(version == 0)
487 unit->firmware_type = SYMBOL_FIRMWARE;
488 else
489 unit->firmware_type = INTERSIL_FIRMWARE;
491 else
493 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_PRIIDENTITY, base);
494 P2Seek(unit, 1, P2_REC_PRIIDENTITY, 0, base);
495 length = unit->LEWordIn(unit->card, P2_REG_DATA1);
496 if(length == 5)
497 unit->firmware_type = LUCENT_FIRMWARE;
498 else
500 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_STAIDENTITY, base);
501 P2Seek(unit, 1, P2_REC_STAIDENTITY, 4, base);
502 id = unit->LEWordIn(unit->card, P2_REG_DATA1);
503 unit->LEWordIn(unit->card, P2_REG_DATA1);
504 version = unit->LEWordIn(unit->card, P2_REG_DATA1);
505 revision = unit->LEWordIn(unit->card, P2_REG_DATA1);
506 if(version > 1)
507 unit->firmware_type = HERMES2G_FIRMWARE;
508 else
509 unit->firmware_type = HERMES2_FIRMWARE;
513 /* Download firmware if necessary or available */
515 loaded = LoadFirmware(unit, base);
516 if(!loaded && unit->firmware_type >= HERMES2_FIRMWARE)
517 success = FALSE;
519 if(success)
521 /* Determine features, and get offsets of certain fields within frame
522 descriptors */
524 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_STAIDENTITY, base);
525 P2Seek(unit, 1, P2_REC_STAIDENTITY, 4, base);
526 unit->LEWordIn(unit->card, P2_REG_DATA1);
527 unit->LEWordIn(unit->card, P2_REG_DATA1);
528 version = unit->LEWordIn(unit->card, P2_REG_DATA1);
529 revision = unit->LEWordIn(unit->card, P2_REG_DATA1);
531 if(P2GetWord(unit, P2_REC_HASWEP, base) != 0)
532 unit->flags |= UNITF_HASWEP | UNITF_HARDWEP;
534 unit->ethernet_offset = P2_FRM_ETHFRAME;
535 unit->data_offset = P2_FRM_DATA;
536 unit->txcontrol_offset = P2_FRM_TXCONTROL;
537 unit->datalen_offset = P2_FRM_DATALEN;
539 if(unit->firmware_type == LUCENT_FIRMWARE)
541 if(version > 6 || version == 6 && revision >= 6)
542 unit->flags |= UNITF_HASADHOC;
543 if(version >= 9)
545 unit->flags |= UNITF_HASTKIP | UNITF_HARDTKIP;
546 unit->txcontrol_offset = P2_FRM_ALTTXCONTROL;
549 else if(unit->firmware_type >= HERMES2_FIRMWARE)
551 unit->flags |= UNITF_HASADHOC | UNITF_HASTKIP | UNITF_HARDTKIP;
552 unit->ethernet_offset = P2_H2FRM_ETHFRAME;
553 unit->data_offset = P2_H2FRM_DATA;
554 unit->txcontrol_offset = P2_H2FRM_TXCONTROL;
555 unit->datalen_offset = P2_H2FRM_DATALEN;
557 else if(unit->firmware_type == INTERSIL_FIRMWARE)
559 unit->flags |= UNITF_HASADHOC | UNITF_HASWEP;
560 if(version == 1 && revision >= 7)
561 unit->flags |= UNITF_HASTKIP | UNITF_HASCCMP;
564 /* Get default channel and MAC address */
566 unit->channel = P2GetWord(unit, P2_REC_OWNCHNL, base);
567 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_ADDRESS, base);
568 P2Seek(unit, 1, P2_REC_ADDRESS, 4, base);
569 unit->WordsIn(unit->card, P2_REG_DATA1, (UWORD *)address,
570 ETH_ADDRESSSIZE / 2);
572 /* If card has been re-inserted, check it has the same address as
573 before */
575 if(reinsertion)
577 for(i = 0; i < ETH_ADDRESSSIZE; i++)
578 if(address[i] != unit->default_address[i])
579 success = FALSE;
583 if(success)
585 CopyMem(address, unit->default_address, ETH_ADDRESSSIZE);
587 /* Get initial on-card TX buffer */
589 unit->tx_frame_id = P2AllocMem(unit, FRAME_BUFFER_SIZE, base);
591 /* Set IV sizes */
593 if((unit->flags & UNITF_HARDWEP) == 0)
594 unit->iv_sizes[S2ENC_WEP] = IV_SIZE;
595 if((unit->flags & UNITF_HARDTKIP) == 0)
596 unit->iv_sizes[S2ENC_TKIP] = EIV_SIZE;
597 unit->iv_sizes[S2ENC_CCMP] = EIV_SIZE;
599 /* Set encryption functions */
601 unit->fragment_encrypt_functions[S2ENC_NONE] = WriteClearFragment;
603 if((unit->flags & UNITF_HARDWEP) != 0)
604 unit->fragment_encrypt_functions[S2ENC_WEP] = WriteClearFragment;
605 else
606 unit->fragment_encrypt_functions[S2ENC_WEP] = EncryptWEPFragment;
608 if((unit->flags & UNITF_HARDTKIP) != 0)
609 unit->fragment_encrypt_functions[S2ENC_TKIP] = WriteClearFragment;
610 else
611 unit->fragment_encrypt_functions[S2ENC_TKIP] = EncryptTKIPFragment;
613 unit->fragment_encrypt_functions[S2ENC_CCMP] = EncryptCCMPFragment;
615 /* Set decryption functions */
617 unit->fragment_decrypt_functions[S2ENC_NONE] = ReadClearFragment;
619 if((unit->flags & UNITF_HARDWEP) != 0)
620 unit->fragment_decrypt_functions[S2ENC_WEP] = ReadClearFragment;
621 else
622 unit->fragment_decrypt_functions[S2ENC_WEP] = DecryptWEPFragment;
624 if((unit->flags & UNITF_HARDTKIP) != 0)
625 unit->fragment_decrypt_functions[S2ENC_TKIP] = ReadClearFragment;
626 else
627 unit->fragment_decrypt_functions[S2ENC_TKIP] = DecryptTKIPFragment;
629 unit->fragment_decrypt_functions[S2ENC_CCMP] = DecryptCCMPFragment;
632 /* Return */
634 return success;
639 /****i* prism2.device/ConfigureAdapter *************************************
641 * NAME
642 * ConfigureAdapter -- Set up card for transmission/reception.
644 * SYNOPSIS
645 * ConfigureAdapter(unit)
647 * VOID ConfigureAdapter(struct DevUnit *);
649 ****************************************************************************
653 VOID ConfigureAdapter(struct DevUnit *unit, struct DevBase *base)
655 UWORD i, key_length, port_type, lowest_enc = S2ENC_CCMP,
656 highest_enc = S2ENC_NONE, enc_flags, size, value;
657 const struct KeyUnion *keys;
659 /* Set MAC address */
661 P2SetData(unit, P2_REC_ADDRESS, unit->address, ETH_ADDRESSSIZE,
662 base);
664 /* Decide on promiscuous mode */
666 P2SetWord(unit, P2_REC_PROMISC, FALSE, base);
667 SetMulticast(unit, base);
669 /* Set wireless parameters */
671 if(unit->mode == S2PORT_ADHOC)
673 P2SetWord(unit, P2_REC_OWNCHNL, unit->channel, base);
674 P2SetID(unit, P2_REC_OWNSSID, unit->ssid, unit->ssid_length, base);
676 if(unit->mode == S2PORT_MANAGED)
677 port_type = 1;
678 else
679 port_type = 0;
680 if((unit->flags & UNITF_ONLINE) == 0)
681 P2SetWord(unit, P2_REC_PORTTYPE, port_type, base);
682 P2SetWord(unit, P2_REC_CREATEIBSS, unit->mode == S2PORT_ADHOC, base);
683 P2SetID(unit, P2_REC_DESIREDSSID, unit->ssid, unit->ssid_length, base);
685 /* Determine highest encryption type in use */
687 for(i = 0; i < WIFI_KEYCOUNT; i++)
689 if(unit->keys[i].type > highest_enc)
690 highest_enc = unit->keys[i].type;
691 if(unit->keys[i].type < lowest_enc)
692 lowest_enc = unit->keys[i].type;
695 if(unit->wpa_ie[1] != 0)
696 highest_enc = S2ENC_TKIP; // TO DO: Be more specific?
698 /* Allow reception of beacon/probe-response frames */
700 if(unit->firmware_type == INTERSIL_FIRMWARE)
701 P2SetWord(unit, P2_REC_RXMGMTFRAMES, 1, base);
703 /* Transmit at 11Mbps, with fallback */
705 if(unit->firmware_type == INTERSIL_FIRMWARE
706 || unit->firmware_type == SYMBOL_FIRMWARE)
707 P2SetWord(unit, P2_REC_TXRATE, 0xf, base);
709 /* Configure authentication and encryption */
711 if(unit->firmware_type >= LUCENT_FIRMWARE)
713 /* Set authentication and encryption modes */
715 P2SetWord(unit, P2_REC_ALTAUTHTYPE, unit->auth_types, base);
717 P2SetWord(unit, P2_REC_ALTENCRYPTION, highest_enc, base);
719 /* Set up firmware-based WEP encryption if appropriate */
721 if(highest_enc == S2ENC_WEP && (unit->flags & UNITF_HARDWEP) != 0)
723 P2SetWord(unit, P2_REC_ALTTXCRYPTKEY, unit->tx_key_no, base);
724 P2Seek(unit, 1, P2_REC_DEFLTCRYPTKEYS, 0, base);
725 unit->LEWordOut(unit->card, P2_REG_DATA1, P2_ALTWEPRECLEN);
726 unit->LEWordOut(unit->card, P2_REG_DATA1, P2_REC_DEFLTCRYPTKEYS);
727 keys = unit->keys;
728 for(i = 0; i < WIFI_KEYCOUNT; i++)
730 key_length = keys[i].u.wep.length;
731 if(key_length == 0)
732 key_length = WIFI_WEP128LEN;
733 unit->LEWordOut(unit->card, P2_REG_DATA1, key_length);
734 unit->WordsOut(unit->card, P2_REG_DATA1,
735 (UWORD *)keys[i].u.wep.key, (key_length + 1) / 2);
738 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE,
739 P2_REC_DEFLTCRYPTKEYS, base);
742 /* Set key management suite to PSK */
744 if(highest_enc > S2ENC_WEP)
746 value = (unit->firmware_type >= HERMES2_FIRMWARE) ? 4 : 2;
747 P2SetWord(unit, P2_REC_KEYMGMTSUITE, value, base);
750 else
752 /* Set authentication mode */
754 P2SetWord(unit, P2_REC_AUTHTYPE, unit->auth_types, base);
756 /* Set encryption flags */
758 if(highest_enc > S2ENC_NONE)
759 enc_flags = P2_REC_ENCRYPTIONF_ENABLE;
760 else
761 enc_flags = 0;
763 if(highest_enc > S2ENC_WEP
764 || highest_enc == S2ENC_WEP && (unit->flags & UNITF_HARDWEP) == 0)
765 enc_flags |= P2_REC_ENCRYPTIONF_HOSTDECRYPT
766 | P2_REC_ENCRYPTIONF_HOSTENCRYPT;
767 P2SetWord(unit, P2_REC_ENCRYPTION, enc_flags, base);
769 /* Set up firmware-based WEP encryption if appropriate */
771 if(highest_enc == S2ENC_WEP && (unit->flags & UNITF_HARDWEP) != 0)
773 P2SetWord(unit, P2_REC_TXCRYPTKEY, unit->tx_key_no, base);
775 keys = unit->keys;
776 for(i = 0; i < WIFI_KEYCOUNT; i++)
778 key_length = keys[i].u.wep.length;
779 if(key_length == 0)
780 key_length = keys[unit->tx_key_no].u.wep.length;
781 P2SetData(unit, P2_REC_CRYPTKEY0 + i, keys[i].u.wep.key,
782 key_length, base);
786 /* Set or clear WPA IE */
788 if(highest_enc > S2ENC_WEP)
789 size = unit->wpa_ie[1] + 2;
790 else
791 size = 0;
792 P2SetID(unit, P2_REC_WPAIE, unit->wpa_ie, size, base);
794 /* Let supplicant handle association and roaming */
796 P2SetWord(unit, P2_REC_ROAMINGMODE, 3, base);
799 /* Restart the transceiver if we're already online */
801 if((unit->flags & UNITF_ONLINE) != 0)
803 P2DoCmd(unit, P2_CMD_DISABLE, 0, base);
804 P2DoCmd(unit, P2_CMD_ENABLE, 0, base);
806 /* Attempt to join specified network */
808 if(unit->firmware_type == INTERSIL_FIRMWARE)
810 typedef union { UBYTE b[2]; UWORD w;} BW;
811 BW *p = (BW*)(unit->bssid + ETH_ADDRESSSIZE);
812 p->w = MakeLEWord(unit->channel);
813 P2SetData(unit, P2_REC_JOIN, unit->bssid, ETH_ADDRESSSIZE + 2,
814 base);
818 /* Return */
820 return;
825 /****i* prism2.device/GoOnline *********************************************
827 * NAME
828 * GoOnline -- Enable transmission/reception.
830 * SYNOPSIS
831 * GoOnline(unit)
833 * VOID GoOnline(struct DevUnit *);
835 ****************************************************************************
839 VOID GoOnline(struct DevUnit *unit, struct DevBase *base)
841 /* Enable interrupts */
843 unit->flags |= UNITF_ONLINE;
844 unit->LEWordOut(unit->card, P2_REG_INTMASK, INT_MASK);
846 /* Enable the transceiver */
848 P2DoCmd(unit, P2_CMD_ENABLE, 0, base);
850 /* Record start time and report Online event */
852 GetSysTime(&unit->stats.LastStart);
853 ReportEvents(unit, S2EVENT_ONLINE, base);
855 return;
860 /****i* prism2.device/GoOffline ********************************************
862 * NAME
863 * GoOffline -- Disable transmission/reception.
865 * SYNOPSIS
866 * GoOffline(unit)
868 * VOID GoOffline(struct DevUnit *);
870 * FUNCTION
872 * INPUTS
873 * unit
875 * RESULT
876 * None.
878 ****************************************************************************
882 VOID GoOffline(struct DevUnit *unit, struct DevBase *base)
884 unit->flags &= ~UNITF_ONLINE;
885 if((unit->flags & UNITF_HAVEADAPTER) != 0)
887 /* Stop interrupts */
889 unit->LEWordOut(unit->card, P2_REG_INTMASK, 0);
890 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
892 /* Update statistics */
894 UpdateStats(unit, base);
896 /* Stop transmission and reception */
898 P2DoCmd(unit, P2_CMD_DISABLE, 0, base);
901 /* Flush pending read and write requests */
903 FlushUnit(unit, WRITE_QUEUE, S2ERR_OUTOFSERVICE, base);
905 /* Report Offline event and return */
907 ReportEvents(unit, S2EVENT_OFFLINE, base);
908 return;
913 /****i* prism2.device/SetOptions *******************************************
915 * NAME
916 * SetOptions -- Set and use interface options.
918 * SYNOPSIS
919 * SetOptions(unit, tag_list)
921 * VOID SetOptions(struct DevUnit *, struct TagItem *);
923 ****************************************************************************
927 VOID SetOptions(struct DevUnit *unit, const struct TagItem *tag_list,
928 struct DevBase *base)
930 struct TagItem *tag_item, *tlist = (struct TagItem *)tag_list;
931 const TEXT *id;
932 UPINT length;
933 const UBYTE *ie;
935 while((tag_item = NextTagItem(&tlist)) != NULL)
937 switch(tag_item->ti_Tag)
939 case S2INFO_SSID:
940 id = (const TEXT *)tag_item->ti_Data;
941 length = StrLen(id);
942 CopyMem(id, unit->ssid, length);
943 unit->ssid_length = length;
944 break;
946 case S2INFO_BSSID:
947 CopyMem((APTR)tag_item->ti_Data, unit->bssid, ETH_ADDRESSSIZE);
948 break;
950 case S2INFO_DefaultKeyNo:
951 unit->tx_key_no = tag_item->ti_Data;
952 break;
954 case S2INFO_PortType:
955 unit->mode = tag_item->ti_Data;
956 break;
958 case S2INFO_Channel:
959 if(tag_item->ti_Data != 0) // ???
960 unit->channel = tag_item->ti_Data;
961 break;
963 case S2INFO_WPAInfo:
964 if(tag_item->ti_Data != (UPINT)NULL)
966 /* Hermes-II uses an "unusual" WPA IE in its association
967 request. So we use a matching IE everywhere else too */
969 if(unit->firmware_type >= HERMES2_FIRMWARE)
970 ie = h2_wpa_ie;
971 else
972 ie = (const UBYTE *)tag_item->ti_Data;
973 CopyMem(ie, unit->wpa_ie, ie[1] + 2);
975 else
977 unit->wpa_ie[0] = 0;
978 unit->wpa_ie[1] = 0;
980 break;
982 case S2INFO_AuthTypes:
983 unit->auth_types = tag_item->ti_Data;
984 break;
988 return;
993 /****i* prism2.device/SetKey ***********************************************
995 * NAME
996 * SetKey -- Set an encryption key.
998 * SYNOPSIS
999 * SetKey(unit, index, type, key, key_length,
1000 * rx_counter)
1002 * VOID SetKey(struct DevUnit *, ULONG, ULONG, UBYTE *, ULONG,
1003 * UBYTE *);
1005 ****************************************************************************
1009 VOID SetKey(struct DevUnit *unit, ULONG index, ULONG type, const UBYTE *key,
1010 ULONG key_length, const UBYTE *rx_counter, struct DevBase *base)
1012 struct KeyUnion *slot;
1013 const UBYTE tx_counter[8] = {0, 0, 0, 0, 0x10, 0, 0, 0};
1014 UWORD i;
1015 struct EClockVal eclock;
1017 Disable();
1018 slot = &unit->keys[index];
1019 switch(type)
1021 case S2ENC_WEP:
1022 CopyMem(key, slot->u.wep.key, key_length);
1023 slot->u.wep.length = key_length;
1025 if((unit->flags & UNITF_HARDWEP) == 0)
1027 /* Create a reasonably random IV */
1029 ReadEClock(&eclock);
1030 slot->u.wep.tx_iv = FastRand(eclock.ev_lo ^ eclock.ev_hi);
1033 break;
1035 case S2ENC_TKIP:
1036 CopyMem(key, slot->u.tkip.key, 16);
1037 CopyMem(key + 16, slot->u.tkip.tx_mic_key, MIC_SIZE);
1038 CopyMem(key + 24, slot->u.tkip.rx_mic_key, MIC_SIZE);
1039 slot->u.tkip.tx_iv_low = 0;
1040 slot->u.tkip.tx_iv_high = 0;
1041 slot->u.tkip.rx_iv_low = LEWord(*(UWORD *)rx_counter);
1042 slot->u.tkip.rx_iv_high = LELong(*(ULONG *)(rx_counter + 2));
1043 slot->u.tkip.tx_ttak_set = FALSE;
1044 slot->u.tkip.rx_ttak_set = FALSE;
1046 if((unit->flags & UNITF_HARDTKIP) != 0)
1048 /* For Hermes, load parameters for hardware encryption. The
1049 pairwise key is treated differently from group keys on
1050 Hermes-II, but not on Hermes-I */
1052 if(unit->firmware_type >= HERMES2_FIRMWARE && index == 0)
1054 P2Seek(unit, 1, P2_REC_ADDMAPPEDTKIPKEY, 0, base);
1055 unit->LEWordOut(unit->card, P2_REG_DATA1, 28);
1056 unit->LEWordOut(unit->card, P2_REG_DATA1,
1057 P2_REC_ADDMAPPEDTKIPKEY);
1058 unit->WordsOut(unit->card, P2_REG_DATA1,
1059 (UWORD *)unit->bssid, ETH_ADDRESSSIZE / 2);
1060 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)key,
1061 16 / 2);
1062 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)tx_counter,
1063 8 / 2);
1064 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)rx_counter,
1065 6 / 2);
1066 unit->LEWordOut(unit->card, P2_REG_DATA1, 0);
1067 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)key + 16,
1068 16 / 2);
1069 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE,
1070 P2_REC_ADDMAPPEDTKIPKEY, base);
1072 else
1074 P2Seek(unit, 1, P2_REC_ADDDEFAULTTKIPKEY, 0, base);
1075 unit->LEWordOut(unit->card, P2_REG_DATA1, 26);
1076 unit->LEWordOut(unit->card, P2_REG_DATA1,
1077 P2_REC_ADDDEFAULTTKIPKEY);
1078 if(index == unit->tx_key_no)
1079 index |= 0x8000;
1080 unit->LEWordOut(unit->card, P2_REG_DATA1, index);
1081 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)rx_counter,
1082 6 / 2);
1083 unit->LEWordOut(unit->card, P2_REG_DATA1, 0);
1084 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)key,
1085 32 / 2);
1086 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)tx_counter,
1087 8 / 2);
1088 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE,
1089 P2_REC_ADDDEFAULTTKIPKEY, base);
1092 else
1094 /* Convert key to native endianness */
1096 for(i = 0; i < 8; i++)
1097 slot->u.tkip.key[i] = LEWord(slot->u.tkip.key[i]);
1100 break;
1102 case S2ENC_CCMP:
1103 CopyMem(key, slot->u.ccmp.key, 16);
1104 slot->u.ccmp.tx_iv_low = 0;
1105 slot->u.ccmp.tx_iv_high = 0;
1106 slot->u.ccmp.rx_iv_low = LEWord(*(UWORD *)rx_counter);
1107 slot->u.ccmp.rx_iv_high = LELong(*(ULONG *)(rx_counter + 2));
1108 slot->u.ccmp.stream_set = FALSE;
1111 /* Clear TKIP key if necessary */
1113 if(slot->type == S2ENC_TKIP && type != S2ENC_TKIP)
1115 if(unit->firmware_type >= HERMES2_FIRMWARE && index == 0)
1116 P2SetData(unit, P2_REC_REMMAPPEDTKIPKEY, unit->bssid,
1117 ETH_ADDRESSSIZE, base);
1118 else if(unit->firmware_type >= LUCENT_FIRMWARE)
1119 P2SetWord(unit, P2_REC_REMDEFAULTTKIPKEY, index, base);
1122 /* Update type of key in selected slot */
1124 slot->type = type;
1125 Enable();
1127 return;
1132 /****i* prism2.device/AddMulticastRange ************************************
1134 * NAME
1135 * AddMulticastRange
1137 * SYNOPSIS
1138 * success = AddMulticastRange(unit, lower_bound, upper_bound)
1140 * BOOL AddMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1142 ****************************************************************************
1146 BOOL AddMulticastRange(struct DevUnit *unit, const UBYTE *lower_bound,
1147 const UBYTE *upper_bound, struct DevBase *base)
1149 struct AddressRange *range;
1150 ULONG lower_bound_left, upper_bound_left;
1151 UWORD lower_bound_right, upper_bound_right;
1153 lower_bound_left = BELong(*((ULONG *)lower_bound));
1154 lower_bound_right = BEWord(*((UWORD *)(lower_bound + 4)));
1155 upper_bound_left = BELong(*((ULONG *)upper_bound));
1156 upper_bound_right = BEWord(*((UWORD *)(upper_bound + 4)));
1158 range = FindMulticastRange(unit, lower_bound_left, lower_bound_right,
1159 upper_bound_left, upper_bound_right, base);
1161 if(range != NULL)
1162 range->add_count++;
1163 else
1165 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
1166 if(range != NULL)
1168 range->lower_bound_left = lower_bound_left;
1169 range->lower_bound_right = lower_bound_right;
1170 range->upper_bound_left = upper_bound_left;
1171 range->upper_bound_right = upper_bound_right;
1172 range->add_count = 1;
1174 Disable();
1175 AddTail((APTR)&unit->multicast_ranges, (APTR)range);
1176 unit->range_count++;
1177 SetMulticast(unit, base);
1178 Enable();
1182 return range != NULL;
1187 /****i* prism2.device/RemMulticastRange ************************************
1189 * NAME
1190 * RemMulticastRange
1192 * SYNOPSIS
1193 * found = RemMulticastRange(unit, lower_bound, upper_bound)
1195 * BOOL RemMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1197 ****************************************************************************
1201 BOOL RemMulticastRange(struct DevUnit *unit, const UBYTE *lower_bound,
1202 const UBYTE *upper_bound, struct DevBase *base)
1204 struct AddressRange *range;
1205 ULONG lower_bound_left, upper_bound_left;
1206 UWORD lower_bound_right, upper_bound_right;
1208 lower_bound_left = BELong(*((ULONG *)lower_bound));
1209 lower_bound_right = BEWord(*((UWORD *)(lower_bound + 4)));
1210 upper_bound_left = BELong(*((ULONG *)upper_bound));
1211 upper_bound_right = BEWord(*((UWORD *)(upper_bound + 4)));
1213 range = FindMulticastRange(unit, lower_bound_left, lower_bound_right,
1214 upper_bound_left, upper_bound_right, base);
1216 if(range != NULL)
1218 if(--range->add_count == 0)
1220 Disable();
1221 Remove((APTR)range);
1222 unit->range_count--;
1223 SetMulticast(unit, base);
1224 Enable();
1225 FreeMem(range, sizeof(struct AddressRange));
1229 return range != NULL;
1234 /****i* prism2.device/FindMulticastRange ***********************************
1236 * NAME
1237 * FindMulticastRange
1239 * SYNOPSIS
1240 * range = FindMulticastRange(unit, lower_bound_left,
1241 * lower_bound_right, upper_bound_left, upper_bound_right)
1243 * struct AddressRange *FindMulticastRange(struct DevUnit *, ULONG,
1244 * UWORD, ULONG, UWORD);
1246 ****************************************************************************
1250 static struct AddressRange *FindMulticastRange(struct DevUnit *unit,
1251 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left,
1252 UWORD upper_bound_right, struct DevBase *base)
1254 struct AddressRange *range, *tail;
1255 BOOL found = FALSE;
1257 range = (APTR)unit->multicast_ranges.mlh_Head;
1258 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
1260 while(range != tail && !found)
1262 if(lower_bound_left == range->lower_bound_left &&
1263 lower_bound_right == range->lower_bound_right &&
1264 upper_bound_left == range->upper_bound_left &&
1265 upper_bound_right == range->upper_bound_right)
1266 found = TRUE;
1267 else
1268 range = (APTR)range->node.mln_Succ;
1271 if(!found)
1272 range = NULL;
1274 return range;
1279 /****i* prism2.device/SetMulticast *****************************************
1281 * NAME
1282 * SetMulticast
1284 * SYNOPSIS
1285 * SetMulticast(unit)
1287 * VOID SetMulticast(struct DevUnit *);
1289 ****************************************************************************
1293 static VOID SetMulticast(struct DevUnit *unit, struct DevBase *base)
1295 ULONG address_left;
1296 UWORD address_right, i = 0;
1297 struct AddressRange *range, *tail;
1298 BOOL range_ended;
1300 /* Fill in multicast list */
1302 P2Seek(unit, 1, P2_REC_MCASTLIST, 4, base);
1304 range = (APTR)unit->multicast_ranges.mlh_Head;
1305 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
1307 while(range != tail && i < P2_MAXMCASTENTRIES)
1309 address_left = range->lower_bound_left;
1310 address_right = range->lower_bound_right;
1311 range_ended = FALSE;
1313 while(!range_ended && i++ < P2_MAXMCASTENTRIES)
1315 unit->BEWordOut(unit->card, P2_REG_DATA1,
1316 (UWORD)(address_left >> 16));
1317 unit->BEWordOut(unit->card, P2_REG_DATA1, (UWORD)address_left);
1318 unit->BEWordOut(unit->card, P2_REG_DATA1, (UWORD)address_right);
1320 if(address_left == range->upper_bound_left &&
1321 address_right == range->upper_bound_right)
1322 range_ended = TRUE;
1323 if(++address_right == 0)
1324 address_left++;
1327 if(range_ended)
1328 range = (APTR)range->node.mln_Succ;
1331 /* Turn promiscuous mode on or off depending on the previous state and
1332 whether we've overflowed the multicast list */
1334 if((unit->flags & UNITF_PROM) == 0)
1336 if(range != tail)
1338 if((unit->flags & UNITF_ALLMCAST) == 0)
1340 P2SetWord(unit, P2_REC_PROMISC, TRUE, base);
1341 unit->flags |= UNITF_ALLMCAST;
1344 else
1346 if((unit->flags & UNITF_ALLMCAST) != 0)
1348 P2SetWord(unit, P2_REC_PROMISC, FALSE, base);
1349 unit->flags &= ~UNITF_ALLMCAST;
1352 /* Only commit multicast list if promiscuity is off */
1354 P2Seek(unit, 1, P2_REC_MCASTLIST, 0, base);
1355 unit->LEWordOut(unit->card, P2_REG_DATA1,
1356 1 + ETH_ADDRESSSIZE / 2 * i);
1357 unit->LEWordOut(unit->card, P2_REG_DATA1, P2_REC_MCASTLIST);
1358 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, P2_REC_MCASTLIST,
1359 base);
1363 return;
1368 /****i* prism2.device/FindTypeStats ****************************************
1370 * NAME
1371 * FindTypeStats
1373 * SYNOPSIS
1374 * stats = FindTypeStats(unit, list,
1375 * packet_type)
1377 * struct TypeStats *FindTypeStats(struct DevUnit *, struct MinList *,
1378 * ULONG);
1380 ****************************************************************************
1384 struct TypeStats *FindTypeStats(struct DevUnit *unit, struct MinList *list,
1385 ULONG packet_type, struct DevBase *base)
1387 struct TypeStats *stats, *tail;
1388 BOOL found = FALSE;
1390 stats = (APTR)list->mlh_Head;
1391 tail = (APTR)&list->mlh_Tail;
1393 while(stats != tail && !found)
1395 if(stats->packet_type == packet_type)
1396 found = TRUE;
1397 else
1398 stats = (APTR)stats->node.mln_Succ;
1401 if(!found)
1402 stats = NULL;
1404 return stats;
1409 /****i* prism2.device/FlushUnit ********************************************
1411 * NAME
1412 * FlushUnit
1414 * SYNOPSIS
1415 * FlushUnit(unit, last_queue, error)
1417 * VOID FlushUnit(struct DevUnit *, UBYTE, BYTE);
1419 ****************************************************************************
1423 VOID FlushUnit(struct DevUnit *unit, UBYTE last_queue, BYTE error,
1424 struct DevBase *base)
1426 struct IORequest *request;
1427 UBYTE i;
1428 struct Opener *opener, *tail;
1430 /* Abort queued requests */
1432 for(i = 0; i <= last_queue; i++)
1434 while((request = (APTR)GetMsg(unit->request_ports[i])) != NULL)
1436 request->io_Error = error;
1437 ReplyMsg((APTR)request);
1441 #if 1
1442 opener = (APTR)unit->openers.mlh_Head;
1443 tail = (APTR)&unit->openers.mlh_Tail;
1445 /* Flush every opener's read queue */
1447 while(opener != tail)
1449 while((request = (APTR)GetMsg(&opener->read_port)) != NULL)
1451 request->io_Error = error;
1452 ReplyMsg((APTR)request);
1454 opener = (APTR)opener->node.mln_Succ;
1457 #else
1458 opener = request->ios2_BufferManagement;
1459 while((request = (APTR)GetMsg(&opener->read_port)) != NULL)
1461 request->io_Error = error;
1462 ReplyMsg((APTR)request);
1464 #endif
1466 /* Return */
1468 return;
1473 /****i* prism2.device/StatusInt ********************************************
1475 * NAME
1476 * StatusInt
1478 * SYNOPSIS
1479 * finished = StatusInt(unit)
1481 * BOOL StatusInt(struct DevUnit *);
1483 * FUNCTION
1485 * INPUTS
1486 * unit
1488 * RESULT
1489 * finished
1491 ****************************************************************************
1493 * int_code is really in A5, but GCC 2.95.3 doesn't seem able to handle that.
1494 * Since we don't use this parameter, we can lie.
1498 BOOL StatusInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
1500 struct DevBase *base;
1501 UWORD events, int_mask;
1503 base = unit->device;
1504 events = unit->LEWordIn(unit->card, P2_REG_EVENTS);
1506 /* Turning off ints acknowledges the request? */
1508 int_mask = unit->LEWordIn(unit->card, P2_REG_INTMASK);
1509 unit->LEWordOut(unit->card, P2_REG_INTMASK, 0);
1511 /* Handle events */
1513 if((events & P2_EVENTF_INFO) != 0)
1515 int_mask &= ~P2_EVENTF_INFO;
1516 Cause(&unit->info_int);
1518 if((events & P2_EVENTF_RX) != 0)
1520 int_mask &= ~P2_EVENTF_RX;
1521 Cause(&unit->rx_int);
1523 if((events & P2_EVENTF_ALLOCMEM) != 0)
1525 unit->tx_frame_id = unit->LEWordIn(unit->card, P2_REG_ALLOCFID);
1526 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_ALLOCMEM);
1527 Cause(&unit->tx_int);
1529 if((events & P2_EVENTF_TXFAIL) != 0)
1531 ReportEvents(unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX,
1532 base);
1533 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_TXFAIL);
1536 #ifdef __MORPHOS__
1537 int_mask = INT_MASK;
1538 #endif
1539 unit->LEWordOut(unit->card, P2_REG_INTMASK, int_mask);
1541 return FALSE;
1546 /****i* prism2.device/RXInt ************************************************
1548 * NAME
1549 * RXInt -- Soft interrupt for packet reception.
1551 * SYNOPSIS
1552 * RXInt(unit)
1554 * VOID RXInt(struct DevUnit *);
1556 * FUNCTION
1558 * INPUTS
1559 * unit - A unit of this device.
1561 * RESULT
1562 * None.
1564 ****************************************************************************
1568 static VOID RXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
1570 UWORD frame_status, frame_id, ieee_length, frame_control, frame_type,
1571 frame_subtype, encryption, key_no, buffer_no, old_length;
1572 struct DevBase *base;
1573 BOOL is_good;
1574 LONG frag_no;
1575 UBYTE *buffer, *p, *frame, *data;
1577 base = unit->device;
1579 while((unit->LEWordIn(unit->card, P2_REG_EVENTS) & P2_EVENTF_RX) != 0)
1581 is_good = TRUE;
1582 frame_id = unit->LEWordIn(unit->card, P2_REG_RXFID);
1583 P2Seek(unit, 1, frame_id, P2_FRM_STATUS, base);
1584 frame_status = unit->LEWordIn(unit->card, P2_REG_DATA1);
1586 if((frame_status & (P2_FRM_STATUSF_BADCRYPT | P2_FRM_STATUSF_BADCRC))
1587 == 0)
1589 /* Read frame descriptor from card */
1591 P2Seek(unit, 1, frame_id, 0, base);
1592 unit->WordsIn(unit->card, P2_REG_DATA1,
1593 (UWORD *)unit->rx_descriptor,
1594 (unit->ethernet_offset + ETH_HEADERSIZE) / 2);
1595 frame = unit->rx_descriptor + unit->ethernet_offset;
1596 ieee_length = BEWord(*(UWORD *)(frame + ETH_PACKET_IEEELEN));
1597 data = frame + ETH_PACKET_DATA;
1598 unit->WordsIn(unit->card, P2_REG_DATA1, (UWORD *)data,
1599 (ieee_length + MIC_SIZE + 1) / 2);
1600 frame_control =
1601 LEWord(*(UWORD *)(unit->rx_descriptor + P2_FRM_HEADER));
1603 /* Get buffer to store fragment in */
1605 frag_no = LEWord(*(UWORD *)(unit->rx_descriptor + P2_FRM_HEADER
1606 + WIFI_FRM_SEQCONTROL));
1607 buffer = GetRXBuffer(unit, frame + ETH_PACKET_SOURCE, frag_no,
1608 &buffer_no, base);
1610 /* Get location to put new data */
1612 if(buffer != NULL)
1614 if((frag_no & 0xf ) > 0)
1615 old_length = BEWord(*(UWORD *)(buffer + ETH_PACKET_IEEELEN));
1616 else
1618 /* Copy header to new frame */
1620 CopyMem(frame, buffer, ETH_HEADERSIZE);
1621 old_length = 0;
1623 p = buffer + ETH_HEADERSIZE + old_length;
1625 /* Get encryption type and key index */
1627 if((frame_control & WIFI_FRM_CONTROLF_WEP) != 0)
1629 key_no = data[3] >> 6 & 0x3;
1630 encryption = unit->keys[key_no].type;
1632 else
1633 encryption = S2ENC_NONE;
1635 /* Append fragment to frame, decrypting/checking fragment if
1636 necessary */
1638 is_good = unit->fragment_decrypt_functions[encryption](unit,
1639 unit->rx_descriptor + P2_FRM_HEADER, data, &ieee_length, p,
1640 base);
1642 /* Update length in frame being built with current fragment, or
1643 increment bad frame counter if fragment is bad */
1645 if(is_good)
1647 ieee_length += old_length;
1648 *(UWORD *)(buffer + ETH_PACKET_IEEELEN) =
1649 MakeBEWord(ieee_length);
1651 else
1652 unit->stats.BadData++;
1654 /* If all fragments have arrived, process the complete frame */
1656 if((frame_control & WIFI_FRM_CONTROLF_MOREFRAGS) == 0)
1658 if(is_good)
1660 /* Decrypt complete frame if necessary */
1662 data = buffer + ETH_HEADERSIZE;
1663 if(encryption == S2ENC_TKIP)
1665 /* Hermes cards don't include MIC in frame length, so
1666 we need to grab the MIC from the original RX
1667 descriptor here */
1669 if(unit->firmware_type >= LUCENT_FIRMWARE)
1671 CopyMem(frame + ETH_PACKET_DATA + ieee_length,
1672 data + ieee_length, MIC_SIZE);
1673 ieee_length += MIC_SIZE;
1676 /* Check Michael MIC */
1678 #ifndef __mc68000
1679 is_good = TKIPDecryptFrame(unit, buffer, data,
1680 ieee_length, data, key_no, base);
1681 #endif
1682 ieee_length -= MIC_SIZE;
1683 *(UWORD *)(buffer + ETH_PACKET_IEEELEN) =
1684 MakeBEWord(ieee_length);
1685 if(!is_good)
1686 unit->stats.BadData++;
1690 if(is_good)
1692 /* Get frame's 802.11 type and subtype */
1694 frame_type = (frame_control & WIFI_FRM_CONTROLF_TYPE)
1695 >> WIFI_FRM_CONTROLB_TYPE;
1696 frame_subtype =
1697 (frame_control & WIFI_FRM_CONTROLF_SUBTYPE)
1698 >> WIFI_FRM_CONTROLB_SUBTYPE;
1700 /* If it's a management frame, process it internally;
1701 otherwise distribute it to clients after filtering */
1703 if(frame_type == WIFI_FRMTYPE_MGMT)
1705 if(frame_subtype == 0x5)
1707 CopyMem(unit->rx_descriptor + P2_FRM_HEADER
1708 + WIFI_FRM_ADDRESS3, buffer + ETH_PACKET_SOURCE,
1709 ETH_ADDRESSSIZE);
1710 SaveBeacon(unit, buffer, base);
1713 else if(AddressFilter(unit, buffer + ETH_PACKET_DEST,
1714 base))
1716 unit->stats.PacketsReceived++;
1717 DistributeRXPacket(unit, buffer, base);
1722 /* Mark fragment buffer as unused for next time */
1724 unit->rx_fragment_nos[buffer_no] = -1;
1726 else
1727 ReportEvents(unit, S2EVENT_ERROR | S2EVENT_RX, base);
1729 else
1731 is_good = FALSE;
1734 if(!is_good)
1736 ReportEvents(unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX,
1737 base);
1740 /* Discard packet */
1742 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_RX);
1745 /* Re-enable RX interrupts */
1747 Disable();
1748 unit->LEWordOut(unit->card, P2_REG_INTMASK,
1749 unit->LEWordIn(unit->card, P2_REG_INTMASK) | P2_EVENTF_RX);
1750 Enable();
1752 return;
1757 /****i* prism2.device/GetRXBuffer ******************************************
1759 * NAME
1760 * GetRXBuffer -- Find an appropriate RX buffer to use.
1762 * SYNOPSIS
1763 * buffer = GetRXBuffer(unit, address, frag_no)
1765 * UBYTE *GetRXBuffer(struct DevUnit *, UBYTE *, UWORD);
1767 ****************************************************************************
1771 static UBYTE *GetRXBuffer(struct DevUnit *unit, const UBYTE *address,
1772 UWORD frag_no, UWORD *buffer_no, struct DevBase *base)
1774 UWORD i;
1775 UBYTE *buffer;
1776 LONG n;
1777 BOOL found;
1779 buffer = unit->rx_buffers;
1780 for(i = 0, found = FALSE; i < RX_BUFFER_COUNT * 2 && !found; i++)
1782 /* Throw away old buffer contents if we didn't find a free slot the
1783 first time around */
1785 if(i >= RX_BUFFER_COUNT)
1786 unit->rx_fragment_nos[i % RX_BUFFER_COUNT] = -1;
1788 /* For a frame's first fragment, find an empty slot; for subsequent
1789 fragments, find a slot with matching source address */
1791 n = unit->rx_fragment_nos[i % RX_BUFFER_COUNT];
1792 if(n == -1 && (frag_no & 0xf) == 0
1793 || *((ULONG *)(buffer + ETH_PACKET_SOURCE))
1794 == *((ULONG *)(address))
1795 && *((UWORD *)(buffer + ETH_PACKET_SOURCE + 4))
1796 == *((UWORD *)(address + 4)))
1798 found = TRUE;
1799 if(n == -1)
1800 unit->rx_fragment_nos[i % RX_BUFFER_COUNT] = frag_no;
1801 *buffer_no = i;
1803 else
1804 buffer += FRAME_BUFFER_SIZE;
1807 if(!found)
1808 buffer = NULL;
1810 return buffer;
1815 /****i* prism2.device/DistributeRXPacket ***********************************
1817 * NAME
1818 * DistributeRXPacket -- Send a packet to all appropriate destinations.
1820 * SYNOPSIS
1821 * DistributeRXPacket(unit, frame)
1823 * VOID DistributeRXPacket(struct DevUnit *, UBYTE *);
1825 ****************************************************************************
1829 static VOID DistributeRXPacket(struct DevUnit *unit, UBYTE *frame,
1830 struct DevBase *base)
1832 UWORD packet_size, ieee_length;
1833 BOOL is_orphan = TRUE, accepted, is_snap = FALSE;
1834 ULONG packet_type;
1835 UBYTE *buffer;
1836 const UBYTE *template = snap_template;
1837 struct IOSana2Req *request, *request_tail;
1838 struct Opener *opener, *opener_tail;
1839 struct TypeStats *tracker;
1841 ieee_length = BEWord(*(UWORD *)(frame + ETH_PACKET_IEEELEN));
1842 packet_size = ETH_HEADERSIZE + ieee_length;
1843 if(ieee_length >= SNAP_HEADERSIZE)
1844 is_snap = *(const ULONG *)(frame + ETH_PACKET_DATA)
1845 == *(const ULONG *)template;
1847 /* De-encapsulate SNAP packets and get packet type */
1849 if(is_snap)
1851 buffer = unit->rx_buffer;
1852 packet_size -= SNAP_HEADERSIZE;
1853 CopyMem(frame, buffer, ETH_PACKET_TYPE);
1854 CopyMem(frame + ETH_HEADERSIZE + SNAP_FRM_TYPE,
1855 buffer + ETH_PACKET_TYPE, packet_size - ETH_PACKET_TYPE);
1857 else
1858 buffer = frame;
1860 packet_type = BEWord(*((UWORD *)(buffer + ETH_PACKET_TYPE)));
1862 if(packet_size <= ETH_MAXPACKETSIZE)
1864 /* Offer packet to every opener */
1866 opener = (APTR)unit->openers.mlh_Head;
1867 opener_tail = (APTR)&unit->openers.mlh_Tail;
1869 while(opener != opener_tail)
1871 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
1872 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
1873 accepted = FALSE;
1875 /* Offer packet to each request until it's accepted */
1877 while(request != request_tail && !accepted)
1879 if(request->ios2_PacketType == packet_type)
1881 CopyPacket(unit, request, packet_size, packet_type,
1882 buffer, base);
1883 accepted = TRUE;
1885 request =
1886 (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
1889 if(accepted)
1890 is_orphan = FALSE;
1891 opener = (APTR)opener->node.mln_Succ;
1894 /* If packet was unwanted, give it to S2_READORPHAN request */
1896 if(is_orphan)
1898 unit->stats.UnknownTypesReceived++;
1899 if(!IsMsgPortEmpty(unit->request_ports[ADOPT_QUEUE]))
1901 CopyPacket(unit,
1902 (APTR)unit->request_ports[ADOPT_QUEUE]->
1903 mp_MsgList.lh_Head, packet_size, packet_type, buffer,
1904 base);
1908 /* Update remaining statistics */
1910 if(packet_type <= ETH_MTU)
1911 packet_type = ETH_MTU;
1912 tracker =
1913 FindTypeStats(unit, &unit->type_trackers, packet_type, base);
1914 if(tracker != NULL)
1916 tracker->stats.PacketsReceived++;
1917 tracker->stats.BytesReceived += packet_size;
1920 else
1921 unit->stats.BadData++;
1923 return;
1928 /****i* prism2.device/CopyPacket *******************************************
1930 * NAME
1931 * CopyPacket -- Copy packet to client's buffer.
1933 * SYNOPSIS
1934 * CopyPacket(unit, request, packet_size, packet_type,
1935 * buffer)
1937 * VOID CopyPacket(struct DevUnit *, struct IOSana2Req *, UWORD, UWORD,
1938 * UBYTE *);
1940 ****************************************************************************
1944 static VOID CopyPacket(struct DevUnit *unit, struct IOSana2Req *request,
1945 UWORD packet_size, UWORD packet_type, UBYTE *buffer,
1946 struct DevBase *base)
1948 struct Opener *opener;
1949 BOOL filtered = FALSE;
1951 /* Set multicast and broadcast flags */
1953 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
1954 if((*((ULONG *)(buffer + ETH_PACKET_DEST)) == 0xffffffff) &&
1955 (*((UWORD *)(buffer + ETH_PACKET_DEST + 4)) == 0xffff))
1956 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
1957 else if((buffer[ETH_PACKET_DEST] & 0x1) != 0)
1958 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
1960 /* Set source and destination addresses and packet type */
1962 CopyMem(buffer + ETH_PACKET_SOURCE, request->ios2_SrcAddr,
1963 ETH_ADDRESSSIZE);
1964 CopyMem(buffer + ETH_PACKET_DEST, request->ios2_DstAddr,
1965 ETH_ADDRESSSIZE);
1966 request->ios2_PacketType = packet_type;
1968 /* Adjust for cooked packet request */
1970 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
1972 packet_size -= ETH_PACKET_DATA;
1973 buffer += ETH_PACKET_DATA;
1975 #ifdef USE_HACKS
1976 else
1977 packet_size += 4; /* Needed for Shapeshifter & Fusion */
1978 #endif
1979 request->ios2_DataLength = packet_size;
1981 /* Filter packet */
1983 opener = request->ios2_BufferManagement;
1984 if(request->ios2_Req.io_Command == CMD_READ &&
1985 opener->filter_hook != NULL)
1986 if(!CallHookPkt(opener->filter_hook, request, buffer))
1987 filtered = TRUE;
1989 if(!filtered)
1991 /* Copy packet into opener's buffer and reply packet */
1993 if(!opener->rx_function(request->ios2_Data, buffer, packet_size))
1995 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
1996 request->ios2_WireError = S2WERR_BUFF_ERROR;
1997 ReportEvents(unit,
1998 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX,
1999 base);
2001 Remove((APTR)request);
2002 ReplyMsg((APTR)request);
2005 return;
2010 /****i* prism2.device/AddressFilter ****************************************
2012 * NAME
2013 * AddressFilter -- Determine if an RX packet should be accepted.
2015 * SYNOPSIS
2016 * accept = AddressFilter(unit, address)
2018 * BOOL AddressFilter(struct DevUnit *, UBYTE *);
2020 ****************************************************************************
2024 static BOOL AddressFilter(struct DevUnit *unit, UBYTE *address,
2025 struct DevBase *base)
2027 struct AddressRange *range, *tail;
2028 BOOL accept = TRUE;
2029 ULONG address_left;
2030 UWORD address_right;
2032 /* Check whether address is unicast/broadcast or multicast */
2034 address_left = BELong(*((ULONG *)address));
2035 address_right = BEWord(*((UWORD *)(address + 4)));
2037 if(((address_left & 0x01000000) != 0) &&
2038 !((address_left == 0xffffffff) && (address_right == 0xffff)))
2040 /* Check if this multicast address is wanted */
2042 range = (APTR)unit->multicast_ranges.mlh_Head;
2043 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
2044 accept = FALSE;
2046 while((range != tail) && !accept)
2048 if((address_left > range->lower_bound_left ||
2049 address_left == range->lower_bound_left &&
2050 address_right >= range->lower_bound_right) &&
2051 (address_left < range->upper_bound_left ||
2052 address_left == range->upper_bound_left &&
2053 address_right <= range->upper_bound_right))
2054 accept = TRUE;
2055 range = (APTR)range->node.mln_Succ;
2058 if(!accept)
2059 unit->special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
2062 return accept;
2067 /****i* prism2.device/SaveBeacon *******************************************
2069 * NAME
2070 * SaveBeacon -- Save beacon frame for later examination.
2072 * SYNOPSIS
2073 * SaveBeacon(unit, frame)
2075 * VOID SaveBeacon(struct DevUnit *, UBYTE *);
2077 ****************************************************************************
2081 static VOID SaveBeacon(struct DevUnit *unit, const UBYTE *frame,
2082 struct DevBase *base)
2084 UWORD size;
2086 /* Store frame for later matching with scan results */
2088 size = ETH_HEADERSIZE + BEWord(*(UWORD *)(frame + ETH_PACKET_IEEELEN));
2089 if(unit->next_beacon + size < unit->beacons + BEACON_BUFFER_SIZE)
2091 CopyMem(frame, unit->next_beacon, size);
2092 unit->beacon_count++;
2093 unit->next_beacon += size + sizeof(ULONG) & ~3;
2096 return;
2101 /****i* prism2.device/TXInt ************************************************
2103 * NAME
2104 * TXInt -- Soft interrupt for packet transmission.
2106 * SYNOPSIS
2107 * TXInt(unit)
2109 * VOID TXInt(struct DevUnit *);
2111 * FUNCTION
2113 * INPUTS
2114 * unit - A unit of this device.
2116 * RESULT
2117 * None.
2119 ****************************************************************************
2123 static VOID TXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
2125 UWORD i, packet_size, send_size, packet_type, data_size, body_size = 0,
2126 frame_id, encryption, control_value, subtype;
2127 UBYTE *buffer, *desc = unit->tx_descriptor, *plaintext, *ciphertext,
2128 *header, mic_header[ETH_ADDRESSSIZE * 2], *q;
2129 const UBYTE *p, *dest, *source;
2130 struct DevBase *base;
2131 struct IOSana2Req *request;
2132 BOOL is_ieee;
2133 struct Opener *opener;
2134 ULONG wire_error;
2135 UBYTE *(*dma_tx_function)(REG(a0, APTR));
2136 BYTE error = 0;
2137 struct MsgPort *port;
2138 struct TypeStats *tracker;
2140 base = unit->device;
2141 port = unit->request_ports[WRITE_QUEUE];
2143 if(unit->tx_frame_id != 0 && !IsMsgPortEmpty(port))
2145 /* Get next request and full packet size */
2147 request = (APTR)port->mp_MsgList.lh_Head;
2148 packet_size = request->ios2_DataLength;
2149 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
2150 packet_size += ETH_PACKET_DATA;
2152 /* Determine encryption type and frame subtype */
2154 if(packet_size > ETH_HEADERSIZE)
2156 encryption = unit->keys[unit->tx_key_no].type;
2157 subtype = 0;
2159 else
2161 encryption = S2ENC_NONE;
2162 subtype = 4;
2165 /* Get packet data */
2167 opener = request->ios2_BufferManagement;
2168 dma_tx_function = opener->dma_tx_function;
2169 if(dma_tx_function != NULL)
2170 buffer = dma_tx_function(request->ios2_Data);
2171 else
2172 buffer = NULL;
2174 if(buffer == NULL)
2176 buffer = unit->tx_buffer;
2177 if(!opener->tx_function(buffer, request->ios2_Data,
2178 request->ios2_DataLength))
2180 error = S2ERR_NO_RESOURCES;
2181 wire_error = S2WERR_BUFF_ERROR;
2182 ReportEvents(unit,
2183 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_TX,
2184 base);
2188 if(error == 0)
2190 /* Get packet type and/or length */
2192 data_size = request->ios2_DataLength;
2193 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) != 0)
2195 data_size -= ETH_PACKET_DATA;
2196 packet_type = BEWord(*(UWORD *)(buffer + ETH_PACKET_TYPE));
2198 else
2199 packet_type = request->ios2_PacketType;
2200 is_ieee = packet_type <= ETH_MTU;
2202 /* Get source and destination addresses */
2204 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) != 0)
2206 dest = buffer;
2207 source = buffer + ETH_ADDRESSSIZE;
2208 buffer += ETH_ADDRESSSIZE * 2 + 2;
2210 else
2212 dest = request->ios2_DstAddr;
2213 source = unit->address;
2216 /* Clear frame descriptor as far as start of 802.11 header */
2218 q = desc;
2219 for(i = 0; i < P2_FRM_HEADER; i++)
2220 *q++ = 0;
2221 header = q;
2223 /* Set TX control field */
2225 control_value = P2_FRM_TXCONTROLF_NATIVE;
2226 if(encryption == S2ENC_TKIP && (unit->flags & UNITF_HARDTKIP) != 0)
2227 control_value |= unit->tx_key_no << P2_FRM_TXCONTROLB_MICKEYID
2228 | P2_FRM_TXCONTROLF_MIC;
2229 else if(encryption == S2ENC_NONE
2230 && unit->firmware_type < LUCENT_FIRMWARE)
2231 control_value |= P2_FRM_TXCONTROLF_NOENC;
2233 *(UWORD *)(desc + unit->txcontrol_offset) =
2234 MakeLEWord(control_value);
2236 /* Write 802.11 header */
2238 *(UWORD *)q = MakeLEWord(
2239 (encryption == S2ENC_NONE ? 0 : WIFI_FRM_CONTROLF_WEP)
2240 | (unit->mode == S2PORT_ADHOC ? 0 : WIFI_FRM_CONTROLF_TODS)
2241 | subtype << WIFI_FRM_CONTROLB_SUBTYPE
2242 | WIFI_FRMTYPE_DATA << WIFI_FRM_CONTROLB_TYPE);
2243 q += 2;
2245 *(UWORD *)q = 0;
2246 q += 2;
2248 if(unit->mode == S2PORT_ADHOC)
2249 p = dest;
2250 else
2251 p = unit->bssid;
2252 for(i = 0; i < ETH_ADDRESSSIZE; i++)
2253 *q++ = *p++;
2255 for(i = 0, p = source; i < ETH_ADDRESSSIZE; i++)
2256 *q++ = *p++;
2258 if(unit->mode == S2PORT_ADHOC)
2259 p = unit->bssid;
2260 else
2261 p = dest;
2262 for(i = 0; i < ETH_ADDRESSSIZE; i++)
2263 *q++ = *p++;
2264 *(UWORD *)q = 0;
2266 /* Clear 802.3 header */
2268 q = desc + unit->ethernet_offset;
2269 for(i = 0; i < ETH_HEADERSIZE; i++)
2270 *q++ = 0;
2272 /* Leave room for encryption overhead */
2274 q = desc + unit->data_offset;
2275 ciphertext = q;
2276 q += unit->iv_sizes[encryption];
2277 plaintext = q;
2279 /* Write SNAP header */
2281 if(!is_ieee)
2283 for(i = 0, p = snap_template; i < SNAP_FRM_TYPE; i++)
2284 *q++ = *p++;
2285 *(UWORD *)q = MakeBEWord(packet_type);
2286 q += 2;
2287 body_size += SNAP_HEADERSIZE;
2290 /* Copy data into frame */
2292 CopyMem(buffer, q, data_size);
2293 body_size += data_size;
2295 /* Append MIC to frame for TKIP */
2297 if(encryption == S2ENC_TKIP)
2299 q = mic_header;
2300 for(i = 0, p = dest; i < ETH_ADDRESSSIZE; i++)
2301 *q++ = *p++;
2302 for(i = 0, p = source; i < ETH_ADDRESSSIZE; i++)
2303 *q++ = *p++;
2304 TKIPEncryptFrame(unit, mic_header, plaintext, body_size,
2305 plaintext, base);
2306 body_size += MIC_SIZE;
2309 /* Encrypt fragment if applicable */
2311 unit->fragment_encrypt_functions[encryption](unit, header,
2312 plaintext, &body_size, ciphertext, base);
2314 /* Calculate total length of data to send to adapter */
2316 send_size = unit->data_offset + body_size;
2318 /* Fill in length field, adjusting for Hermes peculiarities */
2320 if(unit->firmware_type >= LUCENT_FIRMWARE
2321 && encryption == S2ENC_TKIP)
2322 body_size -= MIC_SIZE;
2324 if(unit->firmware_type == LUCENT_FIRMWARE
2325 && (unit->flags & UNITF_HARDTKIP) != 0)
2326 *(UWORD *)(desc + unit->ethernet_offset + ETH_PACKET_IEEELEN) =
2327 MakeBEWord(body_size);
2328 else
2329 *(UWORD *)(desc + unit->datalen_offset) = MakeLEWord(body_size);
2331 /* Write packet to adapter and send */
2333 frame_id = unit->tx_frame_id;
2334 P2Seek(unit, 0, frame_id, 0, base);
2335 unit->WordsOut(unit->card, P2_REG_DATA0, (UWORD *)desc,
2336 (send_size + 1) / 2);
2337 unit->tx_frame_id = 0;
2338 P2DoCmd(unit, P2_CMD_TX | P2_CMDF_RECLAIM, frame_id, base);
2341 /* Reply request */
2343 request->ios2_Req.io_Error = error;
2344 request->ios2_WireError = wire_error;
2345 Remove((APTR)request);
2346 ReplyMsg((APTR)request);
2348 /* Update statistics */
2350 if(error == 0)
2352 unit->stats.PacketsSent++;
2354 tracker = FindTypeStats(unit, &unit->type_trackers,
2355 request->ios2_PacketType, base);
2356 if(tracker != NULL)
2358 tracker->stats.PacketsSent++;
2359 tracker->stats.BytesSent += packet_size;
2364 /* Don't try to keep sending packets if there's no space left */
2366 if(unit->tx_frame_id != 0)
2367 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
2368 else
2369 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
2371 return;
2376 /****i* prism2.device/UpdateStats ******************************************
2378 * NAME
2379 * UpdateStats
2381 * SYNOPSIS
2382 * UpdateStats(unit)
2384 * VOID UpdateStats(struct DevUnit *);
2386 * FUNCTION
2388 * INPUTS
2389 * unit - A unit of this device.
2391 * RESULT
2392 * None.
2394 ****************************************************************************
2398 VOID UpdateStats(struct DevUnit *unit, struct DevBase *base)
2400 /* Ask for and wait for stats */
2402 if((unit->flags & UNITF_ONLINE) != 0)
2404 Disable();
2405 unit->LEWordOut(unit->card, P2_REG_INTMASK,
2406 unit->LEWordIn(unit->card, P2_REG_INTMASK) & ~P2_EVENTF_INFO);
2407 Enable();
2408 P2DoCmd(unit, P2_CMD_INQUIRE, P2_INFO_COUNTERS, base);
2409 while((unit->LEWordIn(unit->card, P2_REG_EVENTS) & P2_EVENTF_INFO)
2410 == 0);
2411 Cause(&unit->info_int);
2414 return;
2419 /****i* prism2.device/InfoInt **********************************************
2421 * NAME
2422 * InfoInt
2424 * SYNOPSIS
2425 * InfoInt(unit)
2427 * VOID InfoInt(struct DevUnit *);
2429 * FUNCTION
2431 * INPUTS
2432 * unit - A unit of this device.
2434 * RESULT
2435 * None.
2437 * NOTES
2438 * The only reason this is a (soft) interrupt is so that it won't
2439 * interfere with RXInt() by interrupting it. This would be dangerous
2440 * because they use the same data channel.
2442 ****************************************************************************
2446 static VOID InfoInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
2448 struct DevBase *base;
2449 UWORD id, length, rec_length, status, ies_length, data_length,
2450 ssid_length, *ap_rec;
2451 UBYTE *ie, *ssid, *descriptor, *frame, *data, *bssid = unit->bssid;
2452 BOOL associated;
2454 base = unit->device;
2455 id = unit->LEWordIn(unit->card, P2_REG_INFOFID);
2457 P2Seek(unit, 1, id, 0, base);
2458 length = (unit->LEWordIn(unit->card, P2_REG_DATA1) + 1) * 2;
2460 switch(unit->LEWordIn(unit->card, P2_REG_DATA1))
2462 case P2_INFO_COUNTERS:
2464 /* Read useful stats and skip others */
2466 unit->LEWordIn(unit->card, P2_REG_DATA1);
2467 unit->LEWordIn(unit->card, P2_REG_DATA1);
2469 unit->LEWordIn(unit->card, P2_REG_DATA1);
2470 unit->LEWordIn(unit->card, P2_REG_DATA1);
2471 unit->LEWordIn(unit->card, P2_REG_DATA1);
2472 unit->LEWordIn(unit->card, P2_REG_DATA1);
2474 unit->special_stats[S2SS_ETHERNET_RETRIES & 0xffff] +=
2475 unit->LEWordIn(unit->card, P2_REG_DATA1) +
2476 unit->LEWordIn(unit->card, P2_REG_DATA1) +
2477 unit->LEWordIn(unit->card, P2_REG_DATA1);
2479 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->LEWordIn(unit->card, P2_REG_DATA1);
2485 unit->LEWordIn(unit->card, P2_REG_DATA1);
2486 unit->LEWordIn(unit->card, P2_REG_DATA1);
2488 unit->stats.BadData += unit->LEWordIn(unit->card, P2_REG_DATA1);
2489 unit->stats.Overruns += unit->LEWordIn(unit->card, P2_REG_DATA1);
2491 unit->LEWordIn(unit->card, P2_REG_DATA1);
2493 unit->stats.BadData += unit->LEWordIn(unit->card, P2_REG_DATA1);
2495 break;
2497 case P2_INFO_SCANRESULTS:
2498 case P2_INFO_HOSTSCANRESULTS:
2500 P2ReadRec(unit, id, unit->scan_results_rec, SCAN_BUFFER_SIZE, base);
2501 Signal(unit->task, unit->scan_complete_signal);
2502 break;
2504 case P2_INFO_SCANRESULT:
2506 descriptor = unit->rx_descriptor;
2507 P2ReadRec(unit, id, descriptor, FRAME_BUFFER_SIZE, base);
2508 if(length > 4)
2510 /* Save IEEE 802.3 portion of scan result */
2512 frame = descriptor + unit->ethernet_offset;
2513 data = frame + ETH_PACKET_DATA;
2514 CopyMem(descriptor + P2_FRM_HEADER + WIFI_FRM_ADDRESS3,
2515 frame + ETH_PACKET_SOURCE, ETH_ADDRESSSIZE);
2516 data_length =
2517 LEWord(*(UWORD *)(descriptor + unit->datalen_offset));
2518 ies_length = data_length - WIFI_BEACON_IES;
2519 *(UWORD *)(frame + ETH_PACKET_IEEELEN) = MakeBEWord(data_length);
2520 SaveBeacon(unit, frame, base);
2522 /* Append a fake old-style scan record on to fake record list */
2524 rec_length = LEWord(unit->scan_results_rec[0]);
2526 if(2 + rec_length * 2 + P2_APRECLEN < SCAN_BUFFER_SIZE)
2528 ap_rec = unit->scan_results_rec + 1 + rec_length;
2529 CopyMem(frame + ETH_PACKET_SOURCE, ap_rec + P2_APREC_BSSID / 2,
2530 ETH_ADDRESSSIZE);
2532 ap_rec[P2_APREC_SIGNAL / 2] =
2533 MakeLEWord(descriptor[P2_FRM_SIGNAL]);
2535 ap_rec[P2_APREC_NOISE / 2] =
2536 MakeLEWord(descriptor[P2_FRM_NOISE]);
2538 ap_rec[P2_APREC_CHANNEL / 2] = MakeLEWord(GetIE(WIFI_IE_CHANNEL,
2539 data + WIFI_BEACON_IES, ies_length, base)[2]);
2541 ap_rec[P2_APREC_INTERVAL / 2] =
2542 *(UWORD *)(data + WIFI_BEACON_INTERVAL);
2544 ap_rec[P2_APREC_CAPABILITIES / 2] =
2545 *(UWORD *)(data + WIFI_BEACON_CAPABILITIES);
2547 ie = GetIE(WIFI_IE_SSID, data + WIFI_BEACON_IES, ies_length,
2548 base);
2549 ssid_length = ie[1];
2550 ssid = ie + 2;
2551 ap_rec[P2_APREC_NAMELEN / 2] = MakeLEWord(ssid_length);
2552 CopyMem(ssid, ap_rec + P2_APREC_NAME / 2, ssid_length);
2554 unit->scan_results_rec[0] =
2555 MakeLEWord(rec_length + P2_APRECLEN / 2);
2558 else
2559 Signal(unit->task, unit->scan_complete_signal);
2560 break;
2562 case P2_INFO_LINKSTATUS:
2564 /* Only report an event if association status has really changed */
2566 status = unit->LEWordIn(unit->card, P2_REG_DATA1);
2568 if(status == 1 || unit->firmware_type < LUCENT_FIRMWARE
2569 && status == 3)
2570 associated = TRUE;
2571 else //if(unit->firmware_type < LUCENT_FIRMWARE || status == 3)
2572 associated = FALSE;
2574 if(!(*(ULONG *)bssid == 0 && *(UWORD *)(bssid + 4) == 0))
2576 if(associated && (unit->flags & UNITF_ASSOCIATED) == 0)
2578 unit->flags |= UNITF_ASSOCIATED;
2579 ReportEvents(unit, S2EVENT_CONNECT, base);
2581 else if(!associated && (unit->flags & UNITF_ASSOCIATED) != 0)
2583 unit->flags &= ~UNITF_ASSOCIATED;
2584 ReportEvents(unit, S2EVENT_DISCONNECT, base);
2589 /* Acknowledge event and re-enable info interrupts */
2591 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_INFO);
2592 Disable();
2593 if((unit->flags & UNITF_ONLINE) != 0)
2594 unit->LEWordOut(unit->card, P2_REG_INTMASK,
2595 unit->LEWordIn(unit->card, P2_REG_INTMASK) | P2_EVENTF_INFO);
2596 Enable();
2598 return;
2603 /****i* prism2.device/ResetHandler *****************************************
2605 * NAME
2606 * ResetHandler -- Disable hardware before a reboot.
2608 * SYNOPSIS
2609 * ResetHandler(unit, int_code)
2611 * VOID ResetHandler(struct DevUnit *, APTR);
2613 ****************************************************************************
2617 static VOID ResetHandler(REG(a1, struct DevUnit *unit),
2618 REG(a6, APTR int_code))
2620 if((unit->flags & UNITF_HAVEADAPTER) != 0)
2622 /* Stop interrupts */
2624 unit->LEWordOut(unit->card, P2_REG_INTMASK, 0);
2626 /* Stop transmission and reception */
2628 unit->LEWordOut(unit->card, P2_REG_PARAM0, 0);
2629 unit->LEWordOut(unit->card, P2_REG_COMMAND, P2_CMD_DISABLE);
2632 return;
2637 /****i* prism2.device/ReportEvents *****************************************
2639 * NAME
2640 * ReportEvents
2642 * SYNOPSIS
2643 * ReportEvents(unit, events)
2645 * VOID ReportEvents(struct DevUnit *, ULONG);
2647 * FUNCTION
2649 * INPUTS
2650 * unit - A unit of this device.
2651 * events - A mask of events to report.
2653 * RESULT
2654 * None.
2656 ****************************************************************************
2660 static VOID ReportEvents(struct DevUnit *unit, ULONG events,
2661 struct DevBase *base)
2663 struct IOSana2Req *request, *tail, *next_request;
2664 struct List *list;
2666 list = &unit->request_ports[EVENT_QUEUE]->mp_MsgList;
2667 next_request = (APTR)list->lh_Head;
2668 tail = (APTR)&list->lh_Tail;
2670 Disable();
2671 while(next_request != tail)
2673 request = next_request;
2674 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
2676 if((request->ios2_WireError & events) != 0)
2678 request->ios2_WireError = events;
2679 Remove((APTR)request);
2680 ReplyMsg((APTR)request);
2683 Enable();
2685 return;
2690 /****i* prism2.device/SendScanResults **************************************
2692 * NAME
2693 * SendScanResults -- Reply to all outstanding scan requests.
2695 * SYNOPSIS
2696 * SendScanResults(unit)
2698 * VOID SendScanResults(struct DevUnit *);
2700 * FUNCTION
2702 * INPUTS
2703 * unit - A unit of this device.
2705 * RESULT
2706 * None.
2708 ****************************************************************************
2712 static VOID SendScanResults(struct DevUnit *unit, struct DevBase *base)
2714 BYTE error = 0;
2715 struct IOSana2Req *request, *tail, *next_request;
2716 struct List *list;
2717 APTR pool;
2718 UWORD count, i, j, ssid_length, length, entry_length, *ap_rec,
2719 data_length, frame_length, ies_length;
2720 struct TagItem **tag_lists, *tag;
2721 UBYTE *bssid, *ies;
2722 const UBYTE *beacon, *ie_bssid;
2723 TEXT *ssid;
2725 list = &unit->request_ports[SCAN_QUEUE]->mp_MsgList;
2726 next_request = (APTR)list->lh_Head;
2727 tail = (APTR)&list->lh_Tail;
2729 while(next_request != tail)
2731 request = next_request;
2732 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
2734 pool = request->ios2_Data;
2736 length = LEWord(unit->scan_results_rec[0]);
2737 ap_rec = unit->scan_results_rec + 2;
2739 if(unit->firmware_type == INTERSIL_FIRMWARE)
2741 entry_length = LEWord(unit->scan_results_rec[2]);
2742 ap_rec += 2;
2743 count = (length - 3) * 2 / entry_length;
2745 else
2747 entry_length = P2_APRECLEN;
2748 count = (length - 1) * 2 / entry_length;
2751 /* Allocate array of tag lists, one for each AP */
2753 if(count > 0)
2755 tag_lists = AllocPooled(pool, count * sizeof(APTR));
2756 if(tag_lists == NULL)
2757 error = S2ERR_NO_RESOURCES;
2759 else
2760 tag_lists = NULL;
2762 for(i = 0; i < count && error == 0; i++, ap_rec += entry_length / 2)
2764 tag_lists[i] =
2765 AllocPooled(pool, SCAN_TAG_COUNT * sizeof(struct TagItem));
2766 if(tag_lists[i] == NULL)
2767 error = S2ERR_NO_RESOURCES;
2769 if(error == 0)
2771 tag = tag_lists[i];
2773 tag->ti_Tag = S2INFO_BSSID;
2774 tag->ti_Data = (UPINT)(bssid =
2775 AllocPooled(pool, ETH_ADDRESSSIZE));
2776 if(bssid != NULL)
2777 CopyMem(ap_rec + P2_APREC_BSSID / 2, bssid,
2778 ETH_ADDRESSSIZE);
2779 else
2780 error = S2ERR_NO_RESOURCES;
2781 tag++;
2783 tag->ti_Tag = TAG_IGNORE;
2784 tag++;
2786 tag->ti_Tag = S2INFO_Channel;
2787 tag->ti_Data = LEWord(ap_rec[P2_APREC_CHANNEL / 2]);
2788 tag++;
2790 tag->ti_Tag = S2INFO_BeaconInterval;
2791 tag->ti_Data = LEWord(ap_rec[P2_APREC_INTERVAL / 2]);
2792 tag++;
2794 tag->ti_Tag = S2INFO_Capabilities;
2795 tag->ti_Data = LEWord(ap_rec[P2_APREC_CAPABILITIES / 2]);
2796 tag++;
2798 tag->ti_Tag = S2INFO_Signal;
2799 tag->ti_Data = ConvertScanLevel(unit,
2800 LEWord(ap_rec[P2_APREC_SIGNAL / 2]), base);
2801 tag++;
2803 tag->ti_Tag = S2INFO_Noise;
2804 tag->ti_Data = ConvertScanLevel(unit,
2805 LEWord(ap_rec[P2_APREC_NOISE / 2]), base);
2806 tag++;
2809 ssid_length = LEWord(ap_rec[P2_APREC_NAMELEN / 2]);
2810 tag->ti_Tag = S2INFO_SSID;
2811 tag->ti_Data = (UPINT)(ssid =
2812 AllocPooled(pool, 31 + 1));
2813 if(ssid != NULL)
2815 CopyMem(ap_rec + P2_APREC_NAME / 2, ssid, ssid_length);
2816 ssid[ssid_length] = '\0';
2818 else
2819 error = S2ERR_NO_RESOURCES;
2820 tag++;
2822 tag->ti_Tag = TAG_END;
2826 /* Find IEs for each BSS and insert them into the BSS's tag list */
2828 for(beacon = unit->beacons, i = 0; i < unit->beacon_count; i++)
2830 /* Extract IEs from beacon descriptor */
2832 data_length = BEWord(*(UWORD *)(beacon + ETH_PACKET_IEEELEN));
2833 ies_length = data_length - 12;
2834 frame_length = ETH_HEADERSIZE + data_length;
2835 ies = AllocPooled(pool, sizeof(UWORD) + ies_length);
2836 if(ies != NULL)
2838 *(UWORD *)ies = ies_length;
2839 CopyMem(beacon + ETH_PACKET_DATA + WIFI_BEACON_IES,
2840 ies + sizeof(UWORD), ies_length);
2842 else
2843 error = S2ERR_NO_RESOURCES;
2845 /* Find matching tag list and add IEs to it */
2847 ie_bssid = beacon + ETH_PACKET_SOURCE;
2848 for(j = 0; j < count; j++)
2850 tag = tag_lists[j];
2851 bssid = (UBYTE *)tag->ti_Data;
2852 if(*(ULONG *)bssid == *(ULONG *)ie_bssid
2853 && *(UWORD *)(bssid + 4) == *(UWORD *)(ie_bssid + 4))
2855 tag++;
2856 tag->ti_Tag = S2INFO_InfoElements;
2857 tag->ti_Data = (PINT)ies;
2861 beacon += frame_length + sizeof(ULONG) & ~3;
2864 /* Return results */
2866 if(error == 0)
2868 request->ios2_StatData = tag_lists;
2869 request->ios2_DataLength = count;
2871 else
2873 request->ios2_Req.io_Error = error;
2874 request->ios2_WireError = S2WERR_GENERIC_ERROR;
2876 Remove((APTR)request);
2877 ReplyMsg((APTR)request);
2880 /* Discard collected beacon frames */
2882 Disable();
2883 unit->next_beacon = unit->beacons;
2884 unit->beacon_count = 0;
2885 Enable();
2887 return;
2892 /****i* prism2.device/GetNetworkInfo ***************************************
2894 * NAME
2895 * GetNetworkInfo -- Get information on current network.
2897 * SYNOPSIS
2898 * tag_list = GetNetworkInfo(unit, pool)
2900 * struct TagItem *GetNetworkInfo(struct DevUnit *, APTR);
2902 * FUNCTION
2904 * INPUTS
2905 * unit - A unit of this device.
2906 * pool - A memory pool.
2908 * RESULT
2909 * None.
2911 ****************************************************************************
2915 struct TagItem *GetNetworkInfo(struct DevUnit *unit, APTR pool,
2916 struct DevBase *base)
2918 BYTE error = 0;
2919 struct TagItem *tag_list, *tag;
2920 UBYTE *bssid, *ie;
2922 tag_list =
2923 AllocPooled(pool, INFO_TAG_COUNT * sizeof(struct TagItem));
2924 if(tag_list == NULL)
2925 error = S2ERR_NO_RESOURCES;
2927 if(error == 0)
2929 tag = tag_list;
2931 tag->ti_Tag = S2INFO_BSSID;
2932 tag->ti_Data = (UPINT)(bssid =
2933 AllocPooled(pool, ETH_ADDRESSSIZE));
2934 if(bssid != NULL)
2935 CopyMem(unit->bssid, bssid, ETH_ADDRESSSIZE);
2936 else
2937 error = S2ERR_NO_RESOURCES;
2938 tag++;
2940 tag->ti_Tag = TAG_IGNORE;
2941 tag++;
2943 tag->ti_Tag = S2INFO_WPAInfo;
2944 tag->ti_Data = (UPINT)(ie =
2945 AllocPooled(pool, unit->wpa_ie[1] + 2));
2946 if(ie != NULL)
2947 CopyMem(unit->wpa_ie, ie, unit->wpa_ie[1] + 2);
2948 else
2949 error = S2ERR_NO_RESOURCES;
2950 tag++;
2952 tag->ti_Tag = TAG_END;
2955 if(error != 0)
2956 tag_list = NULL;
2958 return tag_list;
2963 /****i* prism2.device/UpdateSignalQuality **********************************
2965 * NAME
2966 * UpdateSignalQuality -- Read signal quality from card.
2968 * SYNOPSIS
2969 * UpdateSignalQuality(unit)
2971 * VOID UpdateSignalQuality(struct DevUnit *);
2973 * FUNCTION
2975 * INPUTS
2976 * unit - A unit of this device.
2978 * RESULT
2979 * None.
2981 ****************************************************************************
2985 VOID UpdateSignalQuality(struct DevUnit *unit, struct DevBase *base)
2987 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_LINKQUALITY, base);
2988 P2Seek(unit, 1, P2_REC_LINKQUALITY, 6, base);
2990 unit->signal_quality.SignalLevel =
2991 ConvertLevel(unit, unit->LEWordIn(unit->card, P2_REG_DATA1), base);
2992 unit->signal_quality.NoiseLevel =
2993 ConvertLevel(unit, unit->LEWordIn(unit->card, P2_REG_DATA1), base);
2995 return;
3000 /****i* prism2.device/StartScan ********************************************
3002 * NAME
3003 * StartScan -- Start a scan for available networks.
3005 * SYNOPSIS
3006 * StartScan(unit)
3008 * VOID StartScan(struct DevUnit *);
3010 * FUNCTION
3012 * INPUTS
3013 * unit - A unit of this device.
3015 * RESULT
3016 * None.
3018 ****************************************************************************
3022 VOID StartScan(struct DevUnit *unit, const TEXT *ssid, struct DevBase *base)
3024 UBYTE *params;
3025 UWORD ssid_length = 0;
3027 /* Ask for a scan */
3029 if((unit->flags & UNITF_ONLINE) != 0)
3031 if(ssid != NULL)
3032 ssid_length = StrLen(ssid);
3033 if(unit->firmware_type == INTERSIL_FIRMWARE)
3035 params = AllocVec(sizeof(scan_params) + ssid_length, MEMF_PUBLIC);
3036 if(params != NULL)
3038 CopyMem(scan_params, params, sizeof(scan_params));
3039 if(ssid != NULL)
3040 CopyMem(ssid, params + sizeof(scan_params), ssid_length);
3041 params[4] = ssid_length;
3042 P2SetData(unit, P2_REC_HOSTSCAN, params,
3043 sizeof(scan_params) + ssid_length, base);
3044 FreeVec(params);
3047 else if(unit->firmware_type == SYMBOL_FIRMWARE)
3048 P2SetWord(unit, P2_REC_ALTHOSTSCAN, 0x82, base);
3049 else if(unit->firmware_type >= LUCENT_FIRMWARE
3050 && (unit->flags & UNITF_HARDTKIP) != 0)
3052 /* Initialise fake scan results and ask for a series of raw beacon
3053 descriptors */
3055 unit->scan_results_rec[0] = MakeLEWord(1);
3057 P2SetID(unit, P2_REC_SCANSSID, ssid, ssid_length, base);
3058 P2SetWord(unit, P2_REC_SCANCHANNELS, 0x7fff, base);
3059 unit->LEWordOut(unit->card, P2_REG_PARAM1, 0x3fff);
3060 P2DoCmd(unit, P2_CMD_INQUIRE, P2_INFO_SCANRESULT, base);
3062 else
3064 P2SetID(unit, P2_REC_SCANSSID, ssid, ssid_length, base);
3065 P2DoCmd(unit, P2_CMD_INQUIRE, P2_INFO_SCANRESULTS, base);
3069 return;
3074 /****i* prism2.device/LoadFirmware *****************************************
3076 * NAME
3077 * LoadFirmware
3079 * SYNOPSIS
3080 * success = LoadFirmware(unit)
3082 * BOOL LoadFirmware(struct DevUnit *);
3084 * FUNCTION
3086 * INPUTS
3087 * unit - A unit of this device.
3089 * RESULT
3090 * success - Success indicator.
3092 ****************************************************************************
3096 static BOOL LoadFirmware(struct DevUnit *unit, struct DevBase *base)
3098 BOOL success = TRUE;
3099 const TEXT *file_name;
3100 struct FileInfoBlock *info = NULL;
3101 UWORD control_reg, pdr_no, *pda = NULL, *pdr, *prod_data, length;
3102 ULONG location, start_address;
3103 BPTR file = (BPTR)NULL;
3104 UBYTE *data = NULL;
3105 TEXT *buffer = NULL;
3106 const TEXT *p;
3107 UBYTE type;
3109 /* Read firmware file */
3111 switch(unit->firmware_type)
3113 case LUCENT_FIRMWARE:
3114 file_name = h1_firmware_file_name;
3115 break;
3116 case HERMES2_FIRMWARE:
3117 file_name = h2_firmware_file_name;
3118 break;
3119 case HERMES2G_FIRMWARE:
3120 file_name = h25_firmware_file_name;
3121 break;
3122 default:
3123 file_name = NULL;
3126 if(file_name == NULL)
3127 success = FALSE;
3129 if(success)
3131 file = Open(file_name, MODE_OLDFILE);
3132 if(file == (BPTR)NULL)
3133 success = FALSE;
3136 if(success)
3138 info = AllocDosObject(DOS_FIB, NULL);
3139 if(info == NULL)
3140 success = FALSE;
3143 if(success)
3145 if(!ExamineFH(file, info))
3146 success = FALSE;
3149 if(success)
3151 buffer = AllocVec(info->fib_Size + 1, MEMF_ANY);
3152 data = AllocVec(MAX_S_REC_SIZE, MEMF_ANY);
3153 pda = AllocVec(LUCENT_PDA_SIZE, MEMF_ANY);
3154 if(buffer == NULL || data == NULL || pda == NULL)
3155 success = FALSE;
3158 if(success)
3160 if(Read(file, buffer, info->fib_Size) == -1)
3161 success = FALSE;
3162 buffer[info->fib_Size] = '\0';
3165 if(success)
3167 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3168 P2DoCmd(unit, P2_CMD_INIT | 0x100, 0, base);
3169 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3170 P2DoCmd(unit, P2_CMD_INIT | 0x0, 0, base);
3171 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3173 /* Enable auxiliary ports */
3175 unit->LEWordOut(unit->card, P2_REG_PARAM0, 0xfe01);
3176 unit->LEWordOut(unit->card, P2_REG_PARAM1, 0xdc23);
3177 unit->LEWordOut(unit->card, P2_REG_PARAM2, 0xba45);
3179 control_reg = unit->LEWordIn(unit->card, P2_REG_CONTROL);
3180 control_reg =
3181 control_reg & ~P2_REG_CONTROLF_AUX | P2_REG_CONTROL_ENABLEAUX;
3182 unit->LEWordOut(unit->card, P2_REG_CONTROL, control_reg);
3184 BusyMilliDelay(5, base);
3185 while(
3186 (unit->LEWordIn(unit->card, P2_REG_CONTROL) & P2_REG_CONTROLF_AUX)
3187 != P2_REG_CONTROL_AUXENABLED);
3189 /* Read Production Data Area from card */
3191 if(unit->firmware_type < HERMES2_FIRMWARE)
3193 location = LUCENT_PDA_ADDRESS;
3194 unit->LEWordOut(unit->card, P2_REG_AUXPAGE, location >> 7);
3195 unit->LEWordOut(unit->card, P2_REG_AUXOFFSET,
3196 location & (1 << 7) - 1);
3198 unit->WordsIn(unit->card, P2_REG_AUXDATA,
3199 (UWORD *)pda, LUCENT_PDA_SIZE >> 1);
3202 /* Allow writing to card's RAM */
3204 BusyMilliDelay(100, base);
3205 start_address = 0xf8000;
3206 unit->LEWordOut(unit->card, P2_REG_PARAM1, start_address >> 16);
3207 P2DoCmd(unit, P2_CMD_PROGRAM | P2_CMDF_WRITE, start_address, base);
3209 /* Parse firmware image data and write it to card */
3211 p = buffer;
3212 while(p != NULL)
3214 p = ParseNextSRecord(p, &type, data, &length, &location, base);
3215 if(p != NULL)
3217 switch(type)
3219 case '3':
3221 /* Check that this is not a "special" record */
3223 if(location < 0xff000000)
3225 /* Write data to card */
3227 if(unit->firmware_type < LUCENT_FIRMWARE)
3229 unit->LEWordOut(unit->card, P2_REG_PARAM1,
3230 location >> 16);
3231 P2DoCmd(unit, P2_CMD_PROGRAM | P2_CMDF_WRITE, location,
3232 base);
3235 unit->LEWordOut(unit->card, P2_REG_AUXPAGE,
3236 location >> 7);
3237 unit->LEWordOut(unit->card, P2_REG_AUXOFFSET,
3238 location & (1 << 7) - 1);
3240 unit->WordsOut(unit->card, P2_REG_AUXDATA,
3241 (UWORD *)data, length >> 1);
3243 break;
3245 case '7':
3247 /* Get location in card memory to begin execution of new
3248 firmware at */
3250 start_address = location;
3255 /* Parse PDA plug records and patch firmware */
3257 p = buffer;
3258 while(p != NULL)
3260 p = ParseNextSRecord(p, &type, data, &length, &location, base);
3262 if(p != NULL && type == '3' && location == 0xff000000)
3264 /* Get PDR number and the location where it should be patched
3265 into firmware */
3267 pdr_no = LELong(*(ULONG *)data);
3268 location = LELong(*(ULONG *)(data + 4));
3269 length = LELong(*(ULONG *)(data + 8));
3271 /* Find PDR to copy data from */
3273 prod_data = NULL;
3274 for(pdr = pda; pdr[1] != 0; pdr += LEWord(pdr[0]) + 1)
3276 if(LEWord(pdr[1]) == pdr_no)
3277 prod_data = pdr + 2;
3280 /* Write production data to card if it was found */
3282 if(prod_data != NULL)
3284 if(unit->firmware_type < LUCENT_FIRMWARE)
3286 unit->LEWordOut(unit->card, P2_REG_PARAM1,
3287 location >> 16);
3288 P2DoCmd(unit, P2_CMD_PROGRAM | P2_CMDF_WRITE, location,
3289 base);
3292 unit->LEWordOut(unit->card, P2_REG_AUXPAGE, location >> 7);
3293 unit->LEWordOut(unit->card, P2_REG_AUXOFFSET,
3294 location & (1 << 7) - 1);
3296 unit->WordsOut(unit->card, P2_REG_AUXDATA, prod_data,
3297 length >> 1);
3302 /* Disable auxiliary ports */
3304 control_reg = unit->LEWordIn(unit->card, P2_REG_CONTROL);
3305 control_reg =
3306 control_reg & ~P2_REG_CONTROLF_AUX | P2_REG_CONTROL_DISABLEAUX;
3307 unit->LEWordOut(unit->card, P2_REG_CONTROL, control_reg);
3309 /* Execute downloaded firmware */
3311 if(unit->firmware_type >= HERMES2_FIRMWARE)
3313 unit->LEWordOut(unit->card, P2_REG_PARAM1, start_address >> 16);
3314 P2DoCmd(unit, P2_CMD_EXECUTE, start_address, base);
3316 else if(unit->firmware_type >= LUCENT_FIRMWARE)
3318 P2DoCmd(unit, P2_CMD_PROGRAM, 0, base);
3319 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3320 P2DoCmd(unit, P2_CMD_INIT, 0, base);
3321 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3323 else
3325 unit->LEWordOut(unit->card, P2_REG_PARAM1, start_address >> 16);
3326 P2DoCmd(unit, P2_CMD_PROGRAM, start_address, base);
3327 P2DoCmd(unit, P2_CMD_INIT, 0, base);
3331 /* Free Resources */
3333 FreeVec(pda);
3334 FreeVec(buffer);
3335 FreeVec(data);
3336 FreeDosObject(DOS_FIB, info);
3337 if(file != (BPTR)NULL)
3338 Close(file);
3340 return success;
3345 /****i* prism2.device/ParseNextSRecord *************************************
3347 * NAME
3348 * ParseNextSRecord
3350 ****************************************************************************
3354 static const TEXT *ParseNextSRecord(const TEXT *s, UBYTE *type, UBYTE *data,
3355 UWORD *data_length, ULONG *location, struct DevBase *base)
3357 LONG ch;
3358 ULONG n = 0;
3359 UWORD i;
3360 BOOL found = FALSE;
3362 /* Find start of next record, if any */
3364 while(!found)
3366 ch = *s++;
3367 if(ch == 'S' || ch == '\0')
3368 found = TRUE;
3371 if(ch == 'S')
3373 /* Get record type */
3375 *type = *s++;
3377 /* Skip length field to keep alignment easy */
3379 s += 2;
3381 /* Parse hexadecimal portion of record */
3383 for(i = 0; (ch = *s++) >= '0'; i++)
3385 n <<= 4;
3387 if(ch >= 'A')
3388 n |= ch - 'A' + 10;
3389 else
3390 n |= ch - '0';
3392 if(i >= 8 && (i & 0x1) != 0)
3394 *data++ = n;
3395 n = 0;
3397 else if(i == 7)
3399 *location = n;
3400 n = 0;
3403 *data_length = (i >> 1) - 5;
3405 else
3406 s = NULL;
3408 /* Return updated text pointer */
3410 return s;
3415 /****i* prism2.device/P2DoCmd **********************************************
3417 * NAME
3418 * P2DoCmd
3420 ****************************************************************************
3422 * Commands can't fail without software/firmware bug?
3426 static VOID P2DoCmd(struct DevUnit *unit, UWORD command, UWORD param,
3427 struct DevBase *base)
3429 if(unit->firmware_type < LUCENT_FIRMWARE && command == P2_CMD_INIT)
3430 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3432 unit->LEWordOut(unit->card, P2_REG_PARAM0, param);
3433 unit->LEWordOut(unit->card, P2_REG_COMMAND, command);
3434 while((unit->LEWordIn(unit->card, P2_REG_EVENTS)
3435 & P2_EVENTF_CMD) == 0);
3436 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_CMD);
3438 if(unit->firmware_type < LUCENT_FIRMWARE && command == P2_CMD_INIT)
3439 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3444 /****i* prism2.device/P2Seek ***********************************************
3446 * NAME
3447 * P2Seek
3449 ****************************************************************************
3453 static BOOL P2Seek(struct DevUnit *unit, UWORD path_no, UWORD rec_no,
3454 UWORD offset, struct DevBase *base)
3456 UPINT offset_reg;
3458 path_no <<= 1;
3459 offset_reg = P2_REG_OFFSET0 + path_no;
3460 while((unit->LEWordIn(unit->card, offset_reg) & P2_REG_OFFSETF_BUSY)
3461 != 0);
3462 unit->LEWordOut(unit->card, P2_REG_SELECT0 + path_no, rec_no);
3463 unit->LEWordOut(unit->card, offset_reg, offset);
3464 while((unit->LEWordIn(unit->card, offset_reg) & P2_REG_OFFSETF_BUSY)
3465 != 0);
3467 return (unit->LEWordIn(unit->card, offset_reg) & P2_REG_OFFSETF_ERROR)
3468 == 0;
3473 /****i* prism2.device/P2SetID **********************************************
3475 * NAME
3476 * P2SetID
3478 * NOTES
3479 * id may be NULL as long as length is zero.
3481 ****************************************************************************
3485 static VOID P2SetID(struct DevUnit *unit, UWORD rec_no, const UBYTE *id,
3486 UWORD length, struct DevBase *base)
3488 P2Seek(unit, 1, rec_no, 0, base);
3490 unit->LEWordOut(unit->card, P2_REG_DATA1, length / 2 + 3);
3491 unit->LEWordOut(unit->card, P2_REG_DATA1, rec_no);
3492 unit->LEWordOut(unit->card, P2_REG_DATA1, length);
3493 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)id, (length + 1) / 2);
3495 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, rec_no, base);
3497 return;
3502 /****i* prism2.device/P2SetWord ********************************************
3504 * NAME
3505 * P2SetWord
3507 ****************************************************************************
3511 static VOID P2SetWord(struct DevUnit *unit, UWORD rec_no, UWORD value,
3512 struct DevBase *base)
3514 P2Seek(unit, 1, rec_no, 0, base);
3516 unit->LEWordOut(unit->card, P2_REG_DATA1, 2);
3517 unit->LEWordOut(unit->card, P2_REG_DATA1, rec_no);
3518 unit->LEWordOut(unit->card, P2_REG_DATA1, value);
3520 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, rec_no, base);
3522 return;
3527 /****i* prism2.device/P2GetWord ********************************************
3529 * NAME
3530 * P2GetWord
3532 ****************************************************************************
3536 static UWORD P2GetWord(struct DevUnit *unit, UWORD rec_no,
3537 struct DevBase *base)
3539 P2DoCmd(unit, P2_CMD_ACCESS, rec_no, base);
3540 P2Seek(unit, 1, rec_no, 4, base);
3542 return unit->LEWordIn(unit->card, P2_REG_DATA1);
3547 /****i* prism2.device/P2AllocMem *******************************************
3549 * NAME
3550 * P2AllocMem
3552 ****************************************************************************
3556 static UWORD P2AllocMem(struct DevUnit *unit, UWORD size,
3557 struct DevBase *base)
3559 UWORD id;
3560 P2DoCmd(unit, P2_CMD_ALLOCMEM, size, base);
3561 while((unit->LEWordIn(unit->card, P2_REG_EVENTS) & P2_EVENTF_ALLOCMEM)
3562 == 0);
3563 id = unit->LEWordIn(unit->card, P2_REG_ALLOCFID);
3564 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_ALLOCMEM);
3565 return id;
3570 /****i* prism2.device/P2SetData ********************************************
3572 * NAME
3573 * P2SetData
3575 ****************************************************************************
3579 static VOID P2SetData(struct DevUnit *unit, UWORD rec_no, const UBYTE *data,
3580 UWORD length, struct DevBase *base)
3582 length = (length + 1) / 2;
3583 P2Seek(unit, 1, rec_no, 0, base);
3585 unit->LEWordOut(unit->card, P2_REG_DATA1, 1 + length);
3586 unit->LEWordOut(unit->card, P2_REG_DATA1, rec_no);
3587 unit->WordsOut(unit->card, P2_REG_DATA1, (const UWORD *)data, length);
3589 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, rec_no, base);
3591 return;
3596 /****i* prism2.device/P2ReadRec ********************************************
3598 * NAME
3599 * P2ReadRec -- Load and read an entire record.
3601 * SYNOPSIS
3602 * success = P2ReadRec(unit, rec_no, buffer, max_length)
3604 * BOOL P2ReadRec(struct DevUnit *, UWORD, APTR, UWORD);
3606 * FUNCTION
3608 * INPUTS
3609 * unit - A unit of this device.
3610 * rec_no - Record number to read.
3611 * buffer - Buffer to store data in.
3612 * max_length - Maximum number of bytes to store in buffer.
3614 * RESULT
3615 * success - Success indicator.
3617 ****************************************************************************
3621 static BOOL P2ReadRec(struct DevUnit *unit, UWORD rec_no, APTR buffer,
3622 UWORD max_length, struct DevBase *base)
3624 BOOL success = TRUE;
3625 WORD length;
3627 P2DoCmd(unit, P2_CMD_ACCESS, rec_no, base);
3628 P2Seek(unit, 1, rec_no, 0, base);
3630 length = (unit->LEWordIn(unit->card, P2_REG_DATA1) + 1) * 2;
3631 P2Seek(unit, 1, rec_no, 0, base);
3632 if(length <= max_length)
3633 unit->WordsIn(unit->card, P2_REG_DATA1, (UWORD *)buffer,
3634 length / 2);
3635 else
3636 success = FALSE;
3637 return success;
3642 /****i* prism2.device/ConvertLevel *****************************************
3644 * NAME
3645 * ConvertLevel -- Convert a signal or noise level to dBm.
3647 * SYNOPSIS
3648 * dbm_level = ConvertLevel(unit, raw_level)
3650 * LONG ConvertLevel(struct DevUnit *, UWORD);
3652 * FUNCTION
3654 * INPUTS
3655 * unit - A unit of this device.
3656 * raw_level - The value returned from the hardware.
3658 * RESULT
3659 * dbm_level - The value in dBm.
3661 ****************************************************************************
3665 static LONG ConvertLevel(struct DevUnit *unit, UWORD raw_level,
3666 struct DevBase *base)
3668 LONG dbm_level;
3670 if(unit->firmware_type >= LUCENT_FIRMWARE)
3671 dbm_level = raw_level - LUCENT_DBM_OFFSET;
3672 else
3673 dbm_level = raw_level / 3 - INTERSIL_DBM_OFFSET;
3675 return dbm_level;
3680 /****i* prism2.device/ConvertScanLevel *************************************
3682 * NAME
3683 * ConvertScanLevel -- Convert a signal or noise level to dBm.
3685 * SYNOPSIS
3686 * dbm_level = ConvertScanLevel(unit, raw_level)
3688 * LONG ConvertScanLevel(struct DevUnit *, UWORD);
3690 * FUNCTION
3692 * INPUTS
3693 * unit - A unit of this device.
3694 * raw_level - The value returned from the hardware.
3696 * RESULT
3697 * dbm_level - The value in dBm.
3699 ****************************************************************************
3703 static LONG ConvertScanLevel(struct DevUnit *unit, UWORD raw_level,
3704 struct DevBase *base)
3706 LONG dbm_level;
3708 if(unit->firmware_type >= LUCENT_FIRMWARE)
3709 dbm_level = raw_level - LUCENT_DBM_OFFSET;
3710 else
3711 dbm_level = (WORD)raw_level;
3713 return dbm_level;
3718 /****i* prism2.device/GetIE ************************************************
3720 * NAME
3721 * GetIE
3723 * SYNOPSIS
3724 * ie = GetIE(id, ies, ies_length)
3726 * UBYTE *GetIE(UBYTE, UBYTE *, UWORD);
3728 * FUNCTION
3730 * INPUTS
3731 * id - ID of IE to find.
3732 * ies - A series of IEs.
3733 * ies_length - Length of IE block.
3735 * RESULT
3736 * ie - Pointer to start of IE within block, or NULL if not found.
3738 ****************************************************************************
3742 #if 0
3743 static UBYTE *GetIE(UBYTE id, UBYTE *ies, UWORD ies_length,
3744 struct DevBase *base)
3746 BOOL found = FALSE;
3747 UBYTE *ie, *end;
3749 // for(ie = ies; ie < end && ie + ie[1] < end; ie += length + 2)
3750 end = ies + ies_length;
3751 while(ie < end && !found)
3753 if(ie[0] == id)
3754 found = TRUE;
3755 else
3756 ie += ie[1] + 2;
3758 if(!found)
3759 ie = NULL;
3761 return ie;
3763 #else
3764 static UBYTE *GetIE(UBYTE id, UBYTE *ies, UWORD ies_length,
3765 struct DevBase *base)
3767 UBYTE *ie;
3769 for(ie = ies; ie < ies + ies_length && ie[0] != id; ie += ie[1] + 2);
3770 // for(ie = ies, end = ies + ies_length; ie < end && ie[0] != id; ie += ie[1] + 2);
3771 if(ie >= ies + ies_length)
3772 ie = NULL;
3774 return ie;
3776 #endif
3779 /****i* prism2.device/UnitTask *********************************************
3781 * NAME
3782 * UnitTask
3784 * SYNOPSIS
3785 * UnitTask(sys_base)
3787 * VOID UnitTask(struct ExecBase *);
3789 * FUNCTION
3790 * Completes deferred requests, and handles card insertion and removal
3791 * in conjunction with the relevant interrupts.
3793 ****************************************************************************
3797 #ifdef __MORPHOS__
3798 #undef UnitTask
3799 #endif
3801 static VOID UnitTask(struct ExecBase *sys_base)
3803 struct Task *task;
3804 struct IORequest *request;
3805 struct DevUnit *unit;
3806 struct DevBase *base;
3807 struct MsgPort *general_port;
3808 ULONG signals = 0, wait_signals, card_removed_signal,
3809 card_inserted_signal, scan_complete_signal, general_port_signal;
3811 /* Get parameters */
3813 task = FindTask(NULL);
3814 unit = task->tc_UserData;
3815 base = unit->device;
3817 /* Activate general request port */
3819 general_port = unit->request_ports[GENERAL_QUEUE];
3820 general_port->mp_SigTask = task;
3821 general_port->mp_SigBit = AllocSignal(-1);
3822 general_port_signal = 1 << general_port->mp_SigBit;
3823 general_port->mp_Flags = PA_SIGNAL;
3825 /* Allocate signals for notification of card removal and insertion */
3827 card_removed_signal = unit->card_removed_signal = 1 << AllocSignal(-1);
3828 card_inserted_signal = unit->card_inserted_signal = 1 << AllocSignal(-1);
3829 scan_complete_signal = unit->scan_complete_signal = 1 << AllocSignal(-1);
3830 wait_signals = (1 << general_port->mp_SigBit) | card_removed_signal
3831 | card_inserted_signal | scan_complete_signal | SIGBREAKF_CTRL_C;
3833 /* Tell ourselves to check port for old messages */
3835 Signal(task, general_port_signal);
3837 /* Infinite loop to service requests and signals */
3839 while((signals & SIGBREAKF_CTRL_C) == 0)
3841 signals = Wait(wait_signals);
3843 if((signals & card_inserted_signal) != 0)
3845 if(unit->insertion_function(unit->card, base))
3847 unit->flags |= UNITF_HAVEADAPTER;
3848 if((unit->flags & UNITF_CONFIGURED) != 0)
3849 ConfigureAdapter(unit, base);
3850 if((unit->flags & UNITF_WASONLINE) != 0)
3852 GoOnline(unit, base);
3853 unit->flags &= ~UNITF_WASONLINE;
3858 if((signals & card_removed_signal) != 0)
3860 unit->removal_function(unit->card, base);
3861 if((unit->flags & UNITF_WASONLINE) != 0)
3862 GoOffline(unit, base);
3865 if((signals & scan_complete_signal) != 0)
3866 SendScanResults(unit, base);
3868 if((signals & general_port_signal) != 0)
3870 while((request = (APTR)GetMsg(general_port)) != NULL)
3872 /* Service the request as soon as the unit is free */
3874 ObtainSemaphore(&unit->access_lock);
3875 ServiceRequest((APTR)request, base);
3880 FreeMem(task->tc_SPLower, STACK_SIZE);
3885 /****i* prism2.device/StrLen ***********************************************
3887 * NAME
3888 * StrLen
3890 * SYNOPSIS
3891 * length = StrLen(s)
3893 * UPINT StrLen(TEXT *);
3895 ****************************************************************************
3899 static UPINT StrLen(const TEXT *s)
3901 const TEXT *p;
3903 for(p = s; *p != '\0'; p++);
3904 return p - s;