grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / devs / networks / prism2 / unit.c
blobfb23bb602cc9ea8d9d526312d2374301bd66d8e1
1 /*
3 Copyright (C) 2001-2012 Neil Cafferkey
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 MA 02111-1307, USA.
23 #include <exec/memory.h>
24 #include <exec/execbase.h>
25 #include <exec/errors.h>
27 #include <proto/exec.h>
28 #ifndef __amigaos4__
29 #include <proto/alib.h>
30 #else
31 #include <clib/alib_protos.h>
32 #endif
33 #include <proto/utility.h>
34 #include <proto/dos.h>
35 #include <proto/timer.h>
37 #include "device.h"
38 #include "prism2.h"
40 #include "unit_protos.h"
41 #include "request_protos.h"
42 #include "encryption_protos.h"
43 #include "timer_protos.h"
46 #define TASK_PRIORITY 0
47 #define STACK_SIZE 4096
48 #define INT_MASK \
49 (P2_EVENTF_INFO | P2_EVENTF_ALLOCMEM | P2_EVENTF_TXFAIL | P2_EVENTF_RX)
50 #define MAX_S_REC_SIZE 50
51 #define LUCENT_DBM_OFFSET 149
52 #define INTERSIL_DBM_OFFSET 100
53 #define SCAN_BUFFER_SIZE 2000
54 #define BEACON_BUFFER_SIZE 8000
55 #define SCAN_TAG_COUNT 8 +10
56 #define INFO_TAG_COUNT 4 +10
57 #define LUCENT_PDA_ADDRESS 0x390000
58 #define LUCENT_PDA_SIZE 1000
59 #define FRAME_BUFFER_SIZE (P2_H2FRM_ETHFRAME + ETH_HEADERSIZE \
60 + SNAP_HEADERSIZE + ETH_MTU + EIV_SIZE + ICV_SIZE + MIC_SIZE)
63 #ifndef AbsExecBase
64 #ifdef __AROS__
65 #define AbsExecBase sys_base
66 #else
67 #define AbsExecBase (*(struct ExecBase **)4)
68 #endif
69 #endif
71 static struct AddressRange *FindMulticastRange(struct DevUnit *unit,
72 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left,
73 UWORD upper_bound_right, struct DevBase *base);
74 static VOID SetMulticast(struct DevUnit *unit, struct DevBase *base);
75 static VOID RXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code));
76 static UBYTE *GetRXBuffer(struct DevUnit *unit, const UBYTE *address,
77 UWORD frag_no, UWORD *buffer_no, struct DevBase *base);
78 static VOID DistributeRXPacket(struct DevUnit *unit, UBYTE *frame,
79 struct DevBase *base);
80 static VOID CopyPacket(struct DevUnit *unit, struct IOSana2Req *request,
81 UWORD packet_size, UWORD packet_type, UBYTE *buffer,
82 struct DevBase *base);
83 static BOOL AddressFilter(struct DevUnit *unit, UBYTE *address,
84 struct DevBase *base);
85 static VOID SaveBeacon(struct DevUnit *unit, const UBYTE *frame,
86 struct DevBase *base);
87 static VOID TXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code));
88 static VOID InfoInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code));
89 static VOID ResetHandler(REG(a1, struct DevUnit *unit),
90 REG(a6, APTR int_code));
91 static VOID ReportEvents(struct DevUnit *unit, ULONG events,
92 struct DevBase *base);
93 static BOOL LoadFirmware(struct DevUnit *unit, struct DevBase *base);
94 static const TEXT *ParseNextSRecord(const TEXT *s, UBYTE *type, UBYTE *data,
95 UWORD *data_length, ULONG *location, struct DevBase *base);
96 static VOID P2DoCmd(struct DevUnit *unit, UWORD command, UWORD param,
97 struct DevBase *base);
98 static BOOL P2Seek(struct DevUnit *unit, UWORD path_no, UWORD rec_no,
99 UWORD offset, struct DevBase *base);
100 static VOID P2SetID(struct DevUnit *unit, UWORD rec_no, const UBYTE *id,
101 UWORD length, struct DevBase *base);
102 static VOID P2SetWord(struct DevUnit *unit, UWORD rec_no, UWORD value,
103 struct DevBase *base);
104 static UWORD P2GetWord(struct DevUnit *unit, UWORD rec_no,
105 struct DevBase *base);
106 static UWORD P2AllocMem(struct DevUnit *unit, UWORD size,
107 struct DevBase *base);
108 static VOID P2SetData(struct DevUnit *unit, UWORD rec_no, const UBYTE *data,
109 UWORD length, struct DevBase *base);
110 static BOOL P2ReadRec(struct DevUnit *unit, UWORD rec_no, APTR buffer,
111 UWORD max_length, struct DevBase *base);
112 static LONG ConvertLevel(struct DevUnit *unit, UWORD raw_level,
113 struct DevBase *base);
114 static LONG ConvertScanLevel(struct DevUnit *unit, UWORD raw_level,
115 struct DevBase *base);
116 static UBYTE *GetIE(UBYTE id, UBYTE *ies, UWORD ies_length,
117 struct DevBase *base);
118 static VOID UnitTask(struct ExecBase *sys_base);
119 static UPINT StrLen(const TEXT *s);
122 static const UBYTE snap_template[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
123 static const UBYTE scan_params[] = {0xff, 0x3f, 0x01, 0x00, 0x00, 0x00};
124 #if !defined(__AROS__)
125 static const TEXT options_name[] = "Prism 2 options";
126 #endif
127 static const TEXT h1_firmware_file_name[] = "DEVS:Firmware/HermesI";
128 static const TEXT h2_firmware_file_name[] = "DEVS:Firmware/HermesII";
129 static const TEXT h25_firmware_file_name[] = "DEVS:Firmware/HermesII.5";
130 static const UBYTE h2_wpa_ie[] =
132 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00,
133 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50,
134 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02,
135 0x00, 0x00
139 #ifdef __amigaos4__
140 #undef AddTask
141 #define AddTask(task, initial_pc, final_pc) \
142 IExec->AddTask(task, initial_pc, final_pc, NULL)
143 #endif
144 #ifdef __MORPHOS__
145 static const struct EmulLibEntry mos_task_trap =
147 TRAP_LIB,
149 (APTR)UnitTask
151 #define UnitTask &mos_task_trap
152 #endif
153 #ifdef __AROS__
154 #undef AddTask
155 #define AddTask(task, initial_pc, final_pc) \
156 ({ \
157 struct TagItem _task_tags[] = \
158 {{TASKTAG_ARG1, (IPTR)SysBase}, {TAG_END, 0}}; \
159 NewAddTask(task, initial_pc, final_pc, _task_tags); \
161 #endif
165 /****i* prism2.device/CreateUnit *******************************************
167 * NAME
168 * CreateUnit -- Create a unit.
170 * SYNOPSIS
171 * unit = CreateUnit(index, card, io_tags, bus)
173 * struct DevUnit *CreateUnit(ULONG, APTR, struct TagItem *, UWORD);
175 * FUNCTION
176 * Creates a new unit.
178 ****************************************************************************
182 struct DevUnit *CreateUnit(ULONG index, APTR card,
183 struct TagItem *io_tags, UWORD bus, struct DevBase *base)
185 BOOL success = TRUE;
186 struct DevUnit *unit;
187 struct Task *task;
188 struct MsgPort *port;
189 UBYTE i;
190 APTR stack;
192 unit = AllocMem(sizeof(struct DevUnit), MEMF_CLEAR | MEMF_PUBLIC);
193 if(unit == NULL)
194 success = FALSE;
196 if(success)
198 unit->index = index;
199 unit->device = base;
200 unit->card = card;
201 unit->bus = bus;
202 unit->WordsIn =
203 (APTR)GetTagData(IOTAG_WordsIn, (UPINT)NULL, io_tags);
204 unit->WordsOut =
205 (APTR)GetTagData(IOTAG_WordsOut, (UPINT)NULL, io_tags);
206 unit->BEWordOut =
207 (APTR)GetTagData(IOTAG_BEWordOut, (UPINT)NULL, io_tags);
208 unit->LEWordIn =
209 (APTR)GetTagData(IOTAG_LEWordIn, (UPINT)NULL, io_tags);
210 unit->LEWordOut =
211 (APTR)GetTagData(IOTAG_LEWordOut, (UPINT)NULL, io_tags);
212 if(unit->WordsIn == NULL || unit->WordsOut == NULL
213 || unit->BEWordOut == NULL || unit->LEWordIn == NULL
214 || unit->LEWordOut == NULL)
215 success = FALSE;
218 if(success)
220 InitSemaphore(&unit->access_lock);
221 success = InitialiseAdapter(unit, FALSE, base);
222 unit->flags |= UNITF_HAVEADAPTER;
224 /* Create the message ports for queuing requests */
226 for(i = 0; i < REQUEST_QUEUE_COUNT; i++)
228 unit->request_ports[i] = port = AllocMem(sizeof(struct MsgPort),
229 MEMF_PUBLIC | MEMF_CLEAR);
230 if(port == NULL)
231 success = FALSE;
233 if(success)
235 NewList(&port->mp_MsgList);
236 port->mp_Flags = PA_IGNORE;
237 port->mp_SigTask = &unit->tx_int;
241 /* Allocate buffers */
243 unit->rx_buffer = AllocVec(FRAME_BUFFER_SIZE, MEMF_PUBLIC);
244 unit->rx_buffers = AllocVec(FRAME_BUFFER_SIZE * RX_BUFFER_COUNT,
245 MEMF_PUBLIC);
246 for(i = 0; i < RX_BUFFER_COUNT; i++)
247 unit->rx_fragment_nos[i] = -1;
248 unit->tx_buffer = AllocVec(ETH_MAXPACKETSIZE, MEMF_PUBLIC);
249 unit->rx_descriptor = AllocVec(FRAME_BUFFER_SIZE,
250 MEMF_PUBLIC | MEMF_CLEAR);
251 unit->tx_descriptor = AllocVec(FRAME_BUFFER_SIZE,
252 MEMF_PUBLIC | MEMF_CLEAR);
253 unit->scan_results_rec = AllocVec(SCAN_BUFFER_SIZE, MEMF_PUBLIC);
254 unit->next_beacon = unit->beacons =
255 AllocVec(BEACON_BUFFER_SIZE, MEMF_PUBLIC);
256 if(unit->rx_buffer == NULL || unit->rx_buffers == NULL
257 || unit->tx_buffer == NULL || unit->rx_descriptor == NULL
258 || unit->tx_descriptor == NULL || unit->scan_results_rec == NULL
259 || unit->beacons == NULL)
260 success = FALSE;
263 if(success)
265 NewList((APTR)&unit->openers);
266 NewList((APTR)&unit->type_trackers);
267 NewList((APTR)&unit->multicast_ranges);
269 /* Record maximum speed in BPS */
271 unit->speed = 11000000;
273 /* Initialise status, transmit, receive and stats interrupts */
275 unit->status_int.is_Node.ln_Name =
276 base->device.dd_Library.lib_Node.ln_Name;
277 unit->status_int.is_Code = (APTR)StatusInt;
278 unit->status_int.is_Data = unit;
280 unit->rx_int.is_Node.ln_Name =
281 base->device.dd_Library.lib_Node.ln_Name;
282 unit->rx_int.is_Code = (APTR)RXInt;
283 unit->rx_int.is_Data = unit;
285 unit->tx_int.is_Node.ln_Name =
286 base->device.dd_Library.lib_Node.ln_Name;
287 unit->tx_int.is_Code = (APTR)TXInt;
288 unit->tx_int.is_Data = unit;
290 unit->info_int.is_Node.ln_Name =
291 base->device.dd_Library.lib_Node.ln_Name;
292 unit->info_int.is_Code = (APTR)InfoInt;
293 unit->info_int.is_Data = unit;
295 unit->reset_handler.is_Node.ln_Name =
296 base->device.dd_Library.lib_Node.ln_Name;
297 unit->reset_handler.is_Code = (APTR)ResetHandler;
298 unit->reset_handler.is_Data = unit;
300 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
303 if(success)
305 /* Create a new task */
307 unit->task = task =
308 AllocMem(sizeof(struct Task), MEMF_PUBLIC | MEMF_CLEAR);
309 if(task == NULL)
310 success = FALSE;
313 if(success)
315 stack = AllocMem(STACK_SIZE, MEMF_PUBLIC);
316 if(stack == NULL)
317 success = FALSE;
320 if(success)
322 /* Initialise and start task */
324 task->tc_Node.ln_Type = NT_TASK;
325 task->tc_Node.ln_Pri = TASK_PRIORITY;
326 task->tc_Node.ln_Name = base->device.dd_Library.lib_Node.ln_Name;
327 task->tc_SPUpper = stack + STACK_SIZE;
328 task->tc_SPLower = stack;
329 task->tc_SPReg = stack + STACK_SIZE;
330 NewList(&task->tc_MemEntry);
332 if(AddTask(task, UnitTask, NULL) == NULL)
333 success = FALSE;
336 if(success)
338 /* Send the unit to the new task */
340 task->tc_UserData = unit;
342 /* Set default wireless options */
344 unit->mode = S2PORT_MANAGED;
347 if(!success)
349 DeleteUnit(unit, base);
350 unit = NULL;
353 return unit;
358 /****i* prism2.device/DeleteUnit *******************************************
360 * NAME
361 * DeleteUnit -- Delete a unit.
363 * SYNOPSIS
364 * DeleteUnit(unit)
366 * VOID DeleteUnit(struct DevUnit *);
368 * FUNCTION
369 * Deletes a unit.
371 * INPUTS
372 * unit - Device unit (may be NULL).
374 * RESULT
375 * None.
377 ****************************************************************************
381 VOID DeleteUnit(struct DevUnit *unit, struct DevBase *base)
383 UBYTE i;
384 struct Task *task;
386 if(unit != NULL)
388 /* Remove task */
390 task = unit->task;
391 if(task != NULL)
393 if(task->tc_UserData != NULL)
395 RemTask(task);
396 FreeMem(task->tc_SPLower, STACK_SIZE);
398 FreeMem(task, sizeof(struct Task));
401 /* Free request queues */
403 for(i = 0; i < REQUEST_QUEUE_COUNT; i++)
405 if(unit->request_ports[i] != NULL)
406 FreeMem(unit->request_ports[i], sizeof(struct MsgPort));
409 /* Go offline */
411 if((unit->flags & UNITF_ONLINE) != 0) /* Needed! */
412 GoOffline(unit, base);
414 /* Clear target SSID */
416 P2SetID(unit, P2_REC_DESIREDSSID, unit->ssid, 0, base);
418 /* Free buffers and unit structure */
420 FreeVec(unit->scan_results_rec);
421 FreeVec(unit->tx_descriptor);
422 FreeVec(unit->rx_descriptor);
423 FreeVec(unit->tx_buffer);
424 FreeVec(unit->rx_buffers);
425 FreeVec(unit->rx_buffer);
427 FreeMem(unit, sizeof(struct DevUnit));
430 return;
435 /****i* prism2.device/InitialiseAdapter ************************************
437 * NAME
438 * InitialiseAdapter
440 * SYNOPSIS
441 * success = InitialiseAdapter(unit, reinsertion)
443 * BOOL InitialiseAdapter(struct DevUnit *, BOOL);
445 * FUNCTION
447 * INPUTS
448 * unit
449 * reinsertion
451 * RESULT
452 * success - Success indicator.
454 ****************************************************************************
458 BOOL InitialiseAdapter(struct DevUnit *unit, BOOL reinsertion,
459 struct DevBase *base)
461 UWORD id, version, revision, i;
462 BOOL success = TRUE, loaded;
463 UBYTE address[ETH_ADDRESSSIZE];
464 WORD length;
466 /* Wait for card to be ready following bus-specific reset, then start
467 it */
469 while((unit->LEWordIn(unit->card, P2_REG_COMMAND)
470 & P2_REG_COMMANDF_BUSY) != 0);
472 P2DoCmd(unit, P2_CMD_INIT, 0, base);
474 /* Determine firmware type */
476 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_NICIDENTITY, base);
477 P2Seek(unit, 1, P2_REC_NICIDENTITY, 4, base);
478 id = unit->LEWordIn(unit->card, P2_REG_DATA1);
479 unit->LEWordIn(unit->card, P2_REG_DATA1);
480 version = unit->LEWordIn(unit->card, P2_REG_DATA1);
481 revision = unit->LEWordIn(unit->card, P2_REG_DATA1);
483 if((id & 0x8000) != 0)
485 if(version == 0)
486 unit->firmware_type = SYMBOL_FIRMWARE;
487 else
488 unit->firmware_type = INTERSIL_FIRMWARE;
490 else
492 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_PRIIDENTITY, base);
493 P2Seek(unit, 1, P2_REC_PRIIDENTITY, 0, base);
494 length = unit->LEWordIn(unit->card, P2_REG_DATA1);
495 if(length == 5)
496 unit->firmware_type = LUCENT_FIRMWARE;
497 else
499 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_STAIDENTITY, base);
500 P2Seek(unit, 1, P2_REC_STAIDENTITY, 4, base);
501 id = unit->LEWordIn(unit->card, P2_REG_DATA1);
502 unit->LEWordIn(unit->card, P2_REG_DATA1);
503 version = unit->LEWordIn(unit->card, P2_REG_DATA1);
504 revision = unit->LEWordIn(unit->card, P2_REG_DATA1);
505 if(version > 1)
506 unit->firmware_type = HERMES2G_FIRMWARE;
507 else
508 unit->firmware_type = HERMES2_FIRMWARE;
512 /* Download firmware if necessary or available */
514 loaded = LoadFirmware(unit, base);
515 if(!loaded && unit->firmware_type >= HERMES2_FIRMWARE)
516 success = FALSE;
518 if(success)
520 /* Determine features, and get offsets of certain fields within frame
521 descriptors */
523 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_STAIDENTITY, base);
524 P2Seek(unit, 1, P2_REC_STAIDENTITY, 4, base);
525 unit->LEWordIn(unit->card, P2_REG_DATA1);
526 unit->LEWordIn(unit->card, P2_REG_DATA1);
527 version = unit->LEWordIn(unit->card, P2_REG_DATA1);
528 revision = unit->LEWordIn(unit->card, P2_REG_DATA1);
530 if(P2GetWord(unit, P2_REC_HASWEP, base) != 0)
531 unit->flags |= UNITF_HASWEP | UNITF_HARDWEP;
533 unit->ethernet_offset = P2_FRM_ETHFRAME;
534 unit->data_offset = P2_FRM_DATA;
535 unit->txcontrol_offset = P2_FRM_TXCONTROL;
536 unit->datalen_offset = P2_FRM_DATALEN;
538 if(unit->firmware_type == LUCENT_FIRMWARE)
540 if(version > 6 || version == 6 && revision >= 6)
541 unit->flags |= UNITF_HASADHOC;
542 if(version >= 9)
544 unit->flags |= UNITF_HASTKIP | UNITF_HARDTKIP;
545 unit->txcontrol_offset = P2_FRM_ALTTXCONTROL;
548 else if(unit->firmware_type >= HERMES2_FIRMWARE)
550 unit->flags |= UNITF_HASADHOC | UNITF_HASTKIP | UNITF_HARDTKIP;
551 unit->ethernet_offset = P2_H2FRM_ETHFRAME;
552 unit->data_offset = P2_H2FRM_DATA;
553 unit->txcontrol_offset = P2_H2FRM_TXCONTROL;
554 unit->datalen_offset = P2_H2FRM_DATALEN;
556 else if(unit->firmware_type == INTERSIL_FIRMWARE)
558 unit->flags |= UNITF_HASADHOC | UNITF_HASWEP;
559 if(version == 1 && revision >= 7)
560 unit->flags |= UNITF_HASTKIP | UNITF_HASCCMP;
563 /* Get default channel and MAC address */
565 unit->channel = P2GetWord(unit, P2_REC_OWNCHNL, base);
566 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_ADDRESS, base);
567 P2Seek(unit, 1, P2_REC_ADDRESS, 4, base);
568 unit->WordsIn(unit->card, P2_REG_DATA1, (UWORD *)address,
569 ETH_ADDRESSSIZE / 2);
571 /* If card has been re-inserted, check it has the same address as
572 before */
574 if(reinsertion)
576 for(i = 0; i < ETH_ADDRESSSIZE; i++)
577 if(address[i] != unit->default_address[i])
578 success = FALSE;
582 if(success)
584 CopyMem(address, unit->default_address, ETH_ADDRESSSIZE);
586 /* Get initial on-card TX buffer */
588 unit->tx_frame_id = P2AllocMem(unit, FRAME_BUFFER_SIZE, base);
590 /* Set IV sizes */
592 if((unit->flags & UNITF_HARDWEP) == 0)
593 unit->iv_sizes[S2ENC_WEP] = IV_SIZE;
594 if((unit->flags & UNITF_HARDTKIP) == 0)
595 unit->iv_sizes[S2ENC_TKIP] = EIV_SIZE;
596 unit->iv_sizes[S2ENC_CCMP] = EIV_SIZE;
598 /* Set encryption functions */
600 unit->fragment_encrypt_functions[S2ENC_NONE] = WriteClearFragment;
602 if((unit->flags & UNITF_HARDWEP) != 0)
603 unit->fragment_encrypt_functions[S2ENC_WEP] = WriteClearFragment;
604 else
605 unit->fragment_encrypt_functions[S2ENC_WEP] = EncryptWEPFragment;
607 if((unit->flags & UNITF_HARDTKIP) != 0)
608 unit->fragment_encrypt_functions[S2ENC_TKIP] = WriteClearFragment;
609 else
610 unit->fragment_encrypt_functions[S2ENC_TKIP] = EncryptTKIPFragment;
612 unit->fragment_encrypt_functions[S2ENC_CCMP] = EncryptCCMPFragment;
614 /* Set decryption functions */
616 unit->fragment_decrypt_functions[S2ENC_NONE] = ReadClearFragment;
618 if((unit->flags & UNITF_HARDWEP) != 0)
619 unit->fragment_decrypt_functions[S2ENC_WEP] = ReadClearFragment;
620 else
621 unit->fragment_decrypt_functions[S2ENC_WEP] = DecryptWEPFragment;
623 if((unit->flags & UNITF_HARDTKIP) != 0)
624 unit->fragment_decrypt_functions[S2ENC_TKIP] = ReadClearFragment;
625 else
626 unit->fragment_decrypt_functions[S2ENC_TKIP] = DecryptTKIPFragment;
628 unit->fragment_decrypt_functions[S2ENC_CCMP] = DecryptCCMPFragment;
631 /* Return */
633 return success;
638 /****i* prism2.device/ConfigureAdapter *************************************
640 * NAME
641 * ConfigureAdapter -- Set up card for transmission/reception.
643 * SYNOPSIS
644 * ConfigureAdapter(unit)
646 * VOID ConfigureAdapter(struct DevUnit *);
648 ****************************************************************************
652 VOID ConfigureAdapter(struct DevUnit *unit, struct DevBase *base)
654 UWORD i, key_length, port_type, lowest_enc = S2ENC_CCMP,
655 highest_enc = S2ENC_NONE, enc_flags, size, value;
656 const struct KeyUnion *keys;
658 /* Set MAC address */
660 P2SetData(unit, P2_REC_ADDRESS, unit->address, ETH_ADDRESSSIZE,
661 base);
663 /* Decide on promiscuous mode */
665 P2SetWord(unit, P2_REC_PROMISC, FALSE, base);
666 SetMulticast(unit, base);
668 /* Set wireless parameters */
670 if(unit->mode == S2PORT_ADHOC)
672 P2SetWord(unit, P2_REC_OWNCHNL, unit->channel, base);
673 P2SetID(unit, P2_REC_OWNSSID, unit->ssid, unit->ssid_length, base);
675 if(unit->mode == S2PORT_MANAGED)
676 port_type = 1;
677 else
678 port_type = 0;
679 if((unit->flags & UNITF_ONLINE) == 0)
680 P2SetWord(unit, P2_REC_PORTTYPE, port_type, base);
681 P2SetWord(unit, P2_REC_CREATEIBSS, unit->mode == S2PORT_ADHOC, base);
682 P2SetID(unit, P2_REC_DESIREDSSID, unit->ssid, unit->ssid_length, base);
684 /* Determine highest encryption type in use */
686 for(i = 0; i < WIFI_KEYCOUNT; i++)
688 if(unit->keys[i].type > highest_enc)
689 highest_enc = unit->keys[i].type;
690 if(unit->keys[i].type < lowest_enc)
691 lowest_enc = unit->keys[i].type;
694 if(unit->wpa_ie[1] != 0)
695 highest_enc = S2ENC_TKIP; // TO DO: Be more specific?
697 /* Allow reception of beacon/probe-response frames */
699 if(unit->firmware_type == INTERSIL_FIRMWARE)
700 P2SetWord(unit, P2_REC_RXMGMTFRAMES, 1, base);
702 /* Transmit at 11Mbps, with fallback */
704 if(unit->firmware_type == INTERSIL_FIRMWARE
705 || unit->firmware_type == SYMBOL_FIRMWARE)
706 P2SetWord(unit, P2_REC_TXRATE, 0xf, base);
708 /* Configure authentication and encryption */
710 if(unit->firmware_type >= LUCENT_FIRMWARE)
712 /* Set authentication and encryption modes */
714 P2SetWord(unit, P2_REC_ALTAUTHTYPE, unit->auth_types, base);
716 P2SetWord(unit, P2_REC_ALTENCRYPTION, highest_enc, base);
718 /* Set up firmware-based WEP encryption if appropriate */
720 if(highest_enc == S2ENC_WEP && (unit->flags & UNITF_HARDWEP) != 0)
722 P2SetWord(unit, P2_REC_ALTTXCRYPTKEY, unit->tx_key_no, base);
723 P2Seek(unit, 1, P2_REC_DEFLTCRYPTKEYS, 0, base);
724 unit->LEWordOut(unit->card, P2_REG_DATA1, P2_ALTWEPRECLEN);
725 unit->LEWordOut(unit->card, P2_REG_DATA1, P2_REC_DEFLTCRYPTKEYS);
726 keys = unit->keys;
727 for(i = 0; i < WIFI_KEYCOUNT; i++)
729 key_length = keys[i].u.wep.length;
730 if(key_length == 0)
731 key_length = WIFI_WEP128LEN;
732 unit->LEWordOut(unit->card, P2_REG_DATA1, key_length);
733 unit->WordsOut(unit->card, P2_REG_DATA1,
734 (UWORD *)keys[i].u.wep.key, (key_length + 1) / 2);
737 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE,
738 P2_REC_DEFLTCRYPTKEYS, base);
741 /* Set key management suite to PSK */
743 if(highest_enc > S2ENC_WEP)
745 value = (unit->firmware_type >= HERMES2_FIRMWARE) ? 4 : 2;
746 P2SetWord(unit, P2_REC_KEYMGMTSUITE, value, base);
749 else
751 /* Set authentication mode */
753 P2SetWord(unit, P2_REC_AUTHTYPE, unit->auth_types, base);
755 /* Set encryption flags */
757 if(highest_enc > S2ENC_NONE)
758 enc_flags = P2_REC_ENCRYPTIONF_ENABLE;
759 else
760 enc_flags = 0;
762 if(highest_enc > S2ENC_WEP
763 || highest_enc == S2ENC_WEP && (unit->flags & UNITF_HARDWEP) == 0)
764 enc_flags |= P2_REC_ENCRYPTIONF_HOSTDECRYPT
765 | P2_REC_ENCRYPTIONF_HOSTENCRYPT;
766 P2SetWord(unit, P2_REC_ENCRYPTION, enc_flags, base);
768 /* Set up firmware-based WEP encryption if appropriate */
770 if(highest_enc == S2ENC_WEP && (unit->flags & UNITF_HARDWEP) != 0)
772 P2SetWord(unit, P2_REC_TXCRYPTKEY, unit->tx_key_no, base);
774 keys = unit->keys;
775 for(i = 0; i < WIFI_KEYCOUNT; i++)
777 key_length = keys[i].u.wep.length;
778 if(key_length == 0)
779 key_length = keys[unit->tx_key_no].u.wep.length;
780 P2SetData(unit, P2_REC_CRYPTKEY0 + i, keys[i].u.wep.key,
781 key_length, base);
785 /* Set or clear WPA IE */
787 if(highest_enc > S2ENC_WEP)
788 size = unit->wpa_ie[1] + 2;
789 else
790 size = 0;
791 P2SetID(unit, P2_REC_WPAIE, unit->wpa_ie, size, base);
793 /* Let supplicant handle association and roaming */
795 P2SetWord(unit, P2_REC_ROAMINGMODE, 3, base);
798 /* Restart the transceiver if we're already online */
800 if((unit->flags & UNITF_ONLINE) != 0)
802 P2DoCmd(unit, P2_CMD_DISABLE, 0, base);
803 P2DoCmd(unit, P2_CMD_ENABLE, 0, base);
805 /* Attempt to join specified network */
807 if(unit->firmware_type == INTERSIL_FIRMWARE)
809 typedef union { UBYTE b[2]; UWORD w;} BW;
810 BW *p = (BW*)(unit->bssid + ETH_ADDRESSSIZE);
811 p->w = MakeLEWord(unit->channel);
812 P2SetData(unit, P2_REC_JOIN, unit->bssid, ETH_ADDRESSSIZE + 2,
813 base);
817 /* Return */
819 return;
824 /****i* prism2.device/GoOnline *********************************************
826 * NAME
827 * GoOnline -- Enable transmission/reception.
829 * SYNOPSIS
830 * GoOnline(unit)
832 * VOID GoOnline(struct DevUnit *);
834 ****************************************************************************
838 VOID GoOnline(struct DevUnit *unit, struct DevBase *base)
840 /* Enable interrupts */
842 unit->flags |= UNITF_ONLINE;
843 unit->LEWordOut(unit->card, P2_REG_INTMASK, INT_MASK);
845 /* Enable the transceiver */
847 P2DoCmd(unit, P2_CMD_ENABLE, 0, base);
849 /* Record start time and report Online event */
851 GetSysTime(&unit->stats.LastStart);
852 ReportEvents(unit, S2EVENT_ONLINE, base);
854 return;
859 /****i* prism2.device/GoOffline ********************************************
861 * NAME
862 * GoOffline -- Disable transmission/reception.
864 * SYNOPSIS
865 * GoOffline(unit)
867 * VOID GoOffline(struct DevUnit *);
869 * FUNCTION
871 * INPUTS
872 * unit
874 * RESULT
875 * None.
877 ****************************************************************************
881 VOID GoOffline(struct DevUnit *unit, struct DevBase *base)
883 unit->flags &= ~UNITF_ONLINE;
884 if((unit->flags & UNITF_HAVEADAPTER) != 0)
886 /* Stop interrupts */
888 unit->LEWordOut(unit->card, P2_REG_INTMASK, 0);
889 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
891 /* Update statistics */
893 UpdateStats(unit, base);
895 /* Stop transmission and reception */
897 P2DoCmd(unit, P2_CMD_DISABLE, 0, base);
900 /* Flush pending read and write requests */
902 FlushUnit(unit, WRITE_QUEUE, S2ERR_OUTOFSERVICE, base);
904 /* Report Offline event and return */
906 ReportEvents(unit, S2EVENT_OFFLINE, base);
907 return;
912 /****i* prism2.device/SetOptions *******************************************
914 * NAME
915 * SetOptions -- Set and use interface options.
917 * SYNOPSIS
918 * SetOptions(unit, tag_list)
920 * VOID SetOptions(struct DevUnit *, struct TagItem *);
922 ****************************************************************************
926 VOID SetOptions(struct DevUnit *unit, const struct TagItem *tag_list,
927 struct DevBase *base)
929 struct TagItem *tag_item, *tlist = (struct TagItem *)tag_list;
930 const TEXT *id;
931 UPINT length;
932 const UBYTE *ie;
934 while((tag_item = NextTagItem(&tlist)) != NULL)
936 switch(tag_item->ti_Tag)
938 case S2INFO_SSID:
939 id = (const TEXT *)tag_item->ti_Data;
940 length = StrLen(id);
941 CopyMem(id, unit->ssid, length);
942 unit->ssid_length = length;
943 break;
945 case S2INFO_BSSID:
946 CopyMem((APTR)tag_item->ti_Data, unit->bssid, ETH_ADDRESSSIZE);
947 break;
949 case S2INFO_DefaultKeyNo:
950 unit->tx_key_no = tag_item->ti_Data;
951 break;
953 case S2INFO_PortType:
954 unit->mode = tag_item->ti_Data;
955 break;
957 case S2INFO_Channel:
958 if(tag_item->ti_Data != 0) // ???
959 unit->channel = tag_item->ti_Data;
960 break;
962 case S2INFO_WPAInfo:
963 if(tag_item->ti_Data != (UPINT)NULL)
965 /* Hermes-II uses an "unusual" WPA IE in its association
966 request. So we use a matching IE everywhere else too */
968 if(unit->firmware_type >= HERMES2_FIRMWARE)
969 ie = h2_wpa_ie;
970 else
971 ie = (const UBYTE *)tag_item->ti_Data;
972 CopyMem(ie, unit->wpa_ie, ie[1] + 2);
974 else
976 unit->wpa_ie[0] = 0;
977 unit->wpa_ie[1] = 0;
979 break;
981 case S2INFO_AuthTypes:
982 unit->auth_types = tag_item->ti_Data;
983 break;
987 return;
992 /****i* prism2.device/SetKey ***********************************************
994 * NAME
995 * SetKey -- Set an encryption key.
997 * SYNOPSIS
998 * SetKey(unit, index, type, key, key_length,
999 * rx_counter)
1001 * VOID SetKey(struct DevUnit *, ULONG, ULONG, UBYTE *, ULONG,
1002 * UBYTE *);
1004 ****************************************************************************
1008 VOID SetKey(struct DevUnit *unit, ULONG index, ULONG type, const UBYTE *key,
1009 ULONG key_length, const UBYTE *rx_counter, struct DevBase *base)
1011 struct KeyUnion *slot;
1012 const UBYTE tx_counter[8] = {0, 0, 0, 0, 0x10, 0, 0, 0};
1013 UWORD i;
1014 struct EClockVal eclock;
1016 Disable();
1017 slot = &unit->keys[index];
1018 switch(type)
1020 case S2ENC_WEP:
1021 CopyMem(key, slot->u.wep.key, key_length);
1022 slot->u.wep.length = key_length;
1024 if((unit->flags & UNITF_HARDWEP) == 0)
1026 /* Create a reasonably random IV */
1028 ReadEClock(&eclock);
1029 slot->u.wep.tx_iv = FastRand(eclock.ev_lo ^ eclock.ev_hi);
1032 break;
1034 case S2ENC_TKIP:
1035 CopyMem(key, slot->u.tkip.key, 16);
1036 CopyMem(key + 16, slot->u.tkip.tx_mic_key, MIC_SIZE);
1037 CopyMem(key + 24, slot->u.tkip.rx_mic_key, MIC_SIZE);
1038 slot->u.tkip.tx_iv_low = 0;
1039 slot->u.tkip.tx_iv_high = 0;
1040 slot->u.tkip.rx_iv_low = LEWord(*(UWORD *)rx_counter);
1041 slot->u.tkip.rx_iv_high = LELong(*(ULONG *)(rx_counter + 2));
1042 slot->u.tkip.tx_ttak_set = FALSE;
1043 slot->u.tkip.rx_ttak_set = FALSE;
1045 if((unit->flags & UNITF_HARDTKIP) != 0)
1047 /* For Hermes, load parameters for hardware encryption. The
1048 pairwise key is treated differently from group keys on
1049 Hermes-II, but not on Hermes-I */
1051 if(unit->firmware_type >= HERMES2_FIRMWARE && index == 0)
1053 P2Seek(unit, 1, P2_REC_ADDMAPPEDTKIPKEY, 0, base);
1054 unit->LEWordOut(unit->card, P2_REG_DATA1, 28);
1055 unit->LEWordOut(unit->card, P2_REG_DATA1,
1056 P2_REC_ADDMAPPEDTKIPKEY);
1057 unit->WordsOut(unit->card, P2_REG_DATA1,
1058 (UWORD *)unit->bssid, ETH_ADDRESSSIZE / 2);
1059 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)key,
1060 16 / 2);
1061 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)tx_counter,
1062 8 / 2);
1063 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)rx_counter,
1064 6 / 2);
1065 unit->LEWordOut(unit->card, P2_REG_DATA1, 0);
1066 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)key + 16,
1067 16 / 2);
1068 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE,
1069 P2_REC_ADDMAPPEDTKIPKEY, base);
1071 else
1073 P2Seek(unit, 1, P2_REC_ADDDEFAULTTKIPKEY, 0, base);
1074 unit->LEWordOut(unit->card, P2_REG_DATA1, 26);
1075 unit->LEWordOut(unit->card, P2_REG_DATA1,
1076 P2_REC_ADDDEFAULTTKIPKEY);
1077 if(index == unit->tx_key_no)
1078 index |= 0x8000;
1079 unit->LEWordOut(unit->card, P2_REG_DATA1, index);
1080 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)rx_counter,
1081 6 / 2);
1082 unit->LEWordOut(unit->card, P2_REG_DATA1, 0);
1083 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)key,
1084 32 / 2);
1085 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)tx_counter,
1086 8 / 2);
1087 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE,
1088 P2_REC_ADDDEFAULTTKIPKEY, base);
1091 else
1093 /* Convert key to native endianness */
1095 for(i = 0; i < 8; i++)
1096 slot->u.tkip.key[i] = LEWord(slot->u.tkip.key[i]);
1099 break;
1101 case S2ENC_CCMP:
1102 CopyMem(key, slot->u.ccmp.key, 16);
1103 slot->u.ccmp.tx_iv_low = 0;
1104 slot->u.ccmp.tx_iv_high = 0;
1105 slot->u.ccmp.rx_iv_low = LEWord(*(UWORD *)rx_counter);
1106 slot->u.ccmp.rx_iv_high = LELong(*(ULONG *)(rx_counter + 2));
1107 slot->u.ccmp.stream_set = FALSE;
1110 /* Clear TKIP key if necessary */
1112 if(slot->type == S2ENC_TKIP && type != S2ENC_TKIP)
1114 if(unit->firmware_type >= HERMES2_FIRMWARE && index == 0)
1115 P2SetData(unit, P2_REC_REMMAPPEDTKIPKEY, unit->bssid,
1116 ETH_ADDRESSSIZE, base);
1117 else if(unit->firmware_type >= LUCENT_FIRMWARE)
1118 P2SetWord(unit, P2_REC_REMDEFAULTTKIPKEY, index, base);
1121 /* Update type of key in selected slot */
1123 slot->type = type;
1124 Enable();
1126 return;
1131 /****i* prism2.device/AddMulticastRange ************************************
1133 * NAME
1134 * AddMulticastRange
1136 * SYNOPSIS
1137 * success = AddMulticastRange(unit, lower_bound, upper_bound)
1139 * BOOL AddMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1141 ****************************************************************************
1145 BOOL AddMulticastRange(struct DevUnit *unit, const UBYTE *lower_bound,
1146 const UBYTE *upper_bound, struct DevBase *base)
1148 struct AddressRange *range;
1149 ULONG lower_bound_left, upper_bound_left;
1150 UWORD lower_bound_right, upper_bound_right;
1152 lower_bound_left = BELong(*((ULONG *)lower_bound));
1153 lower_bound_right = BEWord(*((UWORD *)(lower_bound + 4)));
1154 upper_bound_left = BELong(*((ULONG *)upper_bound));
1155 upper_bound_right = BEWord(*((UWORD *)(upper_bound + 4)));
1157 range = FindMulticastRange(unit, lower_bound_left, lower_bound_right,
1158 upper_bound_left, upper_bound_right, base);
1160 if(range != NULL)
1161 range->add_count++;
1162 else
1164 range = AllocMem(sizeof(struct AddressRange), MEMF_PUBLIC);
1165 if(range != NULL)
1167 range->lower_bound_left = lower_bound_left;
1168 range->lower_bound_right = lower_bound_right;
1169 range->upper_bound_left = upper_bound_left;
1170 range->upper_bound_right = upper_bound_right;
1171 range->add_count = 1;
1173 Disable();
1174 AddTail((APTR)&unit->multicast_ranges, (APTR)range);
1175 unit->range_count++;
1176 SetMulticast(unit, base);
1177 Enable();
1181 return range != NULL;
1186 /****i* prism2.device/RemMulticastRange ************************************
1188 * NAME
1189 * RemMulticastRange
1191 * SYNOPSIS
1192 * found = RemMulticastRange(unit, lower_bound, upper_bound)
1194 * BOOL RemMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1196 ****************************************************************************
1200 BOOL RemMulticastRange(struct DevUnit *unit, const UBYTE *lower_bound,
1201 const UBYTE *upper_bound, struct DevBase *base)
1203 struct AddressRange *range;
1204 ULONG lower_bound_left, upper_bound_left;
1205 UWORD lower_bound_right, upper_bound_right;
1207 lower_bound_left = BELong(*((ULONG *)lower_bound));
1208 lower_bound_right = BEWord(*((UWORD *)(lower_bound + 4)));
1209 upper_bound_left = BELong(*((ULONG *)upper_bound));
1210 upper_bound_right = BEWord(*((UWORD *)(upper_bound + 4)));
1212 range = FindMulticastRange(unit, lower_bound_left, lower_bound_right,
1213 upper_bound_left, upper_bound_right, base);
1215 if(range != NULL)
1217 if(--range->add_count == 0)
1219 Disable();
1220 Remove((APTR)range);
1221 unit->range_count--;
1222 SetMulticast(unit, base);
1223 Enable();
1224 FreeMem(range, sizeof(struct AddressRange));
1228 return range != NULL;
1233 /****i* prism2.device/FindMulticastRange ***********************************
1235 * NAME
1236 * FindMulticastRange
1238 * SYNOPSIS
1239 * range = FindMulticastRange(unit, lower_bound_left,
1240 * lower_bound_right, upper_bound_left, upper_bound_right)
1242 * struct AddressRange *FindMulticastRange(struct DevUnit *, ULONG,
1243 * UWORD, ULONG, UWORD);
1245 ****************************************************************************
1249 static struct AddressRange *FindMulticastRange(struct DevUnit *unit,
1250 ULONG lower_bound_left, UWORD lower_bound_right, ULONG upper_bound_left,
1251 UWORD upper_bound_right, struct DevBase *base)
1253 struct AddressRange *range, *tail;
1254 BOOL found = FALSE;
1256 range = (APTR)unit->multicast_ranges.mlh_Head;
1257 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
1259 while(range != tail && !found)
1261 if(lower_bound_left == range->lower_bound_left &&
1262 lower_bound_right == range->lower_bound_right &&
1263 upper_bound_left == range->upper_bound_left &&
1264 upper_bound_right == range->upper_bound_right)
1265 found = TRUE;
1266 else
1267 range = (APTR)range->node.mln_Succ;
1270 if(!found)
1271 range = NULL;
1273 return range;
1278 /****i* prism2.device/SetMulticast *****************************************
1280 * NAME
1281 * SetMulticast
1283 * SYNOPSIS
1284 * SetMulticast(unit)
1286 * VOID SetMulticast(struct DevUnit *);
1288 ****************************************************************************
1292 static VOID SetMulticast(struct DevUnit *unit, struct DevBase *base)
1294 ULONG address_left;
1295 UWORD address_right, i = 0;
1296 struct AddressRange *range, *tail;
1297 BOOL range_ended;
1299 /* Fill in multicast list */
1301 P2Seek(unit, 1, P2_REC_MCASTLIST, 4, base);
1303 range = (APTR)unit->multicast_ranges.mlh_Head;
1304 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
1306 while(range != tail && i < P2_MAXMCASTENTRIES)
1308 address_left = range->lower_bound_left;
1309 address_right = range->lower_bound_right;
1310 range_ended = FALSE;
1312 while(!range_ended && i++ < P2_MAXMCASTENTRIES)
1314 unit->BEWordOut(unit->card, P2_REG_DATA1,
1315 (UWORD)(address_left >> 16));
1316 unit->BEWordOut(unit->card, P2_REG_DATA1, (UWORD)address_left);
1317 unit->BEWordOut(unit->card, P2_REG_DATA1, (UWORD)address_right);
1319 if(address_left == range->upper_bound_left &&
1320 address_right == range->upper_bound_right)
1321 range_ended = TRUE;
1322 if(++address_right == 0)
1323 address_left++;
1326 if(range_ended)
1327 range = (APTR)range->node.mln_Succ;
1330 /* Turn promiscuous mode on or off depending on the previous state and
1331 whether we've overflowed the multicast list */
1333 if((unit->flags & UNITF_PROM) == 0)
1335 if(range != tail)
1337 if((unit->flags & UNITF_ALLMCAST) == 0)
1339 P2SetWord(unit, P2_REC_PROMISC, TRUE, base);
1340 unit->flags |= UNITF_ALLMCAST;
1343 else
1345 if((unit->flags & UNITF_ALLMCAST) != 0)
1347 P2SetWord(unit, P2_REC_PROMISC, FALSE, base);
1348 unit->flags &= ~UNITF_ALLMCAST;
1351 /* Only commit multicast list if promiscuity is off */
1353 P2Seek(unit, 1, P2_REC_MCASTLIST, 0, base);
1354 unit->LEWordOut(unit->card, P2_REG_DATA1,
1355 1 + ETH_ADDRESSSIZE / 2 * i);
1356 unit->LEWordOut(unit->card, P2_REG_DATA1, P2_REC_MCASTLIST);
1357 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, P2_REC_MCASTLIST,
1358 base);
1362 return;
1367 /****i* prism2.device/FindTypeStats ****************************************
1369 * NAME
1370 * FindTypeStats
1372 * SYNOPSIS
1373 * stats = FindTypeStats(unit, list,
1374 * packet_type)
1376 * struct TypeStats *FindTypeStats(struct DevUnit *, struct MinList *,
1377 * ULONG);
1379 ****************************************************************************
1383 struct TypeStats *FindTypeStats(struct DevUnit *unit, struct MinList *list,
1384 ULONG packet_type, struct DevBase *base)
1386 struct TypeStats *stats, *tail;
1387 BOOL found = FALSE;
1389 stats = (APTR)list->mlh_Head;
1390 tail = (APTR)&list->mlh_Tail;
1392 while(stats != tail && !found)
1394 if(stats->packet_type == packet_type)
1395 found = TRUE;
1396 else
1397 stats = (APTR)stats->node.mln_Succ;
1400 if(!found)
1401 stats = NULL;
1403 return stats;
1408 /****i* prism2.device/FlushUnit ********************************************
1410 * NAME
1411 * FlushUnit
1413 * SYNOPSIS
1414 * FlushUnit(unit, last_queue, error)
1416 * VOID FlushUnit(struct DevUnit *, UBYTE, BYTE);
1418 ****************************************************************************
1422 VOID FlushUnit(struct DevUnit *unit, UBYTE last_queue, BYTE error,
1423 struct DevBase *base)
1425 struct IORequest *request;
1426 UBYTE i;
1427 struct Opener *opener, *tail;
1429 /* Abort queued requests */
1431 for(i = 0; i <= last_queue; i++)
1433 while((request = (APTR)GetMsg(unit->request_ports[i])) != NULL)
1435 request->io_Error = error;
1436 ReplyMsg((APTR)request);
1440 #if 1
1441 opener = (APTR)unit->openers.mlh_Head;
1442 tail = (APTR)&unit->openers.mlh_Tail;
1444 /* Flush every opener's read queue */
1446 while(opener != tail)
1448 while((request = (APTR)GetMsg(&opener->read_port)) != NULL)
1450 request->io_Error = error;
1451 ReplyMsg((APTR)request);
1453 opener = (APTR)opener->node.mln_Succ;
1456 #else
1457 opener = request->ios2_BufferManagement;
1458 while((request = (APTR)GetMsg(&opener->read_port)) != NULL)
1460 request->io_Error = error;
1461 ReplyMsg((APTR)request);
1463 #endif
1465 /* Return */
1467 return;
1472 /****i* prism2.device/StatusInt ********************************************
1474 * NAME
1475 * StatusInt
1477 * SYNOPSIS
1478 * finished = StatusInt(unit)
1480 * BOOL StatusInt(struct DevUnit *);
1482 * FUNCTION
1484 * INPUTS
1485 * unit
1487 * RESULT
1488 * finished
1490 ****************************************************************************
1492 * int_code is really in A5, but GCC 2.95.3 doesn't seem able to handle that.
1493 * Since we don't use this parameter, we can lie.
1497 BOOL StatusInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
1499 struct DevBase *base;
1500 UWORD events, int_mask;
1502 base = unit->device;
1503 events = unit->LEWordIn(unit->card, P2_REG_EVENTS);
1505 /* Turning off ints acknowledges the request? */
1507 int_mask = unit->LEWordIn(unit->card, P2_REG_INTMASK);
1508 unit->LEWordOut(unit->card, P2_REG_INTMASK, 0);
1510 /* Handle events */
1512 if((events & P2_EVENTF_INFO) != 0)
1514 int_mask &= ~P2_EVENTF_INFO;
1515 Cause(&unit->info_int);
1517 if((events & P2_EVENTF_RX) != 0)
1519 int_mask &= ~P2_EVENTF_RX;
1520 Cause(&unit->rx_int);
1522 if((events & P2_EVENTF_ALLOCMEM) != 0)
1524 unit->tx_frame_id = unit->LEWordIn(unit->card, P2_REG_ALLOCFID);
1525 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_ALLOCMEM);
1526 Cause(&unit->tx_int);
1528 if((events & P2_EVENTF_TXFAIL) != 0)
1530 ReportEvents(unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_TX,
1531 base);
1532 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_TXFAIL);
1535 #ifdef __MORPHOS__
1536 int_mask = INT_MASK;
1537 #endif
1538 unit->LEWordOut(unit->card, P2_REG_INTMASK, int_mask);
1540 return FALSE;
1545 /****i* prism2.device/RXInt ************************************************
1547 * NAME
1548 * RXInt -- Soft interrupt for packet reception.
1550 * SYNOPSIS
1551 * RXInt(unit)
1553 * VOID RXInt(struct DevUnit *);
1555 * FUNCTION
1557 * INPUTS
1558 * unit - A unit of this device.
1560 * RESULT
1561 * None.
1563 ****************************************************************************
1567 static VOID RXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
1569 UWORD frame_status, frame_id, ieee_length, frame_control, frame_type,
1570 frame_subtype, encryption, key_no, buffer_no, old_length;
1571 struct DevBase *base;
1572 BOOL is_good;
1573 LONG frag_no;
1574 UBYTE *buffer, *p, *frame, *data;
1576 base = unit->device;
1578 while((unit->LEWordIn(unit->card, P2_REG_EVENTS) & P2_EVENTF_RX) != 0)
1580 is_good = TRUE;
1581 frame_id = unit->LEWordIn(unit->card, P2_REG_RXFID);
1582 P2Seek(unit, 1, frame_id, P2_FRM_STATUS, base);
1583 frame_status = unit->LEWordIn(unit->card, P2_REG_DATA1);
1585 if((frame_status & (P2_FRM_STATUSF_BADCRYPT | P2_FRM_STATUSF_BADCRC))
1586 == 0)
1588 /* Read frame descriptor from card */
1590 P2Seek(unit, 1, frame_id, 0, base);
1591 unit->WordsIn(unit->card, P2_REG_DATA1,
1592 (UWORD *)unit->rx_descriptor,
1593 (unit->ethernet_offset + ETH_HEADERSIZE) / 2);
1594 frame = unit->rx_descriptor + unit->ethernet_offset;
1595 ieee_length = BEWord(*(UWORD *)(frame + ETH_PACKET_IEEELEN));
1596 data = frame + ETH_PACKET_DATA;
1597 unit->WordsIn(unit->card, P2_REG_DATA1, (UWORD *)data,
1598 (ieee_length + MIC_SIZE + 1) / 2);
1599 frame_control =
1600 LEWord(*(UWORD *)(unit->rx_descriptor + P2_FRM_HEADER));
1602 /* Get buffer to store fragment in */
1604 frag_no = LEWord(*(UWORD *)(unit->rx_descriptor + P2_FRM_HEADER
1605 + WIFI_FRM_SEQCONTROL));
1606 buffer = GetRXBuffer(unit, frame + ETH_PACKET_SOURCE, frag_no,
1607 &buffer_no, base);
1609 /* Get location to put new data */
1611 if(buffer != NULL)
1613 if((frag_no & 0xf ) > 0)
1614 old_length = BEWord(*(UWORD *)(buffer + ETH_PACKET_IEEELEN));
1615 else
1617 /* Copy header to new frame */
1619 CopyMem(frame, buffer, ETH_HEADERSIZE);
1620 old_length = 0;
1622 p = buffer + ETH_HEADERSIZE + old_length;
1624 /* Get encryption type and key index */
1626 if((frame_control & WIFI_FRM_CONTROLF_WEP) != 0)
1628 key_no = data[3] >> 6 & 0x3;
1629 encryption = unit->keys[key_no].type;
1631 else
1632 encryption = S2ENC_NONE;
1634 /* Append fragment to frame, decrypting/checking fragment if
1635 necessary */
1637 is_good = unit->fragment_decrypt_functions[encryption](unit,
1638 unit->rx_descriptor + P2_FRM_HEADER, data, &ieee_length, p,
1639 base);
1641 /* Update length in frame being built with current fragment, or
1642 increment bad frame counter if fragment is bad */
1644 if(is_good)
1646 ieee_length += old_length;
1647 *(UWORD *)(buffer + ETH_PACKET_IEEELEN) =
1648 MakeBEWord(ieee_length);
1650 else
1651 unit->stats.BadData++;
1653 /* If all fragments have arrived, process the complete frame */
1655 if((frame_control & WIFI_FRM_CONTROLF_MOREFRAGS) == 0)
1657 if(is_good)
1659 /* Decrypt complete frame if necessary */
1661 data = buffer + ETH_HEADERSIZE;
1662 if(encryption == S2ENC_TKIP)
1664 /* Hermes cards don't include MIC in frame length, so
1665 we need to grab the MIC from the original RX
1666 descriptor here */
1668 if(unit->firmware_type >= LUCENT_FIRMWARE)
1670 CopyMem(frame + ETH_PACKET_DATA + ieee_length,
1671 data + ieee_length, MIC_SIZE);
1672 ieee_length += MIC_SIZE;
1675 /* Check Michael MIC */
1677 #ifndef __mc68000
1678 is_good = TKIPDecryptFrame(unit, buffer, data,
1679 ieee_length, data, key_no, base);
1680 #endif
1681 ieee_length -= MIC_SIZE;
1682 *(UWORD *)(buffer + ETH_PACKET_IEEELEN) =
1683 MakeBEWord(ieee_length);
1684 if(!is_good)
1685 unit->stats.BadData++;
1689 if(is_good)
1691 /* Get frame's 802.11 type and subtype */
1693 frame_type = (frame_control & WIFI_FRM_CONTROLF_TYPE)
1694 >> WIFI_FRM_CONTROLB_TYPE;
1695 frame_subtype =
1696 (frame_control & WIFI_FRM_CONTROLF_SUBTYPE)
1697 >> WIFI_FRM_CONTROLB_SUBTYPE;
1699 /* If it's a management frame, process it internally;
1700 otherwise distribute it to clients after filtering */
1702 if(frame_type == WIFI_FRMTYPE_MGMT)
1704 if(frame_subtype == 0x5)
1706 CopyMem(unit->rx_descriptor + P2_FRM_HEADER
1707 + WIFI_FRM_ADDRESS3, buffer + ETH_PACKET_SOURCE,
1708 ETH_ADDRESSSIZE);
1709 SaveBeacon(unit, buffer, base);
1712 else if(AddressFilter(unit, buffer + ETH_PACKET_DEST,
1713 base))
1715 unit->stats.PacketsReceived++;
1716 DistributeRXPacket(unit, buffer, base);
1721 /* Mark fragment buffer as unused for next time */
1723 unit->rx_fragment_nos[buffer_no] = -1;
1725 else
1726 ReportEvents(unit, S2EVENT_ERROR | S2EVENT_RX, base);
1728 else
1730 is_good = FALSE;
1733 if(!is_good)
1735 ReportEvents(unit, S2EVENT_ERROR | S2EVENT_HARDWARE | S2EVENT_RX,
1736 base);
1739 /* Discard packet */
1741 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_RX);
1744 /* Re-enable RX interrupts */
1746 Disable();
1747 unit->LEWordOut(unit->card, P2_REG_INTMASK,
1748 unit->LEWordIn(unit->card, P2_REG_INTMASK) | P2_EVENTF_RX);
1749 Enable();
1751 return;
1756 /****i* prism2.device/GetRXBuffer ******************************************
1758 * NAME
1759 * GetRXBuffer -- Find an appropriate RX buffer to use.
1761 * SYNOPSIS
1762 * buffer = GetRXBuffer(unit, address, frag_no)
1764 * UBYTE *GetRXBuffer(struct DevUnit *, UBYTE *, UWORD);
1766 ****************************************************************************
1770 static UBYTE *GetRXBuffer(struct DevUnit *unit, const UBYTE *address,
1771 UWORD frag_no, UWORD *buffer_no, struct DevBase *base)
1773 UWORD i;
1774 UBYTE *buffer;
1775 LONG n;
1776 BOOL found;
1778 buffer = unit->rx_buffers;
1779 for(i = 0, found = FALSE; i < RX_BUFFER_COUNT * 2 && !found; i++)
1781 /* Throw away old buffer contents if we didn't find a free slot the
1782 first time around */
1784 if(i >= RX_BUFFER_COUNT)
1785 unit->rx_fragment_nos[i % RX_BUFFER_COUNT] = -1;
1787 /* For a frame's first fragment, find an empty slot; for subsequent
1788 fragments, find a slot with matching source address */
1790 n = unit->rx_fragment_nos[i % RX_BUFFER_COUNT];
1791 if(n == -1 && (frag_no & 0xf) == 0
1792 || *((ULONG *)(buffer + ETH_PACKET_SOURCE))
1793 == *((ULONG *)(address))
1794 && *((UWORD *)(buffer + ETH_PACKET_SOURCE + 4))
1795 == *((UWORD *)(address + 4)))
1797 found = TRUE;
1798 if(n == -1)
1799 unit->rx_fragment_nos[i % RX_BUFFER_COUNT] = frag_no;
1800 *buffer_no = i;
1802 else
1803 buffer += FRAME_BUFFER_SIZE;
1806 if(!found)
1807 buffer = NULL;
1809 return buffer;
1814 /****i* prism2.device/DistributeRXPacket ***********************************
1816 * NAME
1817 * DistributeRXPacket -- Send a packet to all appropriate destinations.
1819 * SYNOPSIS
1820 * DistributeRXPacket(unit, frame)
1822 * VOID DistributeRXPacket(struct DevUnit *, UBYTE *);
1824 ****************************************************************************
1828 static VOID DistributeRXPacket(struct DevUnit *unit, UBYTE *frame,
1829 struct DevBase *base)
1831 UWORD packet_size, ieee_length;
1832 BOOL is_orphan = TRUE, accepted, is_snap = FALSE;
1833 ULONG packet_type;
1834 UBYTE *buffer;
1835 const UBYTE *template = snap_template;
1836 struct IOSana2Req *request, *request_tail;
1837 struct Opener *opener, *opener_tail;
1838 struct TypeStats *tracker;
1840 ieee_length = BEWord(*(UWORD *)(frame + ETH_PACKET_IEEELEN));
1841 packet_size = ETH_HEADERSIZE + ieee_length;
1842 if(ieee_length >= SNAP_HEADERSIZE)
1843 is_snap = *(const ULONG *)(frame + ETH_PACKET_DATA)
1844 == *(const ULONG *)template;
1846 /* De-encapsulate SNAP packets and get packet type */
1848 if(is_snap)
1850 buffer = unit->rx_buffer;
1851 packet_size -= SNAP_HEADERSIZE;
1852 CopyMem(frame, buffer, ETH_PACKET_TYPE);
1853 CopyMem(frame + ETH_HEADERSIZE + SNAP_FRM_TYPE,
1854 buffer + ETH_PACKET_TYPE, packet_size - ETH_PACKET_TYPE);
1856 else
1857 buffer = frame;
1859 packet_type = BEWord(*((UWORD *)(buffer + ETH_PACKET_TYPE)));
1861 if(packet_size <= ETH_MAXPACKETSIZE)
1863 /* Offer packet to every opener */
1865 opener = (APTR)unit->openers.mlh_Head;
1866 opener_tail = (APTR)&unit->openers.mlh_Tail;
1868 while(opener != opener_tail)
1870 request = (APTR)opener->read_port.mp_MsgList.lh_Head;
1871 request_tail = (APTR)&opener->read_port.mp_MsgList.lh_Tail;
1872 accepted = FALSE;
1874 /* Offer packet to each request until it's accepted */
1876 while(request != request_tail && !accepted)
1878 if(request->ios2_PacketType == packet_type)
1880 CopyPacket(unit, request, packet_size, packet_type,
1881 buffer, base);
1882 accepted = TRUE;
1884 request =
1885 (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
1888 if(accepted)
1889 is_orphan = FALSE;
1890 opener = (APTR)opener->node.mln_Succ;
1893 /* If packet was unwanted, give it to S2_READORPHAN request */
1895 if(is_orphan)
1897 unit->stats.UnknownTypesReceived++;
1898 if(!IsMsgPortEmpty(unit->request_ports[ADOPT_QUEUE]))
1900 CopyPacket(unit,
1901 (APTR)unit->request_ports[ADOPT_QUEUE]->
1902 mp_MsgList.lh_Head, packet_size, packet_type, buffer,
1903 base);
1907 /* Update remaining statistics */
1909 if(packet_type <= ETH_MTU)
1910 packet_type = ETH_MTU;
1911 tracker =
1912 FindTypeStats(unit, &unit->type_trackers, packet_type, base);
1913 if(tracker != NULL)
1915 tracker->stats.PacketsReceived++;
1916 tracker->stats.BytesReceived += packet_size;
1919 else
1920 unit->stats.BadData++;
1922 return;
1927 /****i* prism2.device/CopyPacket *******************************************
1929 * NAME
1930 * CopyPacket -- Copy packet to client's buffer.
1932 * SYNOPSIS
1933 * CopyPacket(unit, request, packet_size, packet_type,
1934 * buffer)
1936 * VOID CopyPacket(struct DevUnit *, struct IOSana2Req *, UWORD, UWORD,
1937 * UBYTE *);
1939 ****************************************************************************
1943 static VOID CopyPacket(struct DevUnit *unit, struct IOSana2Req *request,
1944 UWORD packet_size, UWORD packet_type, UBYTE *buffer,
1945 struct DevBase *base)
1947 struct Opener *opener;
1948 BOOL filtered = FALSE;
1950 /* Set multicast and broadcast flags */
1952 request->ios2_Req.io_Flags &= ~(SANA2IOF_BCAST | SANA2IOF_MCAST);
1953 if((*((ULONG *)(buffer + ETH_PACKET_DEST)) == 0xffffffff) &&
1954 (*((UWORD *)(buffer + ETH_PACKET_DEST + 4)) == 0xffff))
1955 request->ios2_Req.io_Flags |= SANA2IOF_BCAST;
1956 else if((buffer[ETH_PACKET_DEST] & 0x1) != 0)
1957 request->ios2_Req.io_Flags |= SANA2IOF_MCAST;
1959 /* Set source and destination addresses and packet type */
1961 CopyMem(buffer + ETH_PACKET_SOURCE, request->ios2_SrcAddr,
1962 ETH_ADDRESSSIZE);
1963 CopyMem(buffer + ETH_PACKET_DEST, request->ios2_DstAddr,
1964 ETH_ADDRESSSIZE);
1965 request->ios2_PacketType = packet_type;
1967 /* Adjust for cooked packet request */
1969 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
1971 packet_size -= ETH_PACKET_DATA;
1972 buffer += ETH_PACKET_DATA;
1974 #ifdef USE_HACKS
1975 else
1976 packet_size += 4; /* Needed for Shapeshifter & Fusion */
1977 #endif
1978 request->ios2_DataLength = packet_size;
1980 /* Filter packet */
1982 opener = request->ios2_BufferManagement;
1983 if(request->ios2_Req.io_Command == CMD_READ &&
1984 opener->filter_hook != NULL)
1985 if(!CallHookPkt(opener->filter_hook, request, buffer))
1986 filtered = TRUE;
1988 if(!filtered)
1990 /* Copy packet into opener's buffer and reply packet */
1992 if(!opener->rx_function(request->ios2_Data, buffer, packet_size))
1994 request->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
1995 request->ios2_WireError = S2WERR_BUFF_ERROR;
1996 ReportEvents(unit,
1997 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_RX,
1998 base);
2000 Remove((APTR)request);
2001 ReplyMsg((APTR)request);
2004 return;
2009 /****i* prism2.device/AddressFilter ****************************************
2011 * NAME
2012 * AddressFilter -- Determine if an RX packet should be accepted.
2014 * SYNOPSIS
2015 * accept = AddressFilter(unit, address)
2017 * BOOL AddressFilter(struct DevUnit *, UBYTE *);
2019 ****************************************************************************
2023 static BOOL AddressFilter(struct DevUnit *unit, UBYTE *address,
2024 struct DevBase *base)
2026 struct AddressRange *range, *tail;
2027 BOOL accept = TRUE;
2028 ULONG address_left;
2029 UWORD address_right;
2031 /* Check whether address is unicast/broadcast or multicast */
2033 address_left = BELong(*((ULONG *)address));
2034 address_right = BEWord(*((UWORD *)(address + 4)));
2036 if(((address_left & 0x01000000) != 0) &&
2037 !((address_left == 0xffffffff) && (address_right == 0xffff)))
2039 /* Check if this multicast address is wanted */
2041 range = (APTR)unit->multicast_ranges.mlh_Head;
2042 tail = (APTR)&unit->multicast_ranges.mlh_Tail;
2043 accept = FALSE;
2045 while((range != tail) && !accept)
2047 if((address_left > range->lower_bound_left ||
2048 address_left == range->lower_bound_left &&
2049 address_right >= range->lower_bound_right) &&
2050 (address_left < range->upper_bound_left ||
2051 address_left == range->upper_bound_left &&
2052 address_right <= range->upper_bound_right))
2053 accept = TRUE;
2054 range = (APTR)range->node.mln_Succ;
2057 if(!accept)
2058 unit->special_stats[S2SS_ETHERNET_BADMULTICAST & 0xffff]++;
2061 return accept;
2066 /****i* prism2.device/SaveBeacon *******************************************
2068 * NAME
2069 * SaveBeacon -- Save beacon frame for later examination.
2071 * SYNOPSIS
2072 * SaveBeacon(unit, frame)
2074 * VOID SaveBeacon(struct DevUnit *, UBYTE *);
2076 ****************************************************************************
2080 static VOID SaveBeacon(struct DevUnit *unit, const UBYTE *frame,
2081 struct DevBase *base)
2083 UWORD size;
2085 /* Store frame for later matching with scan results */
2087 size = ETH_HEADERSIZE + BEWord(*(UWORD *)(frame + ETH_PACKET_IEEELEN));
2088 if(unit->next_beacon + size < unit->beacons + BEACON_BUFFER_SIZE)
2090 CopyMem(frame, unit->next_beacon, size);
2091 unit->beacon_count++;
2092 unit->next_beacon += size + sizeof(ULONG) & ~3;
2095 return;
2100 /****i* prism2.device/TXInt ************************************************
2102 * NAME
2103 * TXInt -- Soft interrupt for packet transmission.
2105 * SYNOPSIS
2106 * TXInt(unit)
2108 * VOID TXInt(struct DevUnit *);
2110 * FUNCTION
2112 * INPUTS
2113 * unit - A unit of this device.
2115 * RESULT
2116 * None.
2118 ****************************************************************************
2122 static VOID TXInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
2124 UWORD i, packet_size, send_size, packet_type, data_size, body_size = 0,
2125 frame_id, encryption, control_value, subtype;
2126 UBYTE *buffer, *desc = unit->tx_descriptor, *plaintext, *ciphertext,
2127 *header, mic_header[ETH_ADDRESSSIZE * 2], *q;
2128 const UBYTE *p, *dest, *source;
2129 struct DevBase *base;
2130 struct IOSana2Req *request;
2131 BOOL is_ieee;
2132 struct Opener *opener;
2133 ULONG wire_error;
2134 UBYTE *(*dma_tx_function)(REG(a0, APTR));
2135 BYTE error = 0;
2136 struct MsgPort *port;
2137 struct TypeStats *tracker;
2139 base = unit->device;
2140 port = unit->request_ports[WRITE_QUEUE];
2142 if(unit->tx_frame_id != 0 && !IsMsgPortEmpty(port))
2144 /* Get next request and full packet size */
2146 request = (APTR)port->mp_MsgList.lh_Head;
2147 packet_size = request->ios2_DataLength;
2148 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) == 0)
2149 packet_size += ETH_PACKET_DATA;
2151 /* Determine encryption type and frame subtype */
2153 if(packet_size > ETH_HEADERSIZE)
2155 encryption = unit->keys[unit->tx_key_no].type;
2156 subtype = 0;
2158 else
2160 encryption = S2ENC_NONE;
2161 subtype = 4;
2164 /* Get packet data */
2166 opener = request->ios2_BufferManagement;
2167 dma_tx_function = opener->dma_tx_function;
2168 if(dma_tx_function != NULL)
2169 buffer = dma_tx_function(request->ios2_Data);
2170 else
2171 buffer = NULL;
2173 if(buffer == NULL)
2175 buffer = unit->tx_buffer;
2176 if(!opener->tx_function(buffer, request->ios2_Data,
2177 request->ios2_DataLength))
2179 error = S2ERR_NO_RESOURCES;
2180 wire_error = S2WERR_BUFF_ERROR;
2181 ReportEvents(unit,
2182 S2EVENT_ERROR | S2EVENT_SOFTWARE | S2EVENT_BUFF | S2EVENT_TX,
2183 base);
2187 if(error == 0)
2189 /* Get packet type and/or length */
2191 data_size = request->ios2_DataLength;
2192 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) != 0)
2194 data_size -= ETH_PACKET_DATA;
2195 packet_type = BEWord(*(UWORD *)(buffer + ETH_PACKET_TYPE));
2197 else
2198 packet_type = request->ios2_PacketType;
2199 is_ieee = packet_type <= ETH_MTU;
2201 /* Get source and destination addresses */
2203 if((request->ios2_Req.io_Flags & SANA2IOF_RAW) != 0)
2205 dest = buffer;
2206 source = buffer + ETH_ADDRESSSIZE;
2207 buffer += ETH_ADDRESSSIZE * 2 + 2;
2209 else
2211 dest = request->ios2_DstAddr;
2212 source = unit->address;
2215 /* Clear frame descriptor as far as start of 802.11 header */
2217 q = desc;
2218 for(i = 0; i < P2_FRM_HEADER; i++)
2219 *q++ = 0;
2220 header = q;
2222 /* Set TX control field */
2224 control_value = P2_FRM_TXCONTROLF_NATIVE;
2225 if(encryption == S2ENC_TKIP && (unit->flags & UNITF_HARDTKIP) != 0)
2226 control_value |= unit->tx_key_no << P2_FRM_TXCONTROLB_MICKEYID
2227 | P2_FRM_TXCONTROLF_MIC;
2228 else if(encryption == S2ENC_NONE
2229 && unit->firmware_type < LUCENT_FIRMWARE)
2230 control_value |= P2_FRM_TXCONTROLF_NOENC;
2232 *(UWORD *)(desc + unit->txcontrol_offset) =
2233 MakeLEWord(control_value);
2235 /* Write 802.11 header */
2237 *(UWORD *)q = MakeLEWord(
2238 (encryption == S2ENC_NONE ? 0 : WIFI_FRM_CONTROLF_WEP)
2239 | (unit->mode == S2PORT_ADHOC ? 0 : WIFI_FRM_CONTROLF_TODS)
2240 | subtype << WIFI_FRM_CONTROLB_SUBTYPE
2241 | WIFI_FRMTYPE_DATA << WIFI_FRM_CONTROLB_TYPE);
2242 q += 2;
2244 *(UWORD *)q = 0;
2245 q += 2;
2247 if(unit->mode == S2PORT_ADHOC)
2248 p = dest;
2249 else
2250 p = unit->bssid;
2251 for(i = 0; i < ETH_ADDRESSSIZE; i++)
2252 *q++ = *p++;
2254 for(i = 0, p = source; i < ETH_ADDRESSSIZE; i++)
2255 *q++ = *p++;
2257 if(unit->mode == S2PORT_ADHOC)
2258 p = unit->bssid;
2259 else
2260 p = dest;
2261 for(i = 0; i < ETH_ADDRESSSIZE; i++)
2262 *q++ = *p++;
2263 *(UWORD *)q = 0;
2265 /* Clear 802.3 header */
2267 q = desc + unit->ethernet_offset;
2268 for(i = 0; i < ETH_HEADERSIZE; i++)
2269 *q++ = 0;
2271 /* Leave room for encryption overhead */
2273 q = desc + unit->data_offset;
2274 ciphertext = q;
2275 q += unit->iv_sizes[encryption];
2276 plaintext = q;
2278 /* Write SNAP header */
2280 if(!is_ieee)
2282 for(i = 0, p = snap_template; i < SNAP_FRM_TYPE; i++)
2283 *q++ = *p++;
2284 *(UWORD *)q = MakeBEWord(packet_type);
2285 q += 2;
2286 body_size += SNAP_HEADERSIZE;
2289 /* Copy data into frame */
2291 CopyMem(buffer, q, data_size);
2292 body_size += data_size;
2294 /* Append MIC to frame for TKIP */
2296 if(encryption == S2ENC_TKIP)
2298 q = mic_header;
2299 for(i = 0, p = dest; i < ETH_ADDRESSSIZE; i++)
2300 *q++ = *p++;
2301 for(i = 0, p = source; i < ETH_ADDRESSSIZE; i++)
2302 *q++ = *p++;
2303 TKIPEncryptFrame(unit, mic_header, plaintext, body_size,
2304 plaintext, base);
2305 body_size += MIC_SIZE;
2308 /* Encrypt fragment if applicable */
2310 unit->fragment_encrypt_functions[encryption](unit, header,
2311 plaintext, &body_size, ciphertext, base);
2313 /* Calculate total length of data to send to adapter */
2315 send_size = unit->data_offset + body_size;
2317 /* Fill in length field, adjusting for Hermes peculiarities */
2319 if(unit->firmware_type >= LUCENT_FIRMWARE
2320 && encryption == S2ENC_TKIP)
2321 body_size -= MIC_SIZE;
2323 if(unit->firmware_type == LUCENT_FIRMWARE
2324 && (unit->flags & UNITF_HARDTKIP) != 0)
2325 *(UWORD *)(desc + unit->ethernet_offset + ETH_PACKET_IEEELEN) =
2326 MakeBEWord(body_size);
2327 else
2328 *(UWORD *)(desc + unit->datalen_offset) = MakeLEWord(body_size);
2330 /* Write packet to adapter and send */
2332 frame_id = unit->tx_frame_id;
2333 P2Seek(unit, 0, frame_id, 0, base);
2334 unit->WordsOut(unit->card, P2_REG_DATA0, (UWORD *)desc,
2335 (send_size + 1) / 2);
2336 unit->tx_frame_id = 0;
2337 P2DoCmd(unit, P2_CMD_TX | P2_CMDF_RECLAIM, frame_id, base);
2340 /* Reply request */
2342 request->ios2_Req.io_Error = error;
2343 request->ios2_WireError = wire_error;
2344 Remove((APTR)request);
2345 ReplyMsg((APTR)request);
2347 /* Update statistics */
2349 if(error == 0)
2351 unit->stats.PacketsSent++;
2353 tracker = FindTypeStats(unit, &unit->type_trackers,
2354 request->ios2_PacketType, base);
2355 if(tracker != NULL)
2357 tracker->stats.PacketsSent++;
2358 tracker->stats.BytesSent += packet_size;
2363 /* Don't try to keep sending packets if there's no space left */
2365 if(unit->tx_frame_id != 0)
2366 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_SOFTINT;
2367 else
2368 unit->request_ports[WRITE_QUEUE]->mp_Flags = PA_IGNORE;
2370 return;
2375 /****i* prism2.device/UpdateStats ******************************************
2377 * NAME
2378 * UpdateStats
2380 * SYNOPSIS
2381 * UpdateStats(unit)
2383 * VOID UpdateStats(struct DevUnit *);
2385 * FUNCTION
2387 * INPUTS
2388 * unit - A unit of this device.
2390 * RESULT
2391 * None.
2393 ****************************************************************************
2397 VOID UpdateStats(struct DevUnit *unit, struct DevBase *base)
2399 /* Ask for and wait for stats */
2401 if((unit->flags & UNITF_ONLINE) != 0)
2403 Disable();
2404 unit->LEWordOut(unit->card, P2_REG_INTMASK,
2405 unit->LEWordIn(unit->card, P2_REG_INTMASK) & ~P2_EVENTF_INFO);
2406 Enable();
2407 P2DoCmd(unit, P2_CMD_INQUIRE, P2_INFO_COUNTERS, base);
2408 while((unit->LEWordIn(unit->card, P2_REG_EVENTS) & P2_EVENTF_INFO)
2409 == 0);
2410 Cause(&unit->info_int);
2413 return;
2418 /****i* prism2.device/InfoInt **********************************************
2420 * NAME
2421 * InfoInt
2423 * SYNOPSIS
2424 * InfoInt(unit)
2426 * VOID InfoInt(struct DevUnit *);
2428 * FUNCTION
2430 * INPUTS
2431 * unit - A unit of this device.
2433 * RESULT
2434 * None.
2436 * NOTES
2437 * The only reason this is a (soft) interrupt is so that it won't
2438 * interfere with RXInt() by interrupting it. This would be dangerous
2439 * because they use the same data channel.
2441 ****************************************************************************
2445 static VOID InfoInt(REG(a1, struct DevUnit *unit), REG(a6, APTR int_code))
2447 struct DevBase *base;
2448 UWORD id, length, rec_length, status, ies_length, data_length,
2449 ssid_length, *ap_rec;
2450 UBYTE *ie, *ssid, *descriptor, *frame, *data, *bssid = unit->bssid;
2451 BOOL associated;
2453 base = unit->device;
2454 id = unit->LEWordIn(unit->card, P2_REG_INFOFID);
2456 P2Seek(unit, 1, id, 0, base);
2457 length = (unit->LEWordIn(unit->card, P2_REG_DATA1) + 1) * 2;
2459 switch(unit->LEWordIn(unit->card, P2_REG_DATA1))
2461 case P2_INFO_COUNTERS:
2463 /* Read useful stats and skip others */
2465 unit->LEWordIn(unit->card, P2_REG_DATA1);
2466 unit->LEWordIn(unit->card, P2_REG_DATA1);
2468 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);
2473 unit->special_stats[S2SS_ETHERNET_RETRIES & 0xffff] +=
2474 unit->LEWordIn(unit->card, P2_REG_DATA1) +
2475 unit->LEWordIn(unit->card, P2_REG_DATA1) +
2476 unit->LEWordIn(unit->card, P2_REG_DATA1);
2478 unit->LEWordIn(unit->card, P2_REG_DATA1);
2480 unit->LEWordIn(unit->card, P2_REG_DATA1);
2481 unit->LEWordIn(unit->card, P2_REG_DATA1);
2483 unit->LEWordIn(unit->card, P2_REG_DATA1);
2484 unit->LEWordIn(unit->card, P2_REG_DATA1);
2485 unit->LEWordIn(unit->card, P2_REG_DATA1);
2487 unit->stats.BadData += unit->LEWordIn(unit->card, P2_REG_DATA1);
2488 unit->stats.Overruns += unit->LEWordIn(unit->card, P2_REG_DATA1);
2490 unit->LEWordIn(unit->card, P2_REG_DATA1);
2492 unit->stats.BadData += unit->LEWordIn(unit->card, P2_REG_DATA1);
2494 break;
2496 case P2_INFO_SCANRESULTS:
2497 case P2_INFO_HOSTSCANRESULTS:
2499 P2ReadRec(unit, id, unit->scan_results_rec, SCAN_BUFFER_SIZE, base);
2500 Signal(unit->task, unit->scan_complete_signal);
2501 break;
2503 case P2_INFO_SCANRESULT:
2505 descriptor = unit->rx_descriptor;
2506 P2ReadRec(unit, id, descriptor, FRAME_BUFFER_SIZE, base);
2507 if(length > 4)
2509 /* Save IEEE 802.3 portion of scan result */
2511 frame = descriptor + unit->ethernet_offset;
2512 data = frame + ETH_PACKET_DATA;
2513 CopyMem(descriptor + P2_FRM_HEADER + WIFI_FRM_ADDRESS3,
2514 frame + ETH_PACKET_SOURCE, ETH_ADDRESSSIZE);
2515 data_length =
2516 LEWord(*(UWORD *)(descriptor + unit->datalen_offset));
2517 ies_length = data_length - WIFI_BEACON_IES;
2518 *(UWORD *)(frame + ETH_PACKET_IEEELEN) = MakeBEWord(data_length);
2519 SaveBeacon(unit, frame, base);
2521 /* Append a fake old-style scan record on to fake record list */
2523 rec_length = LEWord(unit->scan_results_rec[0]);
2525 if(2 + rec_length * 2 + P2_APRECLEN < SCAN_BUFFER_SIZE)
2527 ap_rec = unit->scan_results_rec + 1 + rec_length;
2528 CopyMem(frame + ETH_PACKET_SOURCE, ap_rec + P2_APREC_BSSID / 2,
2529 ETH_ADDRESSSIZE);
2531 ap_rec[P2_APREC_SIGNAL / 2] =
2532 MakeLEWord(descriptor[P2_FRM_SIGNAL]);
2534 ap_rec[P2_APREC_NOISE / 2] =
2535 MakeLEWord(descriptor[P2_FRM_NOISE]);
2537 ap_rec[P2_APREC_CHANNEL / 2] = MakeLEWord(GetIE(WIFI_IE_CHANNEL,
2538 data + WIFI_BEACON_IES, ies_length, base)[2]);
2540 ap_rec[P2_APREC_INTERVAL / 2] =
2541 *(UWORD *)(data + WIFI_BEACON_INTERVAL);
2543 ap_rec[P2_APREC_CAPABILITIES / 2] =
2544 *(UWORD *)(data + WIFI_BEACON_CAPABILITIES);
2546 ie = GetIE(WIFI_IE_SSID, data + WIFI_BEACON_IES, ies_length,
2547 base);
2548 ssid_length = ie[1];
2549 ssid = ie + 2;
2550 ap_rec[P2_APREC_NAMELEN / 2] = MakeLEWord(ssid_length);
2551 CopyMem(ssid, ap_rec + P2_APREC_NAME / 2, ssid_length);
2553 unit->scan_results_rec[0] =
2554 MakeLEWord(rec_length + P2_APRECLEN / 2);
2557 else
2558 Signal(unit->task, unit->scan_complete_signal);
2559 break;
2561 case P2_INFO_LINKSTATUS:
2563 /* Only report an event if association status has really changed */
2565 status = unit->LEWordIn(unit->card, P2_REG_DATA1);
2567 if(status == 1 || unit->firmware_type < LUCENT_FIRMWARE
2568 && status == 3)
2569 associated = TRUE;
2570 else //if(unit->firmware_type < LUCENT_FIRMWARE || status == 3)
2571 associated = FALSE;
2573 if(!(*(ULONG *)bssid == 0 && *(UWORD *)(bssid + 4) == 0))
2575 if(associated && (unit->flags & UNITF_ASSOCIATED) == 0)
2577 unit->flags |= UNITF_ASSOCIATED;
2578 ReportEvents(unit, S2EVENT_CONNECT, base);
2580 else if(!associated && (unit->flags & UNITF_ASSOCIATED) != 0)
2582 unit->flags &= ~UNITF_ASSOCIATED;
2583 ReportEvents(unit, S2EVENT_DISCONNECT, base);
2588 /* Acknowledge event and re-enable info interrupts */
2590 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_INFO);
2591 Disable();
2592 if((unit->flags & UNITF_ONLINE) != 0)
2593 unit->LEWordOut(unit->card, P2_REG_INTMASK,
2594 unit->LEWordIn(unit->card, P2_REG_INTMASK) | P2_EVENTF_INFO);
2595 Enable();
2597 return;
2602 /****i* prism2.device/ResetHandler *****************************************
2604 * NAME
2605 * ResetHandler -- Disable hardware before a reboot.
2607 * SYNOPSIS
2608 * ResetHandler(unit, int_code)
2610 * VOID ResetHandler(struct DevUnit *, APTR);
2612 ****************************************************************************
2616 static VOID ResetHandler(REG(a1, struct DevUnit *unit),
2617 REG(a6, APTR int_code))
2619 if((unit->flags & UNITF_HAVEADAPTER) != 0)
2621 /* Stop interrupts */
2623 unit->LEWordOut(unit->card, P2_REG_INTMASK, 0);
2625 /* Stop transmission and reception */
2627 unit->LEWordOut(unit->card, P2_REG_PARAM0, 0);
2628 unit->LEWordOut(unit->card, P2_REG_COMMAND, P2_CMD_DISABLE);
2631 return;
2636 /****i* prism2.device/ReportEvents *****************************************
2638 * NAME
2639 * ReportEvents
2641 * SYNOPSIS
2642 * ReportEvents(unit, events)
2644 * VOID ReportEvents(struct DevUnit *, ULONG);
2646 * FUNCTION
2648 * INPUTS
2649 * unit - A unit of this device.
2650 * events - A mask of events to report.
2652 * RESULT
2653 * None.
2655 ****************************************************************************
2659 static VOID ReportEvents(struct DevUnit *unit, ULONG events,
2660 struct DevBase *base)
2662 struct IOSana2Req *request, *tail, *next_request;
2663 struct List *list;
2665 list = &unit->request_ports[EVENT_QUEUE]->mp_MsgList;
2666 next_request = (APTR)list->lh_Head;
2667 tail = (APTR)&list->lh_Tail;
2669 Disable();
2670 while(next_request != tail)
2672 request = next_request;
2673 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
2675 if((request->ios2_WireError & events) != 0)
2677 request->ios2_WireError = events;
2678 Remove((APTR)request);
2679 ReplyMsg((APTR)request);
2682 Enable();
2684 return;
2689 /****i* prism2.device/SendScanResults **************************************
2691 * NAME
2692 * SendScanResults -- Reply to all outstanding scan requests.
2694 * SYNOPSIS
2695 * SendScanResults(unit)
2697 * VOID SendScanResults(struct DevUnit *);
2699 * FUNCTION
2701 * INPUTS
2702 * unit - A unit of this device.
2704 * RESULT
2705 * None.
2707 ****************************************************************************
2711 static VOID SendScanResults(struct DevUnit *unit, struct DevBase *base)
2713 BYTE error = 0;
2714 struct IOSana2Req *request, *tail, *next_request;
2715 struct List *list;
2716 APTR pool;
2717 UWORD count, i, j, ssid_length, length, entry_length, *ap_rec,
2718 data_length, frame_length, ies_length;
2719 struct TagItem **tag_lists, *tag;
2720 UBYTE *bssid, *ies;
2721 const UBYTE *beacon, *ie_bssid;
2722 TEXT *ssid;
2724 list = &unit->request_ports[SCAN_QUEUE]->mp_MsgList;
2725 next_request = (APTR)list->lh_Head;
2726 tail = (APTR)&list->lh_Tail;
2728 while(next_request != tail)
2730 request = next_request;
2731 next_request = (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ;
2733 pool = request->ios2_Data;
2735 length = LEWord(unit->scan_results_rec[0]);
2736 ap_rec = unit->scan_results_rec + 2;
2738 if(unit->firmware_type == INTERSIL_FIRMWARE)
2740 entry_length = LEWord(unit->scan_results_rec[2]);
2741 ap_rec += 2;
2742 count = (length - 3) * 2 / entry_length;
2744 else
2746 entry_length = P2_APRECLEN;
2747 count = (length - 1) * 2 / entry_length;
2750 /* Allocate array of tag lists, one for each AP */
2752 if(count > 0)
2754 tag_lists = AllocPooled(pool, count * sizeof(APTR));
2755 if(tag_lists == NULL)
2756 error = S2ERR_NO_RESOURCES;
2758 else
2759 tag_lists = NULL;
2761 for(i = 0; i < count && error == 0; i++, ap_rec += entry_length / 2)
2763 tag_lists[i] =
2764 AllocPooled(pool, SCAN_TAG_COUNT * sizeof(struct TagItem));
2765 if(tag_lists[i] == NULL)
2766 error = S2ERR_NO_RESOURCES;
2768 if(error == 0)
2770 tag = tag_lists[i];
2772 tag->ti_Tag = S2INFO_BSSID;
2773 tag->ti_Data = (UPINT)(bssid =
2774 AllocPooled(pool, ETH_ADDRESSSIZE));
2775 if(bssid != NULL)
2776 CopyMem(ap_rec + P2_APREC_BSSID / 2, bssid,
2777 ETH_ADDRESSSIZE);
2778 else
2779 error = S2ERR_NO_RESOURCES;
2780 tag++;
2782 tag->ti_Tag = TAG_IGNORE;
2783 tag++;
2785 tag->ti_Tag = S2INFO_Channel;
2786 tag->ti_Data = LEWord(ap_rec[P2_APREC_CHANNEL / 2]);
2787 tag++;
2789 tag->ti_Tag = S2INFO_BeaconInterval;
2790 tag->ti_Data = LEWord(ap_rec[P2_APREC_INTERVAL / 2]);
2791 tag++;
2793 tag->ti_Tag = S2INFO_Capabilities;
2794 tag->ti_Data = LEWord(ap_rec[P2_APREC_CAPABILITIES / 2]);
2795 tag++;
2797 tag->ti_Tag = S2INFO_Signal;
2798 tag->ti_Data = ConvertScanLevel(unit,
2799 LEWord(ap_rec[P2_APREC_SIGNAL / 2]), base);
2800 tag++;
2802 tag->ti_Tag = S2INFO_Noise;
2803 tag->ti_Data = ConvertScanLevel(unit,
2804 LEWord(ap_rec[P2_APREC_NOISE / 2]), base);
2805 tag++;
2808 ssid_length = LEWord(ap_rec[P2_APREC_NAMELEN / 2]);
2809 tag->ti_Tag = S2INFO_SSID;
2810 tag->ti_Data = (UPINT)(ssid =
2811 AllocPooled(pool, 31 + 1));
2812 if(ssid != NULL)
2814 CopyMem(ap_rec + P2_APREC_NAME / 2, ssid, ssid_length);
2815 ssid[ssid_length] = '\0';
2817 else
2818 error = S2ERR_NO_RESOURCES;
2819 tag++;
2821 tag->ti_Tag = TAG_END;
2825 /* Find IEs for each BSS and insert them into the BSS's tag list */
2827 for(beacon = unit->beacons, i = 0; i < unit->beacon_count; i++)
2829 /* Extract IEs from beacon descriptor */
2831 data_length = BEWord(*(UWORD *)(beacon + ETH_PACKET_IEEELEN));
2832 ies_length = data_length - 12;
2833 frame_length = ETH_HEADERSIZE + data_length;
2834 ies = AllocPooled(pool, sizeof(UWORD) + ies_length);
2835 if(ies != NULL)
2837 *(UWORD *)ies = ies_length;
2838 CopyMem(beacon + ETH_PACKET_DATA + WIFI_BEACON_IES,
2839 ies + sizeof(UWORD), ies_length);
2841 else
2842 error = S2ERR_NO_RESOURCES;
2844 /* Find matching tag list and add IEs to it */
2846 ie_bssid = beacon + ETH_PACKET_SOURCE;
2847 for(j = 0; j < count; j++)
2849 tag = tag_lists[j];
2850 bssid = (UBYTE *)tag->ti_Data;
2851 if(*(ULONG *)bssid == *(ULONG *)ie_bssid
2852 && *(UWORD *)(bssid + 4) == *(UWORD *)(ie_bssid + 4))
2854 tag++;
2855 tag->ti_Tag = S2INFO_InfoElements;
2856 tag->ti_Data = (PINT)ies;
2860 beacon += frame_length + sizeof(ULONG) & ~3;
2863 /* Return results */
2865 if(error == 0)
2867 request->ios2_StatData = tag_lists;
2868 request->ios2_DataLength = count;
2870 else
2872 request->ios2_Req.io_Error = error;
2873 request->ios2_WireError = S2WERR_GENERIC_ERROR;
2875 Remove((APTR)request);
2876 ReplyMsg((APTR)request);
2879 /* Discard collected beacon frames */
2881 Disable();
2882 unit->next_beacon = unit->beacons;
2883 unit->beacon_count = 0;
2884 Enable();
2886 return;
2891 /****i* prism2.device/GetNetworkInfo ***************************************
2893 * NAME
2894 * GetNetworkInfo -- Get information on current network.
2896 * SYNOPSIS
2897 * tag_list = GetNetworkInfo(unit, pool)
2899 * struct TagItem *GetNetworkInfo(struct DevUnit *, APTR);
2901 * FUNCTION
2903 * INPUTS
2904 * unit - A unit of this device.
2905 * pool - A memory pool.
2907 * RESULT
2908 * None.
2910 ****************************************************************************
2914 struct TagItem *GetNetworkInfo(struct DevUnit *unit, APTR pool,
2915 struct DevBase *base)
2917 BYTE error = 0;
2918 struct TagItem *tag_list, *tag;
2919 UBYTE *bssid, *ie;
2921 tag_list =
2922 AllocPooled(pool, INFO_TAG_COUNT * sizeof(struct TagItem));
2923 if(tag_list == NULL)
2924 error = S2ERR_NO_RESOURCES;
2926 if(error == 0)
2928 tag = tag_list;
2930 tag->ti_Tag = S2INFO_BSSID;
2931 tag->ti_Data = (UPINT)(bssid =
2932 AllocPooled(pool, ETH_ADDRESSSIZE));
2933 if(bssid != NULL)
2934 CopyMem(unit->bssid, bssid, ETH_ADDRESSSIZE);
2935 else
2936 error = S2ERR_NO_RESOURCES;
2937 tag++;
2939 tag->ti_Tag = TAG_IGNORE;
2940 tag++;
2942 tag->ti_Tag = S2INFO_WPAInfo;
2943 tag->ti_Data = (UPINT)(ie =
2944 AllocPooled(pool, unit->wpa_ie[1] + 2));
2945 if(ie != NULL)
2946 CopyMem(unit->wpa_ie, ie, unit->wpa_ie[1] + 2);
2947 else
2948 error = S2ERR_NO_RESOURCES;
2949 tag++;
2951 tag->ti_Tag = TAG_END;
2954 if(error != 0)
2955 tag_list = NULL;
2957 return tag_list;
2962 /****i* prism2.device/UpdateSignalQuality **********************************
2964 * NAME
2965 * UpdateSignalQuality -- Read signal quality from card.
2967 * SYNOPSIS
2968 * UpdateSignalQuality(unit)
2970 * VOID UpdateSignalQuality(struct DevUnit *);
2972 * FUNCTION
2974 * INPUTS
2975 * unit - A unit of this device.
2977 * RESULT
2978 * None.
2980 ****************************************************************************
2984 VOID UpdateSignalQuality(struct DevUnit *unit, struct DevBase *base)
2986 P2DoCmd(unit, P2_CMD_ACCESS, P2_REC_LINKQUALITY, base);
2987 P2Seek(unit, 1, P2_REC_LINKQUALITY, 6, base);
2989 unit->signal_quality.SignalLevel =
2990 ConvertLevel(unit, unit->LEWordIn(unit->card, P2_REG_DATA1), base);
2991 unit->signal_quality.NoiseLevel =
2992 ConvertLevel(unit, unit->LEWordIn(unit->card, P2_REG_DATA1), base);
2994 return;
2999 /****i* prism2.device/StartScan ********************************************
3001 * NAME
3002 * StartScan -- Start a scan for available networks.
3004 * SYNOPSIS
3005 * StartScan(unit)
3007 * VOID StartScan(struct DevUnit *);
3009 * FUNCTION
3011 * INPUTS
3012 * unit - A unit of this device.
3014 * RESULT
3015 * None.
3017 ****************************************************************************
3021 VOID StartScan(struct DevUnit *unit, const TEXT *ssid, struct DevBase *base)
3023 UBYTE *params;
3024 UWORD ssid_length = 0;
3026 /* Ask for a scan */
3028 if((unit->flags & UNITF_ONLINE) != 0)
3030 if(ssid != NULL)
3031 ssid_length = StrLen(ssid);
3032 if(unit->firmware_type == INTERSIL_FIRMWARE)
3034 params = AllocVec(sizeof(scan_params) + ssid_length, MEMF_PUBLIC);
3035 if(params != NULL)
3037 CopyMem(scan_params, params, sizeof(scan_params));
3038 if(ssid != NULL)
3039 CopyMem(ssid, params + sizeof(scan_params), ssid_length);
3040 params[4] = ssid_length;
3041 P2SetData(unit, P2_REC_HOSTSCAN, params,
3042 sizeof(scan_params) + ssid_length, base);
3043 FreeVec(params);
3046 else if(unit->firmware_type == SYMBOL_FIRMWARE)
3047 P2SetWord(unit, P2_REC_ALTHOSTSCAN, 0x82, base);
3048 else if(unit->firmware_type >= LUCENT_FIRMWARE
3049 && (unit->flags & UNITF_HARDTKIP) != 0)
3051 /* Initialise fake scan results and ask for a series of raw beacon
3052 descriptors */
3054 unit->scan_results_rec[0] = MakeLEWord(1);
3056 P2SetID(unit, P2_REC_SCANSSID, ssid, ssid_length, base);
3057 P2SetWord(unit, P2_REC_SCANCHANNELS, 0x7fff, base);
3058 unit->LEWordOut(unit->card, P2_REG_PARAM1, 0x3fff);
3059 P2DoCmd(unit, P2_CMD_INQUIRE, P2_INFO_SCANRESULT, base);
3061 else
3063 P2SetID(unit, P2_REC_SCANSSID, ssid, ssid_length, base);
3064 P2DoCmd(unit, P2_CMD_INQUIRE, P2_INFO_SCANRESULTS, base);
3068 return;
3073 /****i* prism2.device/LoadFirmware *****************************************
3075 * NAME
3076 * LoadFirmware
3078 * SYNOPSIS
3079 * success = LoadFirmware(unit)
3081 * BOOL LoadFirmware(struct DevUnit *);
3083 * FUNCTION
3085 * INPUTS
3086 * unit - A unit of this device.
3088 * RESULT
3089 * success - Success indicator.
3091 ****************************************************************************
3095 static BOOL LoadFirmware(struct DevUnit *unit, struct DevBase *base)
3097 BOOL success = TRUE;
3098 const TEXT *file_name;
3099 struct FileInfoBlock *info = NULL;
3100 UWORD control_reg, pdr_no, *pda = NULL, *pdr, *prod_data, length;
3101 ULONG location, start_address;
3102 BPTR file = (BPTR)NULL;
3103 UBYTE *data = NULL;
3104 TEXT *buffer = NULL;
3105 const TEXT *p;
3106 UBYTE type;
3108 /* Read firmware file */
3110 switch(unit->firmware_type)
3112 case LUCENT_FIRMWARE:
3113 file_name = h1_firmware_file_name;
3114 break;
3115 case HERMES2_FIRMWARE:
3116 file_name = h2_firmware_file_name;
3117 break;
3118 case HERMES2G_FIRMWARE:
3119 file_name = h25_firmware_file_name;
3120 break;
3121 default:
3122 file_name = NULL;
3125 if(file_name == NULL)
3126 success = FALSE;
3128 if(success)
3130 file = Open(file_name, MODE_OLDFILE);
3131 if(file == (BPTR)NULL)
3132 success = FALSE;
3135 if(success)
3137 info = AllocDosObject(DOS_FIB, NULL);
3138 if(info == NULL)
3139 success = FALSE;
3142 if(success)
3144 if(!ExamineFH(file, info))
3145 success = FALSE;
3148 if(success)
3150 buffer = AllocVec(info->fib_Size + 1, MEMF_ANY);
3151 data = AllocVec(MAX_S_REC_SIZE, MEMF_ANY);
3152 pda = AllocVec(LUCENT_PDA_SIZE, MEMF_ANY);
3153 if(buffer == NULL || data == NULL || pda == NULL)
3154 success = FALSE;
3157 if(success)
3159 if(Read(file, buffer, info->fib_Size) == -1)
3160 success = FALSE;
3161 buffer[info->fib_Size] = '\0';
3164 if(success)
3166 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3167 P2DoCmd(unit, P2_CMD_INIT | 0x100, 0, base);
3168 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3169 P2DoCmd(unit, P2_CMD_INIT | 0x0, 0, base);
3170 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3172 /* Enable auxiliary ports */
3174 unit->LEWordOut(unit->card, P2_REG_PARAM0, 0xfe01);
3175 unit->LEWordOut(unit->card, P2_REG_PARAM1, 0xdc23);
3176 unit->LEWordOut(unit->card, P2_REG_PARAM2, 0xba45);
3178 control_reg = unit->LEWordIn(unit->card, P2_REG_CONTROL);
3179 control_reg =
3180 control_reg & ~P2_REG_CONTROLF_AUX | P2_REG_CONTROL_ENABLEAUX;
3181 unit->LEWordOut(unit->card, P2_REG_CONTROL, control_reg);
3183 BusyMilliDelay(5, base);
3184 while(
3185 (unit->LEWordIn(unit->card, P2_REG_CONTROL) & P2_REG_CONTROLF_AUX)
3186 != P2_REG_CONTROL_AUXENABLED);
3188 /* Read Production Data Area from card */
3190 if(unit->firmware_type < HERMES2_FIRMWARE)
3192 location = LUCENT_PDA_ADDRESS;
3193 unit->LEWordOut(unit->card, P2_REG_AUXPAGE, location >> 7);
3194 unit->LEWordOut(unit->card, P2_REG_AUXOFFSET,
3195 location & (1 << 7) - 1);
3197 unit->WordsIn(unit->card, P2_REG_AUXDATA,
3198 (UWORD *)pda, LUCENT_PDA_SIZE >> 1);
3201 /* Allow writing to card's RAM */
3203 BusyMilliDelay(100, base);
3204 start_address = 0xf8000;
3205 unit->LEWordOut(unit->card, P2_REG_PARAM1, start_address >> 16);
3206 P2DoCmd(unit, P2_CMD_PROGRAM | P2_CMDF_WRITE, start_address, base);
3208 /* Parse firmware image data and write it to card */
3210 p = buffer;
3211 while(p != NULL)
3213 p = ParseNextSRecord(p, &type, data, &length, &location, base);
3214 if(p != NULL)
3216 switch(type)
3218 case '3':
3220 /* Check that this is not a "special" record */
3222 if(location < 0xff000000)
3224 /* Write data to card */
3226 if(unit->firmware_type < LUCENT_FIRMWARE)
3228 unit->LEWordOut(unit->card, P2_REG_PARAM1,
3229 location >> 16);
3230 P2DoCmd(unit, P2_CMD_PROGRAM | P2_CMDF_WRITE, location,
3231 base);
3234 unit->LEWordOut(unit->card, P2_REG_AUXPAGE,
3235 location >> 7);
3236 unit->LEWordOut(unit->card, P2_REG_AUXOFFSET,
3237 location & (1 << 7) - 1);
3239 unit->WordsOut(unit->card, P2_REG_AUXDATA,
3240 (UWORD *)data, length >> 1);
3242 break;
3244 case '7':
3246 /* Get location in card memory to begin execution of new
3247 firmware at */
3249 start_address = location;
3254 /* Parse PDA plug records and patch firmware */
3256 p = buffer;
3257 while(p != NULL)
3259 p = ParseNextSRecord(p, &type, data, &length, &location, base);
3261 if(p != NULL && type == '3' && location == 0xff000000)
3263 /* Get PDR number and the location where it should be patched
3264 into firmware */
3266 pdr_no = LELong(*(ULONG *)data);
3267 location = LELong(*(ULONG *)(data + 4));
3268 length = LELong(*(ULONG *)(data + 8));
3270 /* Find PDR to copy data from */
3272 prod_data = NULL;
3273 for(pdr = pda; pdr[1] != 0; pdr += LEWord(pdr[0]) + 1)
3275 if(LEWord(pdr[1]) == pdr_no)
3276 prod_data = pdr + 2;
3279 /* Write production data to card if it was found */
3281 if(prod_data != NULL)
3283 if(unit->firmware_type < LUCENT_FIRMWARE)
3285 unit->LEWordOut(unit->card, P2_REG_PARAM1,
3286 location >> 16);
3287 P2DoCmd(unit, P2_CMD_PROGRAM | P2_CMDF_WRITE, location,
3288 base);
3291 unit->LEWordOut(unit->card, P2_REG_AUXPAGE, location >> 7);
3292 unit->LEWordOut(unit->card, P2_REG_AUXOFFSET,
3293 location & (1 << 7) - 1);
3295 unit->WordsOut(unit->card, P2_REG_AUXDATA, prod_data,
3296 length >> 1);
3301 /* Disable auxiliary ports */
3303 control_reg = unit->LEWordIn(unit->card, P2_REG_CONTROL);
3304 control_reg =
3305 control_reg & ~P2_REG_CONTROLF_AUX | P2_REG_CONTROL_DISABLEAUX;
3306 unit->LEWordOut(unit->card, P2_REG_CONTROL, control_reg);
3308 /* Execute downloaded firmware */
3310 if(unit->firmware_type >= HERMES2_FIRMWARE)
3312 unit->LEWordOut(unit->card, P2_REG_PARAM1, start_address >> 16);
3313 P2DoCmd(unit, P2_CMD_EXECUTE, start_address, base);
3315 else if(unit->firmware_type >= LUCENT_FIRMWARE)
3317 P2DoCmd(unit, P2_CMD_PROGRAM, 0, base);
3318 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3319 P2DoCmd(unit, P2_CMD_INIT, 0, base);
3320 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3322 else
3324 unit->LEWordOut(unit->card, P2_REG_PARAM1, start_address >> 16);
3325 P2DoCmd(unit, P2_CMD_PROGRAM, start_address, base);
3326 P2DoCmd(unit, P2_CMD_INIT, 0, base);
3330 /* Free Resources */
3332 FreeVec(pda);
3333 FreeVec(buffer);
3334 FreeVec(data);
3335 FreeDosObject(DOS_FIB, info);
3336 if(file != (BPTR)NULL)
3337 Close(file);
3339 return success;
3344 /****i* prism2.device/ParseNextSRecord *************************************
3346 * NAME
3347 * ParseNextSRecord
3349 ****************************************************************************
3353 static const TEXT *ParseNextSRecord(const TEXT *s, UBYTE *type, UBYTE *data,
3354 UWORD *data_length, ULONG *location, struct DevBase *base)
3356 LONG ch;
3357 ULONG n = 0;
3358 UWORD i;
3359 BOOL found = FALSE;
3361 /* Find start of next record, if any */
3363 while(!found)
3365 ch = *s++;
3366 if(ch == 'S' || ch == '\0')
3367 found = TRUE;
3370 if(ch == 'S')
3372 /* Get record type */
3374 *type = *s++;
3376 /* Skip length field to keep alignment easy */
3378 s += 2;
3380 /* Parse hexadecimal portion of record */
3382 for(i = 0; (ch = *s++) >= '0'; i++)
3384 n <<= 4;
3386 if(ch >= 'A')
3387 n |= ch - 'A' + 10;
3388 else
3389 n |= ch - '0';
3391 if(i >= 8 && (i & 0x1) != 0)
3393 *data++ = n;
3394 n = 0;
3396 else if(i == 7)
3398 *location = n;
3399 n = 0;
3402 *data_length = (i >> 1) - 5;
3404 else
3405 s = NULL;
3407 /* Return updated text pointer */
3409 return s;
3414 /****i* prism2.device/P2DoCmd **********************************************
3416 * NAME
3417 * P2DoCmd
3419 ****************************************************************************
3421 * Commands can't fail without software/firmware bug?
3425 static VOID P2DoCmd(struct DevUnit *unit, UWORD command, UWORD param,
3426 struct DevBase *base)
3428 if(unit->firmware_type < LUCENT_FIRMWARE && command == P2_CMD_INIT)
3429 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3431 unit->LEWordOut(unit->card, P2_REG_PARAM0, param);
3432 unit->LEWordOut(unit->card, P2_REG_COMMAND, command);
3433 while((unit->LEWordIn(unit->card, P2_REG_EVENTS)
3434 & P2_EVENTF_CMD) == 0);
3435 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_CMD);
3437 if(unit->firmware_type < LUCENT_FIRMWARE && command == P2_CMD_INIT)
3438 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, 0xffff);
3443 /****i* prism2.device/P2Seek ***********************************************
3445 * NAME
3446 * P2Seek
3448 ****************************************************************************
3452 static BOOL P2Seek(struct DevUnit *unit, UWORD path_no, UWORD rec_no,
3453 UWORD offset, struct DevBase *base)
3455 UPINT offset_reg;
3457 path_no <<= 1;
3458 offset_reg = P2_REG_OFFSET0 + path_no;
3459 while((unit->LEWordIn(unit->card, offset_reg) & P2_REG_OFFSETF_BUSY)
3460 != 0);
3461 unit->LEWordOut(unit->card, P2_REG_SELECT0 + path_no, rec_no);
3462 unit->LEWordOut(unit->card, offset_reg, offset);
3463 while((unit->LEWordIn(unit->card, offset_reg) & P2_REG_OFFSETF_BUSY)
3464 != 0);
3466 return (unit->LEWordIn(unit->card, offset_reg) & P2_REG_OFFSETF_ERROR)
3467 == 0;
3472 /****i* prism2.device/P2SetID **********************************************
3474 * NAME
3475 * P2SetID
3477 * NOTES
3478 * id may be NULL as long as length is zero.
3480 ****************************************************************************
3484 static VOID P2SetID(struct DevUnit *unit, UWORD rec_no, const UBYTE *id,
3485 UWORD length, struct DevBase *base)
3487 P2Seek(unit, 1, rec_no, 0, base);
3489 unit->LEWordOut(unit->card, P2_REG_DATA1, length / 2 + 3);
3490 unit->LEWordOut(unit->card, P2_REG_DATA1, rec_no);
3491 unit->LEWordOut(unit->card, P2_REG_DATA1, length);
3492 unit->WordsOut(unit->card, P2_REG_DATA1, (UWORD *)id, (length + 1) / 2);
3494 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, rec_no, base);
3496 return;
3501 /****i* prism2.device/P2SetWord ********************************************
3503 * NAME
3504 * P2SetWord
3506 ****************************************************************************
3510 static VOID P2SetWord(struct DevUnit *unit, UWORD rec_no, UWORD value,
3511 struct DevBase *base)
3513 P2Seek(unit, 1, rec_no, 0, base);
3515 unit->LEWordOut(unit->card, P2_REG_DATA1, 2);
3516 unit->LEWordOut(unit->card, P2_REG_DATA1, rec_no);
3517 unit->LEWordOut(unit->card, P2_REG_DATA1, value);
3519 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, rec_no, base);
3521 return;
3526 /****i* prism2.device/P2GetWord ********************************************
3528 * NAME
3529 * P2GetWord
3531 ****************************************************************************
3535 static UWORD P2GetWord(struct DevUnit *unit, UWORD rec_no,
3536 struct DevBase *base)
3538 P2DoCmd(unit, P2_CMD_ACCESS, rec_no, base);
3539 P2Seek(unit, 1, rec_no, 4, base);
3541 return unit->LEWordIn(unit->card, P2_REG_DATA1);
3546 /****i* prism2.device/P2AllocMem *******************************************
3548 * NAME
3549 * P2AllocMem
3551 ****************************************************************************
3555 static UWORD P2AllocMem(struct DevUnit *unit, UWORD size,
3556 struct DevBase *base)
3558 UWORD id;
3559 P2DoCmd(unit, P2_CMD_ALLOCMEM, size, base);
3560 while((unit->LEWordIn(unit->card, P2_REG_EVENTS) & P2_EVENTF_ALLOCMEM)
3561 == 0);
3562 id = unit->LEWordIn(unit->card, P2_REG_ALLOCFID);
3563 unit->LEWordOut(unit->card, P2_REG_ACKEVENTS, P2_EVENTF_ALLOCMEM);
3564 return id;
3569 /****i* prism2.device/P2SetData ********************************************
3571 * NAME
3572 * P2SetData
3574 ****************************************************************************
3578 static VOID P2SetData(struct DevUnit *unit, UWORD rec_no, const UBYTE *data,
3579 UWORD length, struct DevBase *base)
3581 length = (length + 1) / 2;
3582 P2Seek(unit, 1, rec_no, 0, base);
3584 unit->LEWordOut(unit->card, P2_REG_DATA1, 1 + length);
3585 unit->LEWordOut(unit->card, P2_REG_DATA1, rec_no);
3586 unit->WordsOut(unit->card, P2_REG_DATA1, (const UWORD *)data, length);
3588 P2DoCmd(unit, P2_CMD_ACCESS | P2_CMDF_WRITE, rec_no, base);
3590 return;
3595 /****i* prism2.device/P2ReadRec ********************************************
3597 * NAME
3598 * P2ReadRec -- Load and read an entire record.
3600 * SYNOPSIS
3601 * success = P2ReadRec(unit, rec_no, buffer, max_length)
3603 * BOOL P2ReadRec(struct DevUnit *, UWORD, APTR, UWORD);
3605 * FUNCTION
3607 * INPUTS
3608 * unit - A unit of this device.
3609 * rec_no - Record number to read.
3610 * buffer - Buffer to store data in.
3611 * max_length - Maximum number of bytes to store in buffer.
3613 * RESULT
3614 * success - Success indicator.
3616 ****************************************************************************
3620 static BOOL P2ReadRec(struct DevUnit *unit, UWORD rec_no, APTR buffer,
3621 UWORD max_length, struct DevBase *base)
3623 BOOL success = TRUE;
3624 WORD length;
3626 P2DoCmd(unit, P2_CMD_ACCESS, rec_no, base);
3627 P2Seek(unit, 1, rec_no, 0, base);
3629 length = (unit->LEWordIn(unit->card, P2_REG_DATA1) + 1) * 2;
3630 P2Seek(unit, 1, rec_no, 0, base);
3631 if(length <= max_length)
3632 unit->WordsIn(unit->card, P2_REG_DATA1, (UWORD *)buffer,
3633 length / 2);
3634 else
3635 success = FALSE;
3636 return success;
3641 /****i* prism2.device/ConvertLevel *****************************************
3643 * NAME
3644 * ConvertLevel -- Convert a signal or noise level to dBm.
3646 * SYNOPSIS
3647 * dbm_level = ConvertLevel(unit, raw_level)
3649 * LONG ConvertLevel(struct DevUnit *, UWORD);
3651 * FUNCTION
3653 * INPUTS
3654 * unit - A unit of this device.
3655 * raw_level - The value returned from the hardware.
3657 * RESULT
3658 * dbm_level - The value in dBm.
3660 ****************************************************************************
3664 static LONG ConvertLevel(struct DevUnit *unit, UWORD raw_level,
3665 struct DevBase *base)
3667 LONG dbm_level;
3669 if(unit->firmware_type >= LUCENT_FIRMWARE)
3670 dbm_level = raw_level - LUCENT_DBM_OFFSET;
3671 else
3672 dbm_level = raw_level / 3 - INTERSIL_DBM_OFFSET;
3674 return dbm_level;
3679 /****i* prism2.device/ConvertScanLevel *************************************
3681 * NAME
3682 * ConvertScanLevel -- Convert a signal or noise level to dBm.
3684 * SYNOPSIS
3685 * dbm_level = ConvertScanLevel(unit, raw_level)
3687 * LONG ConvertScanLevel(struct DevUnit *, UWORD);
3689 * FUNCTION
3691 * INPUTS
3692 * unit - A unit of this device.
3693 * raw_level - The value returned from the hardware.
3695 * RESULT
3696 * dbm_level - The value in dBm.
3698 ****************************************************************************
3702 static LONG ConvertScanLevel(struct DevUnit *unit, UWORD raw_level,
3703 struct DevBase *base)
3705 LONG dbm_level;
3707 if(unit->firmware_type >= LUCENT_FIRMWARE)
3708 dbm_level = raw_level - LUCENT_DBM_OFFSET;
3709 else
3710 dbm_level = (WORD)raw_level;
3712 return dbm_level;
3717 /****i* prism2.device/GetIE ************************************************
3719 * NAME
3720 * GetIE
3722 * SYNOPSIS
3723 * ie = GetIE(id, ies, ies_length)
3725 * UBYTE *GetIE(UBYTE, UBYTE *, UWORD);
3727 * FUNCTION
3729 * INPUTS
3730 * id - ID of IE to find.
3731 * ies - A series of IEs.
3732 * ies_length - Length of IE block.
3734 * RESULT
3735 * ie - Pointer to start of IE within block, or NULL if not found.
3737 ****************************************************************************
3741 #if 0
3742 static UBYTE *GetIE(UBYTE id, UBYTE *ies, UWORD ies_length,
3743 struct DevBase *base)
3745 BOOL found = FALSE;
3746 UBYTE *ie, *end;
3748 // for(ie = ies; ie < end && ie + ie[1] < end; ie += length + 2)
3749 end = ies + ies_length;
3750 while(ie < end && !found)
3752 if(ie[0] == id)
3753 found = TRUE;
3754 else
3755 ie += ie[1] + 2;
3757 if(!found)
3758 ie = NULL;
3760 return ie;
3762 #else
3763 static UBYTE *GetIE(UBYTE id, UBYTE *ies, UWORD ies_length,
3764 struct DevBase *base)
3766 UBYTE *ie;
3768 for(ie = ies; ie < ies + ies_length && ie[0] != id; ie += ie[1] + 2);
3769 // for(ie = ies, end = ies + ies_length; ie < end && ie[0] != id; ie += ie[1] + 2);
3770 if(ie >= ies + ies_length)
3771 ie = NULL;
3773 return ie;
3775 #endif
3778 /****i* prism2.device/UnitTask *********************************************
3780 * NAME
3781 * UnitTask
3783 * SYNOPSIS
3784 * UnitTask(sys_base)
3786 * VOID UnitTask(struct ExecBase *);
3788 * FUNCTION
3789 * Completes deferred requests, and handles card insertion and removal
3790 * in conjunction with the relevant interrupts.
3792 ****************************************************************************
3796 #ifdef __MORPHOS__
3797 #undef UnitTask
3798 #endif
3800 static VOID UnitTask(struct ExecBase *sys_base)
3802 struct Task *task;
3803 struct IORequest *request;
3804 struct DevUnit *unit;
3805 struct DevBase *base;
3806 struct MsgPort *general_port;
3807 ULONG signals = 0, wait_signals, card_removed_signal,
3808 card_inserted_signal, scan_complete_signal, general_port_signal;
3810 /* Get parameters */
3812 task = AbsExecBase->ThisTask;
3813 unit = task->tc_UserData;
3814 base = unit->device;
3816 /* Activate general request port */
3818 general_port = unit->request_ports[GENERAL_QUEUE];
3819 general_port->mp_SigTask = task;
3820 general_port->mp_SigBit = AllocSignal(-1);
3821 general_port_signal = 1 << general_port->mp_SigBit;
3822 general_port->mp_Flags = PA_SIGNAL;
3824 /* Allocate signals for notification of card removal and insertion */
3826 card_removed_signal = unit->card_removed_signal = 1 << AllocSignal(-1);
3827 card_inserted_signal = unit->card_inserted_signal = 1 << AllocSignal(-1);
3828 scan_complete_signal = unit->scan_complete_signal = 1 << AllocSignal(-1);
3829 wait_signals = (1 << general_port->mp_SigBit) | card_removed_signal
3830 | card_inserted_signal | scan_complete_signal | SIGBREAKF_CTRL_C;
3832 /* Tell ourselves to check port for old messages */
3834 Signal(task, general_port_signal);
3836 /* Infinite loop to service requests and signals */
3838 while((signals & SIGBREAKF_CTRL_C) == 0)
3840 signals = Wait(wait_signals);
3842 if((signals & card_inserted_signal) != 0)
3844 if(unit->insertion_function(unit->card, base))
3846 unit->flags |= UNITF_HAVEADAPTER;
3847 if((unit->flags & UNITF_CONFIGURED) != 0)
3848 ConfigureAdapter(unit, base);
3849 if((unit->flags & UNITF_WASONLINE) != 0)
3851 GoOnline(unit, base);
3852 unit->flags &= ~UNITF_WASONLINE;
3857 if((signals & card_removed_signal) != 0)
3859 unit->removal_function(unit->card, base);
3860 if((unit->flags & UNITF_WASONLINE) != 0)
3861 GoOffline(unit, base);
3864 if((signals & scan_complete_signal) != 0)
3865 SendScanResults(unit, base);
3867 if((signals & general_port_signal) != 0)
3869 while((request = (APTR)GetMsg(general_port)) != NULL)
3871 /* Service the request as soon as the unit is free */
3873 ObtainSemaphore(&unit->access_lock);
3874 ServiceRequest((APTR)request, base);
3879 FreeMem(task->tc_SPLower, STACK_SIZE);
3884 /****i* prism2.device/StrLen ***********************************************
3886 * NAME
3887 * StrLen
3889 * SYNOPSIS
3890 * length = StrLen(s)
3892 * UPINT StrLen(TEXT *);
3894 ****************************************************************************
3898 static UPINT StrLen(const TEXT *s)
3900 const TEXT *p;
3902 for(p = s; *p != '\0'; p++);
3903 return p - s;