3 Copyright (C) 2012-2017 The AROS Dev Team
4 Copyright (C) 2001-2012 Neil Cafferkey
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston,
24 #include <exec/memory.h>
25 #include <exec/execbase.h>
26 #include <exec/errors.h>
28 #include <proto/exec.h>
30 #include <proto/alib.h>
32 #include <clib/alib_protos.h>
34 #include <proto/utility.h>
35 #include <proto/dos.h>
36 #include <proto/timer.h>
41 #include "unit_protos.h"
42 #include "request_protos.h"
43 #include "encryption_protos.h"
44 #include "timer_protos.h"
47 #define TASK_PRIORITY 0
48 #define STACK_SIZE 4096
50 (P2_EVENTF_INFO | P2_EVENTF_ALLOCMEM | P2_EVENTF_TXFAIL | P2_EVENTF_RX)
51 #define MAX_S_REC_SIZE 50
52 #define LUCENT_DBM_OFFSET 149
53 #define INTERSIL_DBM_OFFSET 100
54 #define SCAN_BUFFER_SIZE 2000
55 #define BEACON_BUFFER_SIZE 8000
56 #define SCAN_TAG_COUNT 8 +10
57 #define INFO_TAG_COUNT 4 +10
58 #define LUCENT_PDA_ADDRESS 0x390000
59 #define LUCENT_PDA_SIZE 1000
60 #define FRAME_BUFFER_SIZE (P2_H2FRM_ETHFRAME + ETH_HEADERSIZE \
61 + SNAP_HEADERSIZE + ETH_MTU + EIV_SIZE + ICV_SIZE + MIC_SIZE)
66 #define AbsExecBase sys_base
68 #define AbsExecBase (*(struct ExecBase **)4)
72 static struct AddressRange
*FindMulticastRange(struct DevUnit
*unit
,
73 ULONG lower_bound_left
, UWORD lower_bound_right
, ULONG upper_bound_left
,
74 UWORD upper_bound_right
, struct DevBase
*base
);
75 static VOID
SetMulticast(struct DevUnit
*unit
, struct DevBase
*base
);
76 static VOID
RXInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
));
77 static UBYTE
*GetRXBuffer(struct DevUnit
*unit
, const UBYTE
*address
,
78 UWORD frag_no
, UWORD
*buffer_no
, struct DevBase
*base
);
79 static VOID
DistributeRXPacket(struct DevUnit
*unit
, UBYTE
*frame
,
80 struct DevBase
*base
);
81 static VOID
CopyPacket(struct DevUnit
*unit
, struct IOSana2Req
*request
,
82 UWORD packet_size
, UWORD packet_type
, UBYTE
*buffer
,
83 struct DevBase
*base
);
84 static BOOL
AddressFilter(struct DevUnit
*unit
, UBYTE
*address
,
85 struct DevBase
*base
);
86 static VOID
SaveBeacon(struct DevUnit
*unit
, const UBYTE
*frame
,
87 struct DevBase
*base
);
88 static VOID
TXInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
));
89 static VOID
InfoInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
));
90 static VOID
ResetHandler(REG(a1
, struct DevUnit
*unit
),
91 REG(a6
, APTR int_code
));
92 static VOID
ReportEvents(struct DevUnit
*unit
, ULONG events
,
93 struct DevBase
*base
);
94 static BOOL
LoadFirmware(struct DevUnit
*unit
, struct DevBase
*base
);
95 static const TEXT
*ParseNextSRecord(const TEXT
*s
, UBYTE
*type
, UBYTE
*data
,
96 UWORD
*data_length
, ULONG
*location
, struct DevBase
*base
);
97 static VOID
P2DoCmd(struct DevUnit
*unit
, UWORD command
, UWORD param
,
98 struct DevBase
*base
);
99 static BOOL
P2Seek(struct DevUnit
*unit
, UWORD path_no
, UWORD rec_no
,
100 UWORD offset
, struct DevBase
*base
);
101 static VOID
P2SetID(struct DevUnit
*unit
, UWORD rec_no
, const UBYTE
*id
,
102 UWORD length
, struct DevBase
*base
);
103 static VOID
P2SetWord(struct DevUnit
*unit
, UWORD rec_no
, UWORD value
,
104 struct DevBase
*base
);
105 static UWORD
P2GetWord(struct DevUnit
*unit
, UWORD rec_no
,
106 struct DevBase
*base
);
107 static UWORD
P2AllocMem(struct DevUnit
*unit
, UWORD size
,
108 struct DevBase
*base
);
109 static VOID
P2SetData(struct DevUnit
*unit
, UWORD rec_no
, const UBYTE
*data
,
110 UWORD length
, struct DevBase
*base
);
111 static BOOL
P2ReadRec(struct DevUnit
*unit
, UWORD rec_no
, APTR buffer
,
112 UWORD max_length
, struct DevBase
*base
);
113 static LONG
ConvertLevel(struct DevUnit
*unit
, UWORD raw_level
,
114 struct DevBase
*base
);
115 static LONG
ConvertScanLevel(struct DevUnit
*unit
, UWORD raw_level
,
116 struct DevBase
*base
);
117 static UBYTE
*GetIE(UBYTE id
, UBYTE
*ies
, UWORD ies_length
,
118 struct DevBase
*base
);
119 static VOID
UnitTask(struct ExecBase
*sys_base
);
120 static UPINT
StrLen(const TEXT
*s
);
123 static const UBYTE snap_template
[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
124 static const UBYTE scan_params
[] = {0xff, 0x3f, 0x01, 0x00, 0x00, 0x00};
125 #if !defined(__AROS__)
126 static const TEXT options_name
[] = "Prism 2 options";
128 static const TEXT h1_firmware_file_name
[] = "DEVS:Firmware/HermesI";
129 static const TEXT h2_firmware_file_name
[] = "DEVS:Firmware/HermesII";
130 static const TEXT h25_firmware_file_name
[] = "DEVS:Firmware/HermesII.5";
131 static const UBYTE h2_wpa_ie
[] =
133 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00,
134 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50,
135 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02,
142 #define AddTask(task, initial_pc, final_pc) \
143 IExec->AddTask(task, initial_pc, final_pc, NULL)
146 static const struct EmulLibEntry mos_task_trap
=
152 #define UnitTask &mos_task_trap
156 #define AddTask(task, initial_pc, final_pc) \
158 struct TagItem _task_tags[] = \
159 {{TASKTAG_ARG1, (IPTR)SysBase}, {TAG_END, 0}}; \
160 NewAddTask(task, initial_pc, final_pc, _task_tags); \
166 /****i* prism2.device/CreateUnit *******************************************
169 * CreateUnit -- Create a unit.
172 * unit = CreateUnit(index, card, io_tags, bus)
174 * struct DevUnit *CreateUnit(ULONG, APTR, struct TagItem *, UWORD);
177 * Creates a new unit.
179 ****************************************************************************
183 struct DevUnit
*CreateUnit(ULONG index
, APTR card
,
184 const struct TagItem
*io_tags
, UWORD bus
, struct DevBase
*base
)
187 struct DevUnit
*unit
;
189 struct MsgPort
*port
;
193 unit
= AllocMem(sizeof(struct DevUnit
), MEMF_CLEAR
| MEMF_PUBLIC
);
204 (APTR
)GetTagData(IOTAG_WordsIn
, (UPINT
)NULL
, io_tags
);
206 (APTR
)GetTagData(IOTAG_WordsOut
, (UPINT
)NULL
, io_tags
);
208 (APTR
)GetTagData(IOTAG_BEWordOut
, (UPINT
)NULL
, io_tags
);
210 (APTR
)GetTagData(IOTAG_LEWordIn
, (UPINT
)NULL
, io_tags
);
212 (APTR
)GetTagData(IOTAG_LEWordOut
, (UPINT
)NULL
, io_tags
);
213 if(unit
->WordsIn
== NULL
|| unit
->WordsOut
== NULL
214 || unit
->BEWordOut
== NULL
|| unit
->LEWordIn
== NULL
215 || unit
->LEWordOut
== NULL
)
221 InitSemaphore(&unit
->access_lock
);
222 success
= InitialiseAdapter(unit
, FALSE
, base
);
223 unit
->flags
|= UNITF_HAVEADAPTER
;
225 /* Create the message ports for queuing requests */
227 for(i
= 0; i
< REQUEST_QUEUE_COUNT
; i
++)
229 unit
->request_ports
[i
] = port
= AllocMem(sizeof(struct MsgPort
),
230 MEMF_PUBLIC
| MEMF_CLEAR
);
236 NewList(&port
->mp_MsgList
);
237 port
->mp_Flags
= PA_IGNORE
;
238 port
->mp_SigTask
= &unit
->tx_int
;
242 /* Allocate buffers */
244 unit
->rx_buffer
= AllocVec(FRAME_BUFFER_SIZE
, MEMF_PUBLIC
);
245 unit
->rx_buffers
= AllocVec(FRAME_BUFFER_SIZE
* RX_BUFFER_COUNT
,
247 for(i
= 0; i
< RX_BUFFER_COUNT
; i
++)
248 unit
->rx_fragment_nos
[i
] = -1;
249 unit
->tx_buffer
= AllocVec(ETH_MAXPACKETSIZE
, MEMF_PUBLIC
);
250 unit
->rx_descriptor
= AllocVec(FRAME_BUFFER_SIZE
,
251 MEMF_PUBLIC
| MEMF_CLEAR
);
252 unit
->tx_descriptor
= AllocVec(FRAME_BUFFER_SIZE
,
253 MEMF_PUBLIC
| MEMF_CLEAR
);
254 unit
->scan_results_rec
= AllocVec(SCAN_BUFFER_SIZE
, MEMF_PUBLIC
);
255 unit
->next_beacon
= unit
->beacons
=
256 AllocVec(BEACON_BUFFER_SIZE
, MEMF_PUBLIC
);
257 if(unit
->rx_buffer
== NULL
|| unit
->rx_buffers
== NULL
258 || unit
->tx_buffer
== NULL
|| unit
->rx_descriptor
== NULL
259 || unit
->tx_descriptor
== NULL
|| unit
->scan_results_rec
== NULL
260 || unit
->beacons
== NULL
)
266 NewList((APTR
)&unit
->openers
);
267 NewList((APTR
)&unit
->type_trackers
);
268 NewList((APTR
)&unit
->multicast_ranges
);
270 /* Record maximum speed in BPS */
272 unit
->speed
= 11000000;
274 /* Initialise status, transmit, receive and stats interrupts */
276 unit
->status_int
.is_Node
.ln_Name
=
277 base
->device
.dd_Library
.lib_Node
.ln_Name
;
278 unit
->status_int
.is_Code
= (APTR
)StatusInt
;
279 unit
->status_int
.is_Data
= unit
;
281 unit
->rx_int
.is_Node
.ln_Name
=
282 base
->device
.dd_Library
.lib_Node
.ln_Name
;
283 unit
->rx_int
.is_Code
= (APTR
)RXInt
;
284 unit
->rx_int
.is_Data
= unit
;
286 unit
->tx_int
.is_Node
.ln_Name
=
287 base
->device
.dd_Library
.lib_Node
.ln_Name
;
288 unit
->tx_int
.is_Code
= (APTR
)TXInt
;
289 unit
->tx_int
.is_Data
= unit
;
291 unit
->info_int
.is_Node
.ln_Name
=
292 base
->device
.dd_Library
.lib_Node
.ln_Name
;
293 unit
->info_int
.is_Code
= (APTR
)InfoInt
;
294 unit
->info_int
.is_Data
= unit
;
296 unit
->reset_handler
.is_Node
.ln_Name
=
297 base
->device
.dd_Library
.lib_Node
.ln_Name
;
298 unit
->reset_handler
.is_Code
= (APTR
)ResetHandler
;
299 unit
->reset_handler
.is_Data
= unit
;
301 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
306 /* Create a new task */
309 AllocMem(sizeof(struct Task
), MEMF_PUBLIC
| MEMF_CLEAR
);
316 stack
= AllocMem(STACK_SIZE
, MEMF_PUBLIC
);
323 /* Initialise and start task */
325 task
->tc_Node
.ln_Type
= NT_TASK
;
326 task
->tc_Node
.ln_Pri
= TASK_PRIORITY
;
327 task
->tc_Node
.ln_Name
= base
->device
.dd_Library
.lib_Node
.ln_Name
;
328 task
->tc_SPUpper
= stack
+ STACK_SIZE
;
329 task
->tc_SPLower
= stack
;
330 task
->tc_SPReg
= stack
+ STACK_SIZE
;
331 NewList(&task
->tc_MemEntry
);
333 if(AddTask(task
, UnitTask
, NULL
) == NULL
)
339 /* Send the unit to the new task */
341 task
->tc_UserData
= unit
;
343 /* Set default wireless options */
345 unit
->mode
= S2PORT_MANAGED
;
350 DeleteUnit(unit
, base
);
359 /****i* prism2.device/DeleteUnit *******************************************
362 * DeleteUnit -- Delete a unit.
367 * VOID DeleteUnit(struct DevUnit *);
373 * unit - Device unit (may be NULL).
378 ****************************************************************************
382 VOID
DeleteUnit(struct DevUnit
*unit
, struct DevBase
*base
)
394 if(task
->tc_UserData
!= NULL
)
397 FreeMem(task
->tc_SPLower
, STACK_SIZE
);
399 FreeMem(task
, sizeof(struct Task
));
402 /* Free request queues */
404 for(i
= 0; i
< REQUEST_QUEUE_COUNT
; i
++)
406 if(unit
->request_ports
[i
] != NULL
)
407 FreeMem(unit
->request_ports
[i
], sizeof(struct MsgPort
));
412 if((unit
->flags
& UNITF_ONLINE
) != 0) /* Needed! */
413 GoOffline(unit
, base
);
415 /* Clear target SSID */
417 P2SetID(unit
, P2_REC_DESIREDSSID
, unit
->ssid
, 0, base
);
419 /* Free buffers and unit structure */
421 FreeVec(unit
->scan_results_rec
);
422 FreeVec(unit
->tx_descriptor
);
423 FreeVec(unit
->rx_descriptor
);
424 FreeVec(unit
->tx_buffer
);
425 FreeVec(unit
->rx_buffers
);
426 FreeVec(unit
->rx_buffer
);
428 FreeMem(unit
, sizeof(struct DevUnit
));
436 /****i* prism2.device/InitialiseAdapter ************************************
442 * success = InitialiseAdapter(unit, reinsertion)
444 * BOOL InitialiseAdapter(struct DevUnit *, BOOL);
453 * success - Success indicator.
455 ****************************************************************************
459 BOOL
InitialiseAdapter(struct DevUnit
*unit
, BOOL reinsertion
,
460 struct DevBase
*base
)
462 UWORD id
, version
, revision
, i
;
463 BOOL success
= TRUE
, loaded
;
464 UBYTE address
[ETH_ADDRESSSIZE
];
467 /* Wait for card to be ready following bus-specific reset, then start
470 while((unit
->LEWordIn(unit
->card
, P2_REG_COMMAND
)
471 & P2_REG_COMMANDF_BUSY
) != 0);
473 P2DoCmd(unit
, P2_CMD_INIT
, 0, base
);
475 /* Determine firmware type */
477 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_NICIDENTITY
, base
);
478 P2Seek(unit
, 1, P2_REC_NICIDENTITY
, 4, base
);
479 id
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
480 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
481 version
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
482 revision
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
484 if((id
& 0x8000) != 0)
487 unit
->firmware_type
= SYMBOL_FIRMWARE
;
489 unit
->firmware_type
= INTERSIL_FIRMWARE
;
493 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_PRIIDENTITY
, base
);
494 P2Seek(unit
, 1, P2_REC_PRIIDENTITY
, 0, base
);
495 length
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
497 unit
->firmware_type
= LUCENT_FIRMWARE
;
500 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_STAIDENTITY
, base
);
501 P2Seek(unit
, 1, P2_REC_STAIDENTITY
, 4, base
);
502 id
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
503 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
504 version
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
505 revision
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
507 unit
->firmware_type
= HERMES2G_FIRMWARE
;
509 unit
->firmware_type
= HERMES2_FIRMWARE
;
513 /* Download firmware if necessary or available */
515 loaded
= LoadFirmware(unit
, base
);
516 if(!loaded
&& unit
->firmware_type
>= HERMES2_FIRMWARE
)
521 /* Determine features, and get offsets of certain fields within frame
524 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_STAIDENTITY
, base
);
525 P2Seek(unit
, 1, P2_REC_STAIDENTITY
, 4, base
);
526 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
527 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
528 version
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
529 revision
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
531 if(P2GetWord(unit
, P2_REC_HASWEP
, base
) != 0)
532 unit
->flags
|= UNITF_HASWEP
| UNITF_HARDWEP
;
534 unit
->ethernet_offset
= P2_FRM_ETHFRAME
;
535 unit
->data_offset
= P2_FRM_DATA
;
536 unit
->txcontrol_offset
= P2_FRM_TXCONTROL
;
537 unit
->datalen_offset
= P2_FRM_DATALEN
;
539 if(unit
->firmware_type
== LUCENT_FIRMWARE
)
541 if(version
> 6 || version
== 6 && revision
>= 6)
542 unit
->flags
|= UNITF_HASADHOC
;
545 unit
->flags
|= UNITF_HASTKIP
| UNITF_HARDTKIP
;
546 unit
->txcontrol_offset
= P2_FRM_ALTTXCONTROL
;
549 else if(unit
->firmware_type
>= HERMES2_FIRMWARE
)
551 unit
->flags
|= UNITF_HASADHOC
| UNITF_HASTKIP
| UNITF_HARDTKIP
;
552 unit
->ethernet_offset
= P2_H2FRM_ETHFRAME
;
553 unit
->data_offset
= P2_H2FRM_DATA
;
554 unit
->txcontrol_offset
= P2_H2FRM_TXCONTROL
;
555 unit
->datalen_offset
= P2_H2FRM_DATALEN
;
557 else if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
559 unit
->flags
|= UNITF_HASADHOC
| UNITF_HASWEP
;
560 if(version
== 1 && revision
>= 7)
561 unit
->flags
|= UNITF_HASTKIP
| UNITF_HASCCMP
;
564 /* Get default channel and MAC address */
566 unit
->channel
= P2GetWord(unit
, P2_REC_OWNCHNL
, base
);
567 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_ADDRESS
, base
);
568 P2Seek(unit
, 1, P2_REC_ADDRESS
, 4, base
);
569 unit
->WordsIn(unit
->card
, P2_REG_DATA1
, (UWORD
*)address
,
570 ETH_ADDRESSSIZE
/ 2);
572 /* If card has been re-inserted, check it has the same address as
577 for(i
= 0; i
< ETH_ADDRESSSIZE
; i
++)
578 if(address
[i
] != unit
->default_address
[i
])
585 CopyMem(address
, unit
->default_address
, ETH_ADDRESSSIZE
);
587 /* Get initial on-card TX buffer */
589 unit
->tx_frame_id
= P2AllocMem(unit
, FRAME_BUFFER_SIZE
, base
);
593 if((unit
->flags
& UNITF_HARDWEP
) == 0)
594 unit
->iv_sizes
[S2ENC_WEP
] = IV_SIZE
;
595 if((unit
->flags
& UNITF_HARDTKIP
) == 0)
596 unit
->iv_sizes
[S2ENC_TKIP
] = EIV_SIZE
;
597 unit
->iv_sizes
[S2ENC_CCMP
] = EIV_SIZE
;
599 /* Set encryption functions */
601 unit
->fragment_encrypt_functions
[S2ENC_NONE
] = WriteClearFragment
;
603 if((unit
->flags
& UNITF_HARDWEP
) != 0)
604 unit
->fragment_encrypt_functions
[S2ENC_WEP
] = WriteClearFragment
;
606 unit
->fragment_encrypt_functions
[S2ENC_WEP
] = EncryptWEPFragment
;
608 if((unit
->flags
& UNITF_HARDTKIP
) != 0)
609 unit
->fragment_encrypt_functions
[S2ENC_TKIP
] = WriteClearFragment
;
611 unit
->fragment_encrypt_functions
[S2ENC_TKIP
] = EncryptTKIPFragment
;
613 unit
->fragment_encrypt_functions
[S2ENC_CCMP
] = EncryptCCMPFragment
;
615 /* Set decryption functions */
617 unit
->fragment_decrypt_functions
[S2ENC_NONE
] = ReadClearFragment
;
619 if((unit
->flags
& UNITF_HARDWEP
) != 0)
620 unit
->fragment_decrypt_functions
[S2ENC_WEP
] = ReadClearFragment
;
622 unit
->fragment_decrypt_functions
[S2ENC_WEP
] = DecryptWEPFragment
;
624 if((unit
->flags
& UNITF_HARDTKIP
) != 0)
625 unit
->fragment_decrypt_functions
[S2ENC_TKIP
] = ReadClearFragment
;
627 unit
->fragment_decrypt_functions
[S2ENC_TKIP
] = DecryptTKIPFragment
;
629 unit
->fragment_decrypt_functions
[S2ENC_CCMP
] = DecryptCCMPFragment
;
639 /****i* prism2.device/ConfigureAdapter *************************************
642 * ConfigureAdapter -- Set up card for transmission/reception.
645 * ConfigureAdapter(unit)
647 * VOID ConfigureAdapter(struct DevUnit *);
649 ****************************************************************************
653 VOID
ConfigureAdapter(struct DevUnit
*unit
, struct DevBase
*base
)
655 UWORD i
, key_length
, port_type
, lowest_enc
= S2ENC_CCMP
,
656 highest_enc
= S2ENC_NONE
, enc_flags
, size
, value
;
657 const struct KeyUnion
*keys
;
659 /* Set MAC address */
661 P2SetData(unit
, P2_REC_ADDRESS
, unit
->address
, ETH_ADDRESSSIZE
,
664 /* Decide on promiscuous mode */
666 P2SetWord(unit
, P2_REC_PROMISC
, FALSE
, base
);
667 SetMulticast(unit
, base
);
669 /* Set wireless parameters */
671 if(unit
->mode
== S2PORT_ADHOC
)
673 P2SetWord(unit
, P2_REC_OWNCHNL
, unit
->channel
, base
);
674 P2SetID(unit
, P2_REC_OWNSSID
, unit
->ssid
, unit
->ssid_length
, base
);
676 if(unit
->mode
== S2PORT_MANAGED
)
680 if((unit
->flags
& UNITF_ONLINE
) == 0)
681 P2SetWord(unit
, P2_REC_PORTTYPE
, port_type
, base
);
682 P2SetWord(unit
, P2_REC_CREATEIBSS
, unit
->mode
== S2PORT_ADHOC
, base
);
683 P2SetID(unit
, P2_REC_DESIREDSSID
, unit
->ssid
, unit
->ssid_length
, base
);
685 /* Determine highest encryption type in use */
687 for(i
= 0; i
< WIFI_KEYCOUNT
; i
++)
689 if(unit
->keys
[i
].type
> highest_enc
)
690 highest_enc
= unit
->keys
[i
].type
;
691 if(unit
->keys
[i
].type
< lowest_enc
)
692 lowest_enc
= unit
->keys
[i
].type
;
695 if(unit
->wpa_ie
[1] != 0)
696 highest_enc
= S2ENC_TKIP
; // TO DO: Be more specific?
698 /* Allow reception of beacon/probe-response frames */
700 if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
701 P2SetWord(unit
, P2_REC_RXMGMTFRAMES
, 1, base
);
703 /* Transmit at 11Mbps, with fallback */
705 if(unit
->firmware_type
== INTERSIL_FIRMWARE
706 || unit
->firmware_type
== SYMBOL_FIRMWARE
)
707 P2SetWord(unit
, P2_REC_TXRATE
, 0xf, base
);
709 /* Configure authentication and encryption */
711 if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
713 /* Set authentication and encryption modes */
715 P2SetWord(unit
, P2_REC_ALTAUTHTYPE
, unit
->auth_types
, base
);
717 P2SetWord(unit
, P2_REC_ALTENCRYPTION
, highest_enc
, base
);
719 /* Set up firmware-based WEP encryption if appropriate */
721 if(highest_enc
== S2ENC_WEP
&& (unit
->flags
& UNITF_HARDWEP
) != 0)
723 P2SetWord(unit
, P2_REC_ALTTXCRYPTKEY
, unit
->tx_key_no
, base
);
724 P2Seek(unit
, 1, P2_REC_DEFLTCRYPTKEYS
, 0, base
);
725 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, P2_ALTWEPRECLEN
);
726 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, P2_REC_DEFLTCRYPTKEYS
);
728 for(i
= 0; i
< WIFI_KEYCOUNT
; i
++)
730 key_length
= keys
[i
].u
.wep
.length
;
732 key_length
= WIFI_WEP128LEN
;
733 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, key_length
);
734 unit
->WordsOut(unit
->card
, P2_REG_DATA1
,
735 (UWORD
*)keys
[i
].u
.wep
.key
, (key_length
+ 1) / 2);
738 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
,
739 P2_REC_DEFLTCRYPTKEYS
, base
);
742 /* Set key management suite to PSK */
744 if(highest_enc
> S2ENC_WEP
)
746 value
= (unit
->firmware_type
>= HERMES2_FIRMWARE
) ? 4 : 2;
747 P2SetWord(unit
, P2_REC_KEYMGMTSUITE
, value
, base
);
752 /* Set authentication mode */
754 P2SetWord(unit
, P2_REC_AUTHTYPE
, unit
->auth_types
, base
);
756 /* Set encryption flags */
758 if(highest_enc
> S2ENC_NONE
)
759 enc_flags
= P2_REC_ENCRYPTIONF_ENABLE
;
763 if(highest_enc
> S2ENC_WEP
764 || highest_enc
== S2ENC_WEP
&& (unit
->flags
& UNITF_HARDWEP
) == 0)
765 enc_flags
|= P2_REC_ENCRYPTIONF_HOSTDECRYPT
766 | P2_REC_ENCRYPTIONF_HOSTENCRYPT
;
767 P2SetWord(unit
, P2_REC_ENCRYPTION
, enc_flags
, base
);
769 /* Set up firmware-based WEP encryption if appropriate */
771 if(highest_enc
== S2ENC_WEP
&& (unit
->flags
& UNITF_HARDWEP
) != 0)
773 P2SetWord(unit
, P2_REC_TXCRYPTKEY
, unit
->tx_key_no
, base
);
776 for(i
= 0; i
< WIFI_KEYCOUNT
; i
++)
778 key_length
= keys
[i
].u
.wep
.length
;
780 key_length
= keys
[unit
->tx_key_no
].u
.wep
.length
;
781 P2SetData(unit
, P2_REC_CRYPTKEY0
+ i
, keys
[i
].u
.wep
.key
,
786 /* Set or clear WPA IE */
788 if(highest_enc
> S2ENC_WEP
)
789 size
= unit
->wpa_ie
[1] + 2;
792 P2SetID(unit
, P2_REC_WPAIE
, unit
->wpa_ie
, size
, base
);
794 /* Let supplicant handle association and roaming */
796 P2SetWord(unit
, P2_REC_ROAMINGMODE
, 3, base
);
799 /* Restart the transceiver if we're already online */
801 if((unit
->flags
& UNITF_ONLINE
) != 0)
803 P2DoCmd(unit
, P2_CMD_DISABLE
, 0, base
);
804 P2DoCmd(unit
, P2_CMD_ENABLE
, 0, base
);
806 /* Attempt to join specified network */
808 if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
810 typedef union { UBYTE b
[2]; UWORD w
;} BW
;
811 BW
*p
= (BW
*)(unit
->bssid
+ ETH_ADDRESSSIZE
);
812 p
->w
= MakeLEWord(unit
->channel
);
813 P2SetData(unit
, P2_REC_JOIN
, unit
->bssid
, ETH_ADDRESSSIZE
+ 2,
825 /****i* prism2.device/GoOnline *********************************************
828 * GoOnline -- Enable transmission/reception.
833 * VOID GoOnline(struct DevUnit *);
835 ****************************************************************************
839 VOID
GoOnline(struct DevUnit
*unit
, struct DevBase
*base
)
841 /* Enable interrupts */
843 unit
->flags
|= UNITF_ONLINE
;
844 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, INT_MASK
);
846 /* Enable the transceiver */
848 P2DoCmd(unit
, P2_CMD_ENABLE
, 0, base
);
850 /* Record start time and report Online event */
852 GetSysTime(&unit
->stats
.LastStart
);
853 ReportEvents(unit
, S2EVENT_ONLINE
, base
);
860 /****i* prism2.device/GoOffline ********************************************
863 * GoOffline -- Disable transmission/reception.
868 * VOID GoOffline(struct DevUnit *);
878 ****************************************************************************
882 VOID
GoOffline(struct DevUnit
*unit
, struct DevBase
*base
)
884 unit
->flags
&= ~UNITF_ONLINE
;
885 if((unit
->flags
& UNITF_HAVEADAPTER
) != 0)
887 /* Stop interrupts */
889 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, 0);
890 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
892 /* Update statistics */
894 UpdateStats(unit
, base
);
896 /* Stop transmission and reception */
898 P2DoCmd(unit
, P2_CMD_DISABLE
, 0, base
);
901 /* Flush pending read and write requests */
903 FlushUnit(unit
, WRITE_QUEUE
, S2ERR_OUTOFSERVICE
, base
);
905 /* Report Offline event and return */
907 ReportEvents(unit
, S2EVENT_OFFLINE
, base
);
913 /****i* prism2.device/SetOptions *******************************************
916 * SetOptions -- Set and use interface options.
919 * SetOptions(unit, tag_list)
921 * VOID SetOptions(struct DevUnit *, struct TagItem *);
923 ****************************************************************************
927 VOID
SetOptions(struct DevUnit
*unit
, const struct TagItem
*tag_list
,
928 struct DevBase
*base
)
930 struct TagItem
*tag_item
, *tlist
= (struct TagItem
*)tag_list
;
935 while((tag_item
= NextTagItem(&tlist
)) != NULL
)
937 switch(tag_item
->ti_Tag
)
940 id
= (const TEXT
*)tag_item
->ti_Data
;
942 CopyMem(id
, unit
->ssid
, length
);
943 unit
->ssid_length
= length
;
947 CopyMem((APTR
)tag_item
->ti_Data
, unit
->bssid
, ETH_ADDRESSSIZE
);
950 case S2INFO_DefaultKeyNo
:
951 unit
->tx_key_no
= tag_item
->ti_Data
;
954 case S2INFO_PortType
:
955 unit
->mode
= tag_item
->ti_Data
;
959 if(tag_item
->ti_Data
!= 0) // ???
960 unit
->channel
= tag_item
->ti_Data
;
964 if(tag_item
->ti_Data
!= (UPINT
)NULL
)
966 /* Hermes-II uses an "unusual" WPA IE in its association
967 request. So we use a matching IE everywhere else too */
969 if(unit
->firmware_type
>= HERMES2_FIRMWARE
)
972 ie
= (const UBYTE
*)tag_item
->ti_Data
;
973 CopyMem(ie
, unit
->wpa_ie
, ie
[1] + 2);
982 case S2INFO_AuthTypes
:
983 unit
->auth_types
= tag_item
->ti_Data
;
993 /****i* prism2.device/SetKey ***********************************************
996 * SetKey -- Set an encryption key.
999 * SetKey(unit, index, type, key, key_length,
1002 * VOID SetKey(struct DevUnit *, ULONG, ULONG, UBYTE *, ULONG,
1005 ****************************************************************************
1009 VOID
SetKey(struct DevUnit
*unit
, ULONG index
, ULONG type
, const UBYTE
*key
,
1010 ULONG key_length
, const UBYTE
*rx_counter
, struct DevBase
*base
)
1012 struct KeyUnion
*slot
;
1013 const UBYTE tx_counter
[8] = {0, 0, 0, 0, 0x10, 0, 0, 0};
1015 struct EClockVal eclock
;
1018 slot
= &unit
->keys
[index
];
1022 CopyMem(key
, slot
->u
.wep
.key
, key_length
);
1023 slot
->u
.wep
.length
= key_length
;
1025 if((unit
->flags
& UNITF_HARDWEP
) == 0)
1027 /* Create a reasonably random IV */
1029 ReadEClock(&eclock
);
1030 slot
->u
.wep
.tx_iv
= FastRand(eclock
.ev_lo
^ eclock
.ev_hi
);
1036 CopyMem(key
, slot
->u
.tkip
.key
, 16);
1037 CopyMem(key
+ 16, slot
->u
.tkip
.tx_mic_key
, MIC_SIZE
);
1038 CopyMem(key
+ 24, slot
->u
.tkip
.rx_mic_key
, MIC_SIZE
);
1039 slot
->u
.tkip
.tx_iv_low
= 0;
1040 slot
->u
.tkip
.tx_iv_high
= 0;
1041 slot
->u
.tkip
.rx_iv_low
= LEWord(*(UWORD
*)rx_counter
);
1042 slot
->u
.tkip
.rx_iv_high
= LELong(*(ULONG
*)(rx_counter
+ 2));
1043 slot
->u
.tkip
.tx_ttak_set
= FALSE
;
1044 slot
->u
.tkip
.rx_ttak_set
= FALSE
;
1046 if((unit
->flags
& UNITF_HARDTKIP
) != 0)
1048 /* For Hermes, load parameters for hardware encryption. The
1049 pairwise key is treated differently from group keys on
1050 Hermes-II, but not on Hermes-I */
1052 if(unit
->firmware_type
>= HERMES2_FIRMWARE
&& index
== 0)
1054 P2Seek(unit
, 1, P2_REC_ADDMAPPEDTKIPKEY
, 0, base
);
1055 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 28);
1056 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
,
1057 P2_REC_ADDMAPPEDTKIPKEY
);
1058 unit
->WordsOut(unit
->card
, P2_REG_DATA1
,
1059 (UWORD
*)unit
->bssid
, ETH_ADDRESSSIZE
/ 2);
1060 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)key
,
1062 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)tx_counter
,
1064 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)rx_counter
,
1066 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 0);
1067 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)key
+ 16,
1069 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
,
1070 P2_REC_ADDMAPPEDTKIPKEY
, base
);
1074 P2Seek(unit
, 1, P2_REC_ADDDEFAULTTKIPKEY
, 0, base
);
1075 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 26);
1076 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
,
1077 P2_REC_ADDDEFAULTTKIPKEY
);
1078 if(index
== unit
->tx_key_no
)
1080 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, index
);
1081 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)rx_counter
,
1083 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 0);
1084 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)key
,
1086 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)tx_counter
,
1088 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
,
1089 P2_REC_ADDDEFAULTTKIPKEY
, base
);
1094 /* Convert key to native endianness */
1096 for(i
= 0; i
< 8; i
++)
1097 slot
->u
.tkip
.key
[i
] = LEWord(slot
->u
.tkip
.key
[i
]);
1103 CopyMem(key
, slot
->u
.ccmp
.key
, 16);
1104 slot
->u
.ccmp
.tx_iv_low
= 0;
1105 slot
->u
.ccmp
.tx_iv_high
= 0;
1106 slot
->u
.ccmp
.rx_iv_low
= LEWord(*(UWORD
*)rx_counter
);
1107 slot
->u
.ccmp
.rx_iv_high
= LELong(*(ULONG
*)(rx_counter
+ 2));
1108 slot
->u
.ccmp
.stream_set
= FALSE
;
1111 /* Clear TKIP key if necessary */
1113 if(slot
->type
== S2ENC_TKIP
&& type
!= S2ENC_TKIP
)
1115 if(unit
->firmware_type
>= HERMES2_FIRMWARE
&& index
== 0)
1116 P2SetData(unit
, P2_REC_REMMAPPEDTKIPKEY
, unit
->bssid
,
1117 ETH_ADDRESSSIZE
, base
);
1118 else if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
1119 P2SetWord(unit
, P2_REC_REMDEFAULTTKIPKEY
, index
, base
);
1122 /* Update type of key in selected slot */
1132 /****i* prism2.device/AddMulticastRange ************************************
1138 * success = AddMulticastRange(unit, lower_bound, upper_bound)
1140 * BOOL AddMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1142 ****************************************************************************
1146 BOOL
AddMulticastRange(struct DevUnit
*unit
, const UBYTE
*lower_bound
,
1147 const UBYTE
*upper_bound
, struct DevBase
*base
)
1149 struct AddressRange
*range
;
1150 ULONG lower_bound_left
, upper_bound_left
;
1151 UWORD lower_bound_right
, upper_bound_right
;
1153 lower_bound_left
= BELong(*((ULONG
*)lower_bound
));
1154 lower_bound_right
= BEWord(*((UWORD
*)(lower_bound
+ 4)));
1155 upper_bound_left
= BELong(*((ULONG
*)upper_bound
));
1156 upper_bound_right
= BEWord(*((UWORD
*)(upper_bound
+ 4)));
1158 range
= FindMulticastRange(unit
, lower_bound_left
, lower_bound_right
,
1159 upper_bound_left
, upper_bound_right
, base
);
1165 range
= AllocMem(sizeof(struct AddressRange
), MEMF_PUBLIC
);
1168 range
->lower_bound_left
= lower_bound_left
;
1169 range
->lower_bound_right
= lower_bound_right
;
1170 range
->upper_bound_left
= upper_bound_left
;
1171 range
->upper_bound_right
= upper_bound_right
;
1172 range
->add_count
= 1;
1175 AddTail((APTR
)&unit
->multicast_ranges
, (APTR
)range
);
1176 unit
->range_count
++;
1177 SetMulticast(unit
, base
);
1182 return range
!= NULL
;
1187 /****i* prism2.device/RemMulticastRange ************************************
1193 * found = RemMulticastRange(unit, lower_bound, upper_bound)
1195 * BOOL RemMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1197 ****************************************************************************
1201 BOOL
RemMulticastRange(struct DevUnit
*unit
, const UBYTE
*lower_bound
,
1202 const UBYTE
*upper_bound
, struct DevBase
*base
)
1204 struct AddressRange
*range
;
1205 ULONG lower_bound_left
, upper_bound_left
;
1206 UWORD lower_bound_right
, upper_bound_right
;
1208 lower_bound_left
= BELong(*((ULONG
*)lower_bound
));
1209 lower_bound_right
= BEWord(*((UWORD
*)(lower_bound
+ 4)));
1210 upper_bound_left
= BELong(*((ULONG
*)upper_bound
));
1211 upper_bound_right
= BEWord(*((UWORD
*)(upper_bound
+ 4)));
1213 range
= FindMulticastRange(unit
, lower_bound_left
, lower_bound_right
,
1214 upper_bound_left
, upper_bound_right
, base
);
1218 if(--range
->add_count
== 0)
1221 Remove((APTR
)range
);
1222 unit
->range_count
--;
1223 SetMulticast(unit
, base
);
1225 FreeMem(range
, sizeof(struct AddressRange
));
1229 return range
!= NULL
;
1234 /****i* prism2.device/FindMulticastRange ***********************************
1237 * FindMulticastRange
1240 * range = FindMulticastRange(unit, lower_bound_left,
1241 * lower_bound_right, upper_bound_left, upper_bound_right)
1243 * struct AddressRange *FindMulticastRange(struct DevUnit *, ULONG,
1244 * UWORD, ULONG, UWORD);
1246 ****************************************************************************
1250 static struct AddressRange
*FindMulticastRange(struct DevUnit
*unit
,
1251 ULONG lower_bound_left
, UWORD lower_bound_right
, ULONG upper_bound_left
,
1252 UWORD upper_bound_right
, struct DevBase
*base
)
1254 struct AddressRange
*range
, *tail
;
1257 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
1258 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
1260 while(range
!= tail
&& !found
)
1262 if(lower_bound_left
== range
->lower_bound_left
&&
1263 lower_bound_right
== range
->lower_bound_right
&&
1264 upper_bound_left
== range
->upper_bound_left
&&
1265 upper_bound_right
== range
->upper_bound_right
)
1268 range
= (APTR
)range
->node
.mln_Succ
;
1279 /****i* prism2.device/SetMulticast *****************************************
1285 * SetMulticast(unit)
1287 * VOID SetMulticast(struct DevUnit *);
1289 ****************************************************************************
1293 static VOID
SetMulticast(struct DevUnit
*unit
, struct DevBase
*base
)
1296 UWORD address_right
, i
= 0;
1297 struct AddressRange
*range
, *tail
;
1300 /* Fill in multicast list */
1302 P2Seek(unit
, 1, P2_REC_MCASTLIST
, 4, base
);
1304 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
1305 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
1307 while(range
!= tail
&& i
< P2_MAXMCASTENTRIES
)
1309 address_left
= range
->lower_bound_left
;
1310 address_right
= range
->lower_bound_right
;
1311 range_ended
= FALSE
;
1313 while(!range_ended
&& i
++ < P2_MAXMCASTENTRIES
)
1315 unit
->BEWordOut(unit
->card
, P2_REG_DATA1
,
1316 (UWORD
)(address_left
>> 16));
1317 unit
->BEWordOut(unit
->card
, P2_REG_DATA1
, (UWORD
)address_left
);
1318 unit
->BEWordOut(unit
->card
, P2_REG_DATA1
, (UWORD
)address_right
);
1320 if(address_left
== range
->upper_bound_left
&&
1321 address_right
== range
->upper_bound_right
)
1323 if(++address_right
== 0)
1328 range
= (APTR
)range
->node
.mln_Succ
;
1331 /* Turn promiscuous mode on or off depending on the previous state and
1332 whether we've overflowed the multicast list */
1334 if((unit
->flags
& UNITF_PROM
) == 0)
1338 if((unit
->flags
& UNITF_ALLMCAST
) == 0)
1340 P2SetWord(unit
, P2_REC_PROMISC
, TRUE
, base
);
1341 unit
->flags
|= UNITF_ALLMCAST
;
1346 if((unit
->flags
& UNITF_ALLMCAST
) != 0)
1348 P2SetWord(unit
, P2_REC_PROMISC
, FALSE
, base
);
1349 unit
->flags
&= ~UNITF_ALLMCAST
;
1352 /* Only commit multicast list if promiscuity is off */
1354 P2Seek(unit
, 1, P2_REC_MCASTLIST
, 0, base
);
1355 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
,
1356 1 + ETH_ADDRESSSIZE
/ 2 * i
);
1357 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, P2_REC_MCASTLIST
);
1358 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
, P2_REC_MCASTLIST
,
1368 /****i* prism2.device/FindTypeStats ****************************************
1374 * stats = FindTypeStats(unit, list,
1377 * struct TypeStats *FindTypeStats(struct DevUnit *, struct MinList *,
1380 ****************************************************************************
1384 struct TypeStats
*FindTypeStats(struct DevUnit
*unit
, struct MinList
*list
,
1385 ULONG packet_type
, struct DevBase
*base
)
1387 struct TypeStats
*stats
, *tail
;
1390 stats
= (APTR
)list
->mlh_Head
;
1391 tail
= (APTR
)&list
->mlh_Tail
;
1393 while(stats
!= tail
&& !found
)
1395 if(stats
->packet_type
== packet_type
)
1398 stats
= (APTR
)stats
->node
.mln_Succ
;
1409 /****i* prism2.device/FlushUnit ********************************************
1415 * FlushUnit(unit, last_queue, error)
1417 * VOID FlushUnit(struct DevUnit *, UBYTE, BYTE);
1419 ****************************************************************************
1423 VOID
FlushUnit(struct DevUnit
*unit
, UBYTE last_queue
, BYTE error
,
1424 struct DevBase
*base
)
1426 struct IORequest
*request
;
1428 struct Opener
*opener
, *tail
;
1430 /* Abort queued requests */
1432 for(i
= 0; i
<= last_queue
; i
++)
1434 while((request
= (APTR
)GetMsg(unit
->request_ports
[i
])) != NULL
)
1436 request
->io_Error
= error
;
1437 ReplyMsg((APTR
)request
);
1442 opener
= (APTR
)unit
->openers
.mlh_Head
;
1443 tail
= (APTR
)&unit
->openers
.mlh_Tail
;
1445 /* Flush every opener's read queue */
1447 while(opener
!= tail
)
1449 while((request
= (APTR
)GetMsg(&opener
->read_port
)) != NULL
)
1451 request
->io_Error
= error
;
1452 ReplyMsg((APTR
)request
);
1454 opener
= (APTR
)opener
->node
.mln_Succ
;
1458 opener
= request
->ios2_BufferManagement
;
1459 while((request
= (APTR
)GetMsg(&opener
->read_port
)) != NULL
)
1461 request
->io_Error
= error
;
1462 ReplyMsg((APTR
)request
);
1473 /****i* prism2.device/StatusInt ********************************************
1479 * finished = StatusInt(unit)
1481 * BOOL StatusInt(struct DevUnit *);
1491 ****************************************************************************
1493 * int_code is really in A5, but GCC 2.95.3 doesn't seem able to handle that.
1494 * Since we don't use this parameter, we can lie.
1498 BOOL
StatusInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
))
1500 struct DevBase
*base
;
1501 UWORD events
, int_mask
;
1503 base
= unit
->device
;
1504 events
= unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
);
1506 /* Turning off ints acknowledges the request? */
1508 int_mask
= unit
->LEWordIn(unit
->card
, P2_REG_INTMASK
);
1509 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, 0);
1513 if((events
& P2_EVENTF_INFO
) != 0)
1515 int_mask
&= ~P2_EVENTF_INFO
;
1516 Cause(&unit
->info_int
);
1518 if((events
& P2_EVENTF_RX
) != 0)
1520 int_mask
&= ~P2_EVENTF_RX
;
1521 Cause(&unit
->rx_int
);
1523 if((events
& P2_EVENTF_ALLOCMEM
) != 0)
1525 unit
->tx_frame_id
= unit
->LEWordIn(unit
->card
, P2_REG_ALLOCFID
);
1526 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_ALLOCMEM
);
1527 Cause(&unit
->tx_int
);
1529 if((events
& P2_EVENTF_TXFAIL
) != 0)
1531 ReportEvents(unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_TX
,
1533 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_TXFAIL
);
1537 int_mask
= INT_MASK
;
1539 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, int_mask
);
1546 /****i* prism2.device/RXInt ************************************************
1549 * RXInt -- Soft interrupt for packet reception.
1554 * VOID RXInt(struct DevUnit *);
1559 * unit - A unit of this device.
1564 ****************************************************************************
1568 static VOID
RXInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
))
1570 UWORD frame_status
, frame_id
, ieee_length
, frame_control
, frame_type
,
1571 frame_subtype
, encryption
, key_no
, buffer_no
, old_length
;
1572 struct DevBase
*base
;
1575 UBYTE
*buffer
, *p
, *frame
, *data
;
1577 base
= unit
->device
;
1579 while((unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
) & P2_EVENTF_RX
) != 0)
1582 frame_id
= unit
->LEWordIn(unit
->card
, P2_REG_RXFID
);
1583 P2Seek(unit
, 1, frame_id
, P2_FRM_STATUS
, base
);
1584 frame_status
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
1586 if((frame_status
& (P2_FRM_STATUSF_BADCRYPT
| P2_FRM_STATUSF_BADCRC
))
1589 /* Read frame descriptor from card */
1591 P2Seek(unit
, 1, frame_id
, 0, base
);
1592 unit
->WordsIn(unit
->card
, P2_REG_DATA1
,
1593 (UWORD
*)unit
->rx_descriptor
,
1594 (unit
->ethernet_offset
+ ETH_HEADERSIZE
) / 2);
1595 frame
= unit
->rx_descriptor
+ unit
->ethernet_offset
;
1596 ieee_length
= BEWord(*(UWORD
*)(frame
+ ETH_PACKET_IEEELEN
));
1597 data
= frame
+ ETH_PACKET_DATA
;
1598 unit
->WordsIn(unit
->card
, P2_REG_DATA1
, (UWORD
*)data
,
1599 (ieee_length
+ MIC_SIZE
+ 1) / 2);
1601 LEWord(*(UWORD
*)(unit
->rx_descriptor
+ P2_FRM_HEADER
));
1603 /* Get buffer to store fragment in */
1605 frag_no
= LEWord(*(UWORD
*)(unit
->rx_descriptor
+ P2_FRM_HEADER
1606 + WIFI_FRM_SEQCONTROL
));
1607 buffer
= GetRXBuffer(unit
, frame
+ ETH_PACKET_SOURCE
, frag_no
,
1610 /* Get location to put new data */
1614 if((frag_no
& 0xf ) > 0)
1615 old_length
= BEWord(*(UWORD
*)(buffer
+ ETH_PACKET_IEEELEN
));
1618 /* Copy header to new frame */
1620 CopyMem(frame
, buffer
, ETH_HEADERSIZE
);
1623 p
= buffer
+ ETH_HEADERSIZE
+ old_length
;
1625 /* Get encryption type and key index */
1627 if((frame_control
& WIFI_FRM_CONTROLF_WEP
) != 0)
1629 key_no
= data
[3] >> 6 & 0x3;
1630 encryption
= unit
->keys
[key_no
].type
;
1633 encryption
= S2ENC_NONE
;
1635 /* Append fragment to frame, decrypting/checking fragment if
1638 is_good
= unit
->fragment_decrypt_functions
[encryption
](unit
,
1639 unit
->rx_descriptor
+ P2_FRM_HEADER
, data
, &ieee_length
, p
,
1642 /* Update length in frame being built with current fragment, or
1643 increment bad frame counter if fragment is bad */
1647 ieee_length
+= old_length
;
1648 *(UWORD
*)(buffer
+ ETH_PACKET_IEEELEN
) =
1649 MakeBEWord(ieee_length
);
1652 unit
->stats
.BadData
++;
1654 /* If all fragments have arrived, process the complete frame */
1656 if((frame_control
& WIFI_FRM_CONTROLF_MOREFRAGS
) == 0)
1660 /* Decrypt complete frame if necessary */
1662 data
= buffer
+ ETH_HEADERSIZE
;
1663 if(encryption
== S2ENC_TKIP
)
1665 /* Hermes cards don't include MIC in frame length, so
1666 we need to grab the MIC from the original RX
1669 if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
1671 CopyMem(frame
+ ETH_PACKET_DATA
+ ieee_length
,
1672 data
+ ieee_length
, MIC_SIZE
);
1673 ieee_length
+= MIC_SIZE
;
1676 /* Check Michael MIC */
1679 is_good
= TKIPDecryptFrame(unit
, buffer
, data
,
1680 ieee_length
, data
, key_no
, base
);
1682 ieee_length
-= MIC_SIZE
;
1683 *(UWORD
*)(buffer
+ ETH_PACKET_IEEELEN
) =
1684 MakeBEWord(ieee_length
);
1686 unit
->stats
.BadData
++;
1692 /* Get frame's 802.11 type and subtype */
1694 frame_type
= (frame_control
& WIFI_FRM_CONTROLF_TYPE
)
1695 >> WIFI_FRM_CONTROLB_TYPE
;
1697 (frame_control
& WIFI_FRM_CONTROLF_SUBTYPE
)
1698 >> WIFI_FRM_CONTROLB_SUBTYPE
;
1700 /* If it's a management frame, process it internally;
1701 otherwise distribute it to clients after filtering */
1703 if(frame_type
== WIFI_FRMTYPE_MGMT
)
1705 if(frame_subtype
== 0x5)
1707 CopyMem(unit
->rx_descriptor
+ P2_FRM_HEADER
1708 + WIFI_FRM_ADDRESS3
, buffer
+ ETH_PACKET_SOURCE
,
1710 SaveBeacon(unit
, buffer
, base
);
1713 else if(AddressFilter(unit
, buffer
+ ETH_PACKET_DEST
,
1716 unit
->stats
.PacketsReceived
++;
1717 DistributeRXPacket(unit
, buffer
, base
);
1722 /* Mark fragment buffer as unused for next time */
1724 unit
->rx_fragment_nos
[buffer_no
] = -1;
1727 ReportEvents(unit
, S2EVENT_ERROR
| S2EVENT_RX
, base
);
1736 ReportEvents(unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
,
1740 /* Discard packet */
1742 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_RX
);
1745 /* Re-enable RX interrupts */
1748 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
,
1749 unit
->LEWordIn(unit
->card
, P2_REG_INTMASK
) | P2_EVENTF_RX
);
1757 /****i* prism2.device/GetRXBuffer ******************************************
1760 * GetRXBuffer -- Find an appropriate RX buffer to use.
1763 * buffer = GetRXBuffer(unit, address, frag_no)
1765 * UBYTE *GetRXBuffer(struct DevUnit *, UBYTE *, UWORD);
1767 ****************************************************************************
1771 static UBYTE
*GetRXBuffer(struct DevUnit
*unit
, const UBYTE
*address
,
1772 UWORD frag_no
, UWORD
*buffer_no
, struct DevBase
*base
)
1779 buffer
= unit
->rx_buffers
;
1780 for(i
= 0, found
= FALSE
; i
< RX_BUFFER_COUNT
* 2 && !found
; i
++)
1782 /* Throw away old buffer contents if we didn't find a free slot the
1783 first time around */
1785 if(i
>= RX_BUFFER_COUNT
)
1786 unit
->rx_fragment_nos
[i
% RX_BUFFER_COUNT
] = -1;
1788 /* For a frame's first fragment, find an empty slot; for subsequent
1789 fragments, find a slot with matching source address */
1791 n
= unit
->rx_fragment_nos
[i
% RX_BUFFER_COUNT
];
1792 if(n
== -1 && (frag_no
& 0xf) == 0
1793 || *((ULONG
*)(buffer
+ ETH_PACKET_SOURCE
))
1794 == *((ULONG
*)(address
))
1795 && *((UWORD
*)(buffer
+ ETH_PACKET_SOURCE
+ 4))
1796 == *((UWORD
*)(address
+ 4)))
1800 unit
->rx_fragment_nos
[i
% RX_BUFFER_COUNT
] = frag_no
;
1804 buffer
+= FRAME_BUFFER_SIZE
;
1815 /****i* prism2.device/DistributeRXPacket ***********************************
1818 * DistributeRXPacket -- Send a packet to all appropriate destinations.
1821 * DistributeRXPacket(unit, frame)
1823 * VOID DistributeRXPacket(struct DevUnit *, UBYTE *);
1825 ****************************************************************************
1829 static VOID
DistributeRXPacket(struct DevUnit
*unit
, UBYTE
*frame
,
1830 struct DevBase
*base
)
1832 UWORD packet_size
, ieee_length
;
1833 BOOL is_orphan
= TRUE
, accepted
, is_snap
= FALSE
;
1836 const UBYTE
*template = snap_template
;
1837 struct IOSana2Req
*request
, *request_tail
;
1838 struct Opener
*opener
, *opener_tail
;
1839 struct TypeStats
*tracker
;
1841 ieee_length
= BEWord(*(UWORD
*)(frame
+ ETH_PACKET_IEEELEN
));
1842 packet_size
= ETH_HEADERSIZE
+ ieee_length
;
1843 if(ieee_length
>= SNAP_HEADERSIZE
)
1844 is_snap
= *(const ULONG
*)(frame
+ ETH_PACKET_DATA
)
1845 == *(const ULONG
*)template;
1847 /* De-encapsulate SNAP packets and get packet type */
1851 buffer
= unit
->rx_buffer
;
1852 packet_size
-= SNAP_HEADERSIZE
;
1853 CopyMem(frame
, buffer
, ETH_PACKET_TYPE
);
1854 CopyMem(frame
+ ETH_HEADERSIZE
+ SNAP_FRM_TYPE
,
1855 buffer
+ ETH_PACKET_TYPE
, packet_size
- ETH_PACKET_TYPE
);
1860 packet_type
= BEWord(*((UWORD
*)(buffer
+ ETH_PACKET_TYPE
)));
1862 if(packet_size
<= ETH_MAXPACKETSIZE
)
1864 /* Offer packet to every opener */
1866 opener
= (APTR
)unit
->openers
.mlh_Head
;
1867 opener_tail
= (APTR
)&unit
->openers
.mlh_Tail
;
1869 while(opener
!= opener_tail
)
1871 request
= (APTR
)opener
->read_port
.mp_MsgList
.lh_Head
;
1872 request_tail
= (APTR
)&opener
->read_port
.mp_MsgList
.lh_Tail
;
1875 /* Offer packet to each request until it's accepted */
1877 while(request
!= request_tail
&& !accepted
)
1879 if(request
->ios2_PacketType
== packet_type
)
1881 CopyPacket(unit
, request
, packet_size
, packet_type
,
1886 (APTR
)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
1891 opener
= (APTR
)opener
->node
.mln_Succ
;
1894 /* If packet was unwanted, give it to S2_READORPHAN request */
1898 unit
->stats
.UnknownTypesReceived
++;
1899 if(!IsMsgPortEmpty(unit
->request_ports
[ADOPT_QUEUE
]))
1902 (APTR
)unit
->request_ports
[ADOPT_QUEUE
]->
1903 mp_MsgList
.lh_Head
, packet_size
, packet_type
, buffer
,
1908 /* Update remaining statistics */
1910 if(packet_type
<= ETH_MTU
)
1911 packet_type
= ETH_MTU
;
1913 FindTypeStats(unit
, &unit
->type_trackers
, packet_type
, base
);
1916 tracker
->stats
.PacketsReceived
++;
1917 tracker
->stats
.BytesReceived
+= packet_size
;
1921 unit
->stats
.BadData
++;
1928 /****i* prism2.device/CopyPacket *******************************************
1931 * CopyPacket -- Copy packet to client's buffer.
1934 * CopyPacket(unit, request, packet_size, packet_type,
1937 * VOID CopyPacket(struct DevUnit *, struct IOSana2Req *, UWORD, UWORD,
1940 ****************************************************************************
1944 static VOID
CopyPacket(struct DevUnit
*unit
, struct IOSana2Req
*request
,
1945 UWORD packet_size
, UWORD packet_type
, UBYTE
*buffer
,
1946 struct DevBase
*base
)
1948 struct Opener
*opener
;
1949 BOOL filtered
= FALSE
;
1951 /* Set multicast and broadcast flags */
1953 request
->ios2_Req
.io_Flags
&= ~(SANA2IOF_BCAST
| SANA2IOF_MCAST
);
1954 if((*((ULONG
*)(buffer
+ ETH_PACKET_DEST
)) == 0xffffffff) &&
1955 (*((UWORD
*)(buffer
+ ETH_PACKET_DEST
+ 4)) == 0xffff))
1956 request
->ios2_Req
.io_Flags
|= SANA2IOF_BCAST
;
1957 else if((buffer
[ETH_PACKET_DEST
] & 0x1) != 0)
1958 request
->ios2_Req
.io_Flags
|= SANA2IOF_MCAST
;
1960 /* Set source and destination addresses and packet type */
1962 CopyMem(buffer
+ ETH_PACKET_SOURCE
, request
->ios2_SrcAddr
,
1964 CopyMem(buffer
+ ETH_PACKET_DEST
, request
->ios2_DstAddr
,
1966 request
->ios2_PacketType
= packet_type
;
1968 /* Adjust for cooked packet request */
1970 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) == 0)
1972 packet_size
-= ETH_PACKET_DATA
;
1973 buffer
+= ETH_PACKET_DATA
;
1977 packet_size
+= 4; /* Needed for Shapeshifter & Fusion */
1979 request
->ios2_DataLength
= packet_size
;
1983 opener
= request
->ios2_BufferManagement
;
1984 if(request
->ios2_Req
.io_Command
== CMD_READ
&&
1985 opener
->filter_hook
!= NULL
)
1986 if(!CallHookPkt(opener
->filter_hook
, request
, buffer
))
1991 /* Copy packet into opener's buffer and reply packet */
1993 if(!opener
->rx_function(request
->ios2_Data
, buffer
, packet_size
))
1995 request
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
1996 request
->ios2_WireError
= S2WERR_BUFF_ERROR
;
1998 S2EVENT_ERROR
| S2EVENT_SOFTWARE
| S2EVENT_BUFF
| S2EVENT_RX
,
2001 Remove((APTR
)request
);
2002 ReplyMsg((APTR
)request
);
2010 /****i* prism2.device/AddressFilter ****************************************
2013 * AddressFilter -- Determine if an RX packet should be accepted.
2016 * accept = AddressFilter(unit, address)
2018 * BOOL AddressFilter(struct DevUnit *, UBYTE *);
2020 ****************************************************************************
2024 static BOOL
AddressFilter(struct DevUnit
*unit
, UBYTE
*address
,
2025 struct DevBase
*base
)
2027 struct AddressRange
*range
, *tail
;
2030 UWORD address_right
;
2032 /* Check whether address is unicast/broadcast or multicast */
2034 address_left
= BELong(*((ULONG
*)address
));
2035 address_right
= BEWord(*((UWORD
*)(address
+ 4)));
2037 if(((address_left
& 0x01000000) != 0) &&
2038 !((address_left
== 0xffffffff) && (address_right
== 0xffff)))
2040 /* Check if this multicast address is wanted */
2042 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
2043 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
2046 while((range
!= tail
) && !accept
)
2048 if((address_left
> range
->lower_bound_left
||
2049 address_left
== range
->lower_bound_left
&&
2050 address_right
>= range
->lower_bound_right
) &&
2051 (address_left
< range
->upper_bound_left
||
2052 address_left
== range
->upper_bound_left
&&
2053 address_right
<= range
->upper_bound_right
))
2055 range
= (APTR
)range
->node
.mln_Succ
;
2059 unit
->special_stats
[S2SS_ETHERNET_BADMULTICAST
& 0xffff]++;
2067 /****i* prism2.device/SaveBeacon *******************************************
2070 * SaveBeacon -- Save beacon frame for later examination.
2073 * SaveBeacon(unit, frame)
2075 * VOID SaveBeacon(struct DevUnit *, UBYTE *);
2077 ****************************************************************************
2081 static VOID
SaveBeacon(struct DevUnit
*unit
, const UBYTE
*frame
,
2082 struct DevBase
*base
)
2086 /* Store frame for later matching with scan results */
2088 size
= ETH_HEADERSIZE
+ BEWord(*(UWORD
*)(frame
+ ETH_PACKET_IEEELEN
));
2089 if(unit
->next_beacon
+ size
< unit
->beacons
+ BEACON_BUFFER_SIZE
)
2091 CopyMem(frame
, unit
->next_beacon
, size
);
2092 unit
->beacon_count
++;
2093 unit
->next_beacon
+= size
+ sizeof(ULONG
) & ~3;
2101 /****i* prism2.device/TXInt ************************************************
2104 * TXInt -- Soft interrupt for packet transmission.
2109 * VOID TXInt(struct DevUnit *);
2114 * unit - A unit of this device.
2119 ****************************************************************************
2123 static VOID
TXInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
))
2125 UWORD i
, packet_size
, send_size
, packet_type
, data_size
, body_size
= 0,
2126 frame_id
, encryption
, control_value
, subtype
;
2127 UBYTE
*buffer
, *desc
= unit
->tx_descriptor
, *plaintext
, *ciphertext
,
2128 *header
, mic_header
[ETH_ADDRESSSIZE
* 2], *q
;
2129 const UBYTE
*p
, *dest
, *source
;
2130 struct DevBase
*base
;
2131 struct IOSana2Req
*request
;
2133 struct Opener
*opener
;
2135 UBYTE
*(*dma_tx_function
)(REG(a0
, APTR
));
2137 struct MsgPort
*port
;
2138 struct TypeStats
*tracker
;
2140 base
= unit
->device
;
2141 port
= unit
->request_ports
[WRITE_QUEUE
];
2143 if(unit
->tx_frame_id
!= 0 && !IsMsgPortEmpty(port
))
2145 /* Get next request and full packet size */
2147 request
= (APTR
)port
->mp_MsgList
.lh_Head
;
2148 packet_size
= request
->ios2_DataLength
;
2149 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) == 0)
2150 packet_size
+= ETH_PACKET_DATA
;
2152 /* Determine encryption type and frame subtype */
2154 if(packet_size
> ETH_HEADERSIZE
)
2156 encryption
= unit
->keys
[unit
->tx_key_no
].type
;
2161 encryption
= S2ENC_NONE
;
2165 /* Get packet data */
2167 opener
= request
->ios2_BufferManagement
;
2168 dma_tx_function
= opener
->dma_tx_function
;
2169 if(dma_tx_function
!= NULL
)
2170 buffer
= dma_tx_function(request
->ios2_Data
);
2176 buffer
= unit
->tx_buffer
;
2177 if(!opener
->tx_function(buffer
, request
->ios2_Data
,
2178 request
->ios2_DataLength
))
2180 error
= S2ERR_NO_RESOURCES
;
2181 wire_error
= S2WERR_BUFF_ERROR
;
2183 S2EVENT_ERROR
| S2EVENT_SOFTWARE
| S2EVENT_BUFF
| S2EVENT_TX
,
2190 /* Get packet type and/or length */
2192 data_size
= request
->ios2_DataLength
;
2193 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) != 0)
2195 data_size
-= ETH_PACKET_DATA
;
2196 packet_type
= BEWord(*(UWORD
*)(buffer
+ ETH_PACKET_TYPE
));
2199 packet_type
= request
->ios2_PacketType
;
2200 is_ieee
= packet_type
<= ETH_MTU
;
2202 /* Get source and destination addresses */
2204 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) != 0)
2207 source
= buffer
+ ETH_ADDRESSSIZE
;
2208 buffer
+= ETH_ADDRESSSIZE
* 2 + 2;
2212 dest
= request
->ios2_DstAddr
;
2213 source
= unit
->address
;
2216 /* Clear frame descriptor as far as start of 802.11 header */
2219 for(i
= 0; i
< P2_FRM_HEADER
; i
++)
2223 /* Set TX control field */
2225 control_value
= P2_FRM_TXCONTROLF_NATIVE
;
2226 if(encryption
== S2ENC_TKIP
&& (unit
->flags
& UNITF_HARDTKIP
) != 0)
2227 control_value
|= unit
->tx_key_no
<< P2_FRM_TXCONTROLB_MICKEYID
2228 | P2_FRM_TXCONTROLF_MIC
;
2229 else if(encryption
== S2ENC_NONE
2230 && unit
->firmware_type
< LUCENT_FIRMWARE
)
2231 control_value
|= P2_FRM_TXCONTROLF_NOENC
;
2233 *(UWORD
*)(desc
+ unit
->txcontrol_offset
) =
2234 MakeLEWord(control_value
);
2236 /* Write 802.11 header */
2238 *(UWORD
*)q
= MakeLEWord(
2239 (encryption
== S2ENC_NONE
? 0 : WIFI_FRM_CONTROLF_WEP
)
2240 | (unit
->mode
== S2PORT_ADHOC
? 0 : WIFI_FRM_CONTROLF_TODS
)
2241 | subtype
<< WIFI_FRM_CONTROLB_SUBTYPE
2242 | WIFI_FRMTYPE_DATA
<< WIFI_FRM_CONTROLB_TYPE
);
2248 if(unit
->mode
== S2PORT_ADHOC
)
2252 for(i
= 0; i
< ETH_ADDRESSSIZE
; i
++)
2255 for(i
= 0, p
= source
; i
< ETH_ADDRESSSIZE
; i
++)
2258 if(unit
->mode
== S2PORT_ADHOC
)
2262 for(i
= 0; i
< ETH_ADDRESSSIZE
; i
++)
2266 /* Clear 802.3 header */
2268 q
= desc
+ unit
->ethernet_offset
;
2269 for(i
= 0; i
< ETH_HEADERSIZE
; i
++)
2272 /* Leave room for encryption overhead */
2274 q
= desc
+ unit
->data_offset
;
2276 q
+= unit
->iv_sizes
[encryption
];
2279 /* Write SNAP header */
2283 for(i
= 0, p
= snap_template
; i
< SNAP_FRM_TYPE
; i
++)
2285 *(UWORD
*)q
= MakeBEWord(packet_type
);
2287 body_size
+= SNAP_HEADERSIZE
;
2290 /* Copy data into frame */
2292 CopyMem(buffer
, q
, data_size
);
2293 body_size
+= data_size
;
2295 /* Append MIC to frame for TKIP */
2297 if(encryption
== S2ENC_TKIP
)
2300 for(i
= 0, p
= dest
; i
< ETH_ADDRESSSIZE
; i
++)
2302 for(i
= 0, p
= source
; i
< ETH_ADDRESSSIZE
; i
++)
2304 TKIPEncryptFrame(unit
, mic_header
, plaintext
, body_size
,
2306 body_size
+= MIC_SIZE
;
2309 /* Encrypt fragment if applicable */
2311 unit
->fragment_encrypt_functions
[encryption
](unit
, header
,
2312 plaintext
, &body_size
, ciphertext
, base
);
2314 /* Calculate total length of data to send to adapter */
2316 send_size
= unit
->data_offset
+ body_size
;
2318 /* Fill in length field, adjusting for Hermes peculiarities */
2320 if(unit
->firmware_type
>= LUCENT_FIRMWARE
2321 && encryption
== S2ENC_TKIP
)
2322 body_size
-= MIC_SIZE
;
2324 if(unit
->firmware_type
== LUCENT_FIRMWARE
2325 && (unit
->flags
& UNITF_HARDTKIP
) != 0)
2326 *(UWORD
*)(desc
+ unit
->ethernet_offset
+ ETH_PACKET_IEEELEN
) =
2327 MakeBEWord(body_size
);
2329 *(UWORD
*)(desc
+ unit
->datalen_offset
) = MakeLEWord(body_size
);
2331 /* Write packet to adapter and send */
2333 frame_id
= unit
->tx_frame_id
;
2334 P2Seek(unit
, 0, frame_id
, 0, base
);
2335 unit
->WordsOut(unit
->card
, P2_REG_DATA0
, (UWORD
*)desc
,
2336 (send_size
+ 1) / 2);
2337 unit
->tx_frame_id
= 0;
2338 P2DoCmd(unit
, P2_CMD_TX
| P2_CMDF_RECLAIM
, frame_id
, base
);
2343 request
->ios2_Req
.io_Error
= error
;
2344 request
->ios2_WireError
= wire_error
;
2345 Remove((APTR
)request
);
2346 ReplyMsg((APTR
)request
);
2348 /* Update statistics */
2352 unit
->stats
.PacketsSent
++;
2354 tracker
= FindTypeStats(unit
, &unit
->type_trackers
,
2355 request
->ios2_PacketType
, base
);
2358 tracker
->stats
.PacketsSent
++;
2359 tracker
->stats
.BytesSent
+= packet_size
;
2364 /* Don't try to keep sending packets if there's no space left */
2366 if(unit
->tx_frame_id
!= 0)
2367 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
2369 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_IGNORE
;
2376 /****i* prism2.device/UpdateStats ******************************************
2384 * VOID UpdateStats(struct DevUnit *);
2389 * unit - A unit of this device.
2394 ****************************************************************************
2398 VOID
UpdateStats(struct DevUnit
*unit
, struct DevBase
*base
)
2400 /* Ask for and wait for stats */
2402 if((unit
->flags
& UNITF_ONLINE
) != 0)
2405 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
,
2406 unit
->LEWordIn(unit
->card
, P2_REG_INTMASK
) & ~P2_EVENTF_INFO
);
2408 P2DoCmd(unit
, P2_CMD_INQUIRE
, P2_INFO_COUNTERS
, base
);
2409 while((unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
) & P2_EVENTF_INFO
)
2411 Cause(&unit
->info_int
);
2419 /****i* prism2.device/InfoInt **********************************************
2427 * VOID InfoInt(struct DevUnit *);
2432 * unit - A unit of this device.
2438 * The only reason this is a (soft) interrupt is so that it won't
2439 * interfere with RXInt() by interrupting it. This would be dangerous
2440 * because they use the same data channel.
2442 ****************************************************************************
2446 static VOID
InfoInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
))
2448 struct DevBase
*base
;
2449 UWORD id
, length
, rec_length
, status
, ies_length
, data_length
,
2450 ssid_length
, *ap_rec
;
2451 UBYTE
*ie
, *ssid
, *descriptor
, *frame
, *data
, *bssid
= unit
->bssid
;
2454 base
= unit
->device
;
2455 id
= unit
->LEWordIn(unit
->card
, P2_REG_INFOFID
);
2457 P2Seek(unit
, 1, id
, 0, base
);
2458 length
= (unit
->LEWordIn(unit
->card
, P2_REG_DATA1
) + 1) * 2;
2460 switch(unit
->LEWordIn(unit
->card
, P2_REG_DATA1
))
2462 case P2_INFO_COUNTERS
:
2464 /* Read useful stats and skip others */
2466 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2467 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2469 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2470 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2471 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2472 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2474 unit
->special_stats
[S2SS_ETHERNET_RETRIES
& 0xffff] +=
2475 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
) +
2476 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
) +
2477 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2479 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2481 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2482 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2484 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2485 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2486 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2488 unit
->stats
.BadData
+= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2489 unit
->stats
.Overruns
+= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2491 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2493 unit
->stats
.BadData
+= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2497 case P2_INFO_SCANRESULTS
:
2498 case P2_INFO_HOSTSCANRESULTS
:
2500 P2ReadRec(unit
, id
, unit
->scan_results_rec
, SCAN_BUFFER_SIZE
, base
);
2501 Signal(unit
->task
, unit
->scan_complete_signal
);
2504 case P2_INFO_SCANRESULT
:
2506 descriptor
= unit
->rx_descriptor
;
2507 P2ReadRec(unit
, id
, descriptor
, FRAME_BUFFER_SIZE
, base
);
2510 /* Save IEEE 802.3 portion of scan result */
2512 frame
= descriptor
+ unit
->ethernet_offset
;
2513 data
= frame
+ ETH_PACKET_DATA
;
2514 CopyMem(descriptor
+ P2_FRM_HEADER
+ WIFI_FRM_ADDRESS3
,
2515 frame
+ ETH_PACKET_SOURCE
, ETH_ADDRESSSIZE
);
2517 LEWord(*(UWORD
*)(descriptor
+ unit
->datalen_offset
));
2518 ies_length
= data_length
- WIFI_BEACON_IES
;
2519 *(UWORD
*)(frame
+ ETH_PACKET_IEEELEN
) = MakeBEWord(data_length
);
2520 SaveBeacon(unit
, frame
, base
);
2522 /* Append a fake old-style scan record on to fake record list */
2524 rec_length
= LEWord(unit
->scan_results_rec
[0]);
2526 if(2 + rec_length
* 2 + P2_APRECLEN
< SCAN_BUFFER_SIZE
)
2528 ap_rec
= unit
->scan_results_rec
+ 1 + rec_length
;
2529 CopyMem(frame
+ ETH_PACKET_SOURCE
, ap_rec
+ P2_APREC_BSSID
/ 2,
2532 ap_rec
[P2_APREC_SIGNAL
/ 2] =
2533 MakeLEWord(descriptor
[P2_FRM_SIGNAL
]);
2535 ap_rec
[P2_APREC_NOISE
/ 2] =
2536 MakeLEWord(descriptor
[P2_FRM_NOISE
]);
2538 ap_rec
[P2_APREC_CHANNEL
/ 2] = MakeLEWord(GetIE(WIFI_IE_CHANNEL
,
2539 data
+ WIFI_BEACON_IES
, ies_length
, base
)[2]);
2541 ap_rec
[P2_APREC_INTERVAL
/ 2] =
2542 *(UWORD
*)(data
+ WIFI_BEACON_INTERVAL
);
2544 ap_rec
[P2_APREC_CAPABILITIES
/ 2] =
2545 *(UWORD
*)(data
+ WIFI_BEACON_CAPABILITIES
);
2547 ie
= GetIE(WIFI_IE_SSID
, data
+ WIFI_BEACON_IES
, ies_length
,
2549 ssid_length
= ie
[1];
2551 ap_rec
[P2_APREC_NAMELEN
/ 2] = MakeLEWord(ssid_length
);
2552 CopyMem(ssid
, ap_rec
+ P2_APREC_NAME
/ 2, ssid_length
);
2554 unit
->scan_results_rec
[0] =
2555 MakeLEWord(rec_length
+ P2_APRECLEN
/ 2);
2559 Signal(unit
->task
, unit
->scan_complete_signal
);
2562 case P2_INFO_LINKSTATUS
:
2564 /* Only report an event if association status has really changed */
2566 status
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2568 if(status
== 1 || unit
->firmware_type
< LUCENT_FIRMWARE
2571 else //if(unit->firmware_type < LUCENT_FIRMWARE || status == 3)
2574 if(!(*(ULONG
*)bssid
== 0 && *(UWORD
*)(bssid
+ 4) == 0))
2576 if(associated
&& (unit
->flags
& UNITF_ASSOCIATED
) == 0)
2578 unit
->flags
|= UNITF_ASSOCIATED
;
2579 ReportEvents(unit
, S2EVENT_CONNECT
, base
);
2581 else if(!associated
&& (unit
->flags
& UNITF_ASSOCIATED
) != 0)
2583 unit
->flags
&= ~UNITF_ASSOCIATED
;
2584 ReportEvents(unit
, S2EVENT_DISCONNECT
, base
);
2589 /* Acknowledge event and re-enable info interrupts */
2591 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_INFO
);
2593 if((unit
->flags
& UNITF_ONLINE
) != 0)
2594 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
,
2595 unit
->LEWordIn(unit
->card
, P2_REG_INTMASK
) | P2_EVENTF_INFO
);
2603 /****i* prism2.device/ResetHandler *****************************************
2606 * ResetHandler -- Disable hardware before a reboot.
2609 * ResetHandler(unit, int_code)
2611 * VOID ResetHandler(struct DevUnit *, APTR);
2613 ****************************************************************************
2617 static VOID
ResetHandler(REG(a1
, struct DevUnit
*unit
),
2618 REG(a6
, APTR int_code
))
2620 if((unit
->flags
& UNITF_HAVEADAPTER
) != 0)
2622 /* Stop interrupts */
2624 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, 0);
2626 /* Stop transmission and reception */
2628 unit
->LEWordOut(unit
->card
, P2_REG_PARAM0
, 0);
2629 unit
->LEWordOut(unit
->card
, P2_REG_COMMAND
, P2_CMD_DISABLE
);
2637 /****i* prism2.device/ReportEvents *****************************************
2643 * ReportEvents(unit, events)
2645 * VOID ReportEvents(struct DevUnit *, ULONG);
2650 * unit - A unit of this device.
2651 * events - A mask of events to report.
2656 ****************************************************************************
2660 static VOID
ReportEvents(struct DevUnit
*unit
, ULONG events
,
2661 struct DevBase
*base
)
2663 struct IOSana2Req
*request
, *tail
, *next_request
;
2666 list
= &unit
->request_ports
[EVENT_QUEUE
]->mp_MsgList
;
2667 next_request
= (APTR
)list
->lh_Head
;
2668 tail
= (APTR
)&list
->lh_Tail
;
2671 while(next_request
!= tail
)
2673 request
= next_request
;
2674 next_request
= (APTR
)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
2676 if((request
->ios2_WireError
& events
) != 0)
2678 request
->ios2_WireError
= events
;
2679 Remove((APTR
)request
);
2680 ReplyMsg((APTR
)request
);
2690 /****i* prism2.device/SendScanResults **************************************
2693 * SendScanResults -- Reply to all outstanding scan requests.
2696 * SendScanResults(unit)
2698 * VOID SendScanResults(struct DevUnit *);
2703 * unit - A unit of this device.
2708 ****************************************************************************
2712 static VOID
SendScanResults(struct DevUnit
*unit
, struct DevBase
*base
)
2715 struct IOSana2Req
*request
, *tail
, *next_request
;
2718 UWORD count
, i
, j
, ssid_length
, length
, entry_length
, *ap_rec
,
2719 data_length
, frame_length
, ies_length
;
2720 struct TagItem
**tag_lists
, *tag
;
2722 const UBYTE
*beacon
, *ie_bssid
;
2725 list
= &unit
->request_ports
[SCAN_QUEUE
]->mp_MsgList
;
2726 next_request
= (APTR
)list
->lh_Head
;
2727 tail
= (APTR
)&list
->lh_Tail
;
2729 while(next_request
!= tail
)
2731 request
= next_request
;
2732 next_request
= (APTR
)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
2734 pool
= request
->ios2_Data
;
2736 length
= LEWord(unit
->scan_results_rec
[0]);
2737 ap_rec
= unit
->scan_results_rec
+ 2;
2739 if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
2741 entry_length
= LEWord(unit
->scan_results_rec
[2]);
2743 count
= (length
- 3) * 2 / entry_length
;
2747 entry_length
= P2_APRECLEN
;
2748 count
= (length
- 1) * 2 / entry_length
;
2751 /* Allocate array of tag lists, one for each AP */
2755 tag_lists
= AllocPooled(pool
, count
* sizeof(APTR
));
2756 if(tag_lists
== NULL
)
2757 error
= S2ERR_NO_RESOURCES
;
2762 for(i
= 0; i
< count
&& error
== 0; i
++, ap_rec
+= entry_length
/ 2)
2765 AllocPooled(pool
, SCAN_TAG_COUNT
* sizeof(struct TagItem
));
2766 if(tag_lists
[i
] == NULL
)
2767 error
= S2ERR_NO_RESOURCES
;
2773 tag
->ti_Tag
= S2INFO_BSSID
;
2774 tag
->ti_Data
= (UPINT
)(bssid
=
2775 AllocPooled(pool
, ETH_ADDRESSSIZE
));
2777 CopyMem(ap_rec
+ P2_APREC_BSSID
/ 2, bssid
,
2780 error
= S2ERR_NO_RESOURCES
;
2783 tag
->ti_Tag
= TAG_IGNORE
;
2786 tag
->ti_Tag
= S2INFO_Channel
;
2787 tag
->ti_Data
= LEWord(ap_rec
[P2_APREC_CHANNEL
/ 2]);
2790 tag
->ti_Tag
= S2INFO_BeaconInterval
;
2791 tag
->ti_Data
= LEWord(ap_rec
[P2_APREC_INTERVAL
/ 2]);
2794 tag
->ti_Tag
= S2INFO_Capabilities
;
2795 tag
->ti_Data
= LEWord(ap_rec
[P2_APREC_CAPABILITIES
/ 2]);
2798 tag
->ti_Tag
= S2INFO_Signal
;
2799 tag
->ti_Data
= ConvertScanLevel(unit
,
2800 LEWord(ap_rec
[P2_APREC_SIGNAL
/ 2]), base
);
2803 tag
->ti_Tag
= S2INFO_Noise
;
2804 tag
->ti_Data
= ConvertScanLevel(unit
,
2805 LEWord(ap_rec
[P2_APREC_NOISE
/ 2]), base
);
2809 ssid_length
= LEWord(ap_rec
[P2_APREC_NAMELEN
/ 2]);
2810 tag
->ti_Tag
= S2INFO_SSID
;
2811 tag
->ti_Data
= (UPINT
)(ssid
=
2812 AllocPooled(pool
, 31 + 1));
2815 CopyMem(ap_rec
+ P2_APREC_NAME
/ 2, ssid
, ssid_length
);
2816 ssid
[ssid_length
] = '\0';
2819 error
= S2ERR_NO_RESOURCES
;
2822 tag
->ti_Tag
= TAG_END
;
2826 /* Find IEs for each BSS and insert them into the BSS's tag list */
2828 for(beacon
= unit
->beacons
, i
= 0; i
< unit
->beacon_count
; i
++)
2830 /* Extract IEs from beacon descriptor */
2832 data_length
= BEWord(*(UWORD
*)(beacon
+ ETH_PACKET_IEEELEN
));
2833 ies_length
= data_length
- 12;
2834 frame_length
= ETH_HEADERSIZE
+ data_length
;
2835 ies
= AllocPooled(pool
, sizeof(UWORD
) + ies_length
);
2838 *(UWORD
*)ies
= ies_length
;
2839 CopyMem(beacon
+ ETH_PACKET_DATA
+ WIFI_BEACON_IES
,
2840 ies
+ sizeof(UWORD
), ies_length
);
2843 error
= S2ERR_NO_RESOURCES
;
2845 /* Find matching tag list and add IEs to it */
2847 ie_bssid
= beacon
+ ETH_PACKET_SOURCE
;
2848 for(j
= 0; j
< count
; j
++)
2851 bssid
= (UBYTE
*)tag
->ti_Data
;
2852 if(*(ULONG
*)bssid
== *(ULONG
*)ie_bssid
2853 && *(UWORD
*)(bssid
+ 4) == *(UWORD
*)(ie_bssid
+ 4))
2856 tag
->ti_Tag
= S2INFO_InfoElements
;
2857 tag
->ti_Data
= (PINT
)ies
;
2861 beacon
+= frame_length
+ sizeof(ULONG
) & ~3;
2864 /* Return results */
2868 request
->ios2_StatData
= tag_lists
;
2869 request
->ios2_DataLength
= count
;
2873 request
->ios2_Req
.io_Error
= error
;
2874 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
2876 Remove((APTR
)request
);
2877 ReplyMsg((APTR
)request
);
2880 /* Discard collected beacon frames */
2883 unit
->next_beacon
= unit
->beacons
;
2884 unit
->beacon_count
= 0;
2892 /****i* prism2.device/GetNetworkInfo ***************************************
2895 * GetNetworkInfo -- Get information on current network.
2898 * tag_list = GetNetworkInfo(unit, pool)
2900 * struct TagItem *GetNetworkInfo(struct DevUnit *, APTR);
2905 * unit - A unit of this device.
2906 * pool - A memory pool.
2911 ****************************************************************************
2915 struct TagItem
*GetNetworkInfo(struct DevUnit
*unit
, APTR pool
,
2916 struct DevBase
*base
)
2919 struct TagItem
*tag_list
, *tag
;
2923 AllocPooled(pool
, INFO_TAG_COUNT
* sizeof(struct TagItem
));
2924 if(tag_list
== NULL
)
2925 error
= S2ERR_NO_RESOURCES
;
2931 tag
->ti_Tag
= S2INFO_BSSID
;
2932 tag
->ti_Data
= (UPINT
)(bssid
=
2933 AllocPooled(pool
, ETH_ADDRESSSIZE
));
2935 CopyMem(unit
->bssid
, bssid
, ETH_ADDRESSSIZE
);
2937 error
= S2ERR_NO_RESOURCES
;
2940 tag
->ti_Tag
= TAG_IGNORE
;
2943 tag
->ti_Tag
= S2INFO_WPAInfo
;
2944 tag
->ti_Data
= (UPINT
)(ie
=
2945 AllocPooled(pool
, unit
->wpa_ie
[1] + 2));
2947 CopyMem(unit
->wpa_ie
, ie
, unit
->wpa_ie
[1] + 2);
2949 error
= S2ERR_NO_RESOURCES
;
2952 tag
->ti_Tag
= TAG_END
;
2963 /****i* prism2.device/UpdateSignalQuality **********************************
2966 * UpdateSignalQuality -- Read signal quality from card.
2969 * UpdateSignalQuality(unit)
2971 * VOID UpdateSignalQuality(struct DevUnit *);
2976 * unit - A unit of this device.
2981 ****************************************************************************
2985 VOID
UpdateSignalQuality(struct DevUnit
*unit
, struct DevBase
*base
)
2987 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_LINKQUALITY
, base
);
2988 P2Seek(unit
, 1, P2_REC_LINKQUALITY
, 6, base
);
2990 unit
->signal_quality
.SignalLevel
=
2991 ConvertLevel(unit
, unit
->LEWordIn(unit
->card
, P2_REG_DATA1
), base
);
2992 unit
->signal_quality
.NoiseLevel
=
2993 ConvertLevel(unit
, unit
->LEWordIn(unit
->card
, P2_REG_DATA1
), base
);
3000 /****i* prism2.device/StartScan ********************************************
3003 * StartScan -- Start a scan for available networks.
3008 * VOID StartScan(struct DevUnit *);
3013 * unit - A unit of this device.
3018 ****************************************************************************
3022 VOID
StartScan(struct DevUnit
*unit
, const TEXT
*ssid
, struct DevBase
*base
)
3025 UWORD ssid_length
= 0;
3027 /* Ask for a scan */
3029 if((unit
->flags
& UNITF_ONLINE
) != 0)
3032 ssid_length
= StrLen(ssid
);
3033 if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
3035 params
= AllocVec(sizeof(scan_params
) + ssid_length
, MEMF_PUBLIC
);
3038 CopyMem(scan_params
, params
, sizeof(scan_params
));
3040 CopyMem(ssid
, params
+ sizeof(scan_params
), ssid_length
);
3041 params
[4] = ssid_length
;
3042 P2SetData(unit
, P2_REC_HOSTSCAN
, params
,
3043 sizeof(scan_params
) + ssid_length
, base
);
3047 else if(unit
->firmware_type
== SYMBOL_FIRMWARE
)
3048 P2SetWord(unit
, P2_REC_ALTHOSTSCAN
, 0x82, base
);
3049 else if(unit
->firmware_type
>= LUCENT_FIRMWARE
3050 && (unit
->flags
& UNITF_HARDTKIP
) != 0)
3052 /* Initialise fake scan results and ask for a series of raw beacon
3055 unit
->scan_results_rec
[0] = MakeLEWord(1);
3057 P2SetID(unit
, P2_REC_SCANSSID
, ssid
, ssid_length
, base
);
3058 P2SetWord(unit
, P2_REC_SCANCHANNELS
, 0x7fff, base
);
3059 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, 0x3fff);
3060 P2DoCmd(unit
, P2_CMD_INQUIRE
, P2_INFO_SCANRESULT
, base
);
3064 P2SetID(unit
, P2_REC_SCANSSID
, ssid
, ssid_length
, base
);
3065 P2DoCmd(unit
, P2_CMD_INQUIRE
, P2_INFO_SCANRESULTS
, base
);
3074 /****i* prism2.device/LoadFirmware *****************************************
3080 * success = LoadFirmware(unit)
3082 * BOOL LoadFirmware(struct DevUnit *);
3087 * unit - A unit of this device.
3090 * success - Success indicator.
3092 ****************************************************************************
3096 static BOOL
LoadFirmware(struct DevUnit
*unit
, struct DevBase
*base
)
3098 BOOL success
= TRUE
;
3099 const TEXT
*file_name
;
3100 struct FileInfoBlock
*info
= NULL
;
3101 UWORD control_reg
, pdr_no
, *pda
= NULL
, *pdr
, *prod_data
, length
;
3102 ULONG location
, start_address
;
3103 BPTR file
= (BPTR
)NULL
;
3105 TEXT
*buffer
= NULL
;
3109 /* Read firmware file */
3111 switch(unit
->firmware_type
)
3113 case LUCENT_FIRMWARE
:
3114 file_name
= h1_firmware_file_name
;
3116 case HERMES2_FIRMWARE
:
3117 file_name
= h2_firmware_file_name
;
3119 case HERMES2G_FIRMWARE
:
3120 file_name
= h25_firmware_file_name
;
3126 if(file_name
== NULL
)
3131 file
= Open(file_name
, MODE_OLDFILE
);
3132 if(file
== (BPTR
)NULL
)
3138 info
= AllocDosObject(DOS_FIB
, NULL
);
3145 if(!ExamineFH(file
, info
))
3151 buffer
= AllocVec(info
->fib_Size
+ 1, MEMF_ANY
);
3152 data
= AllocVec(MAX_S_REC_SIZE
, MEMF_ANY
);
3153 pda
= AllocVec(LUCENT_PDA_SIZE
, MEMF_ANY
);
3154 if(buffer
== NULL
|| data
== NULL
|| pda
== NULL
)
3160 if(Read(file
, buffer
, info
->fib_Size
) == -1)
3162 buffer
[info
->fib_Size
] = '\0';
3167 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3168 P2DoCmd(unit
, P2_CMD_INIT
| 0x100, 0, base
);
3169 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3170 P2DoCmd(unit
, P2_CMD_INIT
| 0x0, 0, base
);
3171 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3173 /* Enable auxiliary ports */
3175 unit
->LEWordOut(unit
->card
, P2_REG_PARAM0
, 0xfe01);
3176 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, 0xdc23);
3177 unit
->LEWordOut(unit
->card
, P2_REG_PARAM2
, 0xba45);
3179 control_reg
= unit
->LEWordIn(unit
->card
, P2_REG_CONTROL
);
3181 control_reg
& ~P2_REG_CONTROLF_AUX
| P2_REG_CONTROL_ENABLEAUX
;
3182 unit
->LEWordOut(unit
->card
, P2_REG_CONTROL
, control_reg
);
3184 BusyMilliDelay(5, base
);
3186 (unit
->LEWordIn(unit
->card
, P2_REG_CONTROL
) & P2_REG_CONTROLF_AUX
)
3187 != P2_REG_CONTROL_AUXENABLED
);
3189 /* Read Production Data Area from card */
3191 if(unit
->firmware_type
< HERMES2_FIRMWARE
)
3193 location
= LUCENT_PDA_ADDRESS
;
3194 unit
->LEWordOut(unit
->card
, P2_REG_AUXPAGE
, location
>> 7);
3195 unit
->LEWordOut(unit
->card
, P2_REG_AUXOFFSET
,
3196 location
& (1 << 7) - 1);
3198 unit
->WordsIn(unit
->card
, P2_REG_AUXDATA
,
3199 (UWORD
*)pda
, LUCENT_PDA_SIZE
>> 1);
3202 /* Allow writing to card's RAM */
3204 BusyMilliDelay(100, base
);
3205 start_address
= 0xf8000;
3206 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, start_address
>> 16);
3207 P2DoCmd(unit
, P2_CMD_PROGRAM
| P2_CMDF_WRITE
, start_address
, base
);
3209 /* Parse firmware image data and write it to card */
3214 p
= ParseNextSRecord(p
, &type
, data
, &length
, &location
, base
);
3221 /* Check that this is not a "special" record */
3223 if(location
< 0xff000000)
3225 /* Write data to card */
3227 if(unit
->firmware_type
< LUCENT_FIRMWARE
)
3229 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
,
3231 P2DoCmd(unit
, P2_CMD_PROGRAM
| P2_CMDF_WRITE
, location
,
3235 unit
->LEWordOut(unit
->card
, P2_REG_AUXPAGE
,
3237 unit
->LEWordOut(unit
->card
, P2_REG_AUXOFFSET
,
3238 location
& (1 << 7) - 1);
3240 unit
->WordsOut(unit
->card
, P2_REG_AUXDATA
,
3241 (UWORD
*)data
, length
>> 1);
3247 /* Get location in card memory to begin execution of new
3250 start_address
= location
;
3255 /* Parse PDA plug records and patch firmware */
3260 p
= ParseNextSRecord(p
, &type
, data
, &length
, &location
, base
);
3262 if(p
!= NULL
&& type
== '3' && location
== 0xff000000)
3264 /* Get PDR number and the location where it should be patched
3267 pdr_no
= LELong(*(ULONG
*)data
);
3268 location
= LELong(*(ULONG
*)(data
+ 4));
3269 length
= LELong(*(ULONG
*)(data
+ 8));
3271 /* Find PDR to copy data from */
3274 for(pdr
= pda
; pdr
[1] != 0; pdr
+= LEWord(pdr
[0]) + 1)
3276 if(LEWord(pdr
[1]) == pdr_no
)
3277 prod_data
= pdr
+ 2;
3280 /* Write production data to card if it was found */
3282 if(prod_data
!= NULL
)
3284 if(unit
->firmware_type
< LUCENT_FIRMWARE
)
3286 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
,
3288 P2DoCmd(unit
, P2_CMD_PROGRAM
| P2_CMDF_WRITE
, location
,
3292 unit
->LEWordOut(unit
->card
, P2_REG_AUXPAGE
, location
>> 7);
3293 unit
->LEWordOut(unit
->card
, P2_REG_AUXOFFSET
,
3294 location
& (1 << 7) - 1);
3296 unit
->WordsOut(unit
->card
, P2_REG_AUXDATA
, prod_data
,
3302 /* Disable auxiliary ports */
3304 control_reg
= unit
->LEWordIn(unit
->card
, P2_REG_CONTROL
);
3306 control_reg
& ~P2_REG_CONTROLF_AUX
| P2_REG_CONTROL_DISABLEAUX
;
3307 unit
->LEWordOut(unit
->card
, P2_REG_CONTROL
, control_reg
);
3309 /* Execute downloaded firmware */
3311 if(unit
->firmware_type
>= HERMES2_FIRMWARE
)
3313 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, start_address
>> 16);
3314 P2DoCmd(unit
, P2_CMD_EXECUTE
, start_address
, base
);
3316 else if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
3318 P2DoCmd(unit
, P2_CMD_PROGRAM
, 0, base
);
3319 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3320 P2DoCmd(unit
, P2_CMD_INIT
, 0, base
);
3321 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3325 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, start_address
>> 16);
3326 P2DoCmd(unit
, P2_CMD_PROGRAM
, start_address
, base
);
3327 P2DoCmd(unit
, P2_CMD_INIT
, 0, base
);
3331 /* Free Resources */
3336 FreeDosObject(DOS_FIB
, info
);
3337 if(file
!= (BPTR
)NULL
)
3345 /****i* prism2.device/ParseNextSRecord *************************************
3350 ****************************************************************************
3354 static const TEXT
*ParseNextSRecord(const TEXT
*s
, UBYTE
*type
, UBYTE
*data
,
3355 UWORD
*data_length
, ULONG
*location
, struct DevBase
*base
)
3362 /* Find start of next record, if any */
3367 if(ch
== 'S' || ch
== '\0')
3373 /* Get record type */
3377 /* Skip length field to keep alignment easy */
3381 /* Parse hexadecimal portion of record */
3383 for(i
= 0; (ch
= *s
++) >= '0'; i
++)
3392 if(i
>= 8 && (i
& 0x1) != 0)
3403 *data_length
= (i
>> 1) - 5;
3408 /* Return updated text pointer */
3415 /****i* prism2.device/P2DoCmd **********************************************
3420 ****************************************************************************
3422 * Commands can't fail without software/firmware bug?
3426 static VOID
P2DoCmd(struct DevUnit
*unit
, UWORD command
, UWORD param
,
3427 struct DevBase
*base
)
3429 if(unit
->firmware_type
< LUCENT_FIRMWARE
&& command
== P2_CMD_INIT
)
3430 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3432 unit
->LEWordOut(unit
->card
, P2_REG_PARAM0
, param
);
3433 unit
->LEWordOut(unit
->card
, P2_REG_COMMAND
, command
);
3434 while((unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
)
3435 & P2_EVENTF_CMD
) == 0);
3436 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_CMD
);
3438 if(unit
->firmware_type
< LUCENT_FIRMWARE
&& command
== P2_CMD_INIT
)
3439 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3444 /****i* prism2.device/P2Seek ***********************************************
3449 ****************************************************************************
3453 static BOOL
P2Seek(struct DevUnit
*unit
, UWORD path_no
, UWORD rec_no
,
3454 UWORD offset
, struct DevBase
*base
)
3459 offset_reg
= P2_REG_OFFSET0
+ path_no
;
3460 while((unit
->LEWordIn(unit
->card
, offset_reg
) & P2_REG_OFFSETF_BUSY
)
3462 unit
->LEWordOut(unit
->card
, P2_REG_SELECT0
+ path_no
, rec_no
);
3463 unit
->LEWordOut(unit
->card
, offset_reg
, offset
);
3464 while((unit
->LEWordIn(unit
->card
, offset_reg
) & P2_REG_OFFSETF_BUSY
)
3467 return (unit
->LEWordIn(unit
->card
, offset_reg
) & P2_REG_OFFSETF_ERROR
)
3473 /****i* prism2.device/P2SetID **********************************************
3479 * id may be NULL as long as length is zero.
3481 ****************************************************************************
3485 static VOID
P2SetID(struct DevUnit
*unit
, UWORD rec_no
, const UBYTE
*id
,
3486 UWORD length
, struct DevBase
*base
)
3488 P2Seek(unit
, 1, rec_no
, 0, base
);
3490 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, length
/ 2 + 3);
3491 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, rec_no
);
3492 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, length
);
3493 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)id
, (length
+ 1) / 2);
3495 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
, rec_no
, base
);
3502 /****i* prism2.device/P2SetWord ********************************************
3507 ****************************************************************************
3511 static VOID
P2SetWord(struct DevUnit
*unit
, UWORD rec_no
, UWORD value
,
3512 struct DevBase
*base
)
3514 P2Seek(unit
, 1, rec_no
, 0, base
);
3516 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 2);
3517 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, rec_no
);
3518 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, value
);
3520 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
, rec_no
, base
);
3527 /****i* prism2.device/P2GetWord ********************************************
3532 ****************************************************************************
3536 static UWORD
P2GetWord(struct DevUnit
*unit
, UWORD rec_no
,
3537 struct DevBase
*base
)
3539 P2DoCmd(unit
, P2_CMD_ACCESS
, rec_no
, base
);
3540 P2Seek(unit
, 1, rec_no
, 4, base
);
3542 return unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
3547 /****i* prism2.device/P2AllocMem *******************************************
3552 ****************************************************************************
3556 static UWORD
P2AllocMem(struct DevUnit
*unit
, UWORD size
,
3557 struct DevBase
*base
)
3560 P2DoCmd(unit
, P2_CMD_ALLOCMEM
, size
, base
);
3561 while((unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
) & P2_EVENTF_ALLOCMEM
)
3563 id
= unit
->LEWordIn(unit
->card
, P2_REG_ALLOCFID
);
3564 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_ALLOCMEM
);
3570 /****i* prism2.device/P2SetData ********************************************
3575 ****************************************************************************
3579 static VOID
P2SetData(struct DevUnit
*unit
, UWORD rec_no
, const UBYTE
*data
,
3580 UWORD length
, struct DevBase
*base
)
3582 length
= (length
+ 1) / 2;
3583 P2Seek(unit
, 1, rec_no
, 0, base
);
3585 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 1 + length
);
3586 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, rec_no
);
3587 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (const UWORD
*)data
, length
);
3589 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
, rec_no
, base
);
3596 /****i* prism2.device/P2ReadRec ********************************************
3599 * P2ReadRec -- Load and read an entire record.
3602 * success = P2ReadRec(unit, rec_no, buffer, max_length)
3604 * BOOL P2ReadRec(struct DevUnit *, UWORD, APTR, UWORD);
3609 * unit - A unit of this device.
3610 * rec_no - Record number to read.
3611 * buffer - Buffer to store data in.
3612 * max_length - Maximum number of bytes to store in buffer.
3615 * success - Success indicator.
3617 ****************************************************************************
3621 static BOOL
P2ReadRec(struct DevUnit
*unit
, UWORD rec_no
, APTR buffer
,
3622 UWORD max_length
, struct DevBase
*base
)
3624 BOOL success
= TRUE
;
3627 P2DoCmd(unit
, P2_CMD_ACCESS
, rec_no
, base
);
3628 P2Seek(unit
, 1, rec_no
, 0, base
);
3630 length
= (unit
->LEWordIn(unit
->card
, P2_REG_DATA1
) + 1) * 2;
3631 P2Seek(unit
, 1, rec_no
, 0, base
);
3632 if(length
<= max_length
)
3633 unit
->WordsIn(unit
->card
, P2_REG_DATA1
, (UWORD
*)buffer
,
3642 /****i* prism2.device/ConvertLevel *****************************************
3645 * ConvertLevel -- Convert a signal or noise level to dBm.
3648 * dbm_level = ConvertLevel(unit, raw_level)
3650 * LONG ConvertLevel(struct DevUnit *, UWORD);
3655 * unit - A unit of this device.
3656 * raw_level - The value returned from the hardware.
3659 * dbm_level - The value in dBm.
3661 ****************************************************************************
3665 static LONG
ConvertLevel(struct DevUnit
*unit
, UWORD raw_level
,
3666 struct DevBase
*base
)
3670 if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
3671 dbm_level
= raw_level
- LUCENT_DBM_OFFSET
;
3673 dbm_level
= raw_level
/ 3 - INTERSIL_DBM_OFFSET
;
3680 /****i* prism2.device/ConvertScanLevel *************************************
3683 * ConvertScanLevel -- Convert a signal or noise level to dBm.
3686 * dbm_level = ConvertScanLevel(unit, raw_level)
3688 * LONG ConvertScanLevel(struct DevUnit *, UWORD);
3693 * unit - A unit of this device.
3694 * raw_level - The value returned from the hardware.
3697 * dbm_level - The value in dBm.
3699 ****************************************************************************
3703 static LONG
ConvertScanLevel(struct DevUnit
*unit
, UWORD raw_level
,
3704 struct DevBase
*base
)
3708 if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
3709 dbm_level
= raw_level
- LUCENT_DBM_OFFSET
;
3711 dbm_level
= (WORD
)raw_level
;
3718 /****i* prism2.device/GetIE ************************************************
3724 * ie = GetIE(id, ies, ies_length)
3726 * UBYTE *GetIE(UBYTE, UBYTE *, UWORD);
3731 * id - ID of IE to find.
3732 * ies - A series of IEs.
3733 * ies_length - Length of IE block.
3736 * ie - Pointer to start of IE within block, or NULL if not found.
3738 ****************************************************************************
3743 static UBYTE
*GetIE(UBYTE id
, UBYTE
*ies
, UWORD ies_length
,
3744 struct DevBase
*base
)
3749 // for(ie = ies; ie < end && ie + ie[1] < end; ie += length + 2)
3750 end
= ies
+ ies_length
;
3751 while(ie
< end
&& !found
)
3764 static UBYTE
*GetIE(UBYTE id
, UBYTE
*ies
, UWORD ies_length
,
3765 struct DevBase
*base
)
3769 for(ie
= ies
; ie
< ies
+ ies_length
&& ie
[0] != id
; ie
+= ie
[1] + 2);
3770 // for(ie = ies, end = ies + ies_length; ie < end && ie[0] != id; ie += ie[1] + 2);
3771 if(ie
>= ies
+ ies_length
)
3779 /****i* prism2.device/UnitTask *********************************************
3785 * UnitTask(sys_base)
3787 * VOID UnitTask(struct ExecBase *);
3790 * Completes deferred requests, and handles card insertion and removal
3791 * in conjunction with the relevant interrupts.
3793 ****************************************************************************
3801 static VOID
UnitTask(struct ExecBase
*sys_base
)
3804 struct IORequest
*request
;
3805 struct DevUnit
*unit
;
3806 struct DevBase
*base
;
3807 struct MsgPort
*general_port
;
3808 ULONG signals
= 0, wait_signals
, card_removed_signal
,
3809 card_inserted_signal
, scan_complete_signal
, general_port_signal
;
3811 /* Get parameters */
3813 task
= FindTask(NULL
);
3814 unit
= task
->tc_UserData
;
3815 base
= unit
->device
;
3817 /* Activate general request port */
3819 general_port
= unit
->request_ports
[GENERAL_QUEUE
];
3820 general_port
->mp_SigTask
= task
;
3821 general_port
->mp_SigBit
= AllocSignal(-1);
3822 general_port_signal
= 1 << general_port
->mp_SigBit
;
3823 general_port
->mp_Flags
= PA_SIGNAL
;
3825 /* Allocate signals for notification of card removal and insertion */
3827 card_removed_signal
= unit
->card_removed_signal
= 1 << AllocSignal(-1);
3828 card_inserted_signal
= unit
->card_inserted_signal
= 1 << AllocSignal(-1);
3829 scan_complete_signal
= unit
->scan_complete_signal
= 1 << AllocSignal(-1);
3830 wait_signals
= (1 << general_port
->mp_SigBit
) | card_removed_signal
3831 | card_inserted_signal
| scan_complete_signal
| SIGBREAKF_CTRL_C
;
3833 /* Tell ourselves to check port for old messages */
3835 Signal(task
, general_port_signal
);
3837 /* Infinite loop to service requests and signals */
3839 while((signals
& SIGBREAKF_CTRL_C
) == 0)
3841 signals
= Wait(wait_signals
);
3843 if((signals
& card_inserted_signal
) != 0)
3845 if(unit
->insertion_function(unit
->card
, base
))
3847 unit
->flags
|= UNITF_HAVEADAPTER
;
3848 if((unit
->flags
& UNITF_CONFIGURED
) != 0)
3849 ConfigureAdapter(unit
, base
);
3850 if((unit
->flags
& UNITF_WASONLINE
) != 0)
3852 GoOnline(unit
, base
);
3853 unit
->flags
&= ~UNITF_WASONLINE
;
3858 if((signals
& card_removed_signal
) != 0)
3860 unit
->removal_function(unit
->card
, base
);
3861 if((unit
->flags
& UNITF_WASONLINE
) != 0)
3862 GoOffline(unit
, base
);
3865 if((signals
& scan_complete_signal
) != 0)
3866 SendScanResults(unit
, base
);
3868 if((signals
& general_port_signal
) != 0)
3870 while((request
= (APTR
)GetMsg(general_port
)) != NULL
)
3872 /* Service the request as soon as the unit is free */
3874 ObtainSemaphore(&unit
->access_lock
);
3875 ServiceRequest((APTR
)request
, base
);
3880 FreeMem(task
->tc_SPLower
, STACK_SIZE
);
3885 /****i* prism2.device/StrLen ***********************************************
3891 * length = StrLen(s)
3893 * UPINT StrLen(TEXT *);
3895 ****************************************************************************
3899 static UPINT
StrLen(const TEXT
*s
)
3903 for(p
= s
; *p
!= '\0'; p
++);