summaryrefslogtreecommitdiffstats
path: root/debian/grub-extras/disabled/gpxe/src/include/gpxe/net80211.h
blob: d924941f20f0b5ed6cc6f6540ca423d8695618b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
#ifndef _GPXE_NET80211_H
#define _GPXE_NET80211_H

#include <gpxe/process.h>
#include <gpxe/ieee80211.h>
#include <gpxe/iobuf.h>
#include <gpxe/netdevice.h>
#include <gpxe/rc80211.h>

/** @file
 *
 * The gPXE 802.11 MAC layer.
 */

/*
 * Major things NOT YET supported:
 * - any type of security
 * - 802.11n
 *
 * Major things that probably will NEVER be supported, barring a
 * compelling use case and/or corporate sponsorship:
 * - QoS
 * - 802.1X authentication ("WPA Enterprise")
 * - Contention-free periods
 * - "ad-hoc" networks (IBSS), monitor mode, host AP mode
 * - hidden networks on the 5GHz band due to regulatory issues
 * - spectrum management on the 5GHz band (TPC and DFS), as required
 *   in some non-US regulatory domains
 * - Clause 14 PHYs (Frequency-Hopping Spread Spectrum on 2.4GHz)
 *   and Clause 16 PHYs (infrared) - I'm not aware of any real-world
 *   use of these.
 */

FILE_LICENCE ( GPL2_OR_LATER );

/* All 802.11 devices are handled using a generic "802.11 device"
   net_device, with a link in its `priv' field to a net80211_device
   which we use to handle 802.11-specific details. */


/** @defgroup net80211_band RF bands on which an 802.11 device can transmit */
/** @{ */

/** The 2.4 GHz ISM band, unlicensed in most countries */
#define NET80211_BAND_2GHZ	0
/** The band from 4.9 GHz to 5.7 GHz, which tends to be more restricted */
#define NET80211_BAND_5GHZ	1
/** Number of RF bands */
#define NET80211_NR_BANDS	2

/** Bitmask for the 2GHz band */
#define NET80211_BAND_BIT_2GHZ	(1 << 0)
/** Bitmask for the 5GHz band */
#define NET80211_BAND_BIT_5GHZ	(1 << 1)

/** @} */


/** @defgroup net80211_mode 802.11 operation modes supported by hardware */
/** @{ */

/** 802.11a: 54 Mbps operation using OFDM signaling on the 5GHz band */
#define NET80211_MODE_A		(1 << 0)

/** 802.11b: 1-11 Mbps operation using DSSS/CCK signaling on the 2.4GHz band */
#define NET80211_MODE_B		(1 << 1)

/** 802.11g: 54 Mbps operation using ERP/OFDM signaling on the 2.4GHz band */
#define NET80211_MODE_G		(1 << 2)

/** 802.11n: High-rate operation using MIMO technology on 2.4GHz or 5GHz */
#define NET80211_MODE_N		(1 << 3)

/** @} */


/** @defgroup net80211_cfg Constants for the net80211 config callback */
/** @{ */

/** Channel choice (@c dev->channel) or regulatory parameters have changed */
#define NET80211_CFG_CHANNEL	(1 << 0)

/** Requested transmission rate (@c dev->rate) has changed */
#define NET80211_CFG_RATE	(1 << 1)

/** Association has been established with a new BSS (@c dev->bssid) */
#define NET80211_CFG_ASSOC	(1 << 2)

/** Low-level link parameters (short preamble, protection, etc) have changed */
#define NET80211_CFG_PHY_PARAMS	(1 << 3)

/** @} */


/** An 802.11 security handshaking protocol */
enum net80211_security_proto {
	/** No security handshaking
	 *
	 * This might be used with an open network or with WEP, as
	 * WEP does not have a cryptographic handshaking phase.
	 */
	NET80211_SECPROT_NONE = 0,

	/** Pre-shared key handshaking
	 *
	 * This implements the "WPA Personal" handshake. 802.1X
	 * authentication is not performed -- the user supplies a
	 * pre-shared key directly -- but there is a 4-way handshake
	 * between client and AP to verify that both have the same key
	 * without revealing the contents of that key.
	 */
	NET80211_SECPROT_PSK = 1,

	/** Full EAP 802.1X handshaking
	 *
	 * This implements the "WPA Enterprise" handshake, connecting
	 * to an 802.1X authentication server to provide credentials
	 * and receive a pairwise master key (PMK), which is then used
	 * in the same 4-way handshake as the PSK method.
	 */
	NET80211_SECPROT_EAP = 2,
};


/** An 802.11 data encryption algorithm */
enum net80211_crypto_alg {
	/** No security, an "Open" network */
	NET80211_CRYPT_NONE = 0,

	/** Network protected with WEP (awful RC4-based system)
	 *
	 * WEP uses a naive application of RC4, with a monotonically
	 * increasing initialization vector that is prepended to the
	 * key to initialize the RC4 keystream. It is highly insecure
	 * and can be completely cracked or subverted using automated,
	 * robust, freely available tools (aircrack-ng) in minutes.
	 *
	 * 40-bit and 104-bit WEP are differentiated only by the size
	 * of the key. They may be advertised as 64-bit and 128-bit,
	 * counting the non-random IV as part of the key bits.
	 */
	NET80211_CRYPT_WEP = 1,

	/** Network protected with TKIP (better RC4-based system)
	 *
	 * Usually known by its trade name of WPA (Wi-Fi Protected
	 * Access), TKIP implements a message integrity code (MIC)
	 * called Michael, a timestamp counter for replay prevention,
	 * and a key mixing function that together remove almost all
	 * the security problems with WEP. Countermeasures are
	 * implemented to prevent high data-rate attacks.
	 *
	 * There exists one known attack on TKIP, that allows one to
	 * send between 7 and 15 arbitrary short data packets on a
	 * QoS-enabled network given about an hour of data
	 * gathering. Since gPXE does not support QoS for 802.11
	 * networks, this is not a threat to us. The only other method
	 * is a brute-force passphrase attack.
	 */
	NET80211_CRYPT_TKIP = 2,

	/** Network protected with CCMP (AES-based system)
	 *
	 * Often called WPA2 in commerce, or RSNA (Robust Security
	 * Network Architecture) in the 802.11 standard, CCMP is
	 * highly secure and does not have any known attack vectors.
	 * Since it is based on a block cipher, the statistical
	 * correlation and "chopchop" attacks used with great success
	 * against WEP and minor success against TKIP fail.
	 */
	NET80211_CRYPT_CCMP = 3,
};


/** @defgroup net80211_state Bits for the 802.11 association state field */
/** @{ */

/** An error code indicating the failure mode, or 0 if successful */
#define NET80211_STATUS_MASK    0x7F

/** Whether the error code provided is a "reason" code, not a "status" code */
#define NET80211_IS_REASON	0x80

/** Whether we have found the network we will be associating with */
#define NET80211_PROBED		(1 << 8)

/** Whether we have successfully authenticated with the network
 *
 * This usually has nothing to do with actual security; it is a
 * holdover from older 802.11 implementation ideas.
 */
#define NET80211_AUTHENTICATED  (1 << 9)

/** Whether we have successfully associated with the network */
#define NET80211_ASSOCIATED     (1 << 10)

/** Whether we have completed security handshaking with the network
 *
 * Once this is set, we can send data packets. For that reason this
 * bit is set even in cases where no security handshaking is
 * required.
 */
#define NET80211_CRYPTO_SYNCED  (1 << 11)

/** Whether the auto-association task is running */
#define NET80211_WORKING        (1 << 12)

/** Whether the auto-association task is waiting for a reply from the AP */
#define NET80211_WAITING        (1 << 13)

/** Whether the auto-association task should be suppressed
 *
 * This is set by the `iwlist' command so that it can open the device
 * without starting another probe process that will interfere with its
 * own.
 */
#define NET80211_NO_ASSOC	(1 << 14)

/** Whether this association was performed using a broadcast SSID
 *
 * If the user opened this device without netX/ssid set, the device's
 * SSID will be set to that of the network it chooses to associate
 * with, but the netX/ssid setting will remain blank. If we don't
 * remember that we started from no specified SSID, it will appear
 * every time settings are updated (e.g. after DHCP) that we need to
 * reassociate due to the difference between the set SSID and our own.
 */
#define NET80211_AUTO_SSID	(1 << 15)


/** @} */


/** @defgroup net80211_phy 802.11 physical layer flags */
/** @{ */

/** Whether to use RTS/CTS or CTS-to-self protection for transmissions
 *
 * Since the RTS or CTS is transmitted using 802.11b signaling, and
 * includes a field indicating the amount of time that will be used by
 * transmission of the following packet, this serves as an effective
 * protection mechanism to avoid 802.11b clients interfering with
 * 802.11g clients on mixed networks.
 */
#define NET80211_PHY_USE_PROTECTION      (1 << 1)

/** Whether to use 802.11b short preamble operation
 *
 * Short-preamble operation can moderately increase throughput on
 * 802.11b networks operating between 2Mbps and 11Mbps. It is
 * irrelevant for 802.11g data rates, since they use a different
 * modulation scheme.
 */
#define NET80211_PHY_USE_SHORT_PREAMBLE  (1 << 2)

/** Whether to use 802.11g short slot operation
 *
 * This affects a low-level timing parameter of 802.11g transmissions.
 */
#define NET80211_PHY_USE_SHORT_SLOT      (1 << 3)

/** @} */


/** The maximum number of TX rates we allow to be configured simultaneously */
#define NET80211_MAX_RATES	16

/** The maximum number of channels we allow to be configured simultaneously */
#define NET80211_MAX_CHANNELS	32

/** Seconds we'll wait to get all fragments of a packet */
#define NET80211_FRAG_TIMEOUT	2

/** The number of fragments we can receive at once
 *
 * The 802.11 standard requires that this be at least 3.
 */
#define NET80211_NR_CONCURRENT_FRAGS 3

/** Maximum TX power to allow (dBm), if we don't get a regulatory hint */
#define NET80211_REG_TXPOWER	20


struct net80211_device;

/** Operations that must be implemented by an 802.11 driver */
struct net80211_device_operations {
	/** Open 802.11 device
	 *
	 * @v dev	802.11 device
	 * @ret rc	Return status code
	 *
	 * This method should allocate RX I/O buffers and enable the
	 * hardware to start transmitting and receiving packets on the
	 * channels its net80211_register() call indicated it could
	 * handle. It does not need to tune the antenna to receive
	 * packets on any particular channel.
	 */
	int ( * open ) ( struct net80211_device *dev );

	/** Close 802.11 network device
	 *
	 * @v dev	802.11 device
	 *
	 * This method should stop the flow of packets, and call
	 * net80211_tx_complete() for any packets remaining in the
	 * device's TX queue.
	 */
	void ( * close ) ( struct net80211_device *dev );

	/** Transmit packet on 802.11 network device
	 *
	 * @v dev	802.11 device
	 * @v iobuf	I/O buffer
	 * @ret rc	Return status code
	 *
	 * This method should cause the hardware to initiate
	 * transmission of the I/O buffer, using the channel and rate
	 * most recently indicated by an appropriate call to the
	 * @c config callback. The 802.11 layer guarantees that said
	 * channel and rate will be the same as those currently
	 * reflected in the fields of @a dev.
	 *
	 * If this method returns success, the I/O buffer remains
	 * owned by the network layer's TX queue, and the driver must
	 * eventually call net80211_tx_complete() to free the buffer
	 * whether transmission succeeded or not. If this method
	 * returns failure, it will be interpreted as "failure to
	 * enqueue buffer" and the I/O buffer will be immediately
	 * released.
	 *
	 * This method is guaranteed to be called only when the device
	 * is open.
	 */
	int ( * transmit ) ( struct net80211_device *dev,
			     struct io_buffer *iobuf );

	/** Poll for completed and received packets
	 *
	 * @v dev	802.11 device
	 *
	 * This method should cause the hardware to check for
	 * completed transmissions and received packets. Any received
	 * packets should be delivered via net80211_rx(), and
	 * completed transmissions should be indicated using
	 * net80211_tx_complete().
	 *
	 * This method is guaranteed to be called only when the device
	 * is open.
	 */
	void ( * poll ) ( struct net80211_device *dev );

	/** Enable or disable interrupts
	 *
	 * @v dev	802.11 device
	 * @v enable	If TRUE, interrupts should be enabled
	 */
	void ( * irq ) ( struct net80211_device *dev, int enable );

	/** Update hardware state to match 802.11 layer state
	 *
	 * @v dev	802.11 device
	 * @v changed	Set of flags indicating what may have changed
	 * @ret rc	Return status code
	 *
	 * This method should cause the hardware state to be
	 * reinitialized from the state indicated in fields of
	 * net80211_device, in the areas indicated by bits set in
	 * @a changed. If the hardware is unable to do so, this method
	 * may return an appropriate error indication.
	 *
	 * This method is guaranteed to be called only when the device
	 * is open.
	 */
	int ( * config ) ( struct net80211_device *dev, int changed );
};

/** An 802.11 RF channel. */
struct net80211_channel
{
	/** The band with which this channel is associated */
	u8 band;

	/** A channel number interpreted according to the band
	 *
	 * The 2.4GHz band uses channel numbers from 1-13 at 5MHz
	 * intervals such that channel 1 is 2407 MHz; channel 14,
	 * legal for use only in Japan, is defined separately as 2484
	 * MHz. Adjacent channels will overlap, since 802.11
	 * transmissions use a 20 MHz (4-channel) bandwidth. Most
	 * commonly, channels 1, 6, and 11 are used.
	 *
	 * The 5GHz band uses channel numbers derived directly from
	 * the frequency; channel 0 is 5000 MHz, and channels are
	 * always spaced 5 MHz apart. Channel numbers over 180 are
	 * relative to 4GHz instead of 5GHz, but these are rarely
	 * seen. Most channels are not legal for use.
	 */
	u8 channel_nr;

	/** The center frequency for this channel
	 *
	 * Currently a bandwidth of 20 MHz is assumed.
	 */
	u16 center_freq;

	/** Hardware channel value */
	u16 hw_value;

	/** Maximum allowable transmit power, in dBm
	 *
	 * This should be interpreted as EIRP, the power supplied to
	 * an ideal isotropic antenna in order to achieve the same
	 * average signal intensity as the real hardware at a
	 * particular distance.
	 *
	 * Currently no provision is made for directional antennas.
	 */
	u8 maxpower;
};

/** Information on the capabilities of an 802.11 hardware device
 *
 * In its probe callback, an 802.11 driver must read hardware
 * registers to determine the appropriate contents of this structure,
 * fill it, and pass it to net80211_register() so that the 802.11
 * layer knows how to treat the hardware and what to advertise as
 * supported to access points.
 */
struct net80211_hw_info
{
	/** Default hardware MAC address.
	 *
	 * The user may change this by setting the @c netX/mac setting
	 * before the driver's open function is called; in that case
	 * the driver must set the hardware MAC address to the address
	 * contained in the wrapping net_device's ll_addr field, or if
	 * that is impossible, set that ll_addr field back to the
	 * unchangeable hardware MAC address.
	 */
	u8 hwaddr[ETH_ALEN];

	/** A bitwise OR of the 802.11x modes supported by this device */
	int modes;

	/** A bitwise OR of the bands on which this device can communicate */
	int bands;

	/** A set of flags indicating peculiarities of this device. */
	enum {
		/** Received frames include a frame check sequence. */
		NET80211_HW_RX_HAS_FCS = (1 << 1),

		/** Hardware doesn't support 2.4GHz short preambles
		 *
		 * This is only relevant for 802.11b operation above
		 * 2Mbps. All 802.11g devices support short preambles.
		 */
		NET80211_HW_NO_SHORT_PREAMBLE = (1 << 2),

		/** Hardware doesn't support 802.11g short slot operation */
		NET80211_HW_NO_SHORT_SLOT = (1 << 3),
	} flags;

	/** Signal strength information that can be provided by the device
	 *
	 * Signal strength is passed to net80211_rx(), primarily to
	 * allow determination of the closest access point for a
	 * multi-AP network. The units are provided for completeness
	 * of status displays.
	 */
	enum {
		/** No signal strength information supported */
		NET80211_SIGNAL_NONE = 0,
		/** Signal strength in arbitrary units */
		NET80211_SIGNAL_ARBITRARY,
		/** Signal strength in decibels relative to arbitrary base */
		NET80211_SIGNAL_DB,
		/** Signal strength in decibels relative to 1mW */
		NET80211_SIGNAL_DBM,
	} signal_type;

	/** Maximum signal in arbitrary cases
	 *
	 * If signal_type is NET80211_SIGNAL_ARBITRARY or
	 * NET80211_SIGNAL_DB, the driver should report it on a scale
	 * from 0 to signal_max.
	 */
	unsigned signal_max;

	/** List of RF channels supported by the card */
	struct net80211_channel channels[NET80211_MAX_CHANNELS];

	/** Number of supported channels */
	int nr_channels;

	/** List of transmission rates supported by the card, indexed by band
	 *
	 * Rates should be in 100kbps increments (e.g. 11 Mbps would
	 * be represented as the number 110).
	 */
	u16 rates[NET80211_NR_BANDS][NET80211_MAX_RATES];

	/** Number of supported rates, indexed by band */
	int nr_rates[NET80211_NR_BANDS];

	/** Estimate of the time required to change channels, in microseconds
	 *
	 * If this is not known, a guess on the order of a few
	 * milliseconds (value of 1000-5000) is reasonable.
	 */
	unsigned channel_change_time;
};

/** Structure tracking received fragments for a packet
 *
 * We set up a fragment cache entry when we receive a packet marked as
 * fragment 0 with the "more fragments" bit set in its frame control
 * header. We are required by the 802.11 standard to track 3
 * fragmented packets arriving simultaneously; if we receive more we
 * may drop some. Upon receipt of a new fragment-0 packet, if no entry
 * is available or expired, we take over the most @e recent entry for
 * the new packet, since we don't want to starve old entries from ever
 * finishing at all. If we get a fragment after the zeroth with no
 * cache entry for its packet, we drop it.
 */
struct net80211_frag_cache
{
	/** Whether this cache entry is in use */
	u8 in_use;

	/** Sequence number of this MSDU (packet) */
	u16 seqnr;

	/** Timestamp from point at which first fragment was collected */
	u32 start_ticks;

	/** Buffers for each fragment */
	struct io_buffer *iob[16];
};

/** Interface to an 802.11 cryptographic algorithm
 *
 * Cryptographic algorithms define a net80211_crypto structure
 * statically, using a gPXE linker table to make it available to the
 * 802.11 layer. When the algorithm needs to be used, the 802.11 code
 * will allocate a copy of the static definition plus whatever space
 * the algorithm has requested for private state, and point
 * net80211_device::crypto at it.
 */
struct net80211_crypto
{
	/** The cryptographic algorithm implemented */
	enum net80211_crypto_alg algorithm;

	/** Initialize cryptographic algorithm using a given key
	 *
	 * @v crypto	802.11 cryptographic algorithm
	 * @v key	Pointer to key bytes
	 * @v keylen	Number of key bytes
	 * @ret rc	Return status code
	 *
	 * This method is passed the communication key provided by the
	 * security handshake handler, which will already be in the
	 * low-level form required.
	 */
	int ( * initialize ) ( struct net80211_crypto *crypto, u8 *key,
			       int keylen );

	/** Encrypt a frame using the cryptographic algorithm
	 *
	 * @v crypto	802.11 cryptographic algorithm
	 * @v iob	I/O buffer
	 * @ret eiob	Newly allocated I/O buffer with encrypted packet
	 *
	 * This method is called to encrypt a single frame. It is
	 * guaranteed that initialize() will have completed
	 * successfully before this method is called.
	 *
	 * The frame passed already has an 802.11 header prepended,
	 * but the PROTECTED bit in the frame control field will not
	 * be set; this method is responsible for setting it. The
	 * returned I/O buffer should contain a complete copy of @a
	 * iob, including the 802.11 header, but with the PROTECTED
	 * bit set, the data encrypted, and whatever encryption
	 * headers/trailers are necessary added.
	 *
	 * This method should never free the passed I/O buffer.
	 *
	 * Return NULL if the packet could not be encrypted, due to
	 * memory limitations or otherwise.
	 */
	struct io_buffer * ( * encrypt ) ( struct net80211_crypto *crypto,
					   struct io_buffer *iob );

	/** Decrypt a frame using the cryptographic algorithm
	 *
	 * @v crypto	802.11 cryptographic algorithm
	 * @v eiob	Encrypted I/O buffer
	 * @ret iob	Newly allocated I/O buffer with decrypted packet
	 *
	 * This method is called to decrypt a single frame. It is
	 * guaranteed that initialize() will have completed
	 * successfully before this method is called.
	 *
	 * Decryption follows the reverse of the pattern used for
	 * encryption: this method must copy the 802.11 header into
	 * the returned packet, decrypt the data stream, remove any
	 * encryption header or trailer, and clear the PROTECTED bit
	 * in the frame control header.
	 *
	 * This method should never free the passed I/O buffer.
	 *
	 * Return NULL if memory was not available for decryption, if
	 * a consistency or integrity check on the decrypted frame
	 * failed, or if the decrypted frame should not be processed
	 * by the network stack for any other reason.
	 */
	struct io_buffer * ( * decrypt ) ( struct net80211_crypto *crypto,
					   struct io_buffer *iob );

	/** Length of private data requested to be allocated */
	int priv_len;

	/** Private data for the algorithm to store key and state info */
	void *priv;
};


struct net80211_probe_ctx;
struct net80211_assoc_ctx;


/** Structure encapsulating the complete state of an 802.11 device
 *
 * An 802.11 device is always wrapped by a network device, and this
 * network device is always pointed to by the @a netdev field. In
 * general, operations should never be performed by 802.11 code using
 * netdev functions directly. It is usually the case that the 802.11
 * layer might need to do some processing or bookkeeping on top of
 * what the netdevice code will do.
 */
struct net80211_device
{
	/** The net_device that wraps us. */
	struct net_device *netdev;

	/** List of 802.11 devices. */
	struct list_head list;

	/** 802.11 device operations */
	struct net80211_device_operations *op;

	/** Driver private data */
	void *priv;

	/** Information about the hardware, provided to net80211_register() */
	struct net80211_hw_info *hw;

	/* ---------- Channel and rate fields ---------- */

	/** A list of all possible channels we might use */
	struct net80211_channel channels[NET80211_MAX_CHANNELS];

	/** The number of channels in the channels array */
	u8 nr_channels;

	/** The channel currently in use, as an index into the channels array */
	u8 channel;

	/** A list of all possible TX rates we might use
	 *
	 * Rates are in units of 100 kbps.
	 */
	u16 rates[NET80211_MAX_RATES];

	/** The number of transmission rates in the rates array */
	u8 nr_rates;

	/** The rate currently in use, as an index into the rates array */
	u8 rate;

	/** The rate to use for RTS/CTS transmissions
	 *
	 * This is always the fastest basic rate that is not faster
	 * than the data rate in use. Also an index into the rates array.
	 */
	u8 rtscts_rate;

	/** Bitmask of basic rates
	 *
	 * If bit N is set in this value, with the LSB considered to
	 * be bit 0, then rate N in the rates array is a "basic" rate.
	 *
	 * We don't decide which rates are "basic"; our AP does, and
	 * we respect its wishes. We need to be able to identify basic
	 * rates in order to calculate the duration of a CTS packet
	 * used for 802.11 g/b interoperability.
	 */
	u32 basic_rates;

	/* ---------- Association fields ---------- */

	/** The asynchronous association process.
	 *
	 * When an 802.11 netdev is opened, or when the user changes
	 * the SSID setting on an open 802.11 device, an
	 * autoassociation task is started by net80211_autoassocate()
	 * to associate with the new best network. The association is
	 * asynchronous, but no packets can be transmitted until it is
	 * complete. If it is successful, the wrapping net_device is
	 * set as "link up". If it fails, @c assoc_rc will be set with
	 * an error indication.
	 */
	struct process proc_assoc;

	/** Network with which we are associating
	 *
	 * This will be NULL when we are not actively in the process
	 * of associating with a network we have already successfully
	 * probed for.
	 */
	struct net80211_wlan *associating;

	/** Context for the association process
	 *
	 * This is a probe_ctx if the @c PROBED flag is not set in @c
	 * state, and an assoc_ctx otherwise.
	 */
	union {
		struct net80211_probe_ctx *probe;
		struct net80211_assoc_ctx *assoc;
	} ctx;

	/** State of our association to the network
	 *
	 * Since the association process happens asynchronously, it's
	 * necessary to have some channel of communication so the
	 * driver can say "I got an association reply and we're OK" or
	 * similar. This variable provides that link. It is a bitmask
	 * of any of NET80211_PROBED, NET80211_AUTHENTICATED,
	 * NET80211_ASSOCIATED, NET80211_CRYPTO_SYNCED to indicate how
	 * far along in associating we are; NET80211_WORKING if the
	 * association task is running; and NET80211_WAITING if a
	 * packet has been sent that we're waiting for a reply to. We
	 * can only be crypto-synced if we're associated, we can
	 * only be associated if we're authenticated, we can only be
	 * authenticated if we've probed.
	 *
	 * If an association process fails (that is, we receive a
	 * packet with an error indication), the error code is copied
	 * into bits 6-0 of this variable and bit 7 is set to specify
	 * what type of error code it is. An AP can provide either a
	 * "status code" (0-51 are defined) explaining why it refused
	 * an association immediately, or a "reason code" (0-45 are
	 * defined) explaining why it canceled an association after it
	 * had originally OK'ed it. Status and reason codes serve
	 * similar functions, but they use separate error message
	 * tables. A gPXE-formatted return status code (negative) is
	 * placed in @c assoc_rc.
	 *
	 * If the failure to associate is indicated by a status code,
	 * the NET80211_IS_REASON bit will be clear; if it is
	 * indicated by a reason code, the bit will be set. If we were
	 * successful, both zero status and zero reason mean success,
	 * so there is no ambiguity.
	 *
	 * To prevent association when opening the device, user code
	 * can set the NET80211_NO_ASSOC bit. The final bit in this
	 * variable, NET80211_AUTO_SSID, is used to remember whether
	 * we picked our SSID through automated probing as opposed to
	 * user specification; the distinction becomes relevant in the
	 * settings applicator.
	 */
	u16 state;

	/** Return status code associated with @c state */
	int assoc_rc;

	/* ---------- Parameters of currently associated network ---------- */

	/** 802.11 cryptographic algorithm for our current network
	 *
	 * For an open network, this will be set to NULL.
	 */
	struct net80211_crypto *crypto;

	/** MAC address of the access point most recently associated */
	u8 bssid[ETH_ALEN];

	/** SSID of the access point we are or will be associated with
	 *
	 * Although the SSID field in 802.11 packets is generally not
	 * NUL-terminated, here and in net80211_wlan we add a NUL for
	 * convenience.
	 */
	char essid[IEEE80211_MAX_SSID_LEN+1];

	/** Association ID given to us by the AP */
	u16 aid;

	/** TSFT value for last beacon received, microseconds */
	u64 last_beacon_timestamp;

	/** Time between AP sending beacons, microseconds */
	u32 tx_beacon_interval;

	/** Smoothed average time between beacons, microseconds */
	u32 rx_beacon_interval;

	/* ---------- Physical layer information ---------- */

	/** Physical layer options
	 *
	 * These control the use of CTS protection, short preambles,
	 * and short-slot operation.
	 */
	int phy_flags;

	/** Signal strength of last received packet */
	int last_signal;

	/** Rate control state */
	struct rc80211_ctx *rctl;

	/* ---------- Packet handling state ---------- */

	/** Fragment reassembly state */
	struct net80211_frag_cache frags[NET80211_NR_CONCURRENT_FRAGS];

	/** The sequence number of the last packet we sent */
	u16 last_tx_seqnr;

	/** Packet duplication elimination state
	 *
	 * We are only required to handle immediate duplicates for
	 * each direct sender, and since we can only have one direct
	 * sender (the AP), we need only keep the sequence control
	 * field from the most recent packet we've received. Thus,
	 * this field stores the last sequence control field we've
	 * received for a packet from the AP.
	 */
	u16 last_rx_seq;

	/** RX management packet queue
	 *
	 * Sometimes we want to keep probe, beacon, and action packets
	 * that we receive, such as when we're scanning for networks.
	 * Ordinarily we drop them because they are sent at a large
	 * volume (ten beacons per second per AP, broadcast) and we
	 * have no need of them except when we're scanning.
	 *
	 * When keep_mgmt is TRUE, received probe, beacon, and action
	 * management packets will be stored in this queue.
	 */
	struct list_head mgmt_queue;

	/** RX management packet info queue
	 *
	 * We need to keep track of the signal strength for management
	 * packets we're keeping, because that provides the only way
	 * to distinguish between multiple APs for the same network.
	 * Since we can't extend io_buffer to store signal, this field
	 * heads a linked list of "RX packet info" structures that
	 * contain that signal strength field. Its entries always
	 * parallel the entries in mgmt_queue, because the two queues
	 * are always added to or removed from in parallel.
	 */
	struct list_head mgmt_info_queue;

	/** Whether to store management packets
	 *
	 * Received beacon, probe, and action packets will be added to
	 * mgmt_queue (and their signal strengths added to
	 * mgmt_info_queue) only when this variable is TRUE. It should
	 * be set by net80211_keep_mgmt() (which returns the old
	 * value) only when calling code is prepared to poll the
	 * management queue frequently, because packets will otherwise
	 * pile up and exhaust memory.
	 */
	int keep_mgmt;
};

/** Structure representing a probed network.
 *
 * This is returned from the net80211_probe_finish functions and
 * passed to the low-level association functions. At least essid,
 * bssid, channel, beacon, and security must be filled in if you want
 * to build this structure manually.
 */
struct net80211_wlan
{
	/** The human-readable ESSID (network name)
	 *
	 * Although the 802.11 SSID field is generally not
	 * NUL-terminated, the gPXE code adds an extra NUL (and
	 * expects one in this structure) for convenience.
	 */
	char essid[IEEE80211_MAX_SSID_LEN+1];

	/** MAC address of the strongest-signal access point for this ESSID */
	u8 bssid[ETH_ALEN];

	/** Signal strength of beacon frame from that access point */
	int signal;

	/** The channel on which that access point communicates
	 *
	 * This is a raw channel number (net80211_channel::channel_nr),
	 * so that it will not be affected by reconfiguration of the
	 * device channels array.
	 */
	int channel;

	/** The complete beacon or probe-response frame received */
	struct io_buffer *beacon;

	/** Security handshaking method used on the network */
	enum net80211_security_proto handshaking;

	/** Cryptographic algorithm used on the network */
	enum net80211_crypto_alg crypto;

	/** Link to allow chaining multiple structures into a list to
	    be returned from net80211_probe_finish_all(). */
	struct list_head list;
};


/**
 * @defgroup net80211_probe 802.11 network location API
 * @{
 */
int net80211_prepare_probe ( struct net80211_device *dev, int band,
			     int active );
struct net80211_probe_ctx * net80211_probe_start ( struct net80211_device *dev,
						   const char *essid,
						   int active );
int net80211_probe_step ( struct net80211_probe_ctx *ctx );
struct net80211_wlan *
net80211_probe_finish_best ( struct net80211_probe_ctx *ctx );
struct list_head *net80211_probe_finish_all ( struct net80211_probe_ctx *ctx );

void net80211_free_wlan ( struct net80211_wlan *wlan );
void net80211_free_wlanlist ( struct list_head *list );
/** @} */


/**
 * @defgroup net80211_mgmt 802.11 network management API
 * @{
 */
struct net80211_device * net80211_get ( struct net_device *netdev );
void net80211_autoassociate ( struct net80211_device *dev );

int net80211_change_channel ( struct net80211_device *dev, int channel );
void net80211_set_rate_idx ( struct net80211_device *dev, int rate );

int net80211_keep_mgmt ( struct net80211_device *dev, int enable );
struct io_buffer * net80211_mgmt_dequeue ( struct net80211_device *dev,
					   int *signal );
int net80211_tx_mgmt ( struct net80211_device *dev, u16 fc,
		       u8 bssid[ETH_ALEN], struct io_buffer *iob );
/** @} */


/**
 * @defgroup net80211_assoc 802.11 network association API
 * @{
 */
int net80211_prepare_assoc ( struct net80211_device *dev,
			     struct net80211_wlan *wlan );
int net80211_send_auth ( struct net80211_device *dev,
			 struct net80211_wlan *wlan, int method );
int net80211_send_assoc ( struct net80211_device *dev,
			  struct net80211_wlan *wlan );
/** @} */


/**
 * @defgroup net80211_driver 802.11 driver interface API
 * @{
 */
struct net80211_device *net80211_alloc ( size_t priv_size );
int net80211_register ( struct net80211_device *dev,
			struct net80211_device_operations *ops,
			struct net80211_hw_info *hw );
u16 net80211_duration ( struct net80211_device *dev, int bytes, u16 rate );
void net80211_rx ( struct net80211_device *dev, struct io_buffer *iob,
		   int signal, u16 rate );
void net80211_rx_err ( struct net80211_device *dev,
		       struct io_buffer *iob, int rc );
void net80211_tx_complete ( struct net80211_device *dev,
			    struct io_buffer *iob, int retries, int rc );
void net80211_unregister ( struct net80211_device *dev );
void net80211_free ( struct net80211_device *dev );
/** @} */

/**
 * Calculate duration field for a CTS control frame
 *
 * @v dev	802.11 device
 * @v size	Size of the packet being cleared to send
 *
 * A CTS control frame's duration field captures the frame being
 * protected and its 10-byte ACK.
 */
static inline u16 net80211_cts_duration ( struct net80211_device *dev,
					  int size )
{
	return ( net80211_duration ( dev, 10,
				     dev->rates[dev->rtscts_rate] ) +
		 net80211_duration ( dev, size, dev->rates[dev->rate] ) );
}

#endif