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 #if !defined(__AROS__)
125 static const TEXT options_name
[] = "Prism 2 options";
127 static const TEXT h1_firmware_file_name
[] = "DEVS:Firmware/HermesI";
128 static const TEXT h2_firmware_file_name
[] = "DEVS:Firmware/HermesII";
129 static const TEXT h25_firmware_file_name
[] = "DEVS:Firmware/HermesII.5";
130 static const UBYTE h2_wpa_ie
[] =
132 0xdd, 0x18, 0x00, 0x50, 0xf2, 0x01, 0x01, 0x00,
133 0x00, 0x50, 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50,
134 0xf2, 0x02, 0x01, 0x00, 0x00, 0x50, 0xf2, 0x02,
141 #define AddTask(task, initial_pc, final_pc) \
142 IExec->AddTask(task, initial_pc, final_pc, NULL)
145 static const struct EmulLibEntry mos_task_trap
=
151 #define UnitTask &mos_task_trap
155 #define AddTask(task, initial_pc, final_pc) \
157 struct TagItem _task_tags[] = \
158 {{TASKTAG_ARG1, (IPTR)SysBase}, {TAG_END, 0}}; \
159 NewAddTask(task, initial_pc, final_pc, _task_tags); \
165 /****i* prism2.device/CreateUnit *******************************************
168 * CreateUnit -- Create a unit.
171 * unit = CreateUnit(index, card, io_tags, bus)
173 * struct DevUnit *CreateUnit(ULONG, APTR, struct TagItem *, UWORD);
176 * Creates a new unit.
178 ****************************************************************************
182 struct DevUnit
*CreateUnit(ULONG index
, APTR card
,
183 struct TagItem
*io_tags
, UWORD bus
, struct DevBase
*base
)
186 struct DevUnit
*unit
;
188 struct MsgPort
*port
;
192 unit
= AllocMem(sizeof(struct DevUnit
), MEMF_CLEAR
| MEMF_PUBLIC
);
203 (APTR
)GetTagData(IOTAG_WordsIn
, (UPINT
)NULL
, io_tags
);
205 (APTR
)GetTagData(IOTAG_WordsOut
, (UPINT
)NULL
, io_tags
);
207 (APTR
)GetTagData(IOTAG_BEWordOut
, (UPINT
)NULL
, io_tags
);
209 (APTR
)GetTagData(IOTAG_LEWordIn
, (UPINT
)NULL
, io_tags
);
211 (APTR
)GetTagData(IOTAG_LEWordOut
, (UPINT
)NULL
, io_tags
);
212 if(unit
->WordsIn
== NULL
|| unit
->WordsOut
== NULL
213 || unit
->BEWordOut
== NULL
|| unit
->LEWordIn
== NULL
214 || unit
->LEWordOut
== NULL
)
220 InitSemaphore(&unit
->access_lock
);
221 success
= InitialiseAdapter(unit
, FALSE
, base
);
222 unit
->flags
|= UNITF_HAVEADAPTER
;
224 /* Create the message ports for queuing requests */
226 for(i
= 0; i
< REQUEST_QUEUE_COUNT
; i
++)
228 unit
->request_ports
[i
] = port
= AllocMem(sizeof(struct MsgPort
),
229 MEMF_PUBLIC
| MEMF_CLEAR
);
235 NewList(&port
->mp_MsgList
);
236 port
->mp_Flags
= PA_IGNORE
;
237 port
->mp_SigTask
= &unit
->tx_int
;
241 /* Allocate buffers */
243 unit
->rx_buffer
= AllocVec(FRAME_BUFFER_SIZE
, MEMF_PUBLIC
);
244 unit
->rx_buffers
= AllocVec(FRAME_BUFFER_SIZE
* RX_BUFFER_COUNT
,
246 for(i
= 0; i
< RX_BUFFER_COUNT
; i
++)
247 unit
->rx_fragment_nos
[i
] = -1;
248 unit
->tx_buffer
= AllocVec(ETH_MAXPACKETSIZE
, MEMF_PUBLIC
);
249 unit
->rx_descriptor
= AllocVec(FRAME_BUFFER_SIZE
,
250 MEMF_PUBLIC
| MEMF_CLEAR
);
251 unit
->tx_descriptor
= AllocVec(FRAME_BUFFER_SIZE
,
252 MEMF_PUBLIC
| MEMF_CLEAR
);
253 unit
->scan_results_rec
= AllocVec(SCAN_BUFFER_SIZE
, MEMF_PUBLIC
);
254 unit
->next_beacon
= unit
->beacons
=
255 AllocVec(BEACON_BUFFER_SIZE
, MEMF_PUBLIC
);
256 if(unit
->rx_buffer
== NULL
|| unit
->rx_buffers
== NULL
257 || unit
->tx_buffer
== NULL
|| unit
->rx_descriptor
== NULL
258 || unit
->tx_descriptor
== NULL
|| unit
->scan_results_rec
== NULL
259 || unit
->beacons
== NULL
)
265 NewList((APTR
)&unit
->openers
);
266 NewList((APTR
)&unit
->type_trackers
);
267 NewList((APTR
)&unit
->multicast_ranges
);
269 /* Record maximum speed in BPS */
271 unit
->speed
= 11000000;
273 /* Initialise status, transmit, receive and stats interrupts */
275 unit
->status_int
.is_Node
.ln_Name
=
276 base
->device
.dd_Library
.lib_Node
.ln_Name
;
277 unit
->status_int
.is_Code
= (APTR
)StatusInt
;
278 unit
->status_int
.is_Data
= unit
;
280 unit
->rx_int
.is_Node
.ln_Name
=
281 base
->device
.dd_Library
.lib_Node
.ln_Name
;
282 unit
->rx_int
.is_Code
= (APTR
)RXInt
;
283 unit
->rx_int
.is_Data
= unit
;
285 unit
->tx_int
.is_Node
.ln_Name
=
286 base
->device
.dd_Library
.lib_Node
.ln_Name
;
287 unit
->tx_int
.is_Code
= (APTR
)TXInt
;
288 unit
->tx_int
.is_Data
= unit
;
290 unit
->info_int
.is_Node
.ln_Name
=
291 base
->device
.dd_Library
.lib_Node
.ln_Name
;
292 unit
->info_int
.is_Code
= (APTR
)InfoInt
;
293 unit
->info_int
.is_Data
= unit
;
295 unit
->reset_handler
.is_Node
.ln_Name
=
296 base
->device
.dd_Library
.lib_Node
.ln_Name
;
297 unit
->reset_handler
.is_Code
= (APTR
)ResetHandler
;
298 unit
->reset_handler
.is_Data
= unit
;
300 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
305 /* Create a new task */
308 AllocMem(sizeof(struct Task
), MEMF_PUBLIC
| MEMF_CLEAR
);
315 stack
= AllocMem(STACK_SIZE
, MEMF_PUBLIC
);
322 /* Initialise and start task */
324 task
->tc_Node
.ln_Type
= NT_TASK
;
325 task
->tc_Node
.ln_Pri
= TASK_PRIORITY
;
326 task
->tc_Node
.ln_Name
= base
->device
.dd_Library
.lib_Node
.ln_Name
;
327 task
->tc_SPUpper
= stack
+ STACK_SIZE
;
328 task
->tc_SPLower
= stack
;
329 task
->tc_SPReg
= stack
+ STACK_SIZE
;
330 NewList(&task
->tc_MemEntry
);
332 if(AddTask(task
, UnitTask
, NULL
) == NULL
)
338 /* Send the unit to the new task */
340 task
->tc_UserData
= unit
;
342 /* Set default wireless options */
344 unit
->mode
= S2PORT_MANAGED
;
349 DeleteUnit(unit
, base
);
358 /****i* prism2.device/DeleteUnit *******************************************
361 * DeleteUnit -- Delete a unit.
366 * VOID DeleteUnit(struct DevUnit *);
372 * unit - Device unit (may be NULL).
377 ****************************************************************************
381 VOID
DeleteUnit(struct DevUnit
*unit
, struct DevBase
*base
)
393 if(task
->tc_UserData
!= NULL
)
396 FreeMem(task
->tc_SPLower
, STACK_SIZE
);
398 FreeMem(task
, sizeof(struct Task
));
401 /* Free request queues */
403 for(i
= 0; i
< REQUEST_QUEUE_COUNT
; i
++)
405 if(unit
->request_ports
[i
] != NULL
)
406 FreeMem(unit
->request_ports
[i
], sizeof(struct MsgPort
));
411 if((unit
->flags
& UNITF_ONLINE
) != 0) /* Needed! */
412 GoOffline(unit
, base
);
414 /* Clear target SSID */
416 P2SetID(unit
, P2_REC_DESIREDSSID
, unit
->ssid
, 0, base
);
418 /* Free buffers and unit structure */
420 FreeVec(unit
->scan_results_rec
);
421 FreeVec(unit
->tx_descriptor
);
422 FreeVec(unit
->rx_descriptor
);
423 FreeVec(unit
->tx_buffer
);
424 FreeVec(unit
->rx_buffers
);
425 FreeVec(unit
->rx_buffer
);
427 FreeMem(unit
, sizeof(struct DevUnit
));
435 /****i* prism2.device/InitialiseAdapter ************************************
441 * success = InitialiseAdapter(unit, reinsertion)
443 * BOOL InitialiseAdapter(struct DevUnit *, BOOL);
452 * success - Success indicator.
454 ****************************************************************************
458 BOOL
InitialiseAdapter(struct DevUnit
*unit
, BOOL reinsertion
,
459 struct DevBase
*base
)
461 UWORD id
, version
, revision
, i
;
462 BOOL success
= TRUE
, loaded
;
463 UBYTE address
[ETH_ADDRESSSIZE
];
466 /* Wait for card to be ready following bus-specific reset, then start
469 while((unit
->LEWordIn(unit
->card
, P2_REG_COMMAND
)
470 & P2_REG_COMMANDF_BUSY
) != 0);
472 P2DoCmd(unit
, P2_CMD_INIT
, 0, base
);
474 /* Determine firmware type */
476 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_NICIDENTITY
, base
);
477 P2Seek(unit
, 1, P2_REC_NICIDENTITY
, 4, base
);
478 id
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
479 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
480 version
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
481 revision
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
483 if((id
& 0x8000) != 0)
486 unit
->firmware_type
= SYMBOL_FIRMWARE
;
488 unit
->firmware_type
= INTERSIL_FIRMWARE
;
492 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_PRIIDENTITY
, base
);
493 P2Seek(unit
, 1, P2_REC_PRIIDENTITY
, 0, base
);
494 length
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
496 unit
->firmware_type
= LUCENT_FIRMWARE
;
499 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_STAIDENTITY
, base
);
500 P2Seek(unit
, 1, P2_REC_STAIDENTITY
, 4, base
);
501 id
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
502 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
503 version
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
504 revision
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
506 unit
->firmware_type
= HERMES2G_FIRMWARE
;
508 unit
->firmware_type
= HERMES2_FIRMWARE
;
512 /* Download firmware if necessary or available */
514 loaded
= LoadFirmware(unit
, base
);
515 if(!loaded
&& unit
->firmware_type
>= HERMES2_FIRMWARE
)
520 /* Determine features, and get offsets of certain fields within frame
523 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_STAIDENTITY
, base
);
524 P2Seek(unit
, 1, P2_REC_STAIDENTITY
, 4, base
);
525 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
526 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
527 version
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
528 revision
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
530 if(P2GetWord(unit
, P2_REC_HASWEP
, base
) != 0)
531 unit
->flags
|= UNITF_HASWEP
| UNITF_HARDWEP
;
533 unit
->ethernet_offset
= P2_FRM_ETHFRAME
;
534 unit
->data_offset
= P2_FRM_DATA
;
535 unit
->txcontrol_offset
= P2_FRM_TXCONTROL
;
536 unit
->datalen_offset
= P2_FRM_DATALEN
;
538 if(unit
->firmware_type
== LUCENT_FIRMWARE
)
540 if(version
> 6 || version
== 6 && revision
>= 6)
541 unit
->flags
|= UNITF_HASADHOC
;
544 unit
->flags
|= UNITF_HASTKIP
| UNITF_HARDTKIP
;
545 unit
->txcontrol_offset
= P2_FRM_ALTTXCONTROL
;
548 else if(unit
->firmware_type
>= HERMES2_FIRMWARE
)
550 unit
->flags
|= UNITF_HASADHOC
| UNITF_HASTKIP
| UNITF_HARDTKIP
;
551 unit
->ethernet_offset
= P2_H2FRM_ETHFRAME
;
552 unit
->data_offset
= P2_H2FRM_DATA
;
553 unit
->txcontrol_offset
= P2_H2FRM_TXCONTROL
;
554 unit
->datalen_offset
= P2_H2FRM_DATALEN
;
556 else if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
558 unit
->flags
|= UNITF_HASADHOC
| UNITF_HASWEP
;
559 if(version
== 1 && revision
>= 7)
560 unit
->flags
|= UNITF_HASTKIP
| UNITF_HASCCMP
;
563 /* Get default channel and MAC address */
565 unit
->channel
= P2GetWord(unit
, P2_REC_OWNCHNL
, base
);
566 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_ADDRESS
, base
);
567 P2Seek(unit
, 1, P2_REC_ADDRESS
, 4, base
);
568 unit
->WordsIn(unit
->card
, P2_REG_DATA1
, (UWORD
*)address
,
569 ETH_ADDRESSSIZE
/ 2);
571 /* If card has been re-inserted, check it has the same address as
576 for(i
= 0; i
< ETH_ADDRESSSIZE
; i
++)
577 if(address
[i
] != unit
->default_address
[i
])
584 CopyMem(address
, unit
->default_address
, ETH_ADDRESSSIZE
);
586 /* Get initial on-card TX buffer */
588 unit
->tx_frame_id
= P2AllocMem(unit
, FRAME_BUFFER_SIZE
, base
);
592 if((unit
->flags
& UNITF_HARDWEP
) == 0)
593 unit
->iv_sizes
[S2ENC_WEP
] = IV_SIZE
;
594 if((unit
->flags
& UNITF_HARDTKIP
) == 0)
595 unit
->iv_sizes
[S2ENC_TKIP
] = EIV_SIZE
;
596 unit
->iv_sizes
[S2ENC_CCMP
] = EIV_SIZE
;
598 /* Set encryption functions */
600 unit
->fragment_encrypt_functions
[S2ENC_NONE
] = WriteClearFragment
;
602 if((unit
->flags
& UNITF_HARDWEP
) != 0)
603 unit
->fragment_encrypt_functions
[S2ENC_WEP
] = WriteClearFragment
;
605 unit
->fragment_encrypt_functions
[S2ENC_WEP
] = EncryptWEPFragment
;
607 if((unit
->flags
& UNITF_HARDTKIP
) != 0)
608 unit
->fragment_encrypt_functions
[S2ENC_TKIP
] = WriteClearFragment
;
610 unit
->fragment_encrypt_functions
[S2ENC_TKIP
] = EncryptTKIPFragment
;
612 unit
->fragment_encrypt_functions
[S2ENC_CCMP
] = EncryptCCMPFragment
;
614 /* Set decryption functions */
616 unit
->fragment_decrypt_functions
[S2ENC_NONE
] = ReadClearFragment
;
618 if((unit
->flags
& UNITF_HARDWEP
) != 0)
619 unit
->fragment_decrypt_functions
[S2ENC_WEP
] = ReadClearFragment
;
621 unit
->fragment_decrypt_functions
[S2ENC_WEP
] = DecryptWEPFragment
;
623 if((unit
->flags
& UNITF_HARDTKIP
) != 0)
624 unit
->fragment_decrypt_functions
[S2ENC_TKIP
] = ReadClearFragment
;
626 unit
->fragment_decrypt_functions
[S2ENC_TKIP
] = DecryptTKIPFragment
;
628 unit
->fragment_decrypt_functions
[S2ENC_CCMP
] = DecryptCCMPFragment
;
638 /****i* prism2.device/ConfigureAdapter *************************************
641 * ConfigureAdapter -- Set up card for transmission/reception.
644 * ConfigureAdapter(unit)
646 * VOID ConfigureAdapter(struct DevUnit *);
648 ****************************************************************************
652 VOID
ConfigureAdapter(struct DevUnit
*unit
, struct DevBase
*base
)
654 UWORD i
, key_length
, port_type
, lowest_enc
= S2ENC_CCMP
,
655 highest_enc
= S2ENC_NONE
, enc_flags
, size
, value
;
656 const struct KeyUnion
*keys
;
658 /* Set MAC address */
660 P2SetData(unit
, P2_REC_ADDRESS
, unit
->address
, ETH_ADDRESSSIZE
,
663 /* Decide on promiscuous mode */
665 P2SetWord(unit
, P2_REC_PROMISC
, FALSE
, base
);
666 SetMulticast(unit
, base
);
668 /* Set wireless parameters */
670 if(unit
->mode
== S2PORT_ADHOC
)
672 P2SetWord(unit
, P2_REC_OWNCHNL
, unit
->channel
, base
);
673 P2SetID(unit
, P2_REC_OWNSSID
, unit
->ssid
, unit
->ssid_length
, base
);
675 if(unit
->mode
== S2PORT_MANAGED
)
679 if((unit
->flags
& UNITF_ONLINE
) == 0)
680 P2SetWord(unit
, P2_REC_PORTTYPE
, port_type
, base
);
681 P2SetWord(unit
, P2_REC_CREATEIBSS
, unit
->mode
== S2PORT_ADHOC
, base
);
682 P2SetID(unit
, P2_REC_DESIREDSSID
, unit
->ssid
, unit
->ssid_length
, base
);
684 /* Determine highest encryption type in use */
686 for(i
= 0; i
< WIFI_KEYCOUNT
; i
++)
688 if(unit
->keys
[i
].type
> highest_enc
)
689 highest_enc
= unit
->keys
[i
].type
;
690 if(unit
->keys
[i
].type
< lowest_enc
)
691 lowest_enc
= unit
->keys
[i
].type
;
694 if(unit
->wpa_ie
[1] != 0)
695 highest_enc
= S2ENC_TKIP
; // TO DO: Be more specific?
697 /* Allow reception of beacon/probe-response frames */
699 if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
700 P2SetWord(unit
, P2_REC_RXMGMTFRAMES
, 1, base
);
702 /* Transmit at 11Mbps, with fallback */
704 if(unit
->firmware_type
== INTERSIL_FIRMWARE
705 || unit
->firmware_type
== SYMBOL_FIRMWARE
)
706 P2SetWord(unit
, P2_REC_TXRATE
, 0xf, base
);
708 /* Configure authentication and encryption */
710 if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
712 /* Set authentication and encryption modes */
714 P2SetWord(unit
, P2_REC_ALTAUTHTYPE
, unit
->auth_types
, base
);
716 P2SetWord(unit
, P2_REC_ALTENCRYPTION
, highest_enc
, base
);
718 /* Set up firmware-based WEP encryption if appropriate */
720 if(highest_enc
== S2ENC_WEP
&& (unit
->flags
& UNITF_HARDWEP
) != 0)
722 P2SetWord(unit
, P2_REC_ALTTXCRYPTKEY
, unit
->tx_key_no
, base
);
723 P2Seek(unit
, 1, P2_REC_DEFLTCRYPTKEYS
, 0, base
);
724 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, P2_ALTWEPRECLEN
);
725 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, P2_REC_DEFLTCRYPTKEYS
);
727 for(i
= 0; i
< WIFI_KEYCOUNT
; i
++)
729 key_length
= keys
[i
].u
.wep
.length
;
731 key_length
= WIFI_WEP128LEN
;
732 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, key_length
);
733 unit
->WordsOut(unit
->card
, P2_REG_DATA1
,
734 (UWORD
*)keys
[i
].u
.wep
.key
, (key_length
+ 1) / 2);
737 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
,
738 P2_REC_DEFLTCRYPTKEYS
, base
);
741 /* Set key management suite to PSK */
743 if(highest_enc
> S2ENC_WEP
)
745 value
= (unit
->firmware_type
>= HERMES2_FIRMWARE
) ? 4 : 2;
746 P2SetWord(unit
, P2_REC_KEYMGMTSUITE
, value
, base
);
751 /* Set authentication mode */
753 P2SetWord(unit
, P2_REC_AUTHTYPE
, unit
->auth_types
, base
);
755 /* Set encryption flags */
757 if(highest_enc
> S2ENC_NONE
)
758 enc_flags
= P2_REC_ENCRYPTIONF_ENABLE
;
762 if(highest_enc
> S2ENC_WEP
763 || highest_enc
== S2ENC_WEP
&& (unit
->flags
& UNITF_HARDWEP
) == 0)
764 enc_flags
|= P2_REC_ENCRYPTIONF_HOSTDECRYPT
765 | P2_REC_ENCRYPTIONF_HOSTENCRYPT
;
766 P2SetWord(unit
, P2_REC_ENCRYPTION
, enc_flags
, base
);
768 /* Set up firmware-based WEP encryption if appropriate */
770 if(highest_enc
== S2ENC_WEP
&& (unit
->flags
& UNITF_HARDWEP
) != 0)
772 P2SetWord(unit
, P2_REC_TXCRYPTKEY
, unit
->tx_key_no
, base
);
775 for(i
= 0; i
< WIFI_KEYCOUNT
; i
++)
777 key_length
= keys
[i
].u
.wep
.length
;
779 key_length
= keys
[unit
->tx_key_no
].u
.wep
.length
;
780 P2SetData(unit
, P2_REC_CRYPTKEY0
+ i
, keys
[i
].u
.wep
.key
,
785 /* Set or clear WPA IE */
787 if(highest_enc
> S2ENC_WEP
)
788 size
= unit
->wpa_ie
[1] + 2;
791 P2SetID(unit
, P2_REC_WPAIE
, unit
->wpa_ie
, size
, base
);
793 /* Let supplicant handle association and roaming */
795 P2SetWord(unit
, P2_REC_ROAMINGMODE
, 3, base
);
798 /* Restart the transceiver if we're already online */
800 if((unit
->flags
& UNITF_ONLINE
) != 0)
802 P2DoCmd(unit
, P2_CMD_DISABLE
, 0, base
);
803 P2DoCmd(unit
, P2_CMD_ENABLE
, 0, base
);
805 /* Attempt to join specified network */
807 if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
809 typedef union { UBYTE b
[2]; UWORD w
;} BW
;
810 BW
*p
= (BW
*)(unit
->bssid
+ ETH_ADDRESSSIZE
);
811 p
->w
= MakeLEWord(unit
->channel
);
812 P2SetData(unit
, P2_REC_JOIN
, unit
->bssid
, ETH_ADDRESSSIZE
+ 2,
824 /****i* prism2.device/GoOnline *********************************************
827 * GoOnline -- Enable transmission/reception.
832 * VOID GoOnline(struct DevUnit *);
834 ****************************************************************************
838 VOID
GoOnline(struct DevUnit
*unit
, struct DevBase
*base
)
840 /* Enable interrupts */
842 unit
->flags
|= UNITF_ONLINE
;
843 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, INT_MASK
);
845 /* Enable the transceiver */
847 P2DoCmd(unit
, P2_CMD_ENABLE
, 0, base
);
849 /* Record start time and report Online event */
851 GetSysTime(&unit
->stats
.LastStart
);
852 ReportEvents(unit
, S2EVENT_ONLINE
, base
);
859 /****i* prism2.device/GoOffline ********************************************
862 * GoOffline -- Disable transmission/reception.
867 * VOID GoOffline(struct DevUnit *);
877 ****************************************************************************
881 VOID
GoOffline(struct DevUnit
*unit
, struct DevBase
*base
)
883 unit
->flags
&= ~UNITF_ONLINE
;
884 if((unit
->flags
& UNITF_HAVEADAPTER
) != 0)
886 /* Stop interrupts */
888 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, 0);
889 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
891 /* Update statistics */
893 UpdateStats(unit
, base
);
895 /* Stop transmission and reception */
897 P2DoCmd(unit
, P2_CMD_DISABLE
, 0, base
);
900 /* Flush pending read and write requests */
902 FlushUnit(unit
, WRITE_QUEUE
, S2ERR_OUTOFSERVICE
, base
);
904 /* Report Offline event and return */
906 ReportEvents(unit
, S2EVENT_OFFLINE
, base
);
912 /****i* prism2.device/SetOptions *******************************************
915 * SetOptions -- Set and use interface options.
918 * SetOptions(unit, tag_list)
920 * VOID SetOptions(struct DevUnit *, struct TagItem *);
922 ****************************************************************************
926 VOID
SetOptions(struct DevUnit
*unit
, const struct TagItem
*tag_list
,
927 struct DevBase
*base
)
929 struct TagItem
*tag_item
, *tlist
= (struct TagItem
*)tag_list
;
934 while((tag_item
= NextTagItem(&tlist
)) != NULL
)
936 switch(tag_item
->ti_Tag
)
939 id
= (const TEXT
*)tag_item
->ti_Data
;
941 CopyMem(id
, unit
->ssid
, length
);
942 unit
->ssid_length
= length
;
946 CopyMem((APTR
)tag_item
->ti_Data
, unit
->bssid
, ETH_ADDRESSSIZE
);
949 case S2INFO_DefaultKeyNo
:
950 unit
->tx_key_no
= tag_item
->ti_Data
;
953 case S2INFO_PortType
:
954 unit
->mode
= tag_item
->ti_Data
;
958 if(tag_item
->ti_Data
!= 0) // ???
959 unit
->channel
= tag_item
->ti_Data
;
963 if(tag_item
->ti_Data
!= (UPINT
)NULL
)
965 /* Hermes-II uses an "unusual" WPA IE in its association
966 request. So we use a matching IE everywhere else too */
968 if(unit
->firmware_type
>= HERMES2_FIRMWARE
)
971 ie
= (const UBYTE
*)tag_item
->ti_Data
;
972 CopyMem(ie
, unit
->wpa_ie
, ie
[1] + 2);
981 case S2INFO_AuthTypes
:
982 unit
->auth_types
= tag_item
->ti_Data
;
992 /****i* prism2.device/SetKey ***********************************************
995 * SetKey -- Set an encryption key.
998 * SetKey(unit, index, type, key, key_length,
1001 * VOID SetKey(struct DevUnit *, ULONG, ULONG, UBYTE *, ULONG,
1004 ****************************************************************************
1008 VOID
SetKey(struct DevUnit
*unit
, ULONG index
, ULONG type
, const UBYTE
*key
,
1009 ULONG key_length
, const UBYTE
*rx_counter
, struct DevBase
*base
)
1011 struct KeyUnion
*slot
;
1012 const UBYTE tx_counter
[8] = {0, 0, 0, 0, 0x10, 0, 0, 0};
1014 struct EClockVal eclock
;
1017 slot
= &unit
->keys
[index
];
1021 CopyMem(key
, slot
->u
.wep
.key
, key_length
);
1022 slot
->u
.wep
.length
= key_length
;
1024 if((unit
->flags
& UNITF_HARDWEP
) == 0)
1026 /* Create a reasonably random IV */
1028 ReadEClock(&eclock
);
1029 slot
->u
.wep
.tx_iv
= FastRand(eclock
.ev_lo
^ eclock
.ev_hi
);
1035 CopyMem(key
, slot
->u
.tkip
.key
, 16);
1036 CopyMem(key
+ 16, slot
->u
.tkip
.tx_mic_key
, MIC_SIZE
);
1037 CopyMem(key
+ 24, slot
->u
.tkip
.rx_mic_key
, MIC_SIZE
);
1038 slot
->u
.tkip
.tx_iv_low
= 0;
1039 slot
->u
.tkip
.tx_iv_high
= 0;
1040 slot
->u
.tkip
.rx_iv_low
= LEWord(*(UWORD
*)rx_counter
);
1041 slot
->u
.tkip
.rx_iv_high
= LELong(*(ULONG
*)(rx_counter
+ 2));
1042 slot
->u
.tkip
.tx_ttak_set
= FALSE
;
1043 slot
->u
.tkip
.rx_ttak_set
= FALSE
;
1045 if((unit
->flags
& UNITF_HARDTKIP
) != 0)
1047 /* For Hermes, load parameters for hardware encryption. The
1048 pairwise key is treated differently from group keys on
1049 Hermes-II, but not on Hermes-I */
1051 if(unit
->firmware_type
>= HERMES2_FIRMWARE
&& index
== 0)
1053 P2Seek(unit
, 1, P2_REC_ADDMAPPEDTKIPKEY
, 0, base
);
1054 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 28);
1055 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
,
1056 P2_REC_ADDMAPPEDTKIPKEY
);
1057 unit
->WordsOut(unit
->card
, P2_REG_DATA1
,
1058 (UWORD
*)unit
->bssid
, ETH_ADDRESSSIZE
/ 2);
1059 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)key
,
1061 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)tx_counter
,
1063 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)rx_counter
,
1065 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 0);
1066 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)key
+ 16,
1068 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
,
1069 P2_REC_ADDMAPPEDTKIPKEY
, base
);
1073 P2Seek(unit
, 1, P2_REC_ADDDEFAULTTKIPKEY
, 0, base
);
1074 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 26);
1075 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
,
1076 P2_REC_ADDDEFAULTTKIPKEY
);
1077 if(index
== unit
->tx_key_no
)
1079 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, index
);
1080 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)rx_counter
,
1082 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 0);
1083 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)key
,
1085 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)tx_counter
,
1087 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
,
1088 P2_REC_ADDDEFAULTTKIPKEY
, base
);
1093 /* Convert key to native endianness */
1095 for(i
= 0; i
< 8; i
++)
1096 slot
->u
.tkip
.key
[i
] = LEWord(slot
->u
.tkip
.key
[i
]);
1102 CopyMem(key
, slot
->u
.ccmp
.key
, 16);
1103 slot
->u
.ccmp
.tx_iv_low
= 0;
1104 slot
->u
.ccmp
.tx_iv_high
= 0;
1105 slot
->u
.ccmp
.rx_iv_low
= LEWord(*(UWORD
*)rx_counter
);
1106 slot
->u
.ccmp
.rx_iv_high
= LELong(*(ULONG
*)(rx_counter
+ 2));
1107 slot
->u
.ccmp
.stream_set
= FALSE
;
1110 /* Clear TKIP key if necessary */
1112 if(slot
->type
== S2ENC_TKIP
&& type
!= S2ENC_TKIP
)
1114 if(unit
->firmware_type
>= HERMES2_FIRMWARE
&& index
== 0)
1115 P2SetData(unit
, P2_REC_REMMAPPEDTKIPKEY
, unit
->bssid
,
1116 ETH_ADDRESSSIZE
, base
);
1117 else if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
1118 P2SetWord(unit
, P2_REC_REMDEFAULTTKIPKEY
, index
, base
);
1121 /* Update type of key in selected slot */
1131 /****i* prism2.device/AddMulticastRange ************************************
1137 * success = AddMulticastRange(unit, lower_bound, upper_bound)
1139 * BOOL AddMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1141 ****************************************************************************
1145 BOOL
AddMulticastRange(struct DevUnit
*unit
, const UBYTE
*lower_bound
,
1146 const UBYTE
*upper_bound
, struct DevBase
*base
)
1148 struct AddressRange
*range
;
1149 ULONG lower_bound_left
, upper_bound_left
;
1150 UWORD lower_bound_right
, upper_bound_right
;
1152 lower_bound_left
= BELong(*((ULONG
*)lower_bound
));
1153 lower_bound_right
= BEWord(*((UWORD
*)(lower_bound
+ 4)));
1154 upper_bound_left
= BELong(*((ULONG
*)upper_bound
));
1155 upper_bound_right
= BEWord(*((UWORD
*)(upper_bound
+ 4)));
1157 range
= FindMulticastRange(unit
, lower_bound_left
, lower_bound_right
,
1158 upper_bound_left
, upper_bound_right
, base
);
1164 range
= AllocMem(sizeof(struct AddressRange
), MEMF_PUBLIC
);
1167 range
->lower_bound_left
= lower_bound_left
;
1168 range
->lower_bound_right
= lower_bound_right
;
1169 range
->upper_bound_left
= upper_bound_left
;
1170 range
->upper_bound_right
= upper_bound_right
;
1171 range
->add_count
= 1;
1174 AddTail((APTR
)&unit
->multicast_ranges
, (APTR
)range
);
1175 unit
->range_count
++;
1176 SetMulticast(unit
, base
);
1181 return range
!= NULL
;
1186 /****i* prism2.device/RemMulticastRange ************************************
1192 * found = RemMulticastRange(unit, lower_bound, upper_bound)
1194 * BOOL RemMulticastRange(struct DevUnit *, UBYTE *, UBYTE *);
1196 ****************************************************************************
1200 BOOL
RemMulticastRange(struct DevUnit
*unit
, const UBYTE
*lower_bound
,
1201 const UBYTE
*upper_bound
, struct DevBase
*base
)
1203 struct AddressRange
*range
;
1204 ULONG lower_bound_left
, upper_bound_left
;
1205 UWORD lower_bound_right
, upper_bound_right
;
1207 lower_bound_left
= BELong(*((ULONG
*)lower_bound
));
1208 lower_bound_right
= BEWord(*((UWORD
*)(lower_bound
+ 4)));
1209 upper_bound_left
= BELong(*((ULONG
*)upper_bound
));
1210 upper_bound_right
= BEWord(*((UWORD
*)(upper_bound
+ 4)));
1212 range
= FindMulticastRange(unit
, lower_bound_left
, lower_bound_right
,
1213 upper_bound_left
, upper_bound_right
, base
);
1217 if(--range
->add_count
== 0)
1220 Remove((APTR
)range
);
1221 unit
->range_count
--;
1222 SetMulticast(unit
, base
);
1224 FreeMem(range
, sizeof(struct AddressRange
));
1228 return range
!= NULL
;
1233 /****i* prism2.device/FindMulticastRange ***********************************
1236 * FindMulticastRange
1239 * range = FindMulticastRange(unit, lower_bound_left,
1240 * lower_bound_right, upper_bound_left, upper_bound_right)
1242 * struct AddressRange *FindMulticastRange(struct DevUnit *, ULONG,
1243 * UWORD, ULONG, UWORD);
1245 ****************************************************************************
1249 static struct AddressRange
*FindMulticastRange(struct DevUnit
*unit
,
1250 ULONG lower_bound_left
, UWORD lower_bound_right
, ULONG upper_bound_left
,
1251 UWORD upper_bound_right
, struct DevBase
*base
)
1253 struct AddressRange
*range
, *tail
;
1256 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
1257 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
1259 while(range
!= tail
&& !found
)
1261 if(lower_bound_left
== range
->lower_bound_left
&&
1262 lower_bound_right
== range
->lower_bound_right
&&
1263 upper_bound_left
== range
->upper_bound_left
&&
1264 upper_bound_right
== range
->upper_bound_right
)
1267 range
= (APTR
)range
->node
.mln_Succ
;
1278 /****i* prism2.device/SetMulticast *****************************************
1284 * SetMulticast(unit)
1286 * VOID SetMulticast(struct DevUnit *);
1288 ****************************************************************************
1292 static VOID
SetMulticast(struct DevUnit
*unit
, struct DevBase
*base
)
1295 UWORD address_right
, i
= 0;
1296 struct AddressRange
*range
, *tail
;
1299 /* Fill in multicast list */
1301 P2Seek(unit
, 1, P2_REC_MCASTLIST
, 4, base
);
1303 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
1304 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
1306 while(range
!= tail
&& i
< P2_MAXMCASTENTRIES
)
1308 address_left
= range
->lower_bound_left
;
1309 address_right
= range
->lower_bound_right
;
1310 range_ended
= FALSE
;
1312 while(!range_ended
&& i
++ < P2_MAXMCASTENTRIES
)
1314 unit
->BEWordOut(unit
->card
, P2_REG_DATA1
,
1315 (UWORD
)(address_left
>> 16));
1316 unit
->BEWordOut(unit
->card
, P2_REG_DATA1
, (UWORD
)address_left
);
1317 unit
->BEWordOut(unit
->card
, P2_REG_DATA1
, (UWORD
)address_right
);
1319 if(address_left
== range
->upper_bound_left
&&
1320 address_right
== range
->upper_bound_right
)
1322 if(++address_right
== 0)
1327 range
= (APTR
)range
->node
.mln_Succ
;
1330 /* Turn promiscuous mode on or off depending on the previous state and
1331 whether we've overflowed the multicast list */
1333 if((unit
->flags
& UNITF_PROM
) == 0)
1337 if((unit
->flags
& UNITF_ALLMCAST
) == 0)
1339 P2SetWord(unit
, P2_REC_PROMISC
, TRUE
, base
);
1340 unit
->flags
|= UNITF_ALLMCAST
;
1345 if((unit
->flags
& UNITF_ALLMCAST
) != 0)
1347 P2SetWord(unit
, P2_REC_PROMISC
, FALSE
, base
);
1348 unit
->flags
&= ~UNITF_ALLMCAST
;
1351 /* Only commit multicast list if promiscuity is off */
1353 P2Seek(unit
, 1, P2_REC_MCASTLIST
, 0, base
);
1354 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
,
1355 1 + ETH_ADDRESSSIZE
/ 2 * i
);
1356 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, P2_REC_MCASTLIST
);
1357 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
, P2_REC_MCASTLIST
,
1367 /****i* prism2.device/FindTypeStats ****************************************
1373 * stats = FindTypeStats(unit, list,
1376 * struct TypeStats *FindTypeStats(struct DevUnit *, struct MinList *,
1379 ****************************************************************************
1383 struct TypeStats
*FindTypeStats(struct DevUnit
*unit
, struct MinList
*list
,
1384 ULONG packet_type
, struct DevBase
*base
)
1386 struct TypeStats
*stats
, *tail
;
1389 stats
= (APTR
)list
->mlh_Head
;
1390 tail
= (APTR
)&list
->mlh_Tail
;
1392 while(stats
!= tail
&& !found
)
1394 if(stats
->packet_type
== packet_type
)
1397 stats
= (APTR
)stats
->node
.mln_Succ
;
1408 /****i* prism2.device/FlushUnit ********************************************
1414 * FlushUnit(unit, last_queue, error)
1416 * VOID FlushUnit(struct DevUnit *, UBYTE, BYTE);
1418 ****************************************************************************
1422 VOID
FlushUnit(struct DevUnit
*unit
, UBYTE last_queue
, BYTE error
,
1423 struct DevBase
*base
)
1425 struct IORequest
*request
;
1427 struct Opener
*opener
, *tail
;
1429 /* Abort queued requests */
1431 for(i
= 0; i
<= last_queue
; i
++)
1433 while((request
= (APTR
)GetMsg(unit
->request_ports
[i
])) != NULL
)
1435 request
->io_Error
= error
;
1436 ReplyMsg((APTR
)request
);
1441 opener
= (APTR
)unit
->openers
.mlh_Head
;
1442 tail
= (APTR
)&unit
->openers
.mlh_Tail
;
1444 /* Flush every opener's read queue */
1446 while(opener
!= tail
)
1448 while((request
= (APTR
)GetMsg(&opener
->read_port
)) != NULL
)
1450 request
->io_Error
= error
;
1451 ReplyMsg((APTR
)request
);
1453 opener
= (APTR
)opener
->node
.mln_Succ
;
1457 opener
= request
->ios2_BufferManagement
;
1458 while((request
= (APTR
)GetMsg(&opener
->read_port
)) != NULL
)
1460 request
->io_Error
= error
;
1461 ReplyMsg((APTR
)request
);
1472 /****i* prism2.device/StatusInt ********************************************
1478 * finished = StatusInt(unit)
1480 * BOOL StatusInt(struct DevUnit *);
1490 ****************************************************************************
1492 * int_code is really in A5, but GCC 2.95.3 doesn't seem able to handle that.
1493 * Since we don't use this parameter, we can lie.
1497 BOOL
StatusInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
))
1499 struct DevBase
*base
;
1500 UWORD events
, int_mask
;
1502 base
= unit
->device
;
1503 events
= unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
);
1505 /* Turning off ints acknowledges the request? */
1507 int_mask
= unit
->LEWordIn(unit
->card
, P2_REG_INTMASK
);
1508 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, 0);
1512 if((events
& P2_EVENTF_INFO
) != 0)
1514 int_mask
&= ~P2_EVENTF_INFO
;
1515 Cause(&unit
->info_int
);
1517 if((events
& P2_EVENTF_RX
) != 0)
1519 int_mask
&= ~P2_EVENTF_RX
;
1520 Cause(&unit
->rx_int
);
1522 if((events
& P2_EVENTF_ALLOCMEM
) != 0)
1524 unit
->tx_frame_id
= unit
->LEWordIn(unit
->card
, P2_REG_ALLOCFID
);
1525 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_ALLOCMEM
);
1526 Cause(&unit
->tx_int
);
1528 if((events
& P2_EVENTF_TXFAIL
) != 0)
1530 ReportEvents(unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_TX
,
1532 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_TXFAIL
);
1536 int_mask
= INT_MASK
;
1538 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, int_mask
);
1545 /****i* prism2.device/RXInt ************************************************
1548 * RXInt -- Soft interrupt for packet reception.
1553 * VOID RXInt(struct DevUnit *);
1558 * unit - A unit of this device.
1563 ****************************************************************************
1567 static VOID
RXInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
))
1569 UWORD frame_status
, frame_id
, ieee_length
, frame_control
, frame_type
,
1570 frame_subtype
, encryption
, key_no
, buffer_no
, old_length
;
1571 struct DevBase
*base
;
1574 UBYTE
*buffer
, *p
, *frame
, *data
;
1576 base
= unit
->device
;
1578 while((unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
) & P2_EVENTF_RX
) != 0)
1581 frame_id
= unit
->LEWordIn(unit
->card
, P2_REG_RXFID
);
1582 P2Seek(unit
, 1, frame_id
, P2_FRM_STATUS
, base
);
1583 frame_status
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
1585 if((frame_status
& (P2_FRM_STATUSF_BADCRYPT
| P2_FRM_STATUSF_BADCRC
))
1588 /* Read frame descriptor from card */
1590 P2Seek(unit
, 1, frame_id
, 0, base
);
1591 unit
->WordsIn(unit
->card
, P2_REG_DATA1
,
1592 (UWORD
*)unit
->rx_descriptor
,
1593 (unit
->ethernet_offset
+ ETH_HEADERSIZE
) / 2);
1594 frame
= unit
->rx_descriptor
+ unit
->ethernet_offset
;
1595 ieee_length
= BEWord(*(UWORD
*)(frame
+ ETH_PACKET_IEEELEN
));
1596 data
= frame
+ ETH_PACKET_DATA
;
1597 unit
->WordsIn(unit
->card
, P2_REG_DATA1
, (UWORD
*)data
,
1598 (ieee_length
+ MIC_SIZE
+ 1) / 2);
1600 LEWord(*(UWORD
*)(unit
->rx_descriptor
+ P2_FRM_HEADER
));
1602 /* Get buffer to store fragment in */
1604 frag_no
= LEWord(*(UWORD
*)(unit
->rx_descriptor
+ P2_FRM_HEADER
1605 + WIFI_FRM_SEQCONTROL
));
1606 buffer
= GetRXBuffer(unit
, frame
+ ETH_PACKET_SOURCE
, frag_no
,
1609 /* Get location to put new data */
1613 if((frag_no
& 0xf ) > 0)
1614 old_length
= BEWord(*(UWORD
*)(buffer
+ ETH_PACKET_IEEELEN
));
1617 /* Copy header to new frame */
1619 CopyMem(frame
, buffer
, ETH_HEADERSIZE
);
1622 p
= buffer
+ ETH_HEADERSIZE
+ old_length
;
1624 /* Get encryption type and key index */
1626 if((frame_control
& WIFI_FRM_CONTROLF_WEP
) != 0)
1628 key_no
= data
[3] >> 6 & 0x3;
1629 encryption
= unit
->keys
[key_no
].type
;
1632 encryption
= S2ENC_NONE
;
1634 /* Append fragment to frame, decrypting/checking fragment if
1637 is_good
= unit
->fragment_decrypt_functions
[encryption
](unit
,
1638 unit
->rx_descriptor
+ P2_FRM_HEADER
, data
, &ieee_length
, p
,
1641 /* Update length in frame being built with current fragment, or
1642 increment bad frame counter if fragment is bad */
1646 ieee_length
+= old_length
;
1647 *(UWORD
*)(buffer
+ ETH_PACKET_IEEELEN
) =
1648 MakeBEWord(ieee_length
);
1651 unit
->stats
.BadData
++;
1653 /* If all fragments have arrived, process the complete frame */
1655 if((frame_control
& WIFI_FRM_CONTROLF_MOREFRAGS
) == 0)
1659 /* Decrypt complete frame if necessary */
1661 data
= buffer
+ ETH_HEADERSIZE
;
1662 if(encryption
== S2ENC_TKIP
)
1664 /* Hermes cards don't include MIC in frame length, so
1665 we need to grab the MIC from the original RX
1668 if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
1670 CopyMem(frame
+ ETH_PACKET_DATA
+ ieee_length
,
1671 data
+ ieee_length
, MIC_SIZE
);
1672 ieee_length
+= MIC_SIZE
;
1675 /* Check Michael MIC */
1678 is_good
= TKIPDecryptFrame(unit
, buffer
, data
,
1679 ieee_length
, data
, key_no
, base
);
1681 ieee_length
-= MIC_SIZE
;
1682 *(UWORD
*)(buffer
+ ETH_PACKET_IEEELEN
) =
1683 MakeBEWord(ieee_length
);
1685 unit
->stats
.BadData
++;
1691 /* Get frame's 802.11 type and subtype */
1693 frame_type
= (frame_control
& WIFI_FRM_CONTROLF_TYPE
)
1694 >> WIFI_FRM_CONTROLB_TYPE
;
1696 (frame_control
& WIFI_FRM_CONTROLF_SUBTYPE
)
1697 >> WIFI_FRM_CONTROLB_SUBTYPE
;
1699 /* If it's a management frame, process it internally;
1700 otherwise distribute it to clients after filtering */
1702 if(frame_type
== WIFI_FRMTYPE_MGMT
)
1704 if(frame_subtype
== 0x5)
1706 CopyMem(unit
->rx_descriptor
+ P2_FRM_HEADER
1707 + WIFI_FRM_ADDRESS3
, buffer
+ ETH_PACKET_SOURCE
,
1709 SaveBeacon(unit
, buffer
, base
);
1712 else if(AddressFilter(unit
, buffer
+ ETH_PACKET_DEST
,
1715 unit
->stats
.PacketsReceived
++;
1716 DistributeRXPacket(unit
, buffer
, base
);
1721 /* Mark fragment buffer as unused for next time */
1723 unit
->rx_fragment_nos
[buffer_no
] = -1;
1726 ReportEvents(unit
, S2EVENT_ERROR
| S2EVENT_RX
, base
);
1735 ReportEvents(unit
, S2EVENT_ERROR
| S2EVENT_HARDWARE
| S2EVENT_RX
,
1739 /* Discard packet */
1741 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_RX
);
1744 /* Re-enable RX interrupts */
1747 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
,
1748 unit
->LEWordIn(unit
->card
, P2_REG_INTMASK
) | P2_EVENTF_RX
);
1756 /****i* prism2.device/GetRXBuffer ******************************************
1759 * GetRXBuffer -- Find an appropriate RX buffer to use.
1762 * buffer = GetRXBuffer(unit, address, frag_no)
1764 * UBYTE *GetRXBuffer(struct DevUnit *, UBYTE *, UWORD);
1766 ****************************************************************************
1770 static UBYTE
*GetRXBuffer(struct DevUnit
*unit
, const UBYTE
*address
,
1771 UWORD frag_no
, UWORD
*buffer_no
, struct DevBase
*base
)
1778 buffer
= unit
->rx_buffers
;
1779 for(i
= 0, found
= FALSE
; i
< RX_BUFFER_COUNT
* 2 && !found
; i
++)
1781 /* Throw away old buffer contents if we didn't find a free slot the
1782 first time around */
1784 if(i
>= RX_BUFFER_COUNT
)
1785 unit
->rx_fragment_nos
[i
% RX_BUFFER_COUNT
] = -1;
1787 /* For a frame's first fragment, find an empty slot; for subsequent
1788 fragments, find a slot with matching source address */
1790 n
= unit
->rx_fragment_nos
[i
% RX_BUFFER_COUNT
];
1791 if(n
== -1 && (frag_no
& 0xf) == 0
1792 || *((ULONG
*)(buffer
+ ETH_PACKET_SOURCE
))
1793 == *((ULONG
*)(address
))
1794 && *((UWORD
*)(buffer
+ ETH_PACKET_SOURCE
+ 4))
1795 == *((UWORD
*)(address
+ 4)))
1799 unit
->rx_fragment_nos
[i
% RX_BUFFER_COUNT
] = frag_no
;
1803 buffer
+= FRAME_BUFFER_SIZE
;
1814 /****i* prism2.device/DistributeRXPacket ***********************************
1817 * DistributeRXPacket -- Send a packet to all appropriate destinations.
1820 * DistributeRXPacket(unit, frame)
1822 * VOID DistributeRXPacket(struct DevUnit *, UBYTE *);
1824 ****************************************************************************
1828 static VOID
DistributeRXPacket(struct DevUnit
*unit
, UBYTE
*frame
,
1829 struct DevBase
*base
)
1831 UWORD packet_size
, ieee_length
;
1832 BOOL is_orphan
= TRUE
, accepted
, is_snap
= FALSE
;
1835 const UBYTE
*template = snap_template
;
1836 struct IOSana2Req
*request
, *request_tail
;
1837 struct Opener
*opener
, *opener_tail
;
1838 struct TypeStats
*tracker
;
1840 ieee_length
= BEWord(*(UWORD
*)(frame
+ ETH_PACKET_IEEELEN
));
1841 packet_size
= ETH_HEADERSIZE
+ ieee_length
;
1842 if(ieee_length
>= SNAP_HEADERSIZE
)
1843 is_snap
= *(const ULONG
*)(frame
+ ETH_PACKET_DATA
)
1844 == *(const ULONG
*)template;
1846 /* De-encapsulate SNAP packets and get packet type */
1850 buffer
= unit
->rx_buffer
;
1851 packet_size
-= SNAP_HEADERSIZE
;
1852 CopyMem(frame
, buffer
, ETH_PACKET_TYPE
);
1853 CopyMem(frame
+ ETH_HEADERSIZE
+ SNAP_FRM_TYPE
,
1854 buffer
+ ETH_PACKET_TYPE
, packet_size
- ETH_PACKET_TYPE
);
1859 packet_type
= BEWord(*((UWORD
*)(buffer
+ ETH_PACKET_TYPE
)));
1861 if(packet_size
<= ETH_MAXPACKETSIZE
)
1863 /* Offer packet to every opener */
1865 opener
= (APTR
)unit
->openers
.mlh_Head
;
1866 opener_tail
= (APTR
)&unit
->openers
.mlh_Tail
;
1868 while(opener
!= opener_tail
)
1870 request
= (APTR
)opener
->read_port
.mp_MsgList
.lh_Head
;
1871 request_tail
= (APTR
)&opener
->read_port
.mp_MsgList
.lh_Tail
;
1874 /* Offer packet to each request until it's accepted */
1876 while(request
!= request_tail
&& !accepted
)
1878 if(request
->ios2_PacketType
== packet_type
)
1880 CopyPacket(unit
, request
, packet_size
, packet_type
,
1885 (APTR
)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
1890 opener
= (APTR
)opener
->node
.mln_Succ
;
1893 /* If packet was unwanted, give it to S2_READORPHAN request */
1897 unit
->stats
.UnknownTypesReceived
++;
1898 if(!IsMsgPortEmpty(unit
->request_ports
[ADOPT_QUEUE
]))
1901 (APTR
)unit
->request_ports
[ADOPT_QUEUE
]->
1902 mp_MsgList
.lh_Head
, packet_size
, packet_type
, buffer
,
1907 /* Update remaining statistics */
1909 if(packet_type
<= ETH_MTU
)
1910 packet_type
= ETH_MTU
;
1912 FindTypeStats(unit
, &unit
->type_trackers
, packet_type
, base
);
1915 tracker
->stats
.PacketsReceived
++;
1916 tracker
->stats
.BytesReceived
+= packet_size
;
1920 unit
->stats
.BadData
++;
1927 /****i* prism2.device/CopyPacket *******************************************
1930 * CopyPacket -- Copy packet to client's buffer.
1933 * CopyPacket(unit, request, packet_size, packet_type,
1936 * VOID CopyPacket(struct DevUnit *, struct IOSana2Req *, UWORD, UWORD,
1939 ****************************************************************************
1943 static VOID
CopyPacket(struct DevUnit
*unit
, struct IOSana2Req
*request
,
1944 UWORD packet_size
, UWORD packet_type
, UBYTE
*buffer
,
1945 struct DevBase
*base
)
1947 struct Opener
*opener
;
1948 BOOL filtered
= FALSE
;
1950 /* Set multicast and broadcast flags */
1952 request
->ios2_Req
.io_Flags
&= ~(SANA2IOF_BCAST
| SANA2IOF_MCAST
);
1953 if((*((ULONG
*)(buffer
+ ETH_PACKET_DEST
)) == 0xffffffff) &&
1954 (*((UWORD
*)(buffer
+ ETH_PACKET_DEST
+ 4)) == 0xffff))
1955 request
->ios2_Req
.io_Flags
|= SANA2IOF_BCAST
;
1956 else if((buffer
[ETH_PACKET_DEST
] & 0x1) != 0)
1957 request
->ios2_Req
.io_Flags
|= SANA2IOF_MCAST
;
1959 /* Set source and destination addresses and packet type */
1961 CopyMem(buffer
+ ETH_PACKET_SOURCE
, request
->ios2_SrcAddr
,
1963 CopyMem(buffer
+ ETH_PACKET_DEST
, request
->ios2_DstAddr
,
1965 request
->ios2_PacketType
= packet_type
;
1967 /* Adjust for cooked packet request */
1969 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) == 0)
1971 packet_size
-= ETH_PACKET_DATA
;
1972 buffer
+= ETH_PACKET_DATA
;
1976 packet_size
+= 4; /* Needed for Shapeshifter & Fusion */
1978 request
->ios2_DataLength
= packet_size
;
1982 opener
= request
->ios2_BufferManagement
;
1983 if(request
->ios2_Req
.io_Command
== CMD_READ
&&
1984 opener
->filter_hook
!= NULL
)
1985 if(!CallHookPkt(opener
->filter_hook
, request
, buffer
))
1990 /* Copy packet into opener's buffer and reply packet */
1992 if(!opener
->rx_function(request
->ios2_Data
, buffer
, packet_size
))
1994 request
->ios2_Req
.io_Error
= S2ERR_NO_RESOURCES
;
1995 request
->ios2_WireError
= S2WERR_BUFF_ERROR
;
1997 S2EVENT_ERROR
| S2EVENT_SOFTWARE
| S2EVENT_BUFF
| S2EVENT_RX
,
2000 Remove((APTR
)request
);
2001 ReplyMsg((APTR
)request
);
2009 /****i* prism2.device/AddressFilter ****************************************
2012 * AddressFilter -- Determine if an RX packet should be accepted.
2015 * accept = AddressFilter(unit, address)
2017 * BOOL AddressFilter(struct DevUnit *, UBYTE *);
2019 ****************************************************************************
2023 static BOOL
AddressFilter(struct DevUnit
*unit
, UBYTE
*address
,
2024 struct DevBase
*base
)
2026 struct AddressRange
*range
, *tail
;
2029 UWORD address_right
;
2031 /* Check whether address is unicast/broadcast or multicast */
2033 address_left
= BELong(*((ULONG
*)address
));
2034 address_right
= BEWord(*((UWORD
*)(address
+ 4)));
2036 if(((address_left
& 0x01000000) != 0) &&
2037 !((address_left
== 0xffffffff) && (address_right
== 0xffff)))
2039 /* Check if this multicast address is wanted */
2041 range
= (APTR
)unit
->multicast_ranges
.mlh_Head
;
2042 tail
= (APTR
)&unit
->multicast_ranges
.mlh_Tail
;
2045 while((range
!= tail
) && !accept
)
2047 if((address_left
> range
->lower_bound_left
||
2048 address_left
== range
->lower_bound_left
&&
2049 address_right
>= range
->lower_bound_right
) &&
2050 (address_left
< range
->upper_bound_left
||
2051 address_left
== range
->upper_bound_left
&&
2052 address_right
<= range
->upper_bound_right
))
2054 range
= (APTR
)range
->node
.mln_Succ
;
2058 unit
->special_stats
[S2SS_ETHERNET_BADMULTICAST
& 0xffff]++;
2066 /****i* prism2.device/SaveBeacon *******************************************
2069 * SaveBeacon -- Save beacon frame for later examination.
2072 * SaveBeacon(unit, frame)
2074 * VOID SaveBeacon(struct DevUnit *, UBYTE *);
2076 ****************************************************************************
2080 static VOID
SaveBeacon(struct DevUnit
*unit
, const UBYTE
*frame
,
2081 struct DevBase
*base
)
2085 /* Store frame for later matching with scan results */
2087 size
= ETH_HEADERSIZE
+ BEWord(*(UWORD
*)(frame
+ ETH_PACKET_IEEELEN
));
2088 if(unit
->next_beacon
+ size
< unit
->beacons
+ BEACON_BUFFER_SIZE
)
2090 CopyMem(frame
, unit
->next_beacon
, size
);
2091 unit
->beacon_count
++;
2092 unit
->next_beacon
+= size
+ sizeof(ULONG
) & ~3;
2100 /****i* prism2.device/TXInt ************************************************
2103 * TXInt -- Soft interrupt for packet transmission.
2108 * VOID TXInt(struct DevUnit *);
2113 * unit - A unit of this device.
2118 ****************************************************************************
2122 static VOID
TXInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
))
2124 UWORD i
, packet_size
, send_size
, packet_type
, data_size
, body_size
= 0,
2125 frame_id
, encryption
, control_value
, subtype
;
2126 UBYTE
*buffer
, *desc
= unit
->tx_descriptor
, *plaintext
, *ciphertext
,
2127 *header
, mic_header
[ETH_ADDRESSSIZE
* 2], *q
;
2128 const UBYTE
*p
, *dest
, *source
;
2129 struct DevBase
*base
;
2130 struct IOSana2Req
*request
;
2132 struct Opener
*opener
;
2134 UBYTE
*(*dma_tx_function
)(REG(a0
, APTR
));
2136 struct MsgPort
*port
;
2137 struct TypeStats
*tracker
;
2139 base
= unit
->device
;
2140 port
= unit
->request_ports
[WRITE_QUEUE
];
2142 if(unit
->tx_frame_id
!= 0 && !IsMsgPortEmpty(port
))
2144 /* Get next request and full packet size */
2146 request
= (APTR
)port
->mp_MsgList
.lh_Head
;
2147 packet_size
= request
->ios2_DataLength
;
2148 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) == 0)
2149 packet_size
+= ETH_PACKET_DATA
;
2151 /* Determine encryption type and frame subtype */
2153 if(packet_size
> ETH_HEADERSIZE
)
2155 encryption
= unit
->keys
[unit
->tx_key_no
].type
;
2160 encryption
= S2ENC_NONE
;
2164 /* Get packet data */
2166 opener
= request
->ios2_BufferManagement
;
2167 dma_tx_function
= opener
->dma_tx_function
;
2168 if(dma_tx_function
!= NULL
)
2169 buffer
= dma_tx_function(request
->ios2_Data
);
2175 buffer
= unit
->tx_buffer
;
2176 if(!opener
->tx_function(buffer
, request
->ios2_Data
,
2177 request
->ios2_DataLength
))
2179 error
= S2ERR_NO_RESOURCES
;
2180 wire_error
= S2WERR_BUFF_ERROR
;
2182 S2EVENT_ERROR
| S2EVENT_SOFTWARE
| S2EVENT_BUFF
| S2EVENT_TX
,
2189 /* Get packet type and/or length */
2191 data_size
= request
->ios2_DataLength
;
2192 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) != 0)
2194 data_size
-= ETH_PACKET_DATA
;
2195 packet_type
= BEWord(*(UWORD
*)(buffer
+ ETH_PACKET_TYPE
));
2198 packet_type
= request
->ios2_PacketType
;
2199 is_ieee
= packet_type
<= ETH_MTU
;
2201 /* Get source and destination addresses */
2203 if((request
->ios2_Req
.io_Flags
& SANA2IOF_RAW
) != 0)
2206 source
= buffer
+ ETH_ADDRESSSIZE
;
2207 buffer
+= ETH_ADDRESSSIZE
* 2 + 2;
2211 dest
= request
->ios2_DstAddr
;
2212 source
= unit
->address
;
2215 /* Clear frame descriptor as far as start of 802.11 header */
2218 for(i
= 0; i
< P2_FRM_HEADER
; i
++)
2222 /* Set TX control field */
2224 control_value
= P2_FRM_TXCONTROLF_NATIVE
;
2225 if(encryption
== S2ENC_TKIP
&& (unit
->flags
& UNITF_HARDTKIP
) != 0)
2226 control_value
|= unit
->tx_key_no
<< P2_FRM_TXCONTROLB_MICKEYID
2227 | P2_FRM_TXCONTROLF_MIC
;
2228 else if(encryption
== S2ENC_NONE
2229 && unit
->firmware_type
< LUCENT_FIRMWARE
)
2230 control_value
|= P2_FRM_TXCONTROLF_NOENC
;
2232 *(UWORD
*)(desc
+ unit
->txcontrol_offset
) =
2233 MakeLEWord(control_value
);
2235 /* Write 802.11 header */
2237 *(UWORD
*)q
= MakeLEWord(
2238 (encryption
== S2ENC_NONE
? 0 : WIFI_FRM_CONTROLF_WEP
)
2239 | (unit
->mode
== S2PORT_ADHOC
? 0 : WIFI_FRM_CONTROLF_TODS
)
2240 | subtype
<< WIFI_FRM_CONTROLB_SUBTYPE
2241 | WIFI_FRMTYPE_DATA
<< WIFI_FRM_CONTROLB_TYPE
);
2247 if(unit
->mode
== S2PORT_ADHOC
)
2251 for(i
= 0; i
< ETH_ADDRESSSIZE
; i
++)
2254 for(i
= 0, p
= source
; i
< ETH_ADDRESSSIZE
; i
++)
2257 if(unit
->mode
== S2PORT_ADHOC
)
2261 for(i
= 0; i
< ETH_ADDRESSSIZE
; i
++)
2265 /* Clear 802.3 header */
2267 q
= desc
+ unit
->ethernet_offset
;
2268 for(i
= 0; i
< ETH_HEADERSIZE
; i
++)
2271 /* Leave room for encryption overhead */
2273 q
= desc
+ unit
->data_offset
;
2275 q
+= unit
->iv_sizes
[encryption
];
2278 /* Write SNAP header */
2282 for(i
= 0, p
= snap_template
; i
< SNAP_FRM_TYPE
; i
++)
2284 *(UWORD
*)q
= MakeBEWord(packet_type
);
2286 body_size
+= SNAP_HEADERSIZE
;
2289 /* Copy data into frame */
2291 CopyMem(buffer
, q
, data_size
);
2292 body_size
+= data_size
;
2294 /* Append MIC to frame for TKIP */
2296 if(encryption
== S2ENC_TKIP
)
2299 for(i
= 0, p
= dest
; i
< ETH_ADDRESSSIZE
; i
++)
2301 for(i
= 0, p
= source
; i
< ETH_ADDRESSSIZE
; i
++)
2303 TKIPEncryptFrame(unit
, mic_header
, plaintext
, body_size
,
2305 body_size
+= MIC_SIZE
;
2308 /* Encrypt fragment if applicable */
2310 unit
->fragment_encrypt_functions
[encryption
](unit
, header
,
2311 plaintext
, &body_size
, ciphertext
, base
);
2313 /* Calculate total length of data to send to adapter */
2315 send_size
= unit
->data_offset
+ body_size
;
2317 /* Fill in length field, adjusting for Hermes peculiarities */
2319 if(unit
->firmware_type
>= LUCENT_FIRMWARE
2320 && encryption
== S2ENC_TKIP
)
2321 body_size
-= MIC_SIZE
;
2323 if(unit
->firmware_type
== LUCENT_FIRMWARE
2324 && (unit
->flags
& UNITF_HARDTKIP
) != 0)
2325 *(UWORD
*)(desc
+ unit
->ethernet_offset
+ ETH_PACKET_IEEELEN
) =
2326 MakeBEWord(body_size
);
2328 *(UWORD
*)(desc
+ unit
->datalen_offset
) = MakeLEWord(body_size
);
2330 /* Write packet to adapter and send */
2332 frame_id
= unit
->tx_frame_id
;
2333 P2Seek(unit
, 0, frame_id
, 0, base
);
2334 unit
->WordsOut(unit
->card
, P2_REG_DATA0
, (UWORD
*)desc
,
2335 (send_size
+ 1) / 2);
2336 unit
->tx_frame_id
= 0;
2337 P2DoCmd(unit
, P2_CMD_TX
| P2_CMDF_RECLAIM
, frame_id
, base
);
2342 request
->ios2_Req
.io_Error
= error
;
2343 request
->ios2_WireError
= wire_error
;
2344 Remove((APTR
)request
);
2345 ReplyMsg((APTR
)request
);
2347 /* Update statistics */
2351 unit
->stats
.PacketsSent
++;
2353 tracker
= FindTypeStats(unit
, &unit
->type_trackers
,
2354 request
->ios2_PacketType
, base
);
2357 tracker
->stats
.PacketsSent
++;
2358 tracker
->stats
.BytesSent
+= packet_size
;
2363 /* Don't try to keep sending packets if there's no space left */
2365 if(unit
->tx_frame_id
!= 0)
2366 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_SOFTINT
;
2368 unit
->request_ports
[WRITE_QUEUE
]->mp_Flags
= PA_IGNORE
;
2375 /****i* prism2.device/UpdateStats ******************************************
2383 * VOID UpdateStats(struct DevUnit *);
2388 * unit - A unit of this device.
2393 ****************************************************************************
2397 VOID
UpdateStats(struct DevUnit
*unit
, struct DevBase
*base
)
2399 /* Ask for and wait for stats */
2401 if((unit
->flags
& UNITF_ONLINE
) != 0)
2404 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
,
2405 unit
->LEWordIn(unit
->card
, P2_REG_INTMASK
) & ~P2_EVENTF_INFO
);
2407 P2DoCmd(unit
, P2_CMD_INQUIRE
, P2_INFO_COUNTERS
, base
);
2408 while((unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
) & P2_EVENTF_INFO
)
2410 Cause(&unit
->info_int
);
2418 /****i* prism2.device/InfoInt **********************************************
2426 * VOID InfoInt(struct DevUnit *);
2431 * unit - A unit of this device.
2437 * The only reason this is a (soft) interrupt is so that it won't
2438 * interfere with RXInt() by interrupting it. This would be dangerous
2439 * because they use the same data channel.
2441 ****************************************************************************
2445 static VOID
InfoInt(REG(a1
, struct DevUnit
*unit
), REG(a6
, APTR int_code
))
2447 struct DevBase
*base
;
2448 UWORD id
, length
, rec_length
, status
, ies_length
, data_length
,
2449 ssid_length
, *ap_rec
;
2450 UBYTE
*ie
, *ssid
, *descriptor
, *frame
, *data
, *bssid
= unit
->bssid
;
2453 base
= unit
->device
;
2454 id
= unit
->LEWordIn(unit
->card
, P2_REG_INFOFID
);
2456 P2Seek(unit
, 1, id
, 0, base
);
2457 length
= (unit
->LEWordIn(unit
->card
, P2_REG_DATA1
) + 1) * 2;
2459 switch(unit
->LEWordIn(unit
->card
, P2_REG_DATA1
))
2461 case P2_INFO_COUNTERS
:
2463 /* Read useful stats and skip others */
2465 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2466 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2468 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2469 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2470 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2471 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2473 unit
->special_stats
[S2SS_ETHERNET_RETRIES
& 0xffff] +=
2474 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
) +
2475 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
) +
2476 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2478 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2480 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2481 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2483 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2484 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2485 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2487 unit
->stats
.BadData
+= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2488 unit
->stats
.Overruns
+= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2490 unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2492 unit
->stats
.BadData
+= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2496 case P2_INFO_SCANRESULTS
:
2497 case P2_INFO_HOSTSCANRESULTS
:
2499 P2ReadRec(unit
, id
, unit
->scan_results_rec
, SCAN_BUFFER_SIZE
, base
);
2500 Signal(unit
->task
, unit
->scan_complete_signal
);
2503 case P2_INFO_SCANRESULT
:
2505 descriptor
= unit
->rx_descriptor
;
2506 P2ReadRec(unit
, id
, descriptor
, FRAME_BUFFER_SIZE
, base
);
2509 /* Save IEEE 802.3 portion of scan result */
2511 frame
= descriptor
+ unit
->ethernet_offset
;
2512 data
= frame
+ ETH_PACKET_DATA
;
2513 CopyMem(descriptor
+ P2_FRM_HEADER
+ WIFI_FRM_ADDRESS3
,
2514 frame
+ ETH_PACKET_SOURCE
, ETH_ADDRESSSIZE
);
2516 LEWord(*(UWORD
*)(descriptor
+ unit
->datalen_offset
));
2517 ies_length
= data_length
- WIFI_BEACON_IES
;
2518 *(UWORD
*)(frame
+ ETH_PACKET_IEEELEN
) = MakeBEWord(data_length
);
2519 SaveBeacon(unit
, frame
, base
);
2521 /* Append a fake old-style scan record on to fake record list */
2523 rec_length
= LEWord(unit
->scan_results_rec
[0]);
2525 if(2 + rec_length
* 2 + P2_APRECLEN
< SCAN_BUFFER_SIZE
)
2527 ap_rec
= unit
->scan_results_rec
+ 1 + rec_length
;
2528 CopyMem(frame
+ ETH_PACKET_SOURCE
, ap_rec
+ P2_APREC_BSSID
/ 2,
2531 ap_rec
[P2_APREC_SIGNAL
/ 2] =
2532 MakeLEWord(descriptor
[P2_FRM_SIGNAL
]);
2534 ap_rec
[P2_APREC_NOISE
/ 2] =
2535 MakeLEWord(descriptor
[P2_FRM_NOISE
]);
2537 ap_rec
[P2_APREC_CHANNEL
/ 2] = MakeLEWord(GetIE(WIFI_IE_CHANNEL
,
2538 data
+ WIFI_BEACON_IES
, ies_length
, base
)[2]);
2540 ap_rec
[P2_APREC_INTERVAL
/ 2] =
2541 *(UWORD
*)(data
+ WIFI_BEACON_INTERVAL
);
2543 ap_rec
[P2_APREC_CAPABILITIES
/ 2] =
2544 *(UWORD
*)(data
+ WIFI_BEACON_CAPABILITIES
);
2546 ie
= GetIE(WIFI_IE_SSID
, data
+ WIFI_BEACON_IES
, ies_length
,
2548 ssid_length
= ie
[1];
2550 ap_rec
[P2_APREC_NAMELEN
/ 2] = MakeLEWord(ssid_length
);
2551 CopyMem(ssid
, ap_rec
+ P2_APREC_NAME
/ 2, ssid_length
);
2553 unit
->scan_results_rec
[0] =
2554 MakeLEWord(rec_length
+ P2_APRECLEN
/ 2);
2558 Signal(unit
->task
, unit
->scan_complete_signal
);
2561 case P2_INFO_LINKSTATUS
:
2563 /* Only report an event if association status has really changed */
2565 status
= unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
2567 if(status
== 1 || unit
->firmware_type
< LUCENT_FIRMWARE
2570 else //if(unit->firmware_type < LUCENT_FIRMWARE || status == 3)
2573 if(!(*(ULONG
*)bssid
== 0 && *(UWORD
*)(bssid
+ 4) == 0))
2575 if(associated
&& (unit
->flags
& UNITF_ASSOCIATED
) == 0)
2577 unit
->flags
|= UNITF_ASSOCIATED
;
2578 ReportEvents(unit
, S2EVENT_CONNECT
, base
);
2580 else if(!associated
&& (unit
->flags
& UNITF_ASSOCIATED
) != 0)
2582 unit
->flags
&= ~UNITF_ASSOCIATED
;
2583 ReportEvents(unit
, S2EVENT_DISCONNECT
, base
);
2588 /* Acknowledge event and re-enable info interrupts */
2590 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_INFO
);
2592 if((unit
->flags
& UNITF_ONLINE
) != 0)
2593 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
,
2594 unit
->LEWordIn(unit
->card
, P2_REG_INTMASK
) | P2_EVENTF_INFO
);
2602 /****i* prism2.device/ResetHandler *****************************************
2605 * ResetHandler -- Disable hardware before a reboot.
2608 * ResetHandler(unit, int_code)
2610 * VOID ResetHandler(struct DevUnit *, APTR);
2612 ****************************************************************************
2616 static VOID
ResetHandler(REG(a1
, struct DevUnit
*unit
),
2617 REG(a6
, APTR int_code
))
2619 if((unit
->flags
& UNITF_HAVEADAPTER
) != 0)
2621 /* Stop interrupts */
2623 unit
->LEWordOut(unit
->card
, P2_REG_INTMASK
, 0);
2625 /* Stop transmission and reception */
2627 unit
->LEWordOut(unit
->card
, P2_REG_PARAM0
, 0);
2628 unit
->LEWordOut(unit
->card
, P2_REG_COMMAND
, P2_CMD_DISABLE
);
2636 /****i* prism2.device/ReportEvents *****************************************
2642 * ReportEvents(unit, events)
2644 * VOID ReportEvents(struct DevUnit *, ULONG);
2649 * unit - A unit of this device.
2650 * events - A mask of events to report.
2655 ****************************************************************************
2659 static VOID
ReportEvents(struct DevUnit
*unit
, ULONG events
,
2660 struct DevBase
*base
)
2662 struct IOSana2Req
*request
, *tail
, *next_request
;
2665 list
= &unit
->request_ports
[EVENT_QUEUE
]->mp_MsgList
;
2666 next_request
= (APTR
)list
->lh_Head
;
2667 tail
= (APTR
)&list
->lh_Tail
;
2670 while(next_request
!= tail
)
2672 request
= next_request
;
2673 next_request
= (APTR
)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
2675 if((request
->ios2_WireError
& events
) != 0)
2677 request
->ios2_WireError
= events
;
2678 Remove((APTR
)request
);
2679 ReplyMsg((APTR
)request
);
2689 /****i* prism2.device/SendScanResults **************************************
2692 * SendScanResults -- Reply to all outstanding scan requests.
2695 * SendScanResults(unit)
2697 * VOID SendScanResults(struct DevUnit *);
2702 * unit - A unit of this device.
2707 ****************************************************************************
2711 static VOID
SendScanResults(struct DevUnit
*unit
, struct DevBase
*base
)
2714 struct IOSana2Req
*request
, *tail
, *next_request
;
2717 UWORD count
, i
, j
, ssid_length
, length
, entry_length
, *ap_rec
,
2718 data_length
, frame_length
, ies_length
;
2719 struct TagItem
**tag_lists
, *tag
;
2721 const UBYTE
*beacon
, *ie_bssid
;
2724 list
= &unit
->request_ports
[SCAN_QUEUE
]->mp_MsgList
;
2725 next_request
= (APTR
)list
->lh_Head
;
2726 tail
= (APTR
)&list
->lh_Tail
;
2728 while(next_request
!= tail
)
2730 request
= next_request
;
2731 next_request
= (APTR
)request
->ios2_Req
.io_Message
.mn_Node
.ln_Succ
;
2733 pool
= request
->ios2_Data
;
2735 length
= LEWord(unit
->scan_results_rec
[0]);
2736 ap_rec
= unit
->scan_results_rec
+ 2;
2738 if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
2740 entry_length
= LEWord(unit
->scan_results_rec
[2]);
2742 count
= (length
- 3) * 2 / entry_length
;
2746 entry_length
= P2_APRECLEN
;
2747 count
= (length
- 1) * 2 / entry_length
;
2750 /* Allocate array of tag lists, one for each AP */
2754 tag_lists
= AllocPooled(pool
, count
* sizeof(APTR
));
2755 if(tag_lists
== NULL
)
2756 error
= S2ERR_NO_RESOURCES
;
2761 for(i
= 0; i
< count
&& error
== 0; i
++, ap_rec
+= entry_length
/ 2)
2764 AllocPooled(pool
, SCAN_TAG_COUNT
* sizeof(struct TagItem
));
2765 if(tag_lists
[i
] == NULL
)
2766 error
= S2ERR_NO_RESOURCES
;
2772 tag
->ti_Tag
= S2INFO_BSSID
;
2773 tag
->ti_Data
= (UPINT
)(bssid
=
2774 AllocPooled(pool
, ETH_ADDRESSSIZE
));
2776 CopyMem(ap_rec
+ P2_APREC_BSSID
/ 2, bssid
,
2779 error
= S2ERR_NO_RESOURCES
;
2782 tag
->ti_Tag
= TAG_IGNORE
;
2785 tag
->ti_Tag
= S2INFO_Channel
;
2786 tag
->ti_Data
= LEWord(ap_rec
[P2_APREC_CHANNEL
/ 2]);
2789 tag
->ti_Tag
= S2INFO_BeaconInterval
;
2790 tag
->ti_Data
= LEWord(ap_rec
[P2_APREC_INTERVAL
/ 2]);
2793 tag
->ti_Tag
= S2INFO_Capabilities
;
2794 tag
->ti_Data
= LEWord(ap_rec
[P2_APREC_CAPABILITIES
/ 2]);
2797 tag
->ti_Tag
= S2INFO_Signal
;
2798 tag
->ti_Data
= ConvertScanLevel(unit
,
2799 LEWord(ap_rec
[P2_APREC_SIGNAL
/ 2]), base
);
2802 tag
->ti_Tag
= S2INFO_Noise
;
2803 tag
->ti_Data
= ConvertScanLevel(unit
,
2804 LEWord(ap_rec
[P2_APREC_NOISE
/ 2]), base
);
2808 ssid_length
= LEWord(ap_rec
[P2_APREC_NAMELEN
/ 2]);
2809 tag
->ti_Tag
= S2INFO_SSID
;
2810 tag
->ti_Data
= (UPINT
)(ssid
=
2811 AllocPooled(pool
, 31 + 1));
2814 CopyMem(ap_rec
+ P2_APREC_NAME
/ 2, ssid
, ssid_length
);
2815 ssid
[ssid_length
] = '\0';
2818 error
= S2ERR_NO_RESOURCES
;
2821 tag
->ti_Tag
= TAG_END
;
2825 /* Find IEs for each BSS and insert them into the BSS's tag list */
2827 for(beacon
= unit
->beacons
, i
= 0; i
< unit
->beacon_count
; i
++)
2829 /* Extract IEs from beacon descriptor */
2831 data_length
= BEWord(*(UWORD
*)(beacon
+ ETH_PACKET_IEEELEN
));
2832 ies_length
= data_length
- 12;
2833 frame_length
= ETH_HEADERSIZE
+ data_length
;
2834 ies
= AllocPooled(pool
, sizeof(UWORD
) + ies_length
);
2837 *(UWORD
*)ies
= ies_length
;
2838 CopyMem(beacon
+ ETH_PACKET_DATA
+ WIFI_BEACON_IES
,
2839 ies
+ sizeof(UWORD
), ies_length
);
2842 error
= S2ERR_NO_RESOURCES
;
2844 /* Find matching tag list and add IEs to it */
2846 ie_bssid
= beacon
+ ETH_PACKET_SOURCE
;
2847 for(j
= 0; j
< count
; j
++)
2850 bssid
= (UBYTE
*)tag
->ti_Data
;
2851 if(*(ULONG
*)bssid
== *(ULONG
*)ie_bssid
2852 && *(UWORD
*)(bssid
+ 4) == *(UWORD
*)(ie_bssid
+ 4))
2855 tag
->ti_Tag
= S2INFO_InfoElements
;
2856 tag
->ti_Data
= (PINT
)ies
;
2860 beacon
+= frame_length
+ sizeof(ULONG
) & ~3;
2863 /* Return results */
2867 request
->ios2_StatData
= tag_lists
;
2868 request
->ios2_DataLength
= count
;
2872 request
->ios2_Req
.io_Error
= error
;
2873 request
->ios2_WireError
= S2WERR_GENERIC_ERROR
;
2875 Remove((APTR
)request
);
2876 ReplyMsg((APTR
)request
);
2879 /* Discard collected beacon frames */
2882 unit
->next_beacon
= unit
->beacons
;
2883 unit
->beacon_count
= 0;
2891 /****i* prism2.device/GetNetworkInfo ***************************************
2894 * GetNetworkInfo -- Get information on current network.
2897 * tag_list = GetNetworkInfo(unit, pool)
2899 * struct TagItem *GetNetworkInfo(struct DevUnit *, APTR);
2904 * unit - A unit of this device.
2905 * pool - A memory pool.
2910 ****************************************************************************
2914 struct TagItem
*GetNetworkInfo(struct DevUnit
*unit
, APTR pool
,
2915 struct DevBase
*base
)
2918 struct TagItem
*tag_list
, *tag
;
2922 AllocPooled(pool
, INFO_TAG_COUNT
* sizeof(struct TagItem
));
2923 if(tag_list
== NULL
)
2924 error
= S2ERR_NO_RESOURCES
;
2930 tag
->ti_Tag
= S2INFO_BSSID
;
2931 tag
->ti_Data
= (UPINT
)(bssid
=
2932 AllocPooled(pool
, ETH_ADDRESSSIZE
));
2934 CopyMem(unit
->bssid
, bssid
, ETH_ADDRESSSIZE
);
2936 error
= S2ERR_NO_RESOURCES
;
2939 tag
->ti_Tag
= TAG_IGNORE
;
2942 tag
->ti_Tag
= S2INFO_WPAInfo
;
2943 tag
->ti_Data
= (UPINT
)(ie
=
2944 AllocPooled(pool
, unit
->wpa_ie
[1] + 2));
2946 CopyMem(unit
->wpa_ie
, ie
, unit
->wpa_ie
[1] + 2);
2948 error
= S2ERR_NO_RESOURCES
;
2951 tag
->ti_Tag
= TAG_END
;
2962 /****i* prism2.device/UpdateSignalQuality **********************************
2965 * UpdateSignalQuality -- Read signal quality from card.
2968 * UpdateSignalQuality(unit)
2970 * VOID UpdateSignalQuality(struct DevUnit *);
2975 * unit - A unit of this device.
2980 ****************************************************************************
2984 VOID
UpdateSignalQuality(struct DevUnit
*unit
, struct DevBase
*base
)
2986 P2DoCmd(unit
, P2_CMD_ACCESS
, P2_REC_LINKQUALITY
, base
);
2987 P2Seek(unit
, 1, P2_REC_LINKQUALITY
, 6, base
);
2989 unit
->signal_quality
.SignalLevel
=
2990 ConvertLevel(unit
, unit
->LEWordIn(unit
->card
, P2_REG_DATA1
), base
);
2991 unit
->signal_quality
.NoiseLevel
=
2992 ConvertLevel(unit
, unit
->LEWordIn(unit
->card
, P2_REG_DATA1
), base
);
2999 /****i* prism2.device/StartScan ********************************************
3002 * StartScan -- Start a scan for available networks.
3007 * VOID StartScan(struct DevUnit *);
3012 * unit - A unit of this device.
3017 ****************************************************************************
3021 VOID
StartScan(struct DevUnit
*unit
, const TEXT
*ssid
, struct DevBase
*base
)
3024 UWORD ssid_length
= 0;
3026 /* Ask for a scan */
3028 if((unit
->flags
& UNITF_ONLINE
) != 0)
3031 ssid_length
= StrLen(ssid
);
3032 if(unit
->firmware_type
== INTERSIL_FIRMWARE
)
3034 params
= AllocVec(sizeof(scan_params
) + ssid_length
, MEMF_PUBLIC
);
3037 CopyMem(scan_params
, params
, sizeof(scan_params
));
3039 CopyMem(ssid
, params
+ sizeof(scan_params
), ssid_length
);
3040 params
[4] = ssid_length
;
3041 P2SetData(unit
, P2_REC_HOSTSCAN
, params
,
3042 sizeof(scan_params
) + ssid_length
, base
);
3046 else if(unit
->firmware_type
== SYMBOL_FIRMWARE
)
3047 P2SetWord(unit
, P2_REC_ALTHOSTSCAN
, 0x82, base
);
3048 else if(unit
->firmware_type
>= LUCENT_FIRMWARE
3049 && (unit
->flags
& UNITF_HARDTKIP
) != 0)
3051 /* Initialise fake scan results and ask for a series of raw beacon
3054 unit
->scan_results_rec
[0] = MakeLEWord(1);
3056 P2SetID(unit
, P2_REC_SCANSSID
, ssid
, ssid_length
, base
);
3057 P2SetWord(unit
, P2_REC_SCANCHANNELS
, 0x7fff, base
);
3058 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, 0x3fff);
3059 P2DoCmd(unit
, P2_CMD_INQUIRE
, P2_INFO_SCANRESULT
, base
);
3063 P2SetID(unit
, P2_REC_SCANSSID
, ssid
, ssid_length
, base
);
3064 P2DoCmd(unit
, P2_CMD_INQUIRE
, P2_INFO_SCANRESULTS
, base
);
3073 /****i* prism2.device/LoadFirmware *****************************************
3079 * success = LoadFirmware(unit)
3081 * BOOL LoadFirmware(struct DevUnit *);
3086 * unit - A unit of this device.
3089 * success - Success indicator.
3091 ****************************************************************************
3095 static BOOL
LoadFirmware(struct DevUnit
*unit
, struct DevBase
*base
)
3097 BOOL success
= TRUE
;
3098 const TEXT
*file_name
;
3099 struct FileInfoBlock
*info
= NULL
;
3100 UWORD control_reg
, pdr_no
, *pda
= NULL
, *pdr
, *prod_data
, length
;
3101 ULONG location
, start_address
;
3102 BPTR file
= (BPTR
)NULL
;
3104 TEXT
*buffer
= NULL
;
3108 /* Read firmware file */
3110 switch(unit
->firmware_type
)
3112 case LUCENT_FIRMWARE
:
3113 file_name
= h1_firmware_file_name
;
3115 case HERMES2_FIRMWARE
:
3116 file_name
= h2_firmware_file_name
;
3118 case HERMES2G_FIRMWARE
:
3119 file_name
= h25_firmware_file_name
;
3125 if(file_name
== NULL
)
3130 file
= Open(file_name
, MODE_OLDFILE
);
3131 if(file
== (BPTR
)NULL
)
3137 info
= AllocDosObject(DOS_FIB
, NULL
);
3144 if(!ExamineFH(file
, info
))
3150 buffer
= AllocVec(info
->fib_Size
+ 1, MEMF_ANY
);
3151 data
= AllocVec(MAX_S_REC_SIZE
, MEMF_ANY
);
3152 pda
= AllocVec(LUCENT_PDA_SIZE
, MEMF_ANY
);
3153 if(buffer
== NULL
|| data
== NULL
|| pda
== NULL
)
3159 if(Read(file
, buffer
, info
->fib_Size
) == -1)
3161 buffer
[info
->fib_Size
] = '\0';
3166 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3167 P2DoCmd(unit
, P2_CMD_INIT
| 0x100, 0, base
);
3168 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3169 P2DoCmd(unit
, P2_CMD_INIT
| 0x0, 0, base
);
3170 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3172 /* Enable auxiliary ports */
3174 unit
->LEWordOut(unit
->card
, P2_REG_PARAM0
, 0xfe01);
3175 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, 0xdc23);
3176 unit
->LEWordOut(unit
->card
, P2_REG_PARAM2
, 0xba45);
3178 control_reg
= unit
->LEWordIn(unit
->card
, P2_REG_CONTROL
);
3180 control_reg
& ~P2_REG_CONTROLF_AUX
| P2_REG_CONTROL_ENABLEAUX
;
3181 unit
->LEWordOut(unit
->card
, P2_REG_CONTROL
, control_reg
);
3183 BusyMilliDelay(5, base
);
3185 (unit
->LEWordIn(unit
->card
, P2_REG_CONTROL
) & P2_REG_CONTROLF_AUX
)
3186 != P2_REG_CONTROL_AUXENABLED
);
3188 /* Read Production Data Area from card */
3190 if(unit
->firmware_type
< HERMES2_FIRMWARE
)
3192 location
= LUCENT_PDA_ADDRESS
;
3193 unit
->LEWordOut(unit
->card
, P2_REG_AUXPAGE
, location
>> 7);
3194 unit
->LEWordOut(unit
->card
, P2_REG_AUXOFFSET
,
3195 location
& (1 << 7) - 1);
3197 unit
->WordsIn(unit
->card
, P2_REG_AUXDATA
,
3198 (UWORD
*)pda
, LUCENT_PDA_SIZE
>> 1);
3201 /* Allow writing to card's RAM */
3203 BusyMilliDelay(100, base
);
3204 start_address
= 0xf8000;
3205 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, start_address
>> 16);
3206 P2DoCmd(unit
, P2_CMD_PROGRAM
| P2_CMDF_WRITE
, start_address
, base
);
3208 /* Parse firmware image data and write it to card */
3213 p
= ParseNextSRecord(p
, &type
, data
, &length
, &location
, base
);
3220 /* Check that this is not a "special" record */
3222 if(location
< 0xff000000)
3224 /* Write data to card */
3226 if(unit
->firmware_type
< LUCENT_FIRMWARE
)
3228 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
,
3230 P2DoCmd(unit
, P2_CMD_PROGRAM
| P2_CMDF_WRITE
, location
,
3234 unit
->LEWordOut(unit
->card
, P2_REG_AUXPAGE
,
3236 unit
->LEWordOut(unit
->card
, P2_REG_AUXOFFSET
,
3237 location
& (1 << 7) - 1);
3239 unit
->WordsOut(unit
->card
, P2_REG_AUXDATA
,
3240 (UWORD
*)data
, length
>> 1);
3246 /* Get location in card memory to begin execution of new
3249 start_address
= location
;
3254 /* Parse PDA plug records and patch firmware */
3259 p
= ParseNextSRecord(p
, &type
, data
, &length
, &location
, base
);
3261 if(p
!= NULL
&& type
== '3' && location
== 0xff000000)
3263 /* Get PDR number and the location where it should be patched
3266 pdr_no
= LELong(*(ULONG
*)data
);
3267 location
= LELong(*(ULONG
*)(data
+ 4));
3268 length
= LELong(*(ULONG
*)(data
+ 8));
3270 /* Find PDR to copy data from */
3273 for(pdr
= pda
; pdr
[1] != 0; pdr
+= LEWord(pdr
[0]) + 1)
3275 if(LEWord(pdr
[1]) == pdr_no
)
3276 prod_data
= pdr
+ 2;
3279 /* Write production data to card if it was found */
3281 if(prod_data
!= NULL
)
3283 if(unit
->firmware_type
< LUCENT_FIRMWARE
)
3285 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
,
3287 P2DoCmd(unit
, P2_CMD_PROGRAM
| P2_CMDF_WRITE
, location
,
3291 unit
->LEWordOut(unit
->card
, P2_REG_AUXPAGE
, location
>> 7);
3292 unit
->LEWordOut(unit
->card
, P2_REG_AUXOFFSET
,
3293 location
& (1 << 7) - 1);
3295 unit
->WordsOut(unit
->card
, P2_REG_AUXDATA
, prod_data
,
3301 /* Disable auxiliary ports */
3303 control_reg
= unit
->LEWordIn(unit
->card
, P2_REG_CONTROL
);
3305 control_reg
& ~P2_REG_CONTROLF_AUX
| P2_REG_CONTROL_DISABLEAUX
;
3306 unit
->LEWordOut(unit
->card
, P2_REG_CONTROL
, control_reg
);
3308 /* Execute downloaded firmware */
3310 if(unit
->firmware_type
>= HERMES2_FIRMWARE
)
3312 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, start_address
>> 16);
3313 P2DoCmd(unit
, P2_CMD_EXECUTE
, start_address
, base
);
3315 else if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
3317 P2DoCmd(unit
, P2_CMD_PROGRAM
, 0, base
);
3318 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3319 P2DoCmd(unit
, P2_CMD_INIT
, 0, base
);
3320 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3324 unit
->LEWordOut(unit
->card
, P2_REG_PARAM1
, start_address
>> 16);
3325 P2DoCmd(unit
, P2_CMD_PROGRAM
, start_address
, base
);
3326 P2DoCmd(unit
, P2_CMD_INIT
, 0, base
);
3330 /* Free Resources */
3335 FreeDosObject(DOS_FIB
, info
);
3336 if(file
!= (BPTR
)NULL
)
3344 /****i* prism2.device/ParseNextSRecord *************************************
3349 ****************************************************************************
3353 static const TEXT
*ParseNextSRecord(const TEXT
*s
, UBYTE
*type
, UBYTE
*data
,
3354 UWORD
*data_length
, ULONG
*location
, struct DevBase
*base
)
3361 /* Find start of next record, if any */
3366 if(ch
== 'S' || ch
== '\0')
3372 /* Get record type */
3376 /* Skip length field to keep alignment easy */
3380 /* Parse hexadecimal portion of record */
3382 for(i
= 0; (ch
= *s
++) >= '0'; i
++)
3391 if(i
>= 8 && (i
& 0x1) != 0)
3402 *data_length
= (i
>> 1) - 5;
3407 /* Return updated text pointer */
3414 /****i* prism2.device/P2DoCmd **********************************************
3419 ****************************************************************************
3421 * Commands can't fail without software/firmware bug?
3425 static VOID
P2DoCmd(struct DevUnit
*unit
, UWORD command
, UWORD param
,
3426 struct DevBase
*base
)
3428 if(unit
->firmware_type
< LUCENT_FIRMWARE
&& command
== P2_CMD_INIT
)
3429 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3431 unit
->LEWordOut(unit
->card
, P2_REG_PARAM0
, param
);
3432 unit
->LEWordOut(unit
->card
, P2_REG_COMMAND
, command
);
3433 while((unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
)
3434 & P2_EVENTF_CMD
) == 0);
3435 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_CMD
);
3437 if(unit
->firmware_type
< LUCENT_FIRMWARE
&& command
== P2_CMD_INIT
)
3438 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, 0xffff);
3443 /****i* prism2.device/P2Seek ***********************************************
3448 ****************************************************************************
3452 static BOOL
P2Seek(struct DevUnit
*unit
, UWORD path_no
, UWORD rec_no
,
3453 UWORD offset
, struct DevBase
*base
)
3458 offset_reg
= P2_REG_OFFSET0
+ path_no
;
3459 while((unit
->LEWordIn(unit
->card
, offset_reg
) & P2_REG_OFFSETF_BUSY
)
3461 unit
->LEWordOut(unit
->card
, P2_REG_SELECT0
+ path_no
, rec_no
);
3462 unit
->LEWordOut(unit
->card
, offset_reg
, offset
);
3463 while((unit
->LEWordIn(unit
->card
, offset_reg
) & P2_REG_OFFSETF_BUSY
)
3466 return (unit
->LEWordIn(unit
->card
, offset_reg
) & P2_REG_OFFSETF_ERROR
)
3472 /****i* prism2.device/P2SetID **********************************************
3478 * id may be NULL as long as length is zero.
3480 ****************************************************************************
3484 static VOID
P2SetID(struct DevUnit
*unit
, UWORD rec_no
, const UBYTE
*id
,
3485 UWORD length
, struct DevBase
*base
)
3487 P2Seek(unit
, 1, rec_no
, 0, base
);
3489 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, length
/ 2 + 3);
3490 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, rec_no
);
3491 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, length
);
3492 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (UWORD
*)id
, (length
+ 1) / 2);
3494 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
, rec_no
, base
);
3501 /****i* prism2.device/P2SetWord ********************************************
3506 ****************************************************************************
3510 static VOID
P2SetWord(struct DevUnit
*unit
, UWORD rec_no
, UWORD value
,
3511 struct DevBase
*base
)
3513 P2Seek(unit
, 1, rec_no
, 0, base
);
3515 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 2);
3516 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, rec_no
);
3517 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, value
);
3519 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
, rec_no
, base
);
3526 /****i* prism2.device/P2GetWord ********************************************
3531 ****************************************************************************
3535 static UWORD
P2GetWord(struct DevUnit
*unit
, UWORD rec_no
,
3536 struct DevBase
*base
)
3538 P2DoCmd(unit
, P2_CMD_ACCESS
, rec_no
, base
);
3539 P2Seek(unit
, 1, rec_no
, 4, base
);
3541 return unit
->LEWordIn(unit
->card
, P2_REG_DATA1
);
3546 /****i* prism2.device/P2AllocMem *******************************************
3551 ****************************************************************************
3555 static UWORD
P2AllocMem(struct DevUnit
*unit
, UWORD size
,
3556 struct DevBase
*base
)
3559 P2DoCmd(unit
, P2_CMD_ALLOCMEM
, size
, base
);
3560 while((unit
->LEWordIn(unit
->card
, P2_REG_EVENTS
) & P2_EVENTF_ALLOCMEM
)
3562 id
= unit
->LEWordIn(unit
->card
, P2_REG_ALLOCFID
);
3563 unit
->LEWordOut(unit
->card
, P2_REG_ACKEVENTS
, P2_EVENTF_ALLOCMEM
);
3569 /****i* prism2.device/P2SetData ********************************************
3574 ****************************************************************************
3578 static VOID
P2SetData(struct DevUnit
*unit
, UWORD rec_no
, const UBYTE
*data
,
3579 UWORD length
, struct DevBase
*base
)
3581 length
= (length
+ 1) / 2;
3582 P2Seek(unit
, 1, rec_no
, 0, base
);
3584 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, 1 + length
);
3585 unit
->LEWordOut(unit
->card
, P2_REG_DATA1
, rec_no
);
3586 unit
->WordsOut(unit
->card
, P2_REG_DATA1
, (const UWORD
*)data
, length
);
3588 P2DoCmd(unit
, P2_CMD_ACCESS
| P2_CMDF_WRITE
, rec_no
, base
);
3595 /****i* prism2.device/P2ReadRec ********************************************
3598 * P2ReadRec -- Load and read an entire record.
3601 * success = P2ReadRec(unit, rec_no, buffer, max_length)
3603 * BOOL P2ReadRec(struct DevUnit *, UWORD, APTR, UWORD);
3608 * unit - A unit of this device.
3609 * rec_no - Record number to read.
3610 * buffer - Buffer to store data in.
3611 * max_length - Maximum number of bytes to store in buffer.
3614 * success - Success indicator.
3616 ****************************************************************************
3620 static BOOL
P2ReadRec(struct DevUnit
*unit
, UWORD rec_no
, APTR buffer
,
3621 UWORD max_length
, struct DevBase
*base
)
3623 BOOL success
= TRUE
;
3626 P2DoCmd(unit
, P2_CMD_ACCESS
, rec_no
, base
);
3627 P2Seek(unit
, 1, rec_no
, 0, base
);
3629 length
= (unit
->LEWordIn(unit
->card
, P2_REG_DATA1
) + 1) * 2;
3630 P2Seek(unit
, 1, rec_no
, 0, base
);
3631 if(length
<= max_length
)
3632 unit
->WordsIn(unit
->card
, P2_REG_DATA1
, (UWORD
*)buffer
,
3641 /****i* prism2.device/ConvertLevel *****************************************
3644 * ConvertLevel -- Convert a signal or noise level to dBm.
3647 * dbm_level = ConvertLevel(unit, raw_level)
3649 * LONG ConvertLevel(struct DevUnit *, UWORD);
3654 * unit - A unit of this device.
3655 * raw_level - The value returned from the hardware.
3658 * dbm_level - The value in dBm.
3660 ****************************************************************************
3664 static LONG
ConvertLevel(struct DevUnit
*unit
, UWORD raw_level
,
3665 struct DevBase
*base
)
3669 if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
3670 dbm_level
= raw_level
- LUCENT_DBM_OFFSET
;
3672 dbm_level
= raw_level
/ 3 - INTERSIL_DBM_OFFSET
;
3679 /****i* prism2.device/ConvertScanLevel *************************************
3682 * ConvertScanLevel -- Convert a signal or noise level to dBm.
3685 * dbm_level = ConvertScanLevel(unit, raw_level)
3687 * LONG ConvertScanLevel(struct DevUnit *, UWORD);
3692 * unit - A unit of this device.
3693 * raw_level - The value returned from the hardware.
3696 * dbm_level - The value in dBm.
3698 ****************************************************************************
3702 static LONG
ConvertScanLevel(struct DevUnit
*unit
, UWORD raw_level
,
3703 struct DevBase
*base
)
3707 if(unit
->firmware_type
>= LUCENT_FIRMWARE
)
3708 dbm_level
= raw_level
- LUCENT_DBM_OFFSET
;
3710 dbm_level
= (WORD
)raw_level
;
3717 /****i* prism2.device/GetIE ************************************************
3723 * ie = GetIE(id, ies, ies_length)
3725 * UBYTE *GetIE(UBYTE, UBYTE *, UWORD);
3730 * id - ID of IE to find.
3731 * ies - A series of IEs.
3732 * ies_length - Length of IE block.
3735 * ie - Pointer to start of IE within block, or NULL if not found.
3737 ****************************************************************************
3742 static UBYTE
*GetIE(UBYTE id
, UBYTE
*ies
, UWORD ies_length
,
3743 struct DevBase
*base
)
3748 // for(ie = ies; ie < end && ie + ie[1] < end; ie += length + 2)
3749 end
= ies
+ ies_length
;
3750 while(ie
< end
&& !found
)
3763 static UBYTE
*GetIE(UBYTE id
, UBYTE
*ies
, UWORD ies_length
,
3764 struct DevBase
*base
)
3768 for(ie
= ies
; ie
< ies
+ ies_length
&& ie
[0] != id
; ie
+= ie
[1] + 2);
3769 // for(ie = ies, end = ies + ies_length; ie < end && ie[0] != id; ie += ie[1] + 2);
3770 if(ie
>= ies
+ ies_length
)
3778 /****i* prism2.device/UnitTask *********************************************
3784 * UnitTask(sys_base)
3786 * VOID UnitTask(struct ExecBase *);
3789 * Completes deferred requests, and handles card insertion and removal
3790 * in conjunction with the relevant interrupts.
3792 ****************************************************************************
3800 static VOID
UnitTask(struct ExecBase
*sys_base
)
3803 struct IORequest
*request
;
3804 struct DevUnit
*unit
;
3805 struct DevBase
*base
;
3806 struct MsgPort
*general_port
;
3807 ULONG signals
= 0, wait_signals
, card_removed_signal
,
3808 card_inserted_signal
, scan_complete_signal
, general_port_signal
;
3810 /* Get parameters */
3812 task
= AbsExecBase
->ThisTask
;
3813 unit
= task
->tc_UserData
;
3814 base
= unit
->device
;
3816 /* Activate general request port */
3818 general_port
= unit
->request_ports
[GENERAL_QUEUE
];
3819 general_port
->mp_SigTask
= task
;
3820 general_port
->mp_SigBit
= AllocSignal(-1);
3821 general_port_signal
= 1 << general_port
->mp_SigBit
;
3822 general_port
->mp_Flags
= PA_SIGNAL
;
3824 /* Allocate signals for notification of card removal and insertion */
3826 card_removed_signal
= unit
->card_removed_signal
= 1 << AllocSignal(-1);
3827 card_inserted_signal
= unit
->card_inserted_signal
= 1 << AllocSignal(-1);
3828 scan_complete_signal
= unit
->scan_complete_signal
= 1 << AllocSignal(-1);
3829 wait_signals
= (1 << general_port
->mp_SigBit
) | card_removed_signal
3830 | card_inserted_signal
| scan_complete_signal
| SIGBREAKF_CTRL_C
;
3832 /* Tell ourselves to check port for old messages */
3834 Signal(task
, general_port_signal
);
3836 /* Infinite loop to service requests and signals */
3838 while((signals
& SIGBREAKF_CTRL_C
) == 0)
3840 signals
= Wait(wait_signals
);
3842 if((signals
& card_inserted_signal
) != 0)
3844 if(unit
->insertion_function(unit
->card
, base
))
3846 unit
->flags
|= UNITF_HAVEADAPTER
;
3847 if((unit
->flags
& UNITF_CONFIGURED
) != 0)
3848 ConfigureAdapter(unit
, base
);
3849 if((unit
->flags
& UNITF_WASONLINE
) != 0)
3851 GoOnline(unit
, base
);
3852 unit
->flags
&= ~UNITF_WASONLINE
;
3857 if((signals
& card_removed_signal
) != 0)
3859 unit
->removal_function(unit
->card
, base
);
3860 if((unit
->flags
& UNITF_WASONLINE
) != 0)
3861 GoOffline(unit
, base
);
3864 if((signals
& scan_complete_signal
) != 0)
3865 SendScanResults(unit
, base
);
3867 if((signals
& general_port_signal
) != 0)
3869 while((request
= (APTR
)GetMsg(general_port
)) != NULL
)
3871 /* Service the request as soon as the unit is free */
3873 ObtainSemaphore(&unit
->access_lock
);
3874 ServiceRequest((APTR
)request
, base
);
3879 FreeMem(task
->tc_SPLower
, STACK_SIZE
);
3884 /****i* prism2.device/StrLen ***********************************************
3890 * length = StrLen(s)
3892 * UPINT StrLen(TEXT *);
3894 ****************************************************************************
3898 static UPINT
StrLen(const TEXT
*s
)
3902 for(p
= s
; *p
!= '\0'; p
++);