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,
23 #include <exec/memory.h>
24 #include <exec/execbase.h>
25 #include <exec/errors.h>
27 #include <proto/exec.h>
29 #include <proto/alib.h>
31 #include <clib/alib_protos.h>
33 #include <proto/utility.h>
34 #include <proto/dos.h>
35 #include <proto/timer.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
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)
65 #define AbsExecBase sys_base
67 #define AbsExecBase (*(struct ExecBase **)4)
71 static struct AddressRange
*FindMulticastRange(struct DevUnit
*unit
,
72 ULONG lower_bound_left
, UWORD lower_bound_right
, ULONG upper_bound_left
,
73 UWORD upper_bound_right
, struct DevBase
*base
);
74 static VOID
SetMulticast(struct DevUnit
*unit
, struct DevBase
*base
);
75 static VOID
RXInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
));
76 static UBYTE
*GetRXBuffer(struct DevUnit
*unit
, const UBYTE
*address
,
77 UWORD frag_no
, UWORD
*buffer_no
, struct DevBase
*base
);
78 static VOID
DistributeRXPacket(struct DevUnit
*unit
, UBYTE
*frame
,
79 struct DevBase
*base
);
80 static VOID
CopyPacket(struct DevUnit
*unit
, struct IOSana2Req
*request
,
81 UWORD packet_size
, UWORD packet_type
, UBYTE
*buffer
,
82 struct DevBase
*base
);
83 static BOOL
AddressFilter(struct DevUnit
*unit
, UBYTE
*address
,
84 struct DevBase
*base
);
85 static VOID
SaveBeacon(struct DevUnit
*unit
, const UBYTE
*frame
,
86 struct DevBase
*base
);
87 static VOID
TXInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
));
88 static VOID
InfoInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
));
89 static VOID
ResetHandler(REG(a1
, struct DevUnit
*unit
),
90 REG(a6
, APTR int_code
));
91 static VOID
ReportEvents(struct DevUnit
*unit
, ULONG events
,
92 struct DevBase
*base
);
93 static BOOL
LoadFirmware(struct DevUnit
*unit
, struct DevBase
*base
);
94 static const TEXT
*ParseNextSRecord(const TEXT
*s
, UBYTE
*type
, UBYTE
*data
,
95 UWORD
*data_length
, ULONG
*location
, struct DevBase
*base
);
96 static VOID
P2DoCmd(struct DevUnit
*unit
, UWORD command
, UWORD param
,
97 struct DevBase
*base
);
98 static BOOL
P2Seek(struct DevUnit
*unit
, UWORD path_no
, UWORD rec_no
,
99 UWORD offset
, struct DevBase
*base
);
100 static VOID
P2SetID(struct DevUnit
*unit
, UWORD rec_no
, const UBYTE
*id
,
101 UWORD length
, struct DevBase
*base
);
102 static VOID
P2SetWord(struct DevUnit
*unit
, UWORD rec_no
, UWORD value
,
103 struct DevBase
*base
);
104 static UWORD
P2GetWord(struct DevUnit
*unit
, UWORD rec_no
,
105 struct DevBase
*base
);
106 static UWORD
P2AllocMem(struct DevUnit
*unit
, UWORD size
,
107 struct DevBase
*base
);
108 static VOID
P2SetData(struct DevUnit
*unit
, UWORD rec_no
, const UBYTE
*data
,
109 UWORD length
, struct DevBase
*base
);
110 static BOOL
P2ReadRec(struct DevUnit
*unit
, UWORD rec_no
, APTR buffer
,
111 UWORD max_length
, struct DevBase
*base
);
112 static LONG
ConvertLevel(struct DevUnit
*unit
, UWORD raw_level
,
113 struct DevBase
*base
);
114 static LONG
ConvertScanLevel(struct DevUnit
*unit
, UWORD raw_level
,
115 struct DevBase
*base
);
116 static UBYTE
*GetIE(UBYTE id
, UBYTE
*ies
, UWORD ies_length
,
117 struct DevBase
*base
);
118 static VOID
UnitTask(struct ExecBase
*sys_base
);
119 static UPINT
StrLen(const TEXT
*s
);
122 static const UBYTE snap_template
[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
123 static const UBYTE scan_params
[] = {0xff, 0x3f, 0x01, 0x00, 0x00, 0x00};
124 static const TEXT options_name
[] = "Prism 2 options";
125 static const TEXT h1_firmware_file_name
[] = "DEVS:Firmware/HermesI";
126 static const TEXT h2_firmware_file_name
[] = "DEVS:Firmware/HermesII";
127 static const TEXT h25_firmware_file_name
[] = "DEVS:Firmware/HermesII.5";
128 static const UBYTE h2_wpa_ie
[] =
130 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00,
131 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50,
132 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02,
139 #define AddTask(task, initial_pc, final_pc) \
140 IExec->AddTask(task, initial_pc, final_pc, NULL)
143 static const struct EmulLibEntry mos_task_trap
=
149 #define UnitTask &mos_task_trap
153 #define AddTask(task, initial_pc, final_pc) \
155 struct TagItem _task_tags[] = \
156 {{TASKTAG_ARG1, (IPTR)SysBase}, {TAG_END, 0}}; \
157 NewAddTask(task, initial_pc, final_pc, _task_tags); \
163 /****i* prism2.device/CreateUnit *******************************************
166 * CreateUnit -- Create a unit.
169 * unit = CreateUnit(index, card, io_tags, bus)
171 * struct DevUnit *CreateUnit(ULONG, APTR, struct TagItem *, UWORD);
174 * Creates a new unit.
176 ****************************************************************************
180 struct DevUnit
*CreateUnit(ULONG index
, APTR card
,
181 const struct TagItem
*io_tags
, UWORD bus
, struct DevBase
*base
)
184 struct DevUnit
*unit
;
186 struct MsgPort
*port
;
190 unit
= AllocMem(sizeof(struct DevUnit
), MEMF_CLEAR
| MEMF_PUBLIC
);
201 (APTR
)GetTagData(IOTAG_WordsIn
, (UPINT
)NULL
, io_tags
);
203 (APTR
)GetTagData(IOTAG_WordsOut
, (UPINT
)NULL
, io_tags
);
205 (APTR
)GetTagData(IOTAG_BEWordOut
, (UPINT
)NULL
, io_tags
);
207 (APTR
)GetTagData(IOTAG_LEWordIn
, (UPINT
)NULL
, io_tags
);
209 (APTR
)GetTagData(IOTAG_LEWordOut
, (UPINT
)NULL
, io_tags
);
210 if(unit
->WordsIn
== NULL
|| unit
->WordsOut
== NULL
211 || unit
->BEWordOut
== NULL
|| unit
->LEWordIn
== NULL
212 || unit
->LEWordOut
== NULL
)
218 InitSemaphore(&unit
->access_lock
);
219 success
= InitialiseAdapter(unit
, FALSE
, base
);
220 unit
->flags
|= UNITF_HAVEADAPTER
;
222 /* Create the message ports for queuing requests */
224 for(i
= 0; i
< REQUEST_QUEUE_COUNT
; i
++)
226 unit
->request_ports
[i
] = port
= AllocMem(sizeof(struct MsgPort
),
227 MEMF_PUBLIC
| MEMF_CLEAR
);
233 NewList(&port
->mp_MsgList
);
234 port
->mp_Flags
= PA_IGNORE
;
235 port
->mp_SigTask
= &unit
->tx_int
;
239 /* Allocate buffers */
241 unit
->rx_buffer
= AllocVec(FRAME_BUFFER_SIZE
, MEMF_PUBLIC
);
242 unit
->rx_buffers
= AllocVec(FRAME_BUFFER_SIZE
* RX_BUFFER_COUNT
,
244 for(i
= 0; i
< RX_BUFFER_COUNT
; i
++)
245 unit
->rx_fragment_nos
[i
] = -1;
246 unit
->tx_buffer
= AllocVec(ETH_MAXPACKETSIZE
, MEMF_PUBLIC
);
247 unit
->rx_descriptor
= AllocVec(FRAME_BUFFER_SIZE
,
248 MEMF_PUBLIC
| MEMF_CLEAR
);
249 unit
->tx_descriptor
= AllocVec(FRAME_BUFFER_SIZE
,
250 MEMF_PUBLIC
| MEMF_CLEAR
);
251 unit
->scan_results_rec
= AllocVec(SCAN_BUFFER_SIZE
, MEMF_PUBLIC
);
252 unit
->next_beacon
= unit
->beacons
=
253 AllocVec(BEACON_BUFFER_SIZE
, MEMF_PUBLIC
);
254 if(unit
->rx_buffer
== NULL
|| unit
->rx_buffers
== NULL
255 || unit
->tx_buffer
== NULL
|| unit
->rx_descriptor
== NULL
256 || unit
->tx_descriptor
== NULL
|| unit
->scan_results_rec
== NULL
257 || unit
->beacons
== NULL
)
263 NewList((APTR
)&unit
->openers
);
264 NewList((APTR
)&unit
->type_trackers
);
265 NewList((APTR
)&unit
->multicast_ranges
);
267 /* Record maximum speed in BPS */
269 unit
->speed
= 11000000;
271 /* Initialise status, transmit, receive and stats interrupts */
273 unit
->status_int
.is_Node
.ln_Name
=
274 base
->device
.dd_Library
.lib_Node
.ln_Name
;
275 unit
->status_int
.is_Code
= (APTR
)StatusInt
;
276 unit
->status_int
.is_Data
= unit
;
278 unit
->rx_int
.is_Node
.ln_Name
=
279 base
->device
.dd_Library
.lib_Node
.ln_Name
;
280 unit
->rx_int
.is_Code
= (APTR
)RXInt
;
281 unit
->rx_int
.is_Data
= unit
;
283 unit
->tx_int
.is_Node
.ln_Name
=
284 base
->device
.dd_Library
.lib_Node
.ln_Name
;
285 unit
->tx_int
.is_Code
= (APTR
)TXInt
;
286 unit
->tx_int
.is_Data
= unit
;
288 unit
->info_int
.is_Node
.ln_Name
=
289 base
->device
.dd_Library
.lib_Node
.ln_Name
;
290 unit
->info_int
.is_Code
= (APTR
)InfoInt
;
291 unit
->info_int
.is_Data
= unit
;
293 unit
->reset_handler
.is_Node
.ln_Name
=
294 base
->device
.dd_Library
.lib_Node
.ln_Name
;
295 unit
->reset_handler
.is_Code
= (APTR
)ResetHandler
;
296 unit
->reset_handler
.is_Data
= unit
;
298 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
303 /* Create a new task */
306 AllocMem(sizeof(struct Task
), MEMF_PUBLIC
| MEMF_CLEAR
);
313 stack
= AllocMem(STACK_SIZE
, MEMF_PUBLIC
);
320 /* Initialise and start task */
322 task
->tc_Node
.ln_Type
= NT_TASK
;
323 task
->tc_Node
.ln_Pri
= TASK_PRIORITY
;
324 task
->tc_Node
.ln_Name
= base
->device
.dd_Library
.lib_Node
.ln_Name
;
325 task
->tc_SPUpper
= stack
+ STACK_SIZE
;
326 task
->tc_SPLower
= stack
;
327 task
->tc_SPReg
= stack
+ STACK_SIZE
;
328 NewList(&task
->tc_MemEntry
);
330 if(AddTask(task
, UnitTask
, NULL
) == NULL
)
336 /* Send the unit to the new task */
338 task
->tc_UserData
= unit
;
340 /* Set default wireless options */
342 unit
->mode
= S2PORT_MANAGED
;
347 DeleteUnit(unit
, base
);
356 /****i* prism2.device/DeleteUnit *******************************************
359 * DeleteUnit -- Delete a unit.
364 * VOID DeleteUnit(struct DevUnit *);
370 * unit - Device unit (may be NULL).
375 ****************************************************************************
379 VOID
DeleteUnit(struct DevUnit
*unit
, struct DevBase
*base
)
391 if(task
->tc_UserData
!= NULL
)
394 FreeMem(task
->tc_SPLower
, STACK_SIZE
);
396 FreeMem(task
, sizeof(struct Task
));
399 /* Free request queues */
401 for(i
= 0; i
< REQUEST_QUEUE_COUNT
; i
++)
403 if(unit
->request_ports
[i
] != NULL
)
404 FreeMem(unit
->request_ports
[i
], sizeof(struct MsgPort
));
409 if((unit
->flags
& UNITF_ONLINE
) != 0) /* Needed! */
410 GoOffline(unit
, base
);
412 /* Clear target SSID */
414 P2SetID(unit
, P2_REC_DESIREDSSID
, unit
->ssid
, 0, base
);
416 /* Free buffers and unit structure */
418 FreeVec(unit
->scan_results_rec
);
419 FreeVec(unit
->tx_descriptor
);
420 FreeVec(unit
->rx_descriptor
);
421 FreeVec(unit
->tx_buffer
);
422 FreeVec(unit
->rx_buffers
);
423 FreeVec(unit
->rx_buffer
);
425 FreeMem(unit
, sizeof(struct DevUnit
));
433 /****i* prism2.device/InitialiseAdapter ************************************
439 * success = InitialiseAdapter(unit, reinsertion)
441 * BOOL InitialiseAdapter(struct DevUnit *, BOOL);
450 * success - Success indicator.
452 ****************************************************************************
456 BOOL
InitialiseAdapter(struct DevUnit
*unit
, BOOL reinsertion
,
457 struct DevBase
*base
)
459 UWORD id
, version
, revision
, i
;
460 BOOL success
= TRUE
, loaded
;
461 UBYTE address
[ETH_ADDRESSSIZE
];
464 /* Wait for card to be ready following bus-specific reset, then start
467 while((unit
->LEWordIn(unit
->card
, P2_REG_COMMAND
)
468 & P2_REG_COMMANDF_BUSY
) != 0);
470 P2DoCmd(unit
, P2_CMD_INIT
, 0, base
);
472 /* Determine firmware type */
474 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_NICIDENTITY
, base
);
475 P2Seek(unit
, 1, P2_REC_NICIDENTITY
, 4, base
);
476 id
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
477 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
478 version
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
479 revision
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
481 if((id
& 0x8000) != 0)
484 unit
->firmware_type
= SYMBOL_FIRMWARE
;
486 unit
->firmware_type
= INTERSIL_FIRMWARE
;
490 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_PRIIDENTITY
, base
);
491 P2Seek(unit
, 1, P2_REC_PRIIDENTITY
, 0, base
);
492 length
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
494 unit
->firmware_type
= LUCENT_FIRMWARE
;
497 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_STAIDENTITY
, base
);
498 P2Seek(unit
, 1, P2_REC_STAIDENTITY
, 4, base
);
499 id
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
500 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
501 version
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
502 revision
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
504 unit
->firmware_type
= HERMES2G_FIRMWARE
;
506 unit
->firmware_type
= HERMES2_FIRMWARE
;
510 /* Download firmware if necessary or available */
512 loaded
= LoadFirmware(unit
, base
);
513 if(!loaded
&& unit
->firmware_type
>= HERMES2_FIRMWARE
)
518 /* Determine features, and get offsets of certain fields within frame
521 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_STAIDENTITY
, base
);
522 P2Seek(unit
, 1, P2_REC_STAIDENTITY
, 4, base
);
523 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
524 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
525 version
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
526 revision
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
528 if(P2GetWord(unit
, P2_REC_HASWEP
, base
) != 0)
529 unit
->flags
|= UNITF_HASWEP
| UNITF_HARDWEP
;
531 unit
->ethernet_offset
= P2_FRM_ETHFRAME
;
532 unit
->data_offset
= P2_FRM_DATA
;
533 unit
->txcontrol_offset
= P2_FRM_TXCONTROL
;
534 unit
->datalen_offset
= P2_FRM_DATALEN
;
536 if(unit
->firmware_type
== LUCENT_FIRMWARE
)
538 if(version
> 6 || version
== 6 && revision
>= 6)
539 unit
->flags
|= UNITF_HASADHOC
;
542 unit
->flags
|= UNITF_HASTKIP
| UNITF_HARDTKIP
;
543 unit
->txcontrol_offset
= P2_FRM_ALTTXCONTROL
;
546 else if(unit
->firmware_type
>= HERMES2_FIRMWARE
)
548 unit
->flags
|= UNITF_HASADHOC
| UNITF_HASTKIP
| UNITF_HARDTKIP
;
549 unit
->ethernet_offset
= P2_H2FRM_ETHFRAME
;
550 unit
->data_offset
= P2_H2FRM_DATA
;
551 unit
->txcontrol_offset
= P2_H2FRM_TXCONTROL
;
552 unit
->datalen_offset
= P2_H2FRM_DATALEN
;
554 else if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
556 unit
->flags
|= UNITF_HASADHOC
| UNITF_HASWEP
;
557 if(version
== 1 && revision
>= 7)
558 unit
->flags
|= UNITF_HASTKIP
| UNITF_HASCCMP
;
561 /* Get default channel and MAC address */
563 unit
->channel
= P2GetWord(unit
, P2_REC_OWNCHNL
, base
);
564 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_ADDRESS
, base
);
565 P2Seek(unit
, 1, P2_REC_ADDRESS
, 4, base
);
566 unit
->WordsIn(unit
->card
, P2_REG_DATA1
, (UWORD
*)address
,
567 ETH_ADDRESSSIZE
/ 2);
569 /* If card has been re-inserted, check it has the same address as
574 for(i
= 0; i
< ETH_ADDRESSSIZE
; i
++)
575 if(address
[i
] != unit
->default_address
[i
])
582 CopyMem(address
, unit
->default_address
, ETH_ADDRESSSIZE
);
584 /* Get initial on-card TX buffer */
586 unit
->tx_frame_id
= P2AllocMem(unit
, FRAME_BUFFER_SIZE
, base
);
590 if((unit
->flags
& UNITF_HARDWEP
) == 0)
591 unit
->iv_sizes
[S2ENC_WEP
] = IV_SIZE
;
592 if((unit
->flags
& UNITF_HARDTKIP
) == 0)
593 unit
->iv_sizes
[S2ENC_TKIP
] = EIV_SIZE
;
594 unit
->iv_sizes
[S2ENC_CCMP
] = EIV_SIZE
;
596 /* Set encryption functions */
598 unit
->fragment_encrypt_functions
[S2ENC_NONE
] = WriteClearFragment
;
600 if((unit
->flags
& UNITF_HARDWEP
) != 0)
601 unit
->fragment_encrypt_functions
[S2ENC_WEP
] = WriteClearFragment
;
603 unit
->fragment_encrypt_functions
[S2ENC_WEP
] = EncryptWEPFragment
;
605 if((unit
->flags
& UNITF_HARDTKIP
) != 0)
606 unit
->fragment_encrypt_functions
[S2ENC_TKIP
] = WriteClearFragment
;
608 unit
->fragment_encrypt_functions
[S2ENC_TKIP
] = EncryptTKIPFragment
;
610 unit
->fragment_encrypt_functions
[S2ENC_CCMP
] = EncryptCCMPFragment
;
612 /* Set decryption functions */
614 unit
->fragment_decrypt_functions
[S2ENC_NONE
] = ReadClearFragment
;
616 if((unit
->flags
& UNITF_HARDWEP
) != 0)
617 unit
->fragment_decrypt_functions
[S2ENC_WEP
] = ReadClearFragment
;
619 unit
->fragment_decrypt_functions
[S2ENC_WEP
] = DecryptWEPFragment
;
621 if((unit
->flags
& UNITF_HARDTKIP
) != 0)
622 unit
->fragment_decrypt_functions
[S2ENC_TKIP
] = ReadClearFragment
;
624 unit
->fragment_decrypt_functions
[S2ENC_TKIP
] = DecryptTKIPFragment
;
626 unit
->fragment_decrypt_functions
[S2ENC_CCMP
] = DecryptCCMPFragment
;
636 /****i* prism2.device/ConfigureAdapter *************************************
639 * ConfigureAdapter -- Set up card for transmission/reception.
642 * ConfigureAdapter(unit)
644 * VOID ConfigureAdapter(struct DevUnit *);
646 ****************************************************************************
650 VOID
ConfigureAdapter(struct DevUnit
*unit
, struct DevBase
*base
)
652 UWORD i
, key_length
, port_type
, lowest_enc
= S2ENC_CCMP
,
653 highest_enc
= S2ENC_NONE
, enc_flags
, size
, value
;
654 const struct KeyUnion
*keys
;
656 /* Set MAC address */
658 P2SetData(unit
, P2_REC_ADDRESS
, unit
->address
, ETH_ADDRESSSIZE
,
661 /* Decide on promiscuous mode */
663 P2SetWord(unit
, P2_REC_PROMISC
, FALSE
, base
);
664 SetMulticast(unit
, base
);
666 /* Set wireless parameters */
668 if(unit
->mode
== S2PORT_ADHOC
)
670 P2SetWord(unit
, P2_REC_OWNCHNL
, unit
->channel
, base
);
671 P2SetID(unit
, P2_REC_OWNSSID
, unit
->ssid
, unit
->ssid_length
, base
);
673 if(unit
->mode
== S2PORT_MANAGED
)
677 if((unit
->flags
& UNITF_ONLINE
) == 0)
678 P2SetWord(unit
, P2_REC_PORTTYPE
, port_type
, base
);
679 P2SetWord(unit
, P2_REC_CREATEIBSS
, unit
->mode
== S2PORT_ADHOC
, base
);
680 P2SetID(unit
, P2_REC_DESIREDSSID
, unit
->ssid
, unit
->ssid_length
, base
);
682 /* Determine highest encryption type in use */
684 for(i
= 0; i
< WIFI_KEYCOUNT
; i
++)
686 if(unit
->keys
[i
].type
> highest_enc
)
687 highest_enc
= unit
->keys
[i
].type
;
688 if(unit
->keys
[i
].type
< lowest_enc
)
689 lowest_enc
= unit
->keys
[i
].type
;
692 if(unit
->wpa_ie
[1] != 0)
693 highest_enc
= S2ENC_TKIP
; // TO DO: Be more specific?
695 /* Allow reception of beacon/probe-response frames */
697 if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
698 P2SetWord(unit
, P2_REC_RXMGMTFRAMES
, 1, base
);
700 /* Transmit at 11Mbps, with fallback */
702 if(unit
->firmware_type
== INTERSIL_FIRMWARE
703 || unit
->firmware_type
== SYMBOL_FIRMWARE
)
704 P2SetWord(unit
, P2_REC_TXRATE
, 0xf, base
);
706 /* Configure authentication and encryption */
708 if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
710 /* Set authentication and encryption modes */
712 P2SetWord(unit
, P2_REC_ALTAUTHTYPE
, unit
->auth_types
, base
);
714 P2SetWord(unit
, P2_REC_ALTENCRYPTION
, highest_enc
, base
);
716 /* Set up firmware-based WEP encryption if appropriate */
718 if(highest_enc
== S2ENC_WEP
&& (unit
->flags
& UNITF_HARDWEP
) != 0)
720 P2SetWord(unit
, P2_REC_ALTTXCRYPTKEY
, unit
->tx_key_no
, base
);
721 P2Seek(unit
, 1, P2_REC_DEFLTCRYPTKEYS
, 0, base
);
722 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, P2_ALTWEPRECLEN
);
723 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, P2_REC_DEFLTCRYPTKEYS
);
725 for(i
= 0; i
< WIFI_KEYCOUNT
; i
++)
727 key_length
= keys
[i
].u
.wep
.length
;
729 key_length
= WIFI_WEP128LEN
;
730 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, key_length
);
731 unit
->WordsOut(unit
->card
, P2_REG_DATA1
,
732 (UWORD
*)keys
[i
].u
.wep
.key
, (key_length
+ 1) / 2);
735 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
,
736 P2_REC_DEFLTCRYPTKEYS
, base
);
739 /* Set key management suite to PSK */
741 if(highest_enc
> S2ENC_WEP
)
743 value
= (unit
->firmware_type
>= HERMES2_FIRMWARE
) ? 4 : 2;
744 P2SetWord(unit
, P2_REC_KEYMGMTSUITE
, value
, base
);
749 /* Set authentication mode */
751 P2SetWord(unit
, P2_REC_AUTHTYPE
, unit
->auth_types
, base
);
753 /* Set encryption flags */
755 if(highest_enc
> S2ENC_NONE
)
756 enc_flags
= P2_REC_ENCRYPTIONF_ENABLE
;
760 if(highest_enc
> S2ENC_WEP
761 || highest_enc
== S2ENC_WEP
&& (unit
->flags
& UNITF_HARDWEP
) == 0)
762 enc_flags
|= P2_REC_ENCRYPTIONF_HOSTDECRYPT
763 | P2_REC_ENCRYPTIONF_HOSTENCRYPT
;
764 P2SetWord(unit
, P2_REC_ENCRYPTION
, enc_flags
, base
);
766 /* Set up firmware-based WEP encryption if appropriate */
768 if(highest_enc
== S2ENC_WEP
&& (unit
->flags
& UNITF_HARDWEP
) != 0)
770 P2SetWord(unit
, P2_REC_TXCRYPTKEY
, unit
->tx_key_no
, base
);
773 for(i
= 0; i
< WIFI_KEYCOUNT
; i
++)
775 key_length
= keys
[i
].u
.wep
.length
;
777 key_length
= keys
[unit
->tx_key_no
].u
.wep
.length
;
778 P2SetData(unit
, P2_REC_CRYPTKEY0
+ i
, keys
[i
].u
.wep
.key
,
783 /* Set or clear WPA IE */
785 if(highest_enc
> S2ENC_WEP
)
786 size
= unit
->wpa_ie
[1] + 2;
789 P2SetID(unit
, P2_REC_WPAIE
, unit
->wpa_ie
, size
, base
);
791 /* Let supplicant handle association and roaming */
793 P2SetWord(unit
, P2_REC_ROAMINGMODE
, 3, base
);
796 /* Restart the transceiver if we're already online */
798 if((unit
->flags
& UNITF_ONLINE
) != 0)
800 P2DoCmd(unit
, P2_CMD_DISABLE
, 0, base
);
801 P2DoCmd(unit
, P2_CMD_ENABLE
, 0, base
);
803 /* Attempt to join specified network */
805 if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
807 *(UWORD
*)(unit
->bssid
+ ETH_ADDRESSSIZE
) =
808 MakeLEWord(unit
->channel
);
809 P2SetData(unit
, P2_REC_JOIN
, unit
->bssid
, ETH_ADDRESSSIZE
+ 2,
821 /****i* prism2.device/GoOnline *********************************************
824 * GoOnline -- Enable transmission/reception.
829 * VOID GoOnline(struct DevUnit *);
831 ****************************************************************************
835 VOID
GoOnline(struct DevUnit
*unit
, struct DevBase
*base
)
837 /* Enable interrupts */
839 unit
->flags
|= UNITF_ONLINE
;
840 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, INT_MASK
);
842 /* Enable the transceiver */
844 P2DoCmd(unit
, P2_CMD_ENABLE
, 0, base
);
846 /* Record start time and report Online event */
848 GetSysTime(&unit
->stats
.LastStart
);
849 ReportEvents(unit
, S2EVENT_ONLINE
, base
);
856 /****i* prism2.device/GoOffline ********************************************
859 * GoOffline -- Disable transmission/reception.
864 * VOID GoOffline(struct DevUnit *);
874 ****************************************************************************
878 VOID
GoOffline(struct DevUnit
*unit
, struct DevBase
*base
)
880 unit
->flags
&= ~UNITF_ONLINE
;
881 if((unit
->flags
& UNITF_HAVEADAPTER
) != 0)
883 /* Stop interrupts */
885 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, 0);
886 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
888 /* Update statistics */
890 UpdateStats(unit
, base
);
892 /* Stop transmission and reception */
894 P2DoCmd(unit
, P2_CMD_DISABLE
, 0, base
);
897 /* Flush pending read and write requests */
899 FlushUnit(unit
, WRITE_QUEUE
, S2ERR_OUTOFSERVICE
, base
);
901 /* Report Offline event and return */
903 ReportEvents(unit
, S2EVENT_OFFLINE
, base
);
909 /****i* prism2.device/SetOptions *******************************************
912 * SetOptions -- Set and use interface options.
915 * SetOptions(unit, tag_list)
917 * VOID SetOptions(struct DevUnit *, struct TagItem *);
919 ****************************************************************************
923 VOID
SetOptions(struct DevUnit
*unit
, const struct TagItem
*tag_list
,
924 struct DevBase
*base
)
926 struct TagItem
*tag_item
, *tlist
= (struct TagItem
*)tag_list
;
931 while((tag_item
= NextTagItem(&tlist
)) != NULL
)
933 switch(tag_item
->ti_Tag
)
936 id
= (const TEXT
*)tag_item
->ti_Data
;
938 CopyMem(id
, unit
->ssid
, length
);
939 unit
->ssid_length
= length
;
943 CopyMem((APTR
)tag_item
->ti_Data
, unit
->bssid
, ETH_ADDRESSSIZE
);
946 case S2INFO_DefaultKeyNo
:
947 unit
->tx_key_no
= tag_item
->ti_Data
;
950 case S2INFO_PortType
:
951 unit
->mode
= tag_item
->ti_Data
;
955 if(tag_item
->ti_Data
!= 0) // ???
956 unit
->channel
= tag_item
->ti_Data
;
960 if(tag_item
->ti_Data
!= (UPINT
)NULL
)
962 /* Hermes-II uses an "unusual" WPA IE in its association
963 request. So we use a matching IE everywhere else too */
965 if(unit
->firmware_type
>= HERMES2_FIRMWARE
)
968 ie
= (const UBYTE
*)tag_item
->ti_Data
;
969 CopyMem(ie
, unit
->wpa_ie
, ie
[1] + 2);
978 case S2INFO_AuthTypes
:
979 unit
->auth_types
= tag_item
->ti_Data
;
989 /****i* prism2.device/SetKey ***********************************************
992 * SetKey -- Set an encryption key.
995 * SetKey(unit, index, type, key, key_length,
998 * VOID SetKey(struct DevUnit *, ULONG, ULONG, UBYTE *, ULONG,
1001 ****************************************************************************
1005 VOID
SetKey(struct DevUnit
*unit
, ULONG index
, ULONG type
, const UBYTE
*key
,
1006 ULONG key_length
, const UBYTE
*rx_counter
, struct DevBase
*base
)
1008 struct KeyUnion
*slot
;
1009 const UBYTE tx_counter
[8] = {0, 0, 0, 0, 0x10, 0, 0, 0};
1011 struct EClockVal eclock
;
1014 slot
= &unit
->keys
[index
];
1018 CopyMem(key
, slot
->u
.wep
.key
, key_length
);
1019 slot
->u
.wep
.length
= key_length
;
1021 if((unit
->flags
& UNITF_HARDWEP
) == 0)
1023 /* Create a reasonably random IV */
1025 ReadEClock(&eclock
);
1026 slot
->u
.wep
.tx_iv
= FastRand(eclock
.ev_lo
^ eclock
.ev_hi
);
1032 CopyMem(key
, slot
->u
.tkip
.key
, 16);
1033 CopyMem(key
+ 16, slot
->u
.tkip
.tx_mic_key
, MIC_SIZE
);
1034 CopyMem(key
+ 24, slot
->u
.tkip
.rx_mic_key
, MIC_SIZE
);
1035 slot
->u
.tkip
.tx_iv_low
= 0;
1036 slot
->u
.tkip
.tx_iv_high
= 0;
1037 slot
->u
.tkip
.rx_iv_low
= LEWord(*(UWORD
*)rx_counter
);
1038 slot
->u
.tkip
.rx_iv_high
= LELong(*(ULONG
*)(rx_counter
+ 2));
1039 slot
->u
.tkip
.tx_ttak_set
= FALSE
;
1040 slot
->u
.tkip
.rx_ttak_set
= FALSE
;
1042 if((unit
->flags
& UNITF_HARDTKIP
) != 0)
1044 /* For Hermes, load parameters for hardware encryption. The
1045 pairwise key is treated differently from group keys on
1046 Hermes-II, but not on Hermes-I */
1048 if(unit
->firmware_type
>= HERMES2_FIRMWARE
&& index
== 0)
1050 P2Seek(unit
, 1, P2_REC_ADDMAPPEDTKIPKEY
, 0, base
);
1051 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 28);
1052 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
,
1053 P2_REC_ADDMAPPEDTKIPKEY
);
1054 unit
->WordsOut(unit
->card
, P2_REG_DATA1
,
1055 (UWORD
*)unit
->bssid
, ETH_ADDRESSSIZE
/ 2);
1056 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)key
,
1058 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)tx_counter
,
1060 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)rx_counter
,
1062 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 0);
1063 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)key
+ 16,
1065 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
,
1066 P2_REC_ADDMAPPEDTKIPKEY
, base
);
1070 P2Seek(unit
, 1, P2_REC_ADDDEFAULTTKIPKEY
, 0, base
);
1071 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 26);
1072 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
,
1073 P2_REC_ADDDEFAULTTKIPKEY
);
1074 if(index
== unit
->tx_key_no
)
1076 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, index
);
1077 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)rx_counter
,
1079 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 0);
1080 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)key
,
1082 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)tx_counter
,
1084 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
,
1085 P2_REC_ADDDEFAULTTKIPKEY
, base
);
1090 /* Convert key to native endianness */
1092 for(i
= 0; i
< 8; i
++)
1093 slot
->u
.tkip
.key
[i
] = LEWord(slot
->u
.tkip
.key
[i
]);
1099 CopyMem(key
, slot
->u
.ccmp
.key
, 16);
1100 slot
->u
.ccmp
.tx_iv_low
= 0;
1101 slot
->u
.ccmp
.tx_iv_high
= 0;
1102 slot
->u
.ccmp
.rx_iv_low
= LEWord(*(UWORD
*)rx_counter
);
1103 slot
->u
.ccmp
.rx_iv_high
= LELong(*(ULONG
*)(rx_counter
+ 2));
1104 slot
->u
.ccmp
.stream_set
= FALSE
;
1107 /* Clear TKIP key if necessary */
1109 if(slot
->type
== S2ENC_TKIP
&& type
!= S2ENC_TKIP
)
1111 if(unit
->firmware_type
>= HERMES2_FIRMWARE
&& index
== 0)
1112 P2SetData(unit
, P2_REC_REMMAPPEDTKIPKEY
, unit
->bssid
,
1113 ETH_ADDRESSSIZE
, base
);
1114 else if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
1115 P2SetWord(unit
, P2_REC_REMDEFAULTTKIPKEY
, index
, base
);
1118 /* Update type of key in selected slot */
1128 /****i* prism2.device/AddMulticastRange ************************************
1134 * success = AddMulticastRange(unit, lower_bound, upper_bound)
1136 * BOOL AddMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1138 ****************************************************************************
1142 BOOL
AddMulticastRange(struct DevUnit
*unit
, const UBYTE
*lower_bound
,
1143 const UBYTE
*upper_bound
, struct DevBase
*base
)
1145 struct AddressRange
*range
;
1146 ULONG lower_bound_left
, upper_bound_left
;
1147 UWORD lower_bound_right
, upper_bound_right
;
1149 lower_bound_left
= BELong(*((ULONG
*)lower_bound
));
1150 lower_bound_right
= BEWord(*((UWORD
*)(lower_bound
+ 4)));
1151 upper_bound_left
= BELong(*((ULONG
*)upper_bound
));
1152 upper_bound_right
= BEWord(*((UWORD
*)(upper_bound
+ 4)));
1154 range
= FindMulticastRange(unit
, lower_bound_left
, lower_bound_right
,
1155 upper_bound_left
, upper_bound_right
, base
);
1161 range
= AllocMem(sizeof(struct AddressRange
), MEMF_PUBLIC
);
1164 range
->lower_bound_left
= lower_bound_left
;
1165 range
->lower_bound_right
= lower_bound_right
;
1166 range
->upper_bound_left
= upper_bound_left
;
1167 range
->upper_bound_right
= upper_bound_right
;
1168 range
->add_count
= 1;
1171 AddTail((APTR
)&unit
->multicast_ranges
, (APTR
)range
);
1172 unit
->range_count
++;
1173 SetMulticast(unit
, base
);
1178 return range
!= NULL
;
1183 /****i* prism2.device/RemMulticastRange ************************************
1189 * found = RemMulticastRange(unit, lower_bound, upper_bound)
1191 * BOOL RemMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1193 ****************************************************************************
1197 BOOL
RemMulticastRange(struct DevUnit
*unit
, const UBYTE
*lower_bound
,
1198 const UBYTE
*upper_bound
, struct DevBase
*base
)
1200 struct AddressRange
*range
;
1201 ULONG lower_bound_left
, upper_bound_left
;
1202 UWORD lower_bound_right
, upper_bound_right
;
1204 lower_bound_left
= BELong(*((ULONG
*)lower_bound
));
1205 lower_bound_right
= BEWord(*((UWORD
*)(lower_bound
+ 4)));
1206 upper_bound_left
= BELong(*((ULONG
*)upper_bound
));
1207 upper_bound_right
= BEWord(*((UWORD
*)(upper_bound
+ 4)));
1209 range
= FindMulticastRange(unit
, lower_bound_left
, lower_bound_right
,
1210 upper_bound_left
, upper_bound_right
, base
);
1214 if(--range
->add_count
== 0)
1217 Remove((APTR
)range
);
1218 unit
->range_count
--;
1219 SetMulticast(unit
, base
);
1221 FreeMem(range
, sizeof(struct AddressRange
));
1225 return range
!= NULL
;
1230 /****i* prism2.device/FindMulticastRange ***********************************
1233 * FindMulticastRange
1236 * range = FindMulticastRange(unit, lower_bound_left,
1237 * lower_bound_right, upper_bound_left, upper_bound_right)
1239 * struct AddressRange *FindMulticastRange(struct DevUnit *, ULONG,
1240 * UWORD, ULONG, UWORD);
1242 ****************************************************************************
1246 static struct AddressRange
*FindMulticastRange(struct DevUnit
*unit
,
1247 ULONG lower_bound_left
, UWORD lower_bound_right
, ULONG upper_bound_left
,
1248 UWORD upper_bound_right
, struct DevBase
*base
)
1250 struct AddressRange
*range
, *tail
;
1253 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
1254 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
1256 while(range
!= tail
&& !found
)
1258 if(lower_bound_left
== range
->lower_bound_left
&&
1259 lower_bound_right
== range
->lower_bound_right
&&
1260 upper_bound_left
== range
->upper_bound_left
&&
1261 upper_bound_right
== range
->upper_bound_right
)
1264 range
= (APTR
)range
->node
.mln_Succ
;
1275 /****i* prism2.device/SetMulticast *****************************************
1281 * SetMulticast(unit)
1283 * VOID SetMulticast(struct DevUnit *);
1285 ****************************************************************************
1289 static VOID
SetMulticast(struct DevUnit
*unit
, struct DevBase
*base
)
1292 UWORD address_right
, i
= 0;
1293 struct AddressRange
*range
, *tail
;
1296 /* Fill in multicast list */
1298 P2Seek(unit
, 1, P2_REC_MCASTLIST
, 4, base
);
1300 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
1301 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
1303 while(range
!= tail
&& i
< P2_MAXMCASTENTRIES
)
1305 address_left
= range
->lower_bound_left
;
1306 address_right
= range
->lower_bound_right
;
1307 range_ended
= FALSE
;
1309 while(!range_ended
&& i
++ < P2_MAXMCASTENTRIES
)
1311 unit
->BEWordOut(unit
->card
, P2_REG_DATA1
,
1312 (UWORD
)(address_left
>> 16));
1313 unit
->BEWordOut(unit
->card
, P2_REG_DATA1
, (UWORD
)address_left
);
1314 unit
->BEWordOut(unit
->card
, P2_REG_DATA1
, (UWORD
)address_right
);
1316 if(address_left
== range
->upper_bound_left
&&
1317 address_right
== range
->upper_bound_right
)
1319 if(++address_right
== 0)
1324 range
= (APTR
)range
->node
.mln_Succ
;
1327 /* Turn promiscuous mode on or off depending on the previous state and
1328 whether we've overflowed the multicast list */
1330 if((unit
->flags
& UNITF_PROM
) == 0)
1334 if((unit
->flags
& UNITF_ALLMCAST
) == 0)
1336 P2SetWord(unit
, P2_REC_PROMISC
, TRUE
, base
);
1337 unit
->flags
|= UNITF_ALLMCAST
;
1342 if((unit
->flags
& UNITF_ALLMCAST
) != 0)
1344 P2SetWord(unit
, P2_REC_PROMISC
, FALSE
, base
);
1345 unit
->flags
&= ~UNITF_ALLMCAST
;
1348 /* Only commit multicast list if promiscuity is off */
1350 P2Seek(unit
, 1, P2_REC_MCASTLIST
, 0, base
);
1351 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
,
1352 1 + ETH_ADDRESSSIZE
/ 2 * i
);
1353 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, P2_REC_MCASTLIST
);
1354 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
, P2_REC_MCASTLIST
,
1364 /****i* prism2.device/FindTypeStats ****************************************
1370 * stats = FindTypeStats(unit, list,
1373 * struct TypeStats *FindTypeStats(struct DevUnit *, struct MinList *,
1376 ****************************************************************************
1380 struct TypeStats
*FindTypeStats(struct DevUnit
*unit
, struct MinList
*list
,
1381 ULONG packet_type
, struct DevBase
*base
)
1383 struct TypeStats
*stats
, *tail
;
1386 stats
= (APTR
)list
->mlh_Head
;
1387 tail
= (APTR
)&list
->mlh_Tail
;
1389 while(stats
!= tail
&& !found
)
1391 if(stats
->packet_type
== packet_type
)
1394 stats
= (APTR
)stats
->node
.mln_Succ
;
1405 /****i* prism2.device/FlushUnit ********************************************
1411 * FlushUnit(unit, last_queue, error)
1413 * VOID FlushUnit(struct DevUnit *, UBYTE, BYTE);
1415 ****************************************************************************
1419 VOID
FlushUnit(struct DevUnit
*unit
, UBYTE last_queue
, BYTE error
,
1420 struct DevBase
*base
)
1422 struct IORequest
*request
;
1424 struct Opener
*opener
, *tail
;
1426 /* Abort queued requests */
1428 for(i
= 0; i
<= last_queue
; i
++)
1430 while((request
= (APTR
)GetMsg(unit
->request_ports
[i
])) != NULL
)
1432 request
->io_Error
= error
;
1433 ReplyMsg((APTR
)request
);
1438 opener
= (APTR
)unit
->openers
.mlh_Head
;
1439 tail
= (APTR
)&unit
->openers
.mlh_Tail
;
1441 /* Flush every opener's read queue */
1443 while(opener
!= tail
)
1445 while((request
= (APTR
)GetMsg(&opener
->read_port
)) != NULL
)
1447 request
->io_Error
= error
;
1448 ReplyMsg((APTR
)request
);
1450 opener
= (APTR
)opener
->node
.mln_Succ
;
1454 opener
= request
->ios2_BufferManagement
;
1455 while((request
= (APTR
)GetMsg(&opener
->read_port
)) != NULL
)
1457 request
->io_Error
= error
;
1458 ReplyMsg((APTR
)request
);
1469 /****i* prism2.device/StatusInt ********************************************
1475 * finished = StatusInt(unit)
1477 * BOOL StatusInt(struct DevUnit *);
1487 ****************************************************************************
1489 * int_code is really in A5, but GCC 2.95.3 doesn't seem able to handle that.
1490 * Since we don't use this parameter, we can lie.
1494 BOOL
StatusInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
))
1496 struct DevBase
*base
;
1497 UWORD events
, int_mask
;
1499 base
= unit
->device
;
1500 events
= unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
);
1502 /* Turning off ints acknowledges the request? */
1504 int_mask
= unit
->LEWordIn(unit
->card
, P2_REG_INTMASK
);
1505 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, 0);
1509 if((events
& P2_EVENTF_INFO
) != 0)
1511 int_mask
&= ~P2_EVENTF_INFO
;
1512 Cause(&unit
->info_int
);
1514 if((events
& P2_EVENTF_RX
) != 0)
1516 int_mask
&= ~P2_EVENTF_RX
;
1517 Cause(&unit
->rx_int
);
1519 if((events
& P2_EVENTF_ALLOCMEM
) != 0)
1521 unit
->tx_frame_id
= unit
->LEWordIn(unit
->card
, P2_REG_ALLOCFID
);
1522 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_ALLOCMEM
);
1523 Cause(&unit
->tx_int
);
1525 if((events
& P2_EVENTF_TXFAIL
) != 0)
1527 ReportEvents(unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_TX
,
1529 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_TXFAIL
);
1533 int_mask
= INT_MASK
;
1535 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, int_mask
);
1542 /****i* prism2.device/RXInt ************************************************
1545 * RXInt -- Soft interrupt for packet reception.
1550 * VOID RXInt(struct DevUnit *);
1555 * unit - A unit of this device.
1560 ****************************************************************************
1564 static VOID
RXInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
))
1566 UWORD frame_status
, frame_id
, ieee_length
, frame_control
, frame_type
,
1567 frame_subtype
, encryption
, key_no
, buffer_no
, old_length
;
1568 struct DevBase
*base
;
1571 UBYTE
*buffer
, *p
, *frame
, *data
;
1573 base
= unit
->device
;
1575 while((unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
) & P2_EVENTF_RX
) != 0)
1578 frame_id
= unit
->LEWordIn(unit
->card
, P2_REG_RXFID
);
1579 P2Seek(unit
, 1, frame_id
, P2_FRM_STATUS
, base
);
1580 frame_status
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
1582 if((frame_status
& (P2_FRM_STATUSF_BADCRYPT
| P2_FRM_STATUSF_BADCRC
))
1585 /* Read frame descriptor from card */
1587 P2Seek(unit
, 1, frame_id
, 0, base
);
1588 unit
->WordsIn(unit
->card
, P2_REG_DATA1
,
1589 (UWORD
*)unit
->rx_descriptor
,
1590 (unit
->ethernet_offset
+ ETH_HEADERSIZE
) / 2);
1591 frame
= unit
->rx_descriptor
+ unit
->ethernet_offset
;
1592 ieee_length
= BEWord(*(UWORD
*)(frame
+ ETH_PACKET_IEEELEN
));
1593 data
= frame
+ ETH_PACKET_DATA
;
1594 unit
->WordsIn(unit
->card
, P2_REG_DATA1
, (UWORD
*)data
,
1595 (ieee_length
+ MIC_SIZE
+ 1) / 2);
1597 LEWord(*(UWORD
*)(unit
->rx_descriptor
+ P2_FRM_HEADER
));
1599 /* Get buffer to store fragment in */
1601 frag_no
= LEWord(*(UWORD
*)(unit
->rx_descriptor
+ P2_FRM_HEADER
1602 + WIFI_FRM_SEQCONTROL
));
1603 buffer
= GetRXBuffer(unit
, frame
+ ETH_PACKET_SOURCE
, frag_no
,
1606 /* Get location to put new data */
1610 if((frag_no
& 0xf ) > 0)
1611 old_length
= BEWord(*(UWORD
*)(buffer
+ ETH_PACKET_IEEELEN
));
1614 /* Copy header to new frame */
1616 CopyMem(frame
, buffer
, ETH_HEADERSIZE
);
1619 p
= buffer
+ ETH_HEADERSIZE
+ old_length
;
1621 /* Get encryption type and key index */
1623 if((frame_control
& WIFI_FRM_CONTROLF_WEP
) != 0)
1625 key_no
= data
[3] >> 6 & 0x3;
1626 encryption
= unit
->keys
[key_no
].type
;
1629 encryption
= S2ENC_NONE
;
1631 /* Append fragment to frame, decrypting/checking fragment if
1634 is_good
= unit
->fragment_decrypt_functions
[encryption
](unit
,
1635 unit
->rx_descriptor
+ P2_FRM_HEADER
, data
, &ieee_length
, p
,
1638 /* Update length in frame being built with current fragment, or
1639 increment bad frame counter if fragment is bad */
1643 ieee_length
+= old_length
;
1644 *(UWORD
*)(buffer
+ ETH_PACKET_IEEELEN
) =
1645 MakeBEWord(ieee_length
);
1648 unit
->stats
.BadData
++;
1650 /* If all fragments have arrived, process the complete frame */
1652 if((frame_control
& WIFI_FRM_CONTROLF_MOREFRAGS
) == 0)
1656 /* Decrypt complete frame if necessary */
1658 data
= buffer
+ ETH_HEADERSIZE
;
1659 if(encryption
== S2ENC_TKIP
)
1661 /* Hermes cards don't include MIC in frame length, so
1662 we need to grab the MIC from the original RX
1665 if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
1667 CopyMem(frame
+ ETH_PACKET_DATA
+ ieee_length
,
1668 data
+ ieee_length
, MIC_SIZE
);
1669 ieee_length
+= MIC_SIZE
;
1672 /* Check Michael MIC */
1675 is_good
= TKIPDecryptFrame(unit
, buffer
, data
,
1676 ieee_length
, data
, key_no
, base
);
1678 ieee_length
-= MIC_SIZE
;
1679 *(UWORD
*)(buffer
+ ETH_PACKET_IEEELEN
) =
1680 MakeBEWord(ieee_length
);
1682 unit
->stats
.BadData
++;
1688 /* Get frame's 802.11 type and subtype */
1690 frame_type
= (frame_control
& WIFI_FRM_CONTROLF_TYPE
)
1691 >> WIFI_FRM_CONTROLB_TYPE
;
1693 (frame_control
& WIFI_FRM_CONTROLF_SUBTYPE
)
1694 >> WIFI_FRM_CONTROLB_SUBTYPE
;
1696 /* If it's a management frame, process it internally;
1697 otherwise distribute it to clients after filtering */
1699 if(frame_type
== WIFI_FRMTYPE_MGMT
)
1701 if(frame_subtype
== 0x5)
1703 CopyMem(unit
->rx_descriptor
+ P2_FRM_HEADER
1704 + WIFI_FRM_ADDRESS3
, buffer
+ ETH_PACKET_SOURCE
,
1706 SaveBeacon(unit
, buffer
, base
);
1709 else if(AddressFilter(unit
, buffer
+ ETH_PACKET_DEST
,
1712 unit
->stats
.PacketsReceived
++;
1713 DistributeRXPacket(unit
, buffer
, base
);
1718 /* Mark fragment buffer as unused for next time */
1720 unit
->rx_fragment_nos
[buffer_no
] = -1;
1723 ReportEvents(unit
, S2EVENT_ERROR
| S2EVENT_RX
, base
);
1732 ReportEvents(unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
,
1736 /* Discard packet */
1738 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_RX
);
1741 /* Re-enable RX interrupts */
1744 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
,
1745 unit
->LEWordIn(unit
->card
, P2_REG_INTMASK
) | P2_EVENTF_RX
);
1753 /****i* prism2.device/GetRXBuffer ******************************************
1756 * GetRXBuffer -- Find an appropriate RX buffer to use.
1759 * buffer = GetRXBuffer(unit, address, frag_no)
1761 * UBYTE *GetRXBuffer(struct DevUnit *, UBYTE *, UWORD);
1763 ****************************************************************************
1767 static UBYTE
*GetRXBuffer(struct DevUnit
*unit
, const UBYTE
*address
,
1768 UWORD frag_no
, UWORD
*buffer_no
, struct DevBase
*base
)
1775 buffer
= unit
->rx_buffers
;
1776 for(i
= 0, found
= FALSE
; i
< RX_BUFFER_COUNT
* 2 && !found
; i
++)
1778 /* Throw away old buffer contents if we didn't find a free slot the
1779 first time around */
1781 if(i
>= RX_BUFFER_COUNT
)
1782 unit
->rx_fragment_nos
[i
% RX_BUFFER_COUNT
] = -1;
1784 /* For a frame's first fragment, find an empty slot; for subsequent
1785 fragments, find a slot with matching source address */
1787 n
= unit
->rx_fragment_nos
[i
% RX_BUFFER_COUNT
];
1788 if(n
== -1 && (frag_no
& 0xf) == 0
1789 || *((ULONG
*)(buffer
+ ETH_PACKET_SOURCE
))
1790 == *((ULONG
*)(address
))
1791 && *((UWORD
*)(buffer
+ ETH_PACKET_SOURCE
+ 4))
1792 == *((UWORD
*)(address
+ 4)))
1796 unit
->rx_fragment_nos
[i
% RX_BUFFER_COUNT
] = frag_no
;
1800 buffer
+= FRAME_BUFFER_SIZE
;
1811 /****i* prism2.device/DistributeRXPacket ***********************************
1814 * DistributeRXPacket -- Send a packet to all appropriate destinations.
1817 * DistributeRXPacket(unit, frame)
1819 * VOID DistributeRXPacket(struct DevUnit *, UBYTE *);
1821 ****************************************************************************
1825 static VOID
DistributeRXPacket(struct DevUnit
*unit
, UBYTE
*frame
,
1826 struct DevBase
*base
)
1828 UWORD packet_size
, ieee_length
;
1829 BOOL is_orphan
= TRUE
, accepted
, is_snap
= FALSE
;
1832 const UBYTE
*template = snap_template
;
1833 struct IOSana2Req
*request
, *request_tail
;
1834 struct Opener
*opener
, *opener_tail
;
1835 struct TypeStats
*tracker
;
1837 ieee_length
= BEWord(*(UWORD
*)(frame
+ ETH_PACKET_IEEELEN
));
1838 packet_size
= ETH_HEADERSIZE
+ ieee_length
;
1839 if(ieee_length
>= SNAP_HEADERSIZE
)
1840 is_snap
= *(const ULONG
*)(frame
+ ETH_PACKET_DATA
)
1841 == *(const ULONG
*)template;
1843 /* De-encapsulate SNAP packets and get packet type */
1847 buffer
= unit
->rx_buffer
;
1848 packet_size
-= SNAP_HEADERSIZE
;
1849 CopyMem(frame
, buffer
, ETH_PACKET_TYPE
);
1850 CopyMem(frame
+ ETH_HEADERSIZE
+ SNAP_FRM_TYPE
,
1851 buffer
+ ETH_PACKET_TYPE
, packet_size
- ETH_PACKET_TYPE
);
1856 packet_type
= BEWord(*((UWORD
*)(buffer
+ ETH_PACKET_TYPE
)));
1858 if(packet_size
<= ETH_MAXPACKETSIZE
)
1860 /* Offer packet to every opener */
1862 opener
= (APTR
)unit
->openers
.mlh_Head
;
1863 opener_tail
= (APTR
)&unit
->openers
.mlh_Tail
;
1865 while(opener
!= opener_tail
)
1867 request
= (APTR
)opener
->read_port
.mp_MsgList
.lh_Head
;
1868 request_tail
= (APTR
)&opener
->read_port
.mp_MsgList
.lh_Tail
;
1871 /* Offer packet to each request until it's accepted */
1873 while(request
!= request_tail
&& !accepted
)
1875 if(request
->ios2_PacketType
== packet_type
)
1877 CopyPacket(unit
, request
, packet_size
, packet_type
,
1882 (APTR
)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
1887 opener
= (APTR
)opener
->node
.mln_Succ
;
1890 /* If packet was unwanted, give it to S2_READORPHAN request */
1894 unit
->stats
.UnknownTypesReceived
++;
1895 if(!IsMsgPortEmpty(unit
->request_ports
[ADOPT_QUEUE
]))
1898 (APTR
)unit
->request_ports
[ADOPT_QUEUE
]->
1899 mp_MsgList
.lh_Head
, packet_size
, packet_type
, buffer
,
1904 /* Update remaining statistics */
1906 if(packet_type
<= ETH_MTU
)
1907 packet_type
= ETH_MTU
;
1909 FindTypeStats(unit
, &unit
->type_trackers
, packet_type
, base
);
1912 tracker
->stats
.PacketsReceived
++;
1913 tracker
->stats
.BytesReceived
+= packet_size
;
1917 unit
->stats
.BadData
++;
1924 /****i* prism2.device/CopyPacket *******************************************
1927 * CopyPacket -- Copy packet to client's buffer.
1930 * CopyPacket(unit, request, packet_size, packet_type,
1933 * VOID CopyPacket(struct DevUnit *, struct IOSana2Req *, UWORD, UWORD,
1936 ****************************************************************************
1940 static VOID
CopyPacket(struct DevUnit
*unit
, struct IOSana2Req
*request
,
1941 UWORD packet_size
, UWORD packet_type
, UBYTE
*buffer
,
1942 struct DevBase
*base
)
1944 struct Opener
*opener
;
1945 BOOL filtered
= FALSE
;
1947 /* Set multicast and broadcast flags */
1949 request
->ios2_Req
.io_Flags
&= ~(SANA2IOF_BCAST
| SANA2IOF_MCAST
);
1950 if((*((ULONG
*)(buffer
+ ETH_PACKET_DEST
)) == 0xffffffff) &&
1951 (*((UWORD
*)(buffer
+ ETH_PACKET_DEST
+ 4)) == 0xffff))
1952 request
->ios2_Req
.io_Flags
|= SANA2IOF_BCAST
;
1953 else if((buffer
[ETH_PACKET_DEST
] & 0x1) != 0)
1954 request
->ios2_Req
.io_Flags
|= SANA2IOF_MCAST
;
1956 /* Set source and destination addresses and packet type */
1958 CopyMem(buffer
+ ETH_PACKET_SOURCE
, request
->ios2_SrcAddr
,
1960 CopyMem(buffer
+ ETH_PACKET_DEST
, request
->ios2_DstAddr
,
1962 request
->ios2_PacketType
= packet_type
;
1964 /* Adjust for cooked packet request */
1966 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) == 0)
1968 packet_size
-= ETH_PACKET_DATA
;
1969 buffer
+= ETH_PACKET_DATA
;
1973 packet_size
+= 4; /* Needed for Shapeshifter & Fusion */
1975 request
->ios2_DataLength
= packet_size
;
1979 opener
= request
->ios2_BufferManagement
;
1980 if(request
->ios2_Req
.io_Command
== CMD_READ
&&
1981 opener
->filter_hook
!= NULL
)
1982 if(!CallHookPkt(opener
->filter_hook
, request
, buffer
))
1987 /* Copy packet into opener's buffer and reply packet */
1989 if(!opener
->rx_function(request
->ios2_Data
, buffer
, packet_size
))
1991 request
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
1992 request
->ios2_WireError
= S2WERR_BUFF_ERROR
;
1994 S2EVENT_ERROR
| S2EVENT_SOFTWARE
| S2EVENT_BUFF
| S2EVENT_RX
,
1997 Remove((APTR
)request
);
1998 ReplyMsg((APTR
)request
);
2006 /****i* prism2.device/AddressFilter ****************************************
2009 * AddressFilter -- Determine if an RX packet should be accepted.
2012 * accept = AddressFilter(unit, address)
2014 * BOOL AddressFilter(struct DevUnit *, UBYTE *);
2016 ****************************************************************************
2020 static BOOL
AddressFilter(struct DevUnit
*unit
, UBYTE
*address
,
2021 struct DevBase
*base
)
2023 struct AddressRange
*range
, *tail
;
2026 UWORD address_right
;
2028 /* Check whether address is unicast/broadcast or multicast */
2030 address_left
= BELong(*((ULONG
*)address
));
2031 address_right
= BEWord(*((UWORD
*)(address
+ 4)));
2033 if(((address_left
& 0x01000000) != 0) &&
2034 !((address_left
== 0xffffffff) && (address_right
== 0xffff)))
2036 /* Check if this multicast address is wanted */
2038 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
2039 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
2042 while((range
!= tail
) && !accept
)
2044 if((address_left
> range
->lower_bound_left
||
2045 address_left
== range
->lower_bound_left
&&
2046 address_right
>= range
->lower_bound_right
) &&
2047 (address_left
< range
->upper_bound_left
||
2048 address_left
== range
->upper_bound_left
&&
2049 address_right
<= range
->upper_bound_right
))
2051 range
= (APTR
)range
->node
.mln_Succ
;
2055 unit
->special_stats
[S2SS_ETHERNET_BADMULTICAST
& 0xffff]++;
2063 /****i* prism2.device/SaveBeacon *******************************************
2066 * SaveBeacon -- Save beacon frame for later examination.
2069 * SaveBeacon(unit, frame)
2071 * VOID SaveBeacon(struct DevUnit *, UBYTE *);
2073 ****************************************************************************
2077 static VOID
SaveBeacon(struct DevUnit
*unit
, const UBYTE
*frame
,
2078 struct DevBase
*base
)
2082 /* Store frame for later matching with scan results */
2084 size
= ETH_HEADERSIZE
+ BEWord(*(UWORD
*)(frame
+ ETH_PACKET_IEEELEN
));
2085 if(unit
->next_beacon
+ size
< unit
->beacons
+ BEACON_BUFFER_SIZE
)
2087 CopyMem(frame
, unit
->next_beacon
, size
);
2088 unit
->beacon_count
++;
2089 unit
->next_beacon
+= size
+ sizeof(ULONG
) & ~3;
2097 /****i* prism2.device/TXInt ************************************************
2100 * TXInt -- Soft interrupt for packet transmission.
2105 * VOID TXInt(struct DevUnit *);
2110 * unit - A unit of this device.
2115 ****************************************************************************
2119 static VOID
TXInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
))
2121 UWORD i
, packet_size
, send_size
, packet_type
, data_size
, body_size
= 0,
2122 frame_id
, encryption
, control_value
, subtype
;
2123 UBYTE
*buffer
, *desc
= unit
->tx_descriptor
, *plaintext
, *ciphertext
,
2124 *header
, mic_header
[ETH_ADDRESSSIZE
* 2], *q
;
2125 const UBYTE
*p
, *dest
, *source
;
2126 struct DevBase
*base
;
2127 struct IOSana2Req
*request
;
2129 struct Opener
*opener
;
2131 UBYTE
*(*dma_tx_function
)(REG(a0
, APTR
));
2133 struct MsgPort
*port
;
2134 struct TypeStats
*tracker
;
2136 base
= unit
->device
;
2137 port
= unit
->request_ports
[WRITE_QUEUE
];
2139 if(unit
->tx_frame_id
!= 0 && !IsMsgPortEmpty(port
))
2141 /* Get next request and full packet size */
2143 request
= (APTR
)port
->mp_MsgList
.lh_Head
;
2144 packet_size
= request
->ios2_DataLength
;
2145 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) == 0)
2146 packet_size
+= ETH_PACKET_DATA
;
2148 /* Determine encryption type and frame subtype */
2150 if(packet_size
> ETH_HEADERSIZE
)
2152 encryption
= unit
->keys
[unit
->tx_key_no
].type
;
2157 encryption
= S2ENC_NONE
;
2161 /* Get packet data */
2163 opener
= request
->ios2_BufferManagement
;
2164 dma_tx_function
= opener
->dma_tx_function
;
2165 if(dma_tx_function
!= NULL
)
2166 buffer
= dma_tx_function(request
->ios2_Data
);
2172 buffer
= unit
->tx_buffer
;
2173 if(!opener
->tx_function(buffer
, request
->ios2_Data
,
2174 request
->ios2_DataLength
))
2176 error
= S2ERR_NO_RESOURCES
;
2177 wire_error
= S2WERR_BUFF_ERROR
;
2179 S2EVENT_ERROR
| S2EVENT_SOFTWARE
| S2EVENT_BUFF
| S2EVENT_TX
,
2186 /* Get packet type and/or length */
2188 data_size
= request
->ios2_DataLength
;
2189 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) != 0)
2191 data_size
-= ETH_PACKET_DATA
;
2192 packet_type
= BEWord(*(UWORD
*)(buffer
+ ETH_PACKET_TYPE
));
2195 packet_type
= request
->ios2_PacketType
;
2196 is_ieee
= packet_type
<= ETH_MTU
;
2198 /* Get source and destination addresses */
2200 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) != 0)
2203 source
= buffer
+ ETH_ADDRESSSIZE
;
2204 buffer
+= ETH_ADDRESSSIZE
* 2 + 2;
2208 dest
= request
->ios2_DstAddr
;
2209 source
= unit
->address
;
2212 /* Clear frame descriptor as far as start of 802.11 header */
2215 for(i
= 0; i
< P2_FRM_HEADER
; i
++)
2219 /* Set TX control field */
2221 control_value
= P2_FRM_TXCONTROLF_NATIVE
;
2222 if(encryption
== S2ENC_TKIP
&& (unit
->flags
& UNITF_HARDTKIP
) != 0)
2223 control_value
|= unit
->tx_key_no
<< P2_FRM_TXCONTROLB_MICKEYID
2224 | P2_FRM_TXCONTROLF_MIC
;
2225 else if(encryption
== S2ENC_NONE
2226 && unit
->firmware_type
< LUCENT_FIRMWARE
)
2227 control_value
|= P2_FRM_TXCONTROLF_NOENC
;
2229 *(UWORD
*)(desc
+ unit
->txcontrol_offset
) =
2230 MakeLEWord(control_value
);
2232 /* Write 802.11 header */
2234 *(UWORD
*)q
= MakeLEWord(
2235 (encryption
== S2ENC_NONE
? 0 : WIFI_FRM_CONTROLF_WEP
)
2236 | (unit
->mode
== S2PORT_ADHOC
? 0 : WIFI_FRM_CONTROLF_TODS
)
2237 | subtype
<< WIFI_FRM_CONTROLB_SUBTYPE
2238 | WIFI_FRMTYPE_DATA
<< WIFI_FRM_CONTROLB_TYPE
);
2244 if(unit
->mode
== S2PORT_ADHOC
)
2248 for(i
= 0; i
< ETH_ADDRESSSIZE
; i
++)
2251 for(i
= 0, p
= source
; i
< ETH_ADDRESSSIZE
; i
++)
2254 if(unit
->mode
== S2PORT_ADHOC
)
2258 for(i
= 0; i
< ETH_ADDRESSSIZE
; i
++)
2262 /* Clear 802.3 header */
2264 q
= desc
+ unit
->ethernet_offset
;
2265 for(i
= 0; i
< ETH_HEADERSIZE
; i
++)
2268 /* Leave room for encryption overhead */
2270 q
= desc
+ unit
->data_offset
;
2272 q
+= unit
->iv_sizes
[encryption
];
2275 /* Write SNAP header */
2279 for(i
= 0, p
= snap_template
; i
< SNAP_FRM_TYPE
; i
++)
2281 *(UWORD
*)q
= MakeBEWord(packet_type
);
2283 body_size
+= SNAP_HEADERSIZE
;
2286 /* Copy data into frame */
2288 CopyMem(buffer
, q
, data_size
);
2289 body_size
+= data_size
;
2291 /* Append MIC to frame for TKIP */
2293 if(encryption
== S2ENC_TKIP
)
2296 for(i
= 0, p
= dest
; i
< ETH_ADDRESSSIZE
; i
++)
2298 for(i
= 0, p
= source
; i
< ETH_ADDRESSSIZE
; i
++)
2300 TKIPEncryptFrame(unit
, mic_header
, plaintext
, body_size
,
2302 body_size
+= MIC_SIZE
;
2305 /* Encrypt fragment if applicable */
2307 unit
->fragment_encrypt_functions
[encryption
](unit
, header
,
2308 plaintext
, &body_size
, ciphertext
, base
);
2310 /* Calculate total length of data to send to adapter */
2312 send_size
= unit
->data_offset
+ body_size
;
2314 /* Fill in length field, adjusting for Hermes peculiarities */
2316 if(unit
->firmware_type
>= LUCENT_FIRMWARE
2317 && encryption
== S2ENC_TKIP
)
2318 body_size
-= MIC_SIZE
;
2320 if(unit
->firmware_type
== LUCENT_FIRMWARE
2321 && (unit
->flags
& UNITF_HARDTKIP
) != 0)
2322 *(UWORD
*)(desc
+ unit
->ethernet_offset
+ ETH_PACKET_IEEELEN
) =
2323 MakeBEWord(body_size
);
2325 *(UWORD
*)(desc
+ unit
->datalen_offset
) = MakeLEWord(body_size
);
2327 /* Write packet to adapter and send */
2329 frame_id
= unit
->tx_frame_id
;
2330 P2Seek(unit
, 0, frame_id
, 0, base
);
2331 unit
->WordsOut(unit
->card
, P2_REG_DATA0
, (UWORD
*)desc
,
2332 (send_size
+ 1) / 2);
2333 unit
->tx_frame_id
= 0;
2334 P2DoCmd(unit
, P2_CMD_TX
| P2_CMDF_RECLAIM
, frame_id
, base
);
2339 request
->ios2_Req
.io_Error
= error
;
2340 request
->ios2_WireError
= wire_error
;
2341 Remove((APTR
)request
);
2342 ReplyMsg((APTR
)request
);
2344 /* Update statistics */
2348 unit
->stats
.PacketsSent
++;
2350 tracker
= FindTypeStats(unit
, &unit
->type_trackers
,
2351 request
->ios2_PacketType
, base
);
2354 tracker
->stats
.PacketsSent
++;
2355 tracker
->stats
.BytesSent
+= packet_size
;
2360 /* Don't try to keep sending packets if there's no space left */
2362 if(unit
->tx_frame_id
!= 0)
2363 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
2365 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_IGNORE
;
2372 /****i* prism2.device/UpdateStats ******************************************
2380 * VOID UpdateStats(struct DevUnit *);
2385 * unit - A unit of this device.
2390 ****************************************************************************
2394 VOID
UpdateStats(struct DevUnit
*unit
, struct DevBase
*base
)
2396 /* Ask for and wait for stats */
2398 if((unit
->flags
& UNITF_ONLINE
) != 0)
2401 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
,
2402 unit
->LEWordIn(unit
->card
, P2_REG_INTMASK
) & ~P2_EVENTF_INFO
);
2404 P2DoCmd(unit
, P2_CMD_INQUIRE
, P2_INFO_COUNTERS
, base
);
2405 while((unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
) & P2_EVENTF_INFO
)
2407 Cause(&unit
->info_int
);
2415 /****i* prism2.device/InfoInt **********************************************
2423 * VOID InfoInt(struct DevUnit *);
2428 * unit - A unit of this device.
2434 * The only reason this is a (soft) interrupt is so that it won't
2435 * interfere with RXInt() by interrupting it. This would be dangerous
2436 * because they use the same data channel.
2438 ****************************************************************************
2442 static VOID
InfoInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
))
2444 struct DevBase
*base
;
2445 UWORD id
, length
, rec_length
, status
, ies_length
, data_length
,
2446 ssid_length
, *ap_rec
;
2447 UBYTE
*ie
, *ssid
, *descriptor
, *frame
, *data
, *bssid
= unit
->bssid
;
2450 base
= unit
->device
;
2451 id
= unit
->LEWordIn(unit
->card
, P2_REG_INFOFID
);
2453 P2Seek(unit
, 1, id
, 0, base
);
2454 length
= (unit
->LEWordIn(unit
->card
, P2_REG_DATA1
) + 1) * 2;
2456 switch(unit
->LEWordIn(unit
->card
, P2_REG_DATA1
))
2458 case P2_INFO_COUNTERS
:
2460 /* Read useful stats and skip others */
2462 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2463 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2465 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2466 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2467 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2468 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2470 unit
->special_stats
[S2SS_ETHERNET_RETRIES
& 0xffff] +=
2471 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
) +
2472 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
) +
2473 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2475 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2477 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2478 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2480 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2481 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2482 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2484 unit
->stats
.BadData
+= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2485 unit
->stats
.Overruns
+= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2487 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2489 unit
->stats
.BadData
+= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2493 case P2_INFO_SCANRESULTS
:
2494 case P2_INFO_HOSTSCANRESULTS
:
2496 P2ReadRec(unit
, id
, unit
->scan_results_rec
, SCAN_BUFFER_SIZE
, base
);
2497 Signal(unit
->task
, unit
->scan_complete_signal
);
2500 case P2_INFO_SCANRESULT
:
2502 descriptor
= unit
->rx_descriptor
;
2503 P2ReadRec(unit
, id
, descriptor
, FRAME_BUFFER_SIZE
, base
);
2506 /* Save IEEE 802.3 portion of scan result */
2508 frame
= descriptor
+ unit
->ethernet_offset
;
2509 data
= frame
+ ETH_PACKET_DATA
;
2510 CopyMem(descriptor
+ P2_FRM_HEADER
+ WIFI_FRM_ADDRESS3
,
2511 frame
+ ETH_PACKET_SOURCE
, ETH_ADDRESSSIZE
);
2513 LEWord(*(UWORD
*)(descriptor
+ unit
->datalen_offset
));
2514 ies_length
= data_length
- WIFI_BEACON_IES
;
2515 *(UWORD
*)(frame
+ ETH_PACKET_IEEELEN
) = MakeBEWord(data_length
);
2516 SaveBeacon(unit
, frame
, base
);
2518 /* Append a fake old-style scan record on to fake record list */
2520 rec_length
= LEWord(unit
->scan_results_rec
[0]);
2522 if(2 + rec_length
* 2 + P2_APRECLEN
< SCAN_BUFFER_SIZE
)
2524 ap_rec
= unit
->scan_results_rec
+ 1 + rec_length
;
2525 CopyMem(frame
+ ETH_PACKET_SOURCE
, ap_rec
+ P2_APREC_BSSID
/ 2,
2528 ap_rec
[P2_APREC_SIGNAL
/ 2] =
2529 MakeLEWord(descriptor
[P2_FRM_SIGNAL
]);
2531 ap_rec
[P2_APREC_NOISE
/ 2] =
2532 MakeLEWord(descriptor
[P2_FRM_NOISE
]);
2534 ap_rec
[P2_APREC_CHANNEL
/ 2] = MakeLEWord(GetIE(WIFI_IE_CHANNEL
,
2535 data
+ WIFI_BEACON_IES
, ies_length
, base
)[2]);
2537 ap_rec
[P2_APREC_INTERVAL
/ 2] =
2538 *(UWORD
*)(data
+ WIFI_BEACON_INTERVAL
);
2540 ap_rec
[P2_APREC_CAPABILITIES
/ 2] =
2541 *(UWORD
*)(data
+ WIFI_BEACON_CAPABILITIES
);
2543 ie
= GetIE(WIFI_IE_SSID
, data
+ WIFI_BEACON_IES
, ies_length
,
2545 ssid_length
= ie
[1];
2547 ap_rec
[P2_APREC_NAMELEN
/ 2] = MakeLEWord(ssid_length
);
2548 CopyMem(ssid
, ap_rec
+ P2_APREC_NAME
/ 2, ssid_length
);
2550 unit
->scan_results_rec
[0] =
2551 MakeLEWord(rec_length
+ P2_APRECLEN
/ 2);
2555 Signal(unit
->task
, unit
->scan_complete_signal
);
2558 case P2_INFO_LINKSTATUS
:
2560 /* Only report an event if association status has really changed */
2562 status
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2564 if(status
== 1 || unit
->firmware_type
< LUCENT_FIRMWARE
2567 else //if(unit->firmware_type < LUCENT_FIRMWARE || status == 3)
2570 if(!(*(ULONG
*)bssid
== 0 && *(UWORD
*)(bssid
+ 4) == 0))
2572 if(associated
&& (unit
->flags
& UNITF_ASSOCIATED
) == 0)
2574 unit
->flags
|= UNITF_ASSOCIATED
;
2575 ReportEvents(unit
, S2EVENT_CONNECT
, base
);
2577 else if(!associated
&& (unit
->flags
& UNITF_ASSOCIATED
) != 0)
2579 unit
->flags
&= ~UNITF_ASSOCIATED
;
2580 ReportEvents(unit
, S2EVENT_DISCONNECT
, base
);
2585 /* Acknowledge event and re-enable info interrupts */
2587 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_INFO
);
2589 if((unit
->flags
& UNITF_ONLINE
) != 0)
2590 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
,
2591 unit
->LEWordIn(unit
->card
, P2_REG_INTMASK
) | P2_EVENTF_INFO
);
2599 /****i* prism2.device/ResetHandler *****************************************
2602 * ResetHandler -- Disable hardware before a reboot.
2605 * ResetHandler(unit, int_code)
2607 * VOID ResetHandler(struct DevUnit *, APTR);
2609 ****************************************************************************
2613 static VOID
ResetHandler(REG(a1
, struct DevUnit
*unit
),
2614 REG(a6
, APTR int_code
))
2616 if((unit
->flags
& UNITF_HAVEADAPTER
) != 0)
2618 /* Stop interrupts */
2620 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, 0);
2622 /* Stop transmission and reception */
2624 unit
->LEWordOut(unit
->card
, P2_REG_PARAM0
, 0);
2625 unit
->LEWordOut(unit
->card
, P2_REG_COMMAND
, P2_CMD_DISABLE
);
2633 /****i* prism2.device/ReportEvents *****************************************
2639 * ReportEvents(unit, events)
2641 * VOID ReportEvents(struct DevUnit *, ULONG);
2646 * unit - A unit of this device.
2647 * events - A mask of events to report.
2652 ****************************************************************************
2656 static VOID
ReportEvents(struct DevUnit
*unit
, ULONG events
,
2657 struct DevBase
*base
)
2659 struct IOSana2Req
*request
, *tail
, *next_request
;
2662 list
= &unit
->request_ports
[EVENT_QUEUE
]->mp_MsgList
;
2663 next_request
= (APTR
)list
->lh_Head
;
2664 tail
= (APTR
)&list
->lh_Tail
;
2667 while(next_request
!= tail
)
2669 request
= next_request
;
2670 next_request
= (APTR
)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
2672 if((request
->ios2_WireError
& events
) != 0)
2674 request
->ios2_WireError
= events
;
2675 Remove((APTR
)request
);
2676 ReplyMsg((APTR
)request
);
2686 /****i* prism2.device/SendScanResults **************************************
2689 * SendScanResults -- Reply to all outstanding scan requests.
2692 * SendScanResults(unit)
2694 * VOID SendScanResults(struct DevUnit *);
2699 * unit - A unit of this device.
2704 ****************************************************************************
2708 static VOID
SendScanResults(struct DevUnit
*unit
, struct DevBase
*base
)
2711 struct IOSana2Req
*request
, *tail
, *next_request
;
2714 UWORD count
, i
, j
, ssid_length
, length
, entry_length
, *ap_rec
,
2715 data_length
, frame_length
, ies_length
;
2716 struct TagItem
**tag_lists
, *tag
;
2718 const UBYTE
*beacon
, *ie_bssid
;
2721 list
= &unit
->request_ports
[SCAN_QUEUE
]->mp_MsgList
;
2722 next_request
= (APTR
)list
->lh_Head
;
2723 tail
= (APTR
)&list
->lh_Tail
;
2725 while(next_request
!= tail
)
2727 request
= next_request
;
2728 next_request
= (APTR
)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
2730 pool
= request
->ios2_Data
;
2732 length
= LEWord(unit
->scan_results_rec
[0]);
2733 ap_rec
= unit
->scan_results_rec
+ 2;
2735 if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
2737 entry_length
= LEWord(unit
->scan_results_rec
[2]);
2739 count
= (length
- 3) * 2 / entry_length
;
2743 entry_length
= P2_APRECLEN
;
2744 count
= (length
- 1) * 2 / entry_length
;
2747 /* Allocate array of tag lists, one for each AP */
2751 tag_lists
= AllocPooled(pool
, count
* sizeof(APTR
));
2752 if(tag_lists
== NULL
)
2753 error
= S2ERR_NO_RESOURCES
;
2758 for(i
= 0; i
< count
&& error
== 0; i
++, ap_rec
+= entry_length
/ 2)
2761 AllocPooled(pool
, SCAN_TAG_COUNT
* sizeof(struct TagItem
));
2762 if(tag_lists
[i
] == NULL
)
2763 error
= S2ERR_NO_RESOURCES
;
2769 tag
->ti_Tag
= S2INFO_BSSID
;
2770 tag
->ti_Data
= (UPINT
)(bssid
=
2771 AllocPooled(pool
, ETH_ADDRESSSIZE
));
2773 CopyMem(ap_rec
+ P2_APREC_BSSID
/ 2, bssid
,
2776 error
= S2ERR_NO_RESOURCES
;
2779 tag
->ti_Tag
= TAG_IGNORE
;
2782 tag
->ti_Tag
= S2INFO_Channel
;
2783 tag
->ti_Data
= LEWord(ap_rec
[P2_APREC_CHANNEL
/ 2]);
2786 tag
->ti_Tag
= S2INFO_BeaconInterval
;
2787 tag
->ti_Data
= LEWord(ap_rec
[P2_APREC_INTERVAL
/ 2]);
2790 tag
->ti_Tag
= S2INFO_Capabilities
;
2791 tag
->ti_Data
= LEWord(ap_rec
[P2_APREC_CAPABILITIES
/ 2]);
2794 tag
->ti_Tag
= S2INFO_Signal
;
2795 tag
->ti_Data
= ConvertScanLevel(unit
,
2796 LEWord(ap_rec
[P2_APREC_SIGNAL
/ 2]), base
);
2799 tag
->ti_Tag
= S2INFO_Noise
;
2800 tag
->ti_Data
= ConvertScanLevel(unit
,
2801 LEWord(ap_rec
[P2_APREC_NOISE
/ 2]), base
);
2805 ssid_length
= LEWord(ap_rec
[P2_APREC_NAMELEN
/ 2]);
2806 tag
->ti_Tag
= S2INFO_SSID
;
2807 tag
->ti_Data
= (UPINT
)(ssid
=
2808 AllocPooled(pool
, 31 + 1));
2811 CopyMem(ap_rec
+ P2_APREC_NAME
/ 2, ssid
, ssid_length
);
2812 ssid
[ssid_length
] = '\0';
2815 error
= S2ERR_NO_RESOURCES
;
2818 tag
->ti_Tag
= TAG_END
;
2822 /* Find IEs for each BSS and insert them into the BSS's tag list */
2824 for(beacon
= unit
->beacons
, i
= 0; i
< unit
->beacon_count
; i
++)
2826 /* Extract IEs from beacon descriptor */
2828 data_length
= BEWord(*(UWORD
*)(beacon
+ ETH_PACKET_IEEELEN
));
2829 ies_length
= data_length
- 12;
2830 frame_length
= ETH_HEADERSIZE
+ data_length
;
2831 ies
= AllocPooled(pool
, sizeof(UWORD
) + ies_length
);
2834 *(UWORD
*)ies
= ies_length
;
2835 CopyMem(beacon
+ ETH_PACKET_DATA
+ WIFI_BEACON_IES
,
2836 ies
+ sizeof(UWORD
), ies_length
);
2839 error
= S2ERR_NO_RESOURCES
;
2841 /* Find matching tag list and add IEs to it */
2843 ie_bssid
= beacon
+ ETH_PACKET_SOURCE
;
2844 for(j
= 0; j
< count
; j
++)
2847 bssid
= (UBYTE
*)tag
->ti_Data
;
2848 if(*(ULONG
*)bssid
== *(ULONG
*)ie_bssid
2849 && *(UWORD
*)(bssid
+ 4) == *(UWORD
*)(ie_bssid
+ 4))
2852 tag
->ti_Tag
= S2INFO_InfoElements
;
2853 tag
->ti_Data
= (PINT
)ies
;
2857 beacon
+= frame_length
+ sizeof(ULONG
) & ~3;
2860 /* Return results */
2864 request
->ios2_StatData
= tag_lists
;
2865 request
->ios2_DataLength
= count
;
2869 request
->ios2_Req
.io_Error
= error
;
2870 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
2872 Remove((APTR
)request
);
2873 ReplyMsg((APTR
)request
);
2876 /* Discard collected beacon frames */
2879 unit
->next_beacon
= unit
->beacons
;
2880 unit
->beacon_count
= 0;
2888 /****i* prism2.device/GetNetworkInfo ***************************************
2891 * GetNetworkInfo -- Get information on current network.
2894 * tag_list = GetNetworkInfo(unit, pool)
2896 * struct TagItem *GetNetworkInfo(struct DevUnit *, APTR);
2901 * unit - A unit of this device.
2902 * pool - A memory pool.
2907 ****************************************************************************
2911 struct TagItem
*GetNetworkInfo(struct DevUnit
*unit
, APTR pool
,
2912 struct DevBase
*base
)
2915 struct TagItem
*tag_list
, *tag
;
2919 AllocPooled(pool
, INFO_TAG_COUNT
* sizeof(struct TagItem
));
2920 if(tag_list
== NULL
)
2921 error
= S2ERR_NO_RESOURCES
;
2927 tag
->ti_Tag
= S2INFO_BSSID
;
2928 tag
->ti_Data
= (UPINT
)(bssid
=
2929 AllocPooled(pool
, ETH_ADDRESSSIZE
));
2931 CopyMem(unit
->bssid
, bssid
, ETH_ADDRESSSIZE
);
2933 error
= S2ERR_NO_RESOURCES
;
2936 tag
->ti_Tag
= TAG_IGNORE
;
2939 tag
->ti_Tag
= S2INFO_WPAInfo
;
2940 tag
->ti_Data
= (UPINT
)(ie
=
2941 AllocPooled(pool
, unit
->wpa_ie
[1] + 2));
2943 CopyMem(unit
->wpa_ie
, ie
, unit
->wpa_ie
[1] + 2);
2945 error
= S2ERR_NO_RESOURCES
;
2948 tag
->ti_Tag
= TAG_END
;
2959 /****i* prism2.device/UpdateSignalQuality **********************************
2962 * UpdateSignalQuality -- Read signal quality from card.
2965 * UpdateSignalQuality(unit)
2967 * VOID UpdateSignalQuality(struct DevUnit *);
2972 * unit - A unit of this device.
2977 ****************************************************************************
2981 VOID
UpdateSignalQuality(struct DevUnit
*unit
, struct DevBase
*base
)
2983 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_LINKQUALITY
, base
);
2984 P2Seek(unit
, 1, P2_REC_LINKQUALITY
, 6, base
);
2986 unit
->signal_quality
.SignalLevel
=
2987 ConvertLevel(unit
, unit
->LEWordIn(unit
->card
, P2_REG_DATA1
), base
);
2988 unit
->signal_quality
.NoiseLevel
=
2989 ConvertLevel(unit
, unit
->LEWordIn(unit
->card
, P2_REG_DATA1
), base
);
2996 /****i* prism2.device/StartScan ********************************************
2999 * StartScan -- Start a scan for available networks.
3004 * VOID StartScan(struct DevUnit *);
3009 * unit - A unit of this device.
3014 ****************************************************************************
3018 VOID
StartScan(struct DevUnit
*unit
, const TEXT
*ssid
, struct DevBase
*base
)
3021 UWORD ssid_length
= 0;
3023 /* Ask for a scan */
3025 if((unit
->flags
& UNITF_ONLINE
) != 0)
3028 ssid_length
= StrLen(ssid
);
3029 if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
3031 params
= AllocVec(sizeof(scan_params
) + ssid_length
, MEMF_PUBLIC
);
3034 CopyMem(scan_params
, params
, sizeof(scan_params
));
3036 CopyMem(ssid
, params
+ sizeof(scan_params
), ssid_length
);
3037 params
[4] = ssid_length
;
3038 P2SetData(unit
, P2_REC_HOSTSCAN
, params
,
3039 sizeof(scan_params
) + ssid_length
, base
);
3043 else if(unit
->firmware_type
== SYMBOL_FIRMWARE
)
3044 P2SetWord(unit
, P2_REC_ALTHOSTSCAN
, 0x82, base
);
3045 else if(unit
->firmware_type
>= LUCENT_FIRMWARE
3046 && (unit
->flags
& UNITF_HARDTKIP
) != 0)
3048 /* Initialise fake scan results and ask for a series of raw beacon
3051 unit
->scan_results_rec
[0] = MakeLEWord(1);
3053 P2SetID(unit
, P2_REC_SCANSSID
, ssid
, ssid_length
, base
);
3054 P2SetWord(unit
, P2_REC_SCANCHANNELS
, 0x7fff, base
);
3055 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, 0x3fff);
3056 P2DoCmd(unit
, P2_CMD_INQUIRE
, P2_INFO_SCANRESULT
, base
);
3060 P2SetID(unit
, P2_REC_SCANSSID
, ssid
, ssid_length
, base
);
3061 P2DoCmd(unit
, P2_CMD_INQUIRE
, P2_INFO_SCANRESULTS
, base
);
3070 /****i* prism2.device/LoadFirmware *****************************************
3076 * success = LoadFirmware(unit)
3078 * BOOL LoadFirmware(struct DevUnit *);
3083 * unit - A unit of this device.
3086 * success - Success indicator.
3088 ****************************************************************************
3092 static BOOL
LoadFirmware(struct DevUnit
*unit
, struct DevBase
*base
)
3094 BOOL success
= TRUE
;
3095 const TEXT
*file_name
;
3096 struct FileInfoBlock
*info
= NULL
;
3097 UWORD control_reg
, pdr_no
, *pda
= NULL
, *pdr
, *prod_data
, length
;
3098 ULONG location
, start_address
;
3099 BPTR file
= (BPTR
)NULL
;
3101 TEXT
*buffer
= NULL
;
3105 /* Read firmware file */
3107 switch(unit
->firmware_type
)
3109 case LUCENT_FIRMWARE
:
3110 file_name
= h1_firmware_file_name
;
3112 case HERMES2_FIRMWARE
:
3113 file_name
= h2_firmware_file_name
;
3115 case HERMES2G_FIRMWARE
:
3116 file_name
= h25_firmware_file_name
;
3122 if(file_name
== NULL
)
3127 file
= Open(file_name
, MODE_OLDFILE
);
3128 if(file
== (BPTR
)NULL
)
3134 info
= AllocDosObject(DOS_FIB
, NULL
);
3141 if(!ExamineFH(file
, info
))
3147 buffer
= AllocVec(info
->fib_Size
+ 1, MEMF_ANY
);
3148 data
= AllocVec(MAX_S_REC_SIZE
, MEMF_ANY
);
3149 pda
= AllocVec(LUCENT_PDA_SIZE
, MEMF_ANY
);
3150 if(buffer
== NULL
|| data
== NULL
|| pda
== NULL
)
3156 if(Read(file
, buffer
, info
->fib_Size
) == -1)
3158 buffer
[info
->fib_Size
] = '\0';
3163 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3164 P2DoCmd(unit
, P2_CMD_INIT
| 0x100, 0, base
);
3165 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3166 P2DoCmd(unit
, P2_CMD_INIT
| 0x0, 0, base
);
3167 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3169 /* Enable auxiliary ports */
3171 unit
->LEWordOut(unit
->card
, P2_REG_PARAM0
, 0xfe01);
3172 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, 0xdc23);
3173 unit
->LEWordOut(unit
->card
, P2_REG_PARAM2
, 0xba45);
3175 control_reg
= unit
->LEWordIn(unit
->card
, P2_REG_CONTROL
);
3177 control_reg
& ~P2_REG_CONTROLF_AUX
| P2_REG_CONTROL_ENABLEAUX
;
3178 unit
->LEWordOut(unit
->card
, P2_REG_CONTROL
, control_reg
);
3180 BusyMilliDelay(5, base
);
3182 (unit
->LEWordIn(unit
->card
, P2_REG_CONTROL
) & P2_REG_CONTROLF_AUX
)
3183 != P2_REG_CONTROL_AUXENABLED
);
3185 /* Read Production Data Area from card */
3187 if(unit
->firmware_type
< HERMES2_FIRMWARE
)
3189 location
= LUCENT_PDA_ADDRESS
;
3190 unit
->LEWordOut(unit
->card
, P2_REG_AUXPAGE
, location
>> 7);
3191 unit
->LEWordOut(unit
->card
, P2_REG_AUXOFFSET
,
3192 location
& (1 << 7) - 1);
3194 unit
->WordsIn(unit
->card
, P2_REG_AUXDATA
,
3195 (UWORD
*)pda
, LUCENT_PDA_SIZE
>> 1);
3198 /* Allow writing to card's RAM */
3200 BusyMilliDelay(100, base
);
3201 start_address
= 0xf8000;
3202 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, start_address
>> 16);
3203 P2DoCmd(unit
, P2_CMD_PROGRAM
| P2_CMDF_WRITE
, start_address
, base
);
3205 /* Parse firmware image data and write it to card */
3210 p
= ParseNextSRecord(p
, &type
, data
, &length
, &location
, base
);
3217 /* Check that this is not a "special" record */
3219 if(location
< 0xff000000)
3221 /* Write data to card */
3223 if(unit
->firmware_type
< LUCENT_FIRMWARE
)
3225 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
,
3227 P2DoCmd(unit
, P2_CMD_PROGRAM
| P2_CMDF_WRITE
, location
,
3231 unit
->LEWordOut(unit
->card
, P2_REG_AUXPAGE
,
3233 unit
->LEWordOut(unit
->card
, P2_REG_AUXOFFSET
,
3234 location
& (1 << 7) - 1);
3236 unit
->WordsOut(unit
->card
, P2_REG_AUXDATA
,
3237 (UWORD
*)data
, length
>> 1);
3243 /* Get location in card memory to begin execution of new
3246 start_address
= location
;
3251 /* Parse PDA plug records and patch firmware */
3256 p
= ParseNextSRecord(p
, &type
, data
, &length
, &location
, base
);
3258 if(p
!= NULL
&& type
== '3' && location
== 0xff000000)
3260 /* Get PDR number and the location where it should be patched
3263 pdr_no
= LELong(*(ULONG
*)data
);
3264 location
= LELong(*(ULONG
*)(data
+ 4));
3265 length
= LELong(*(ULONG
*)(data
+ 8));
3267 /* Find PDR to copy data from */
3270 for(pdr
= pda
; pdr
[1] != 0; pdr
+= LEWord(pdr
[0]) + 1)
3272 if(LEWord(pdr
[1]) == pdr_no
)
3273 prod_data
= pdr
+ 2;
3276 /* Write production data to card if it was found */
3278 if(prod_data
!= NULL
)
3280 if(unit
->firmware_type
< LUCENT_FIRMWARE
)
3282 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
,
3284 P2DoCmd(unit
, P2_CMD_PROGRAM
| P2_CMDF_WRITE
, location
,
3288 unit
->LEWordOut(unit
->card
, P2_REG_AUXPAGE
, location
>> 7);
3289 unit
->LEWordOut(unit
->card
, P2_REG_AUXOFFSET
,
3290 location
& (1 << 7) - 1);
3292 unit
->WordsOut(unit
->card
, P2_REG_AUXDATA
, prod_data
,
3298 /* Disable auxiliary ports */
3300 control_reg
= unit
->LEWordIn(unit
->card
, P2_REG_CONTROL
);
3302 control_reg
& ~P2_REG_CONTROLF_AUX
| P2_REG_CONTROL_DISABLEAUX
;
3303 unit
->LEWordOut(unit
->card
, P2_REG_CONTROL
, control_reg
);
3305 /* Execute downloaded firmware */
3307 if(unit
->firmware_type
>= HERMES2_FIRMWARE
)
3309 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, start_address
>> 16);
3310 P2DoCmd(unit
, P2_CMD_EXECUTE
, start_address
, base
);
3312 else if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
3314 P2DoCmd(unit
, P2_CMD_PROGRAM
, 0, base
);
3315 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3316 P2DoCmd(unit
, P2_CMD_INIT
, 0, base
);
3317 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3321 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, start_address
>> 16);
3322 P2DoCmd(unit
, P2_CMD_PROGRAM
, start_address
, base
);
3323 P2DoCmd(unit
, P2_CMD_INIT
, 0, base
);
3327 /* Free Resources */
3332 FreeDosObject(DOS_FIB
, info
);
3333 if(file
!= (BPTR
)NULL
)
3341 /****i* prism2.device/ParseNextSRecord *************************************
3346 ****************************************************************************
3350 static const TEXT
*ParseNextSRecord(const TEXT
*s
, UBYTE
*type
, UBYTE
*data
,
3351 UWORD
*data_length
, ULONG
*location
, struct DevBase
*base
)
3358 /* Find start of next record, if any */
3363 if(ch
== 'S' || ch
== '\0')
3369 /* Get record type */
3373 /* Skip length field to keep alignment easy */
3377 /* Parse hexadecimal portion of record */
3379 for(i
= 0; (ch
= *s
++) >= '0'; i
++)
3388 if(i
>= 8 && (i
& 0x1) != 0)
3399 *data_length
= (i
>> 1) - 5;
3404 /* Return updated text pointer */
3411 /****i* prism2.device/P2DoCmd **********************************************
3416 ****************************************************************************
3418 * Commands can't fail without software/firmware bug?
3422 static VOID
P2DoCmd(struct DevUnit
*unit
, UWORD command
, UWORD param
,
3423 struct DevBase
*base
)
3425 if(unit
->firmware_type
< LUCENT_FIRMWARE
&& command
== P2_CMD_INIT
)
3426 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3428 unit
->LEWordOut(unit
->card
, P2_REG_PARAM0
, param
);
3429 unit
->LEWordOut(unit
->card
, P2_REG_COMMAND
, command
);
3430 while((unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
)
3431 & P2_EVENTF_CMD
) == 0);
3432 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_CMD
);
3434 if(unit
->firmware_type
< LUCENT_FIRMWARE
&& command
== P2_CMD_INIT
)
3435 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3440 /****i* prism2.device/P2Seek ***********************************************
3445 ****************************************************************************
3449 static BOOL
P2Seek(struct DevUnit
*unit
, UWORD path_no
, UWORD rec_no
,
3450 UWORD offset
, struct DevBase
*base
)
3455 offset_reg
= P2_REG_OFFSET0
+ path_no
;
3456 while((unit
->LEWordIn(unit
->card
, offset_reg
) & P2_REG_OFFSETF_BUSY
)
3458 unit
->LEWordOut(unit
->card
, P2_REG_SELECT0
+ path_no
, rec_no
);
3459 unit
->LEWordOut(unit
->card
, offset_reg
, offset
);
3460 while((unit
->LEWordIn(unit
->card
, offset_reg
) & P2_REG_OFFSETF_BUSY
)
3463 return (unit
->LEWordIn(unit
->card
, offset_reg
) & P2_REG_OFFSETF_ERROR
)
3469 /****i* prism2.device/P2SetID **********************************************
3475 * id may be NULL as long as length is zero.
3477 ****************************************************************************
3481 static VOID
P2SetID(struct DevUnit
*unit
, UWORD rec_no
, const UBYTE
*id
,
3482 UWORD length
, struct DevBase
*base
)
3484 P2Seek(unit
, 1, rec_no
, 0, base
);
3486 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, length
/ 2 + 3);
3487 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, rec_no
);
3488 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, length
);
3489 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)id
, (length
+ 1) / 2);
3491 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
, rec_no
, base
);
3498 /****i* prism2.device/P2SetWord ********************************************
3503 ****************************************************************************
3507 static VOID
P2SetWord(struct DevUnit
*unit
, UWORD rec_no
, UWORD value
,
3508 struct DevBase
*base
)
3510 P2Seek(unit
, 1, rec_no
, 0, base
);
3512 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 2);
3513 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, rec_no
);
3514 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, value
);
3516 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
, rec_no
, base
);
3523 /****i* prism2.device/P2GetWord ********************************************
3528 ****************************************************************************
3532 static UWORD
P2GetWord(struct DevUnit
*unit
, UWORD rec_no
,
3533 struct DevBase
*base
)
3535 P2DoCmd(unit
, P2_CMD_ACCESS
, rec_no
, base
);
3536 P2Seek(unit
, 1, rec_no
, 4, base
);
3538 return unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
3543 /****i* prism2.device/P2AllocMem *******************************************
3548 ****************************************************************************
3552 static UWORD
P2AllocMem(struct DevUnit
*unit
, UWORD size
,
3553 struct DevBase
*base
)
3556 P2DoCmd(unit
, P2_CMD_ALLOCMEM
, size
, base
);
3557 while((unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
) & P2_EVENTF_ALLOCMEM
)
3559 id
= unit
->LEWordIn(unit
->card
, P2_REG_ALLOCFID
);
3560 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_ALLOCMEM
);
3566 /****i* prism2.device/P2SetData ********************************************
3571 ****************************************************************************
3575 static VOID
P2SetData(struct DevUnit
*unit
, UWORD rec_no
, const UBYTE
*data
,
3576 UWORD length
, struct DevBase
*base
)
3578 length
= (length
+ 1) / 2;
3579 P2Seek(unit
, 1, rec_no
, 0, base
);
3581 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 1 + length
);
3582 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, rec_no
);
3583 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (const UWORD
*)data
, length
);
3585 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
, rec_no
, base
);
3592 /****i* prism2.device/P2ReadRec ********************************************
3595 * P2ReadRec -- Load and read an entire record.
3598 * success = P2ReadRec(unit, rec_no, buffer, max_length)
3600 * BOOL P2ReadRec(struct DevUnit *, UWORD, APTR, UWORD);
3605 * unit - A unit of this device.
3606 * rec_no - Record number to read.
3607 * buffer - Buffer to store data in.
3608 * max_length - Maximum number of bytes to store in buffer.
3611 * success - Success indicator.
3613 ****************************************************************************
3617 static BOOL
P2ReadRec(struct DevUnit
*unit
, UWORD rec_no
, APTR buffer
,
3618 UWORD max_length
, struct DevBase
*base
)
3620 BOOL success
= TRUE
;
3623 P2DoCmd(unit
, P2_CMD_ACCESS
, rec_no
, base
);
3624 P2Seek(unit
, 1, rec_no
, 0, base
);
3626 length
= (unit
->LEWordIn(unit
->card
, P2_REG_DATA1
) + 1) * 2;
3627 P2Seek(unit
, 1, rec_no
, 0, base
);
3628 if(length
<= max_length
)
3629 unit
->WordsIn(unit
->card
, P2_REG_DATA1
, (UWORD
*)buffer
,
3638 /****i* prism2.device/ConvertLevel *****************************************
3641 * ConvertLevel -- Convert a signal or noise level to dBm.
3644 * dbm_level = ConvertLevel(unit, raw_level)
3646 * LONG ConvertLevel(struct DevUnit *, UWORD);
3651 * unit - A unit of this device.
3652 * raw_level - The value returned from the hardware.
3655 * dbm_level - The value in dBm.
3657 ****************************************************************************
3661 static LONG
ConvertLevel(struct DevUnit
*unit
, UWORD raw_level
,
3662 struct DevBase
*base
)
3666 if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
3667 dbm_level
= raw_level
- LUCENT_DBM_OFFSET
;
3669 dbm_level
= raw_level
/ 3 - INTERSIL_DBM_OFFSET
;
3676 /****i* prism2.device/ConvertScanLevel *************************************
3679 * ConvertScanLevel -- Convert a signal or noise level to dBm.
3682 * dbm_level = ConvertScanLevel(unit, raw_level)
3684 * LONG ConvertScanLevel(struct DevUnit *, UWORD);
3689 * unit - A unit of this device.
3690 * raw_level - The value returned from the hardware.
3693 * dbm_level - The value in dBm.
3695 ****************************************************************************
3699 static LONG
ConvertScanLevel(struct DevUnit
*unit
, UWORD raw_level
,
3700 struct DevBase
*base
)
3704 if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
3705 dbm_level
= raw_level
- LUCENT_DBM_OFFSET
;
3707 dbm_level
= (WORD
)raw_level
;
3714 /****i* prism2.device/GetIE ************************************************
3720 * ie = GetIE(id, ies, ies_length)
3722 * UBYTE *GetIE(UBYTE, UBYTE *, UWORD);
3727 * id - ID of IE to find.
3728 * ies - A series of IEs.
3729 * ies_length - Length of IE block.
3732 * ie - Pointer to start of IE within block, or NULL if not found.
3734 ****************************************************************************
3739 static UBYTE
*GetIE(UBYTE id
, UBYTE
*ies
, UWORD ies_length
,
3740 struct DevBase
*base
)
3745 // for(ie = ies; ie < end && ie + ie[1] < end; ie += length + 2)
3746 end
= ies
+ ies_length
;
3747 while(ie
< end
&& !found
)
3760 static UBYTE
*GetIE(UBYTE id
, UBYTE
*ies
, UWORD ies_length
,
3761 struct DevBase
*base
)
3765 for(ie
= ies
; ie
< ies
+ ies_length
&& ie
[0] != id
; ie
+= ie
[1] + 2);
3766 // for(ie = ies, end = ies + ies_length; ie < end && ie[0] != id; ie += ie[1] + 2);
3767 if(ie
>= ies
+ ies_length
)
3775 /****i* prism2.device/UnitTask *********************************************
3781 * UnitTask(sys_base)
3783 * VOID UnitTask(struct ExecBase *);
3786 * Completes deferred requests, and handles card insertion and removal
3787 * in conjunction with the relevant interrupts.
3789 ****************************************************************************
3797 static VOID
UnitTask(struct ExecBase
*sys_base
)
3800 struct IORequest
*request
;
3801 struct DevUnit
*unit
;
3802 struct DevBase
*base
;
3803 struct MsgPort
*general_port
;
3804 ULONG signals
= 0, wait_signals
, card_removed_signal
,
3805 card_inserted_signal
, scan_complete_signal
, general_port_signal
;
3807 /* Get parameters */
3809 task
= AbsExecBase
->ThisTask
;
3810 unit
= task
->tc_UserData
;
3811 base
= unit
->device
;
3813 /* Activate general request port */
3815 general_port
= unit
->request_ports
[GENERAL_QUEUE
];
3816 general_port
->mp_SigTask
= task
;
3817 general_port
->mp_SigBit
= AllocSignal(-1);
3818 general_port_signal
= 1 << general_port
->mp_SigBit
;
3819 general_port
->mp_Flags
= PA_SIGNAL
;
3821 /* Allocate signals for notification of card removal and insertion */
3823 card_removed_signal
= unit
->card_removed_signal
= 1 << AllocSignal(-1);
3824 card_inserted_signal
= unit
->card_inserted_signal
= 1 << AllocSignal(-1);
3825 scan_complete_signal
= unit
->scan_complete_signal
= 1 << AllocSignal(-1);
3826 wait_signals
= (1 << general_port
->mp_SigBit
) | card_removed_signal
3827 | card_inserted_signal
| scan_complete_signal
| SIGBREAKF_CTRL_C
;
3829 /* Tell ourselves to check port for old messages */
3831 Signal(task
, general_port_signal
);
3833 /* Infinite loop to service requests and signals */
3835 while((signals
& SIGBREAKF_CTRL_C
) == 0)
3837 signals
= Wait(wait_signals
);
3839 if((signals
& card_inserted_signal
) != 0)
3841 if(unit
->insertion_function(unit
->card
, base
))
3843 unit
->flags
|= UNITF_HAVEADAPTER
;
3844 if((unit
->flags
& UNITF_CONFIGURED
) != 0)
3845 ConfigureAdapter(unit
, base
);
3846 if((unit
->flags
& UNITF_WASONLINE
) != 0)
3848 GoOnline(unit
, base
);
3849 unit
->flags
&= ~UNITF_WASONLINE
;
3854 if((signals
& card_removed_signal
) != 0)
3856 unit
->removal_function(unit
->card
, base
);
3857 if((unit
->flags
& UNITF_WASONLINE
) != 0)
3858 GoOffline(unit
, base
);
3861 if((signals
& scan_complete_signal
) != 0)
3862 SendScanResults(unit
, base
);
3864 if((signals
& general_port_signal
) != 0)
3866 while((request
= (APTR
)GetMsg(general_port
)) != NULL
)
3868 /* Service the request as soon as the unit is free */
3870 ObtainSemaphore(&unit
->access_lock
);
3871 ServiceRequest((APTR
)request
, base
);
3876 FreeMem(task
->tc_SPLower
, STACK_SIZE
);
3881 /****i* prism2.device/StrLen ***********************************************
3887 * length = StrLen(s)
3889 * UPINT StrLen(TEXT *);
3891 ****************************************************************************
3895 static UPINT
StrLen(const TEXT
*s
)
3899 for(p
= s
; *p
!= '\0'; p
++);