Browse Source

[802.11] Add core support for detecting and using encrypted networks

Signed-off-by: Marty Connor <mdc@etherboot.org>
tags/v1.0.0-rc1
Joshua Oreman 15 years ago
parent
commit
dd8a3e2e70

+ 1
- 0
src/include/gpxe/errfile.h View File

@@ -158,6 +158,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
158 158
 #define ERRFILE_ib_mi			( ERRFILE_NET | 0x00200000 )
159 159
 #define ERRFILE_ib_cmrc			( ERRFILE_NET | 0x00210000 )
160 160
 #define ERRFILE_ib_srp			( ERRFILE_NET | 0x00220000 )
161
+#define ERRFILE_sec80211		( ERRFILE_NET | 0x00230000 )
161 162
 
162 163
 #define ERRFILE_image		      ( ERRFILE_IMAGE | 0x00000000 )
163 164
 #define ERRFILE_elf		      ( ERRFILE_IMAGE | 0x00010000 )

+ 105
- 127
src/include/gpxe/ieee80211.h View File

@@ -2,6 +2,7 @@
2 2
 #define _GPXE_IEEE80211_H
3 3
 
4 4
 #include <gpxe/if_ether.h>	/* for ETH_ALEN */
5
+#include <endian.h>
5 6
 
6 7
 /** @file
7 8
  * Constants and data structures defined in IEEE 802.11, subsetted
@@ -779,10 +780,9 @@ struct ieee80211_ie_erp_info {
779 780
  *
780 781
  * Showing once again a striking clarity of design, the IEEE folks put
781 782
  * dynamically-sized data in the middle of this structure. As such,
782
- * the below structure definition is only a guideline; the
783
- * @c IEEE80211_RSN_FIELD, @c IEEE80211_RSN_CIPHER, and
784
- * @c IEEE80211_RSN_AUTHTYPE macros should be used to access any
785
- * data.
783
+ * the below structure definition only works for IEs we create
784
+ * ourselves, which always have one pairwise cipher and one AKM;
785
+ * received IEs should be parsed piecemeal.
786 786
  *
787 787
  * Also inspired was IEEE's choice of 16-bit fields to count the
788 788
  * number of 4-byte elements in a structure with a maximum length of
@@ -790,11 +790,9 @@ struct ieee80211_ie_erp_info {
790 790
  *
791 791
  * Many fields reference a cipher or authentication-type ID; this is a
792 792
  * three-byte OUI followed by one byte identifying the cipher with
793
- * respect to that OUI. For all standard ciphers the OUI is 00:0F:AC.
794
- *
795
- * The authentication types referenced in this structure have nothing
796
- * to do with 802.11 authentication frames or the @c algorithm field
797
- * within them.
793
+ * respect to that OUI. For all standard ciphers the OUI is 00:0F:AC,
794
+ * except in old-style WPA IEs encapsulated in vendor-specific IEs,
795
+ * where it's 00:50:F2.
798 796
  */
799 797
 struct ieee80211_ie_rsn {
800 798
 	/** Information element ID */
@@ -807,21 +805,21 @@ struct ieee80211_ie_rsn {
807 805
 	u16 version;
808 806
 
809 807
 	/** Cipher ID for the cipher used in multicast/broadcast frames */
810
-	u8 group_cipher[4];
808
+	u32 group_cipher;
811 809
 
812 810
 	/** Number of unicast ciphers supported */
813 811
 	u16 pairwise_count;
814 812
 
815 813
 	/** List of cipher IDs for supported unicast frame ciphers */
816
-	u8 pairwise_cipher[4];
814
+	u32 pairwise_cipher[1];
817 815
 
818 816
 	/** Number of authentication types supported */
819 817
 	u16 akm_count;
820 818
 
821 819
 	/** List of authentication type IDs for supported types */
822
-	u8 akm_list[4];
820
+	u32 akm_list[1];
823 821
 
824
-	/** Security capabilities field. */
822
+	/** Security capabilities field (RSN only) */
825 823
 	u16 rsn_capab;
826 824
 
827 825
 	/** Number of PMKIDs included (present only in association frames) */
@@ -834,140 +832,69 @@ struct ieee80211_ie_rsn {
834 832
 /** Information element ID for Robust Security Network information element */
835 833
 #define IEEE80211_IE_RSN	48
836 834
 
837
-/** OUI for standard ciphers in RSN information element */
838
-#define  IEEE80211_RSN_OUI	"\x00\x0F\xAC"
839
-
840
-/** Extract RSN IE version field */
841
-#define  IEEE80211_RSN_FIELD_version( rsnp ) ( (rsnp)->version )
842
-
843
-/** Extract RSN IE group_cipher field */
844
-#define  IEEE80211_RSN_FIELD_group_cipher( rsnp ) ( (rsnp)->group_cipher )
845
-
846
-/** Extract RSN IE pairwise_count field */
847
-#define  IEEE80211_RSN_FIELD_pairwise_count( rsnp ) ( (rsnp)->pairwise_count )
848
-
849
-/** Extract RSN IE akm_count field */
850
-#define  IEEE80211_RSN_FIELD_akm_count( rsnp )			\
851
-	( ( ( struct ieee80211_ie_rsn * ) ( ( void * ) ( rsnp ) + \
852
-		4*( ( rsnp )->pairwise_count - 1 ) ) )->akm_count )
853
-
854
-/** Extract RSN IE rsn_capab field */
855
-#define  IEEE80211_RSN_FIELD_rsn_capab( rsnp )			\
856
-	( ( ( struct ieee80211_ie_rsn * ) ( ( void * ) ( rsnp ) + \
857
-		4*( ( rsnp )->pairwise_count - 1 ) +		\
858
-		4*( ( rsnp )->akm_count - 1 ) ) )->rsn_capab )
859
-
860
-/** Extract RSN IE pmkid_count field */
861
-#define  IEEE80211_RSN_FIELD_pmkid_count( rsnp )		\
862
-	( ( ( struct ieee80211_ie_rsn * ) ( ( void * ) ( rsnp ) + \
863
-		4*( ( rsnp )->pairwise_count - 1 ) +		\
864
-		4*( ( rsnp )->akm_count - 1 ) ) )->pmkid_count )
865
-
866
-/** Extract field from RSN information element
867
- *
868
- * @v rsnp	Pointer to RSN information element
869
- * @v field	Name of field to extract
870
- * @ret val	Lvalue of the requested field
871
- *
872
- * You must fill the fields of the structure in order for this to work
873
- * properly.
874
- */
875
-#define  IEEE80211_RSN_FIELD( rsnp, field )	\
876
-	IEEE80211_RSN_FIELD_ ## field ( rsnp )
877
-
878
-/** Get pointer to pairwise cipher from RSN information element
879
- *
880
- * @v rsnp	Pointer to RSN information element
881
- * @v cipher	Index of pairwise cipher to extract
882
- * @ret ptr	Pointer to requested cipher
883
- */
884
-#define  IEEE80211_RSN_CIPHER( rsnp, cipher )	\
885
-	( ( rsnp )->pairwise_cipher + 4 * ( cipher ) )
886
-
887
-/** Get pointer to authentication type from RSN information element
888
- *
889
- * @v rsnp	Pointer to RSN information element
890
- * @v akm	Index of authentication type to extract
891
- * @ret ptr	Pointer to requested authentication type
892
- *
893
- * The @c pairwise_count field must be correct.
894
- */
895
-#define  IEEE80211_RSN_AUTHTYPE( rsnp, akm )	\
896
-    ( ( rsnp )->akm_list + 4 * ( ( rsnp )->pairwise_count - 1 ) + 4 * ( akm ) )
897
-
898
-/** Get pointer to PMKID from RSN information element
899
- *
900
- * @v rsnp	Pointer to RSN information element
901
- * @v idx	Index of PMKID to extract
902
- * @ret ptr	Pointer to requested PMKID
903
- *
904
- * The @c pairwise_count and @c akm_count fields must be correct.
905
- */
906
-#define  IEEE80211_RSN_PMKID( rsnp, idx )	\
907
-	( ( rsnp )->pmkid_list + 4 * ( ( rsnp )->pairwise_count - 1 ) +	\
908
-			4 * ( ( rsnp )->akm_count - 1 ) + 16 * ( idx ) )
909
-
910
-/** Verify size of RSN information element
911
- *
912
- * @v rsnp	Pointer to RSN information element
913
- * @ret ok	TRUE if count fields are consistent with length field
914
- *
915
- * It is important to drop any RSN IE that does not pass this function
916
- * before using the @c IEEE80211_RSN_FIELD, @c IEEE80211_RSN_CIPHER,
917
- * and @c IEEE80211_RSN_AUTHTYPE macros, to avoid potential security
918
- * compromise due to a malformed RSN IE.
919
- *
920
- * This function does not consider the possibility of some PMKIDs
921
- * included in the RSN IE, because PMKIDs are only included in RSN IEs
922
- * sent in association request frames, and we should never receive an
923
- * association request frame. An RSN IE that includes PMKIDs will
924
- * always fail this check.
925
- */
926
-static inline int ieee80211_rsn_check ( struct ieee80211_ie_rsn *rsnp ) {
927
-	if ( rsnp->len < 12 + 4 * rsnp->pairwise_count )
928
-		return 0;
929
-	return ( rsnp->len == 12 + 4 * ( rsnp->pairwise_count +
930
-				IEEE80211_RSN_FIELD ( rsnp, akm_count ) ) );
931
-}
932
-
933 835
 /** Calculate necessary size of RSN information element
934 836
  *
935 837
  * @v npair	Number of pairwise ciphers supported
936 838
  * @v nauth	Number of authentication types supported
937 839
  * @v npmkid	Number of PMKIDs to include
938
- * @ret size	Necessary size of RSN IE, including header bytes
840
+ * @v is_rsn	If TRUE, calculate RSN IE size; if FALSE, calculate WPA IE size
841
+ * @ret size	Necessary size of IE, including header bytes
939 842
  */
940
-static inline size_t ieee80211_rsn_size ( int npair, int nauth, int npmkid ) {
941
-	return 16 + 4 * ( npair + nauth ) + 16 * npmkid;
843
+static inline size_t ieee80211_rsn_size ( int npair, int nauth, int npmkid,
844
+					  int rsn_ie ) {
845
+	return 16 + 4 * ( npair + nauth ) + 16 * npmkid - 4 * ! rsn_ie;
942 846
 }
943 847
 
848
+/** Make OUI plus type byte into 32-bit integer for easy comparison */
849
+#if __BYTE_ORDER == __BIG_ENDIAN
850
+#define _MKOUI( a, b, c, t )	\
851
+		( ( ( a ) << 24 ) | ( ( b ) << 16 ) | ( ( c ) << 8 ) | ( d ) )
852
+#define  OUI_ORG_MASK		0xFFFFFF00
853
+#define  OUI_TYPE_MASK		0x000000FF
854
+#else
855
+#define _MKOUI( a, b, c, t )	\
856
+		( ( ( t ) << 24 ) | ( ( c ) << 16 ) | ( ( b ) << 8 ) | ( a ) )
857
+#define  OUI_ORG_MASK		0x00FFFFFF
858
+#define  OUI_TYPE_MASK		0xFF000000
859
+#endif
860
+
861
+/** Organization part for OUIs in standard RSN IE */
862
+#define  IEEE80211_RSN_OUI	_MKOUI ( 0x00, 0x0F, 0xAC, 0 )
863
+
864
+/** Organization part for OUIs in old WPA IE */
865
+#define  IEEE80211_WPA_OUI	_MKOUI ( 0x00, 0x50, 0xF2, 0 )
866
+
867
+/** Old vendor-type WPA IE OUI type + subtype */
868
+#define  IEEE80211_WPA_OUI_VEN	_MKOUI ( 0x00, 0x50, 0xF2, 0x01 )
869
+
870
+
944 871
 /** 802.11 RSN IE: expected version number */
945 872
 #define  IEEE80211_RSN_VERSION		1
946 873
 
947
-/** 802.11 RSN IE: fourth byte of cipher type for 40-bit WEP */
948
-#define  IEEE80211_RSN_CTYPE_WEP40	1
874
+/** 802.11 RSN IE: cipher type for 40-bit WEP */
875
+#define  IEEE80211_RSN_CTYPE_WEP40	_MKOUI ( 0, 0, 0, 0x01 )
949 876
 
950
-/** 802.11 RSN IE: fourth byte of cipher type for 104-bit WEP */
951
-#define  IEEE80211_RSN_CTYPE_WEP104	5
877
+/** 802.11 RSN IE: cipher type for 104-bit WEP */
878
+#define  IEEE80211_RSN_CTYPE_WEP104	_MKOUI ( 0, 0, 0, 0x05 )
952 879
 
953
-/** 802.11 RSN IE: fourth byte of cipher type for TKIP ("WPA") */
954
-#define  IEEE80211_RSN_CTYPE_TKIP	2
880
+/** 802.11 RSN IE: cipher type for TKIP ("WPA") */
881
+#define  IEEE80211_RSN_CTYPE_TKIP	_MKOUI ( 0, 0, 0, 0x02 )
955 882
 
956
-/** 802.11 RSN IE: fourth byte of cipher type for CCMP ("WPA2") */
957
-#define  IEEE80211_RSN_CTYPE_CCMP	4
883
+/** 802.11 RSN IE: cipher type for CCMP ("WPA2") */
884
+#define  IEEE80211_RSN_CTYPE_CCMP	_MKOUI ( 0, 0, 0, 0x04 )
958 885
 
959
-/** 802.11 RSN IE: fourth byte of cipher type for "use group"
886
+/** 802.11 RSN IE: cipher type for "use group"
960 887
  *
961 888
  * This can only appear as a pairwise cipher, and means unicast frames
962 889
  * should be encrypted in the same way as broadcast/multicast frames.
963 890
  */
964
-#define  IEEE80211_RSN_CTYPE_USEGROUP	0
891
+#define  IEEE80211_RSN_CTYPE_USEGROUP	_MKOUI ( 0, 0, 0, 0x00 )
965 892
 
966
-/** 802.11 RSN IE: fourth byte of auth method type for using an 802.1X server */
967
-#define  IEEE80211_RSN_ATYPE_8021X	1
893
+/** 802.11 RSN IE: auth method type for using an 802.1X server */
894
+#define  IEEE80211_RSN_ATYPE_8021X	_MKOUI ( 0, 0, 0, 0x01 )
968 895
 
969
-/** 802.11 RSN IE: fourth byte of auth method type for using a pre-shared key */
970
-#define  IEEE80211_RSN_ATYPE_PSK	2
896
+/** 802.11 RSN IE: auth method type for using a pre-shared key */
897
+#define  IEEE80211_RSN_ATYPE_PSK	_MKOUI ( 0, 0, 0, 0x02 )
971 898
 
972 899
 /** 802.11 RSN IE capabilities: AP supports pre-authentication */
973 900
 #define  IEEE80211_RSN_CAPAB_PREAUTH	0x001
@@ -997,6 +924,42 @@ static inline size_t ieee80211_rsn_size ( int npair, int nauth, int npmkid ) {
997 924
 #define  IEEE80211_RSN_CAPAB_PEERKEY	0x200
998 925
 
999 926
 
927
+/** 802.11 RSN IE capabilities: One replay counter
928
+ *
929
+ * This should be AND'ed with @c IEEE80211_RSN_CAPAB_PTKSA_REPLAY or
930
+ * @c IEEE80211_RSN_CAPAB_GTKSA_REPLAY (or both) to produce a value
931
+ * which can be OR'ed into the capabilities field.
932
+ */
933
+#define IEEE80211_RSN_1_CTR		0x000
934
+
935
+/** 802.11 RSN IE capabilities: Two replay counters */
936
+#define IEEE80211_RSN_2_CTR		0x014
937
+
938
+/** 802.11 RSN IE capabilities: Four replay counters */
939
+#define IEEE80211_RSN_4_CTR		0x028
940
+
941
+/** 802.11 RSN IE capabilities: 16 replay counters */
942
+#define IEEE80211_RSN_16_CTR		0x03C
943
+
944
+
945
+/** 802.11 Vendor Specific information element
946
+ *
947
+ * One often sees the RSN IE masquerading as vendor-specific on
948
+ * devices that were produced prior to 802.11i (the WPA amendment)
949
+ * being finalized.
950
+ */
951
+struct ieee80211_ie_vendor {
952
+	u8 id;			/**< Vendor-specific ID: 221 */
953
+	u8 len;			/**< Vendor-specific length: variable */
954
+	u32 oui;		/**< OUI and vendor-specific type byte */
955
+	u8 data[0];		/**< Vendor-specific data */
956
+} __attribute__ ((packed));
957
+
958
+/** Information element ID for Vendor Specific information element */
959
+#define IEEE80211_IE_VENDOR	221
960
+
961
+
962
+
1000 963
 
1001 964
 /** Any 802.11 information element
1002 965
  *
@@ -1034,8 +997,23 @@ union ieee80211_ie
1034 997
 
1035 998
 	/** Security information */
1036 999
 	struct ieee80211_ie_rsn rsn;
1000
+
1001
+	/** Vendor-specific */
1002
+	struct ieee80211_ie_vendor vendor;
1037 1003
 };
1038 1004
 
1005
+/** Check that 802.11 information element is bounded by buffer
1006
+ *
1007
+ * @v ie	Information element
1008
+ * @v end	End of buffer in which information element is stored
1009
+ * @ret ok	TRUE if the IE is completely contained within the buffer
1010
+ */
1011
+static inline int ieee80211_ie_bound ( union ieee80211_ie *ie, void *end )
1012
+{
1013
+	void *iep = ie;
1014
+	return ( iep + 2 <= end && iep + 2 + ie->len <= end );
1015
+}
1016
+
1039 1017
 /** Advance to next 802.11 information element
1040 1018
  *
1041 1019
  * @v ie	Current information element pointer
@@ -1055,7 +1033,7 @@ static inline union ieee80211_ie * ieee80211_next_ie ( union ieee80211_ie *ie,
1055 1033
 	if ( ! end )
1056 1034
 		return next_ie;
1057 1035
 
1058
-	if ( next_ie_byte < end && next_ie_byte + next_ie->len <= end )
1036
+	if ( ieee80211_ie_bound ( next_ie, end ) )
1059 1037
 		return next_ie;
1060 1038
 
1061 1039
 	return NULL;

+ 187
- 17
src/include/gpxe/net80211.h View File

@@ -119,6 +119,9 @@ enum net80211_security_proto {
119 119
 	 * in the same 4-way handshake as the PSK method.
120 120
 	 */
121 121
 	NET80211_SECPROT_EAP = 2,
122
+
123
+	/** Dummy value used when the handshaking type can't be detected */
124
+	NET80211_SECPROT_UNKNOWN = 3,
122 125
 };
123 126
 
124 127
 
@@ -169,6 +172,9 @@ enum net80211_crypto_alg {
169 172
 	 * against WEP and minor success against TKIP fail.
170 173
 	 */
171 174
 	NET80211_CRYPT_CCMP = 3,
175
+
176
+	/** Dummy value used when the cryptosystem can't be detected */
177
+	NET80211_CRYPT_UNKNOWN = 4,
172 178
 };
173 179
 
174 180
 
@@ -539,37 +545,171 @@ struct net80211_frag_cache
539 545
 	struct io_buffer *iob[16];
540 546
 };
541 547
 
542
-/** Interface to an 802.11 cryptographic algorithm
548
+
549
+/** Interface to an 802.11 security handshaking protocol
550
+ *
551
+ * Security handshaking protocols handle parsing a user-specified key
552
+ * into a suitable input to the encryption algorithm, and for WPA and
553
+ * better systems, manage performing whatever authentication with the
554
+ * network is necessary.
543 555
  *
544
- * Cryptographic algorithms define a net80211_crypto structure
545
- * statically, using a gPXE linker table to make it available to the
546
- * 802.11 layer. When the algorithm needs to be used, the 802.11 code
547
- * will allocate a copy of the static definition plus whatever space
548
- * the algorithm has requested for private state, and point
549
- * net80211_device::crypto at it.
556
+ * At all times when any method in this structure is called with a
557
+ * net80211_device argument @a dev, a dynamically allocated copy of
558
+ * the handshaker structure itself with space for the requested amount
559
+ * of private data may be accessed as @c dev->handshaker. The
560
+ * structure will not be modified, and will only be freed during
561
+ * reassociation and device closing after the @a stop method has been
562
+ * called.
563
+ */
564
+struct net80211_handshaker
565
+{
566
+	/** The security handshaking protocol implemented */
567
+	enum net80211_security_proto protocol;
568
+
569
+	/** Initialize security handshaking protocol
570
+	 *
571
+	 * @v dev	802.11 device
572
+	 * @ret rc	Return status code
573
+	 *
574
+	 * This method is expected to access @c netX/key or other
575
+	 * applicable settings to determine the parameters for
576
+	 * handshaking. If no handshaking is required, it should call
577
+	 * sec80211_install() with the cryptosystem and key that are
578
+	 * to be used, and @c start and @c step should be set to @c
579
+	 * NULL.
580
+	 *
581
+	 * This is always called just before association is performed,
582
+	 * but after its parameters have been set; in particular, you
583
+	 * may rely on the contents of the @a essid field in @a dev.
584
+	 */
585
+	int ( * init ) ( struct net80211_device *dev );
586
+
587
+	/** Start handshaking
588
+	 *
589
+	 * @v dev	802.11 device
590
+	 * @ret rc	Return status code
591
+	 *
592
+	 * This method is expected to set up internal state so that
593
+	 * packets sent immediately after association, before @a step
594
+	 * can be called, will be handled appropriately.
595
+	 *
596
+	 * This is always called just before association is attempted.
597
+	 */
598
+	int ( * start ) ( struct net80211_device *dev );
599
+
600
+	/** Process handshaking state
601
+	 *
602
+	 * @v dev	802.11 device
603
+	 * @ret rc	Return status code, or positive if done
604
+	 *
605
+	 * This method is expected to perform as much progress on the
606
+	 * protocol it implements as is possible without blocking. It
607
+	 * should return 0 if it wishes to be called again, a negative
608
+	 * return status code on error, or a positive value if
609
+	 * handshaking is complete. In the case of a positive return,
610
+	 * net80211_crypto_install() must have been called.
611
+	 *
612
+	 * If handshaking may require further action (e.g. an AP that
613
+	 * might decide to rekey), handlers must be installed by this
614
+	 * function that will act without further calls to @a step.
615
+	 */
616
+	int ( * step ) ( struct net80211_device *dev );
617
+
618
+	/** Change cryptographic key based on setting
619
+	 *
620
+	 * @v dev	802.11 device
621
+	 * @ret rc	Return status code
622
+	 *
623
+	 * This method is called whenever the @c netX/key setting
624
+	 * @e may have been changed. It is expected to determine
625
+	 * whether it did in fact change, and if so, to install the
626
+	 * new key using net80211_crypto_install(). If it is not
627
+	 * possible to do this immediately, this method should return
628
+	 * an error; in that case the 802.11 stack will reassociate,
629
+	 * following the usual init/start/step sequence.
630
+	 *
631
+	 * This method is only relevant when it is possible to
632
+	 * associate successfully with an incorrect key. When it is
633
+	 * not, a failed association will be retried until the user
634
+	 * changes the key setting, and a successful association will
635
+	 * not be dropped due to such a change. When association with
636
+	 * an incorrect key is impossible, this function should return
637
+	 * 0 after performing no action.
638
+	 */
639
+	int ( * change_key ) ( struct net80211_device *dev );
640
+
641
+	/** Stop security handshaking handlers
642
+	 *
643
+	 * @v dev	802.11 device
644
+	 *
645
+	 * This method is called just before freeing a security
646
+	 * handshaker; it could, for example, delete a process that @a
647
+	 * start had created to manage the security of the connection.
648
+	 * If not needed it may be set to NULL.
649
+	 */
650
+	void ( * stop ) ( struct net80211_device *dev );
651
+
652
+	/** Amount of private data requested
653
+	 *
654
+	 * Before @c init is called for the first time, this structure's
655
+	 * @c priv pointer will point to this many bytes of allocated
656
+	 * data, where the allocation will be performed separately for
657
+	 * each net80211_device.
658
+	 */
659
+	int priv_len;
660
+
661
+	/** Whether @a start has been called
662
+	 *
663
+	 * Reset to 0 after @a stop is called.
664
+	 */
665
+	int started;
666
+
667
+	/** Pointer to private data
668
+	 *
669
+	 * In initializing this structure statically for a linker
670
+	 * table, set this to NULL.
671
+	 */
672
+	void *priv;
673
+};
674
+
675
+#define NET80211_HANDSHAKERS __table ( struct net80211_handshaker, \
676
+				       "net80211_handshakers" )
677
+#define __net80211_handshaker __table_entry ( NET80211_HANDSHAKERS, 01 )
678
+
679
+
680
+/** Interface to an 802.11 cryptosystem
681
+ *
682
+ * Cryptosystems define a net80211_crypto structure statically, using
683
+ * a gPXE linker table to make it available to the 802.11 layer. When
684
+ * the cryptosystem needs to be used, the 802.11 code will allocate a
685
+ * copy of the static definition plus whatever space the algorithm has
686
+ * requested for private state, and point net80211_device::crypto or
687
+ * net80211_device::gcrypto at it.
550 688
  */
551 689
 struct net80211_crypto
552 690
 {
553 691
 	/** The cryptographic algorithm implemented */
554 692
 	enum net80211_crypto_alg algorithm;
555 693
 
556
-	/** Initialize cryptographic algorithm using a given key
694
+	/** Initialize cryptosystem using a given key
557 695
 	 *
558
-	 * @v crypto	802.11 cryptographic algorithm
696
+	 * @v crypto	802.11 cryptosystem
559 697
 	 * @v key	Pointer to key bytes
560 698
 	 * @v keylen	Number of key bytes
699
+	 * @v rsc	Initial receive sequence counter, if applicable
561 700
 	 * @ret rc	Return status code
562 701
 	 *
563 702
 	 * This method is passed the communication key provided by the
564 703
 	 * security handshake handler, which will already be in the
565
-	 * low-level form required.
704
+	 * low-level form required. It may not store a pointer to the
705
+	 * key after returning; it must copy it to its private storage.
566 706
 	 */
567
-	int ( * initialize ) ( struct net80211_crypto *crypto, u8 *key,
568
-			       int keylen );
707
+	int ( * init ) ( struct net80211_crypto *crypto, const void *key,
708
+			 int keylen, const void *rsc );
569 709
 
570
-	/** Encrypt a frame using the cryptographic algorithm
710
+	/** Encrypt a frame using the cryptosystem
571 711
 	 *
572
-	 * @v crypto	802.11 cryptographic algorithm
712
+	 * @v crypto	802.11 cryptosystem
573 713
 	 * @v iob	I/O buffer
574 714
 	 * @ret eiob	Newly allocated I/O buffer with encrypted packet
575 715
 	 *
@@ -593,9 +733,9 @@ struct net80211_crypto
593 733
 	struct io_buffer * ( * encrypt ) ( struct net80211_crypto *crypto,
594 734
 					   struct io_buffer *iob );
595 735
 
596
-	/** Decrypt a frame using the cryptographic algorithm
736
+	/** Decrypt a frame using the cryptosystem
597 737
 	 *
598
-	 * @v crypto	802.11 cryptographic algorithm
738
+	 * @v crypto	802.11 cryptosystem
599 739
 	 * @v eiob	Encrypted I/O buffer
600 740
 	 * @ret iob	Newly allocated I/O buffer with decrypted packet
601 741
 	 *
@@ -626,6 +766,9 @@ struct net80211_crypto
626 766
 	void *priv;
627 767
 };
628 768
 
769
+#define NET80211_CRYPTOS __table ( struct net80211_crypto, "net80211_cryptos" )
770
+#define __net80211_crypto __table_entry ( NET80211_CRYPTOS, 01 )
771
+
629 772
 
630 773
 struct net80211_probe_ctx;
631 774
 struct net80211_assoc_ctx;
@@ -732,6 +875,9 @@ struct net80211_device
732 875
 		struct net80211_assoc_ctx *assoc;
733 876
 	} ctx;
734 877
 
878
+	/** Security handshaker being used */
879
+	struct net80211_handshaker *handshaker;
880
+
735 881
 	/** State of our association to the network
736 882
 	 *
737 883
 	 * Since the association process happens asynchronously, it's
@@ -777,14 +923,33 @@ struct net80211_device
777 923
 	/** Return status code associated with @c state */
778 924
 	int assoc_rc;
779 925
 
926
+	/** RSN or WPA information element to include with association
927
+	 *
928
+	 * If set to @c NULL, none will be included. It is expected
929
+	 * that this will be set by the @a init function of a security
930
+	 * handshaker if it is needed.
931
+	 */
932
+	union ieee80211_ie *rsn_ie;
933
+
780 934
 	/* ---------- Parameters of currently associated network ---------- */
781 935
 
782
-	/** 802.11 cryptographic algorithm for our current network
936
+	/** 802.11 cryptosystem for our current network
783 937
 	 *
784 938
 	 * For an open network, this will be set to NULL.
785 939
 	 */
786 940
 	struct net80211_crypto *crypto;
787 941
 
942
+	/** 802.11 cryptosystem for multicast and broadcast frames
943
+	 *
944
+	 * If this is NULL, the cryptosystem used for receiving
945
+	 * unicast frames will also be used for receiving multicast
946
+	 * and broadcast frames. Transmitted multicast and broadcast
947
+	 * frames are always sent unicast to the AP, who multicasts
948
+	 * them on our behalf; thus they always use the unicast
949
+	 * cryptosystem.
950
+	 */
951
+	struct net80211_crypto *gcrypto;
952
+
788 953
 	/** MAC address of the access point most recently associated */
789 954
 	u8 bssid[ETH_ALEN];
790 955
 
@@ -927,6 +1092,10 @@ struct net80211_wlan
927 1092
 };
928 1093
 
929 1094
 
1095
+/** 802.11 encryption key setting */
1096
+extern struct setting net80211_key_setting __setting;
1097
+
1098
+
930 1099
 /**
931 1100
  * @defgroup net80211_probe 802.11 network location API
932 1101
  * @{
@@ -974,6 +1143,7 @@ int net80211_send_auth ( struct net80211_device *dev,
974 1143
 			 struct net80211_wlan *wlan, int method );
975 1144
 int net80211_send_assoc ( struct net80211_device *dev,
976 1145
 			  struct net80211_wlan *wlan );
1146
+void net80211_deauthenticate ( struct net80211_device *dev, int rc );
977 1147
 /** @} */
978 1148
 
979 1149
 

+ 83
- 0
src/include/gpxe/sec80211.h View File

@@ -0,0 +1,83 @@
1
+/*
2
+ * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+#ifndef _GPXE_SEC80211_H
20
+#define _GPXE_SEC80211_H
21
+
22
+FILE_LICENCE ( GPL2_OR_LATER );
23
+
24
+#include <gpxe/net80211.h>
25
+#include <errno.h>
26
+
27
+/** @file
28
+ *
29
+ * Definitions for general secured-network routines.
30
+ *
31
+ * Any function in this file which may be referenced by code which is
32
+ * not exclusive to encryption-enabled builds (e.g. sec80211_detect(),
33
+ * which is called by net80211_probe_step() to fill the net80211_wlan
34
+ * structure's security fields) must be declared as a weak symbol,
35
+ * using an inline interface similar to that used for
36
+ * sec80211_detect() below. This prevents secure network support from
37
+ * bloating general builds by any more than a few tiny hooks to call
38
+ * crypto functions when crypto structures are non-NULL.
39
+ */
40
+
41
+int _sec80211_detect ( struct io_buffer *iob,
42
+		       enum net80211_security_proto *secprot,
43
+		       enum net80211_crypto_alg *crypt )
44
+	__attribute__ (( weak ));
45
+
46
+
47
+/**
48
+ * Inline safety wrapper for _sec80211_detect()
49
+ *
50
+ * @v iob	I/O buffer containing beacon frame
51
+ * @ret secprot	Security handshaking protocol used by network
52
+ * @ret crypt	Cryptosystem used by network
53
+ * @ret rc	Return status code
54
+ *
55
+ * This function transparently calls _sec80211_detect() if the file
56
+ * containing it was compiled in, or returns an error indication of
57
+ * @c -ENOTSUP if not.
58
+ */
59
+static inline int sec80211_detect ( struct io_buffer *iob,
60
+				    enum net80211_security_proto *secprot,
61
+				    enum net80211_crypto_alg *crypt ) {
62
+	if ( _sec80211_detect )
63
+		return _sec80211_detect ( iob, secprot, crypt );
64
+	return -ENOTSUP;
65
+}
66
+
67
+int sec80211_detect_ie ( int is_rsn, u8 *start, u8 *end,
68
+			 enum net80211_security_proto *secprot,
69
+			 enum net80211_crypto_alg *crypt );
70
+u8 * sec80211_find_rsn ( union ieee80211_ie *ie, void *ie_end,
71
+			 int *is_rsn, u8 **end );
72
+
73
+int sec80211_install ( struct net80211_crypto **which,
74
+		       enum net80211_crypto_alg crypt,
75
+		       const void *key, int len, const void *rsc );
76
+
77
+u32 sec80211_rsn_get_crypto_desc ( enum net80211_crypto_alg crypt, int rsnie );
78
+u32 sec80211_rsn_get_akm_desc ( enum net80211_security_proto secprot,
79
+				int rsnie );
80
+enum net80211_crypto_alg sec80211_rsn_get_net80211_crypt ( u32 desc );
81
+
82
+#endif /* _GPXE_SEC80211_H */
83
+

+ 248
- 59
src/net/80211/net80211.c View File

@@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
29 29
 #include <gpxe/ieee80211.h>
30 30
 #include <gpxe/netdevice.h>
31 31
 #include <gpxe/net80211.h>
32
+#include <gpxe/sec80211.h>
32 33
 #include <gpxe/timer.h>
33 34
 #include <gpxe/nap.h>
34 35
 #include <unistd.h>
@@ -188,7 +189,8 @@ static void net80211_handle_auth ( struct net80211_device *dev,
188 189
 				   struct io_buffer *iob );
189 190
 static void net80211_handle_assoc_reply ( struct net80211_device *dev,
190 191
 					  struct io_buffer *iob );
191
-static int net80211_send_disassoc ( struct net80211_device *dev, int reason );
192
+static int net80211_send_disassoc ( struct net80211_device *dev, int reason,
193
+				    int deauth );
192 194
 static void net80211_handle_mgmt ( struct net80211_device *dev,
193 195
 				   struct io_buffer *iob, int signal );
194 196
 /** @} */
@@ -208,15 +210,16 @@ static void net80211_rx_frag ( struct net80211_device *dev,
208 210
  * @defgroup net80211_settings 802.11 settings handlers
209 211
  * @{
210 212
  */
211
-static int net80211_check_ssid_update ( void );
213
+static int net80211_check_settings_update ( void );
212 214
 
213 215
 /** 802.11 settings applicator
214 216
  *
215 217
  * When the SSID is changed, this will cause any open devices to
216
- * re-associate.
218
+ * re-associate; when the encryption key is changed, we similarly
219
+ * update their state.
217 220
  */
218
-struct settings_applicator net80211_ssid_applicator __settings_applicator = {
219
-	.apply = net80211_check_ssid_update,
221
+struct settings_applicator net80211_applicator __settings_applicator = {
222
+	.apply = net80211_check_settings_update,
220 223
 };
221 224
 
222 225
 /** The network name to associate with
@@ -242,6 +245,18 @@ struct setting net80211_active_setting __setting = {
242 245
 	.type = &setting_type_int8,
243 246
 };
244 247
 
248
+/** The cryptographic key to use
249
+ *
250
+ * For hex WEP keys, as is common, this must be entered using the
251
+ * normal gPXE method for entering hex settings; an ASCII string of
252
+ * hex characters will not behave as expected.
253
+ */
254
+struct setting net80211_key_setting __setting = {
255
+	.name = "key",
256
+	.description = "Encryption key for protected 802.11 networks",
257
+	.type = &setting_type_string,
258
+};
259
+
245 260
 /** @} */
246 261
 
247 262
 
@@ -294,7 +309,16 @@ static void net80211_netdev_close ( struct net_device *netdev )
294 309
 
295 310
 	/* Send disassociation frame to AP, to be polite */
296 311
 	if ( dev->state & NET80211_ASSOCIATED )
297
-		net80211_send_disassoc ( dev, IEEE80211_REASON_LEAVING );
312
+		net80211_send_disassoc ( dev, IEEE80211_REASON_LEAVING, 0 );
313
+
314
+	if ( dev->handshaker && dev->handshaker->stop &&
315
+	     dev->handshaker->started )
316
+		dev->handshaker->stop ( dev );
317
+
318
+	free ( dev->crypto );
319
+	free ( dev->handshaker );
320
+	dev->crypto = NULL;
321
+	dev->handshaker = NULL;
298 322
 
299 323
 	netdev_link_down ( netdev );
300 324
 	dev->state = 0;
@@ -317,16 +341,25 @@ static int net80211_netdev_transmit ( struct net_device *netdev,
317 341
 				      struct io_buffer *iobuf )
318 342
 {
319 343
 	struct net80211_device *dev = netdev->priv;
344
+	struct ieee80211_frame *hdr = iobuf->data;
320 345
 	int rc = -ENOSYS;
321 346
 
322
-	if ( dev->crypto ) {
347
+	if ( dev->crypto && ! ( hdr->fc & IEEE80211_FC_PROTECTED ) &&
348
+	     ( ( hdr->fc & IEEE80211_FC_TYPE ) == IEEE80211_TYPE_DATA ) ) {
323 349
 		struct io_buffer *niob = dev->crypto->encrypt ( dev->crypto,
324 350
 								iobuf );
325 351
 		if ( ! niob )
326 352
 			return -ENOMEM;	/* only reason encryption could fail */
327 353
 
328
-		free_iob ( iobuf );
329
-		iobuf = niob;
354
+		/* Free the non-encrypted iob */
355
+		netdev_tx_complete ( netdev, iobuf );
356
+
357
+		/* Transmit the encrypted iob; the Protected flag is
358
+		   set, so we won't recurse into here again */
359
+		netdev_tx ( netdev, niob );
360
+
361
+		/* Don't transmit the freed packet */
362
+		return 0;
330 363
 	}
331 364
 
332 365
 	if ( dev->op->transmit )
@@ -482,7 +515,7 @@ static int net80211_ll_push ( struct net_device *netdev,
482 515
 		( void * ) hdr + IEEE80211_TYP_FRAME_HEADER_LEN;
483 516
 
484 517
 	/* We can't send data packets if we're not associated. */
485
-	if ( ! netdev_link_ok ( netdev ) ) {
518
+	if ( ! ( dev->state & NET80211_ASSOCIATED ) ) {
486 519
 		if ( dev->assoc_rc )
487 520
 			return dev->assoc_rc;
488 521
 		return -ENETUNREACH;
@@ -1032,7 +1065,7 @@ static int net80211_process_ie ( struct net80211_device *dev,
1032 1065
 	int changed = 0;
1033 1066
 	int band = dev->channels[dev->channel].band;
1034 1067
 
1035
-	if ( ( void * ) ie >= ie_end )
1068
+	if ( ! ieee80211_ie_bound ( ie, ie_end ) )
1036 1069
 		return 0;
1037 1070
 
1038 1071
 	for ( ; ie; ie = ieee80211_next_ie ( ie, ie_end ) ) {
@@ -1103,10 +1136,6 @@ static int net80211_process_ie ( struct net80211_device *dev,
1103 1136
 			if ( ! ( ie->erp_info & IEEE80211_ERP_BARKER_LONG ) )
1104 1137
 				dev->phy_flags |= NET80211_PHY_USE_SHORT_PREAMBLE;
1105 1138
 			break;
1106
-
1107
-		case IEEE80211_IE_RSN:
1108
-			/* XXX need to implement WPA stuff */
1109
-			break;
1110 1139
 		}
1111 1140
 	}
1112 1141
 
@@ -1140,10 +1169,20 @@ static int net80211_process_ie ( struct net80211_device *dev,
1140 1169
 		   exist, so insertion sort works well. */
1141 1170
 		for ( i = 1; i < dev->nr_rates; i++ ) {
1142 1171
 			u16 rate = dev->rates[i];
1172
+			u32 tmp, br, mask;
1143 1173
 
1144 1174
 			for ( j = i - 1; j >= 0 && dev->rates[j] >= rate; j-- )
1145 1175
 				dev->rates[j + 1] = dev->rates[j];
1146 1176
 			dev->rates[j + 1] = rate;
1177
+
1178
+			/* Adjust basic_rates to match by rotating the
1179
+			   bits from bit j+1 to bit i left one position. */
1180
+			mask = ( ( 1 << i ) - 1 ) & ~( ( 1 << ( j + 1 ) ) - 1 );
1181
+			br = dev->basic_rates;
1182
+			tmp = br & ( 1 << i );
1183
+			br = ( br & ~( mask | tmp ) ) | ( ( br & mask ) << 1 );
1184
+			br |= ( tmp >> ( i - j - 1 ) );
1185
+			dev->basic_rates = br;
1147 1186
 		}
1148 1187
 
1149 1188
 		net80211_set_rtscts_rate ( dev );
@@ -1187,28 +1226,42 @@ net80211_marshal_request_info ( struct net80211_device *dev,
1187 1226
 
1188 1227
 	ie->id = IEEE80211_IE_RATES;
1189 1228
 	ie->len = dev->nr_rates;
1229
+	if ( ie->len > 8 )
1230
+		ie->len = 8;
1231
+
1190 1232
 	for ( i = 0; i < ie->len; i++ ) {
1191 1233
 		ie->rates[i] = dev->rates[i] / 5;
1192 1234
 		if ( dev->basic_rates & ( 1 << i ) )
1193 1235
 			ie->rates[i] |= 0x80;
1194 1236
 	}
1195 1237
 
1196
-	if ( ie->len > 8 ) {
1238
+	ie = ieee80211_next_ie ( ie, NULL );
1239
+
1240
+	if ( dev->rsn_ie && dev->rsn_ie->id == IEEE80211_IE_RSN ) {
1241
+		memcpy ( ie, dev->rsn_ie, dev->rsn_ie->len + 2 );
1242
+		ie = ieee80211_next_ie ( ie, NULL );
1243
+	}
1244
+
1245
+	if ( dev->nr_rates > 8 ) {
1197 1246
 		/* 802.11 requires we use an Extended Basic Rates IE
1198 1247
 		   for the rates beyond the eighth. */
1199
-		int rates = ie->len;
1200 1248
 
1201
-		memmove ( ( void * ) ie + 2 + 8 + 2, ( void * ) ie + 2 + 8,
1202
-			  rates - 8 );
1203
-		ie->len = 8;
1249
+		ie->id = IEEE80211_IE_EXT_RATES;
1250
+		ie->len = dev->nr_rates - 8;
1204 1251
 
1205
-		ie = ieee80211_next_ie ( ie, NULL );
1252
+		for ( ; i < dev->nr_rates; i++ ) {
1253
+			ie->rates[i - 8] = dev->rates[i] / 5;
1254
+			if ( dev->basic_rates & ( 1 << i ) )
1255
+				ie->rates[i - 8] |= 0x80;
1256
+		}
1206 1257
 
1207
-		ie->id = IEEE80211_IE_EXT_RATES;
1208
-		ie->len = rates - 8;
1258
+		ie = ieee80211_next_ie ( ie, NULL );
1209 1259
 	}
1210 1260
 
1211
-	ie = ieee80211_next_ie ( ie, NULL );
1261
+	if ( dev->rsn_ie && dev->rsn_ie->id == IEEE80211_IE_VENDOR ) {
1262
+		memcpy ( ie, dev->rsn_ie, dev->rsn_ie->len + 2 );
1263
+		ie = ieee80211_next_ie ( ie, NULL );
1264
+	}
1212 1265
 
1213 1266
 	return ie;
1214 1267
 }
@@ -1275,13 +1328,6 @@ struct net80211_probe_ctx * net80211_probe_start ( struct net80211_device *dev,
1275 1328
 
1276 1329
 		ie = net80211_marshal_request_info ( dev,
1277 1330
 						     probe_req->info_element );
1278
-		ie->id = IEEE80211_IE_REQUEST;
1279
-		ie->len = 3;
1280
-		ie->request[0] = IEEE80211_IE_COUNTRY;
1281
-		ie->request[1] = IEEE80211_IE_ERP_INFO;
1282
-		ie->request[2] = IEEE80211_IE_RSN;
1283
-
1284
-		ie = ieee80211_next_ie ( ie, NULL );
1285 1331
 
1286 1332
 		iob_put ( ctx->probe, ( void * ) ie - ctx->probe->data );
1287 1333
 	}
@@ -1404,6 +1450,10 @@ int net80211_probe_step ( struct net80211_probe_ctx *ctx )
1404 1450
 		}
1405 1451
 
1406 1452
 		ie = beacon->info_element;
1453
+
1454
+		if ( ! ieee80211_ie_bound ( ie, iob->tail ) )
1455
+			ie = NULL;
1456
+
1407 1457
 		while ( ie && ie->id != IEEE80211_IE_SSID )
1408 1458
 			ie = ieee80211_next_ie ( ie, iob->tail );
1409 1459
 
@@ -1459,10 +1509,27 @@ int net80211_probe_step ( struct net80211_probe_ctx *ctx )
1459 1509
 		memcpy ( iob_put ( wlan->beacon, iob_len ( iob ) ),
1460 1510
 			 iob->data, iob_len ( iob ) );
1461 1511
 
1462
-		/* XXX actually check capab and RSN ie to
1463
-		   figure this out */
1464
-		wlan->handshaking = NET80211_SECPROT_NONE;
1465
-		wlan->crypto = NET80211_CRYPT_NONE;
1512
+		if ( ( rc = sec80211_detect ( wlan->beacon, &wlan->handshaking,
1513
+					      &wlan->crypto ) ) == -ENOTSUP ) {
1514
+			struct ieee80211_beacon *beacon =
1515
+				( struct ieee80211_beacon * ) hdr->data;
1516
+
1517
+			if ( beacon->capability & IEEE80211_CAPAB_PRIVACY ) {
1518
+				DBG ( "802.11 %p probe: secured network %s but "
1519
+				      "encryption support not compiled in\n",
1520
+				      dev, wlan->essid );
1521
+				wlan->handshaking = NET80211_SECPROT_UNKNOWN;
1522
+				wlan->crypto = NET80211_CRYPT_UNKNOWN;
1523
+			} else {
1524
+				wlan->handshaking = NET80211_SECPROT_NONE;
1525
+				wlan->crypto = NET80211_CRYPT_NONE;
1526
+			}
1527
+		} else if ( rc != 0 ) {
1528
+			DBGC ( dev, "802.11 %p probe warning: network "
1529
+			       "%s with unidentifiable security "
1530
+			       "settings: %s\n", dev, wlan->essid,
1531
+			       strerror ( rc ) );
1532
+		}
1466 1533
 
1467 1534
 		ctx->ticks_beacon = now;
1468 1535
 
@@ -1739,6 +1806,14 @@ static void net80211_step_associate ( struct process *proc )
1739 1806
 
1740 1807
 		DBGC ( dev, "802.11 %p associating\n", dev );
1741 1808
 
1809
+		if ( dev->handshaker && dev->handshaker->start &&
1810
+		     ! dev->handshaker->started ) {
1811
+			rc = dev->handshaker->start ( dev );
1812
+			if ( rc < 0 )
1813
+				goto fail;
1814
+			dev->handshaker->started = 1;
1815
+		}
1816
+
1742 1817
 		rc = net80211_send_assoc ( dev, dev->associating );
1743 1818
 		if ( rc )
1744 1819
 			goto fail;
@@ -1750,9 +1825,29 @@ static void net80211_step_associate ( struct process *proc )
1750 1825
 		/* state: crypto sync */
1751 1826
 		DBGC ( dev, "802.11 %p security handshaking\n", dev );
1752 1827
 
1753
-		dev->state |= NET80211_CRYPTO_SYNCED;
1754
-		/* XXX need to actually do something here once we
1755
-		   support WPA */
1828
+		if ( ! dev->handshaker || ! dev->handshaker->step ) {
1829
+			dev->state |= NET80211_CRYPTO_SYNCED;
1830
+			return;
1831
+		}
1832
+
1833
+		rc = dev->handshaker->step ( dev );
1834
+
1835
+		if ( rc < 0 ) {
1836
+			/* Only record the returned error if we're
1837
+			   still marked as associated, because an
1838
+			   asynchronous error will have already been
1839
+			   reported to net80211_deauthenticate() and
1840
+			   assoc_rc thereby set. */
1841
+			if ( dev->state & NET80211_ASSOCIATED )
1842
+				dev->assoc_rc = rc;
1843
+			rc = 0;
1844
+			goto fail;
1845
+		}
1846
+
1847
+		if ( rc > 0 ) {
1848
+			dev->assoc_rc = 0;
1849
+			dev->state |= NET80211_CRYPTO_SYNCED;
1850
+		}
1756 1851
 		return;
1757 1852
 	}
1758 1853
 
@@ -1804,27 +1899,36 @@ static void net80211_step_associate ( struct process *proc )
1804 1899
 }
1805 1900
 
1806 1901
 /**
1807
- * Check for 802.11 SSID updates
1902
+ * Check for 802.11 SSID or key updates
1808 1903
  *
1809 1904
  * This acts as a settings applicator; if the user changes netX/ssid,
1810 1905
  * and netX is currently open, the association task will be invoked
1811
- * again.
1906
+ * again. If the user changes the encryption key, the current security
1907
+ * handshaker will be asked to update its state to match; if that is
1908
+ * impossible without reassociation, we reassociate.
1812 1909
  */
1813
-static int net80211_check_ssid_update ( void )
1910
+static int net80211_check_settings_update ( void )
1814 1911
 {
1815 1912
 	struct net80211_device *dev;
1816 1913
 	char ssid[IEEE80211_MAX_SSID_LEN + 1];
1914
+	int key_reassoc;
1817 1915
 
1818 1916
 	list_for_each_entry ( dev, &net80211_devices, list ) {
1819 1917
 		if ( ! ( dev->netdev->state & NETDEV_OPEN ) )
1820 1918
 			continue;
1821 1919
 
1920
+		key_reassoc = 0;
1921
+		if ( dev->handshaker && dev->handshaker->change_key &&
1922
+		     dev->handshaker->change_key ( dev ) < 0 )
1923
+			key_reassoc = 1;
1924
+
1822 1925
 		fetch_string_setting ( netdev_settings ( dev->netdev ),
1823 1926
 				       &net80211_ssid_setting, ssid,
1824 1927
 				       IEEE80211_MAX_SSID_LEN + 1 );
1825 1928
 
1826
-		if ( strcmp ( ssid, dev->essid ) != 0 &&
1827
-		     ! ( ! ssid[0] && ( dev->state & NET80211_AUTO_SSID ) ) ) {
1929
+		if ( key_reassoc ||
1930
+		     ( ! ( ! ssid[0] && ( dev->state & NET80211_AUTO_SSID ) ) &&
1931
+		       strcmp ( ssid, dev->essid ) != 0 ) ) {
1828 1932
 			DBGC ( dev, "802.11 %p updating association: "
1829 1933
 			       "%s -> %s\n", dev, dev->essid, ssid );
1830 1934
 			net80211_autoassociate ( dev );
@@ -1846,6 +1950,8 @@ void net80211_autoassociate ( struct net80211_device *dev )
1846 1950
 	if ( ! ( dev->state & NET80211_WORKING ) ) {
1847 1951
 		DBGC2 ( dev, "802.11 %p spawning association process\n", dev );
1848 1952
 		process_add ( &dev->proc_assoc );
1953
+	} else {
1954
+		DBGC2 ( dev, "802.11 %p restarting association\n", dev );
1849 1955
 	}
1850 1956
 
1851 1957
 	/* Clean up everything an earlier association process might
@@ -1865,6 +1971,7 @@ void net80211_autoassociate ( struct net80211_device *dev )
1865 1971
 			       IEEE80211_MAX_SSID_LEN + 1 );
1866 1972
 	dev->ctx.probe = NULL;
1867 1973
 	dev->associating = NULL;
1974
+	dev->assoc_rc = 0;
1868 1975
 	net80211_set_state ( dev, NET80211_PROBED, NET80211_WORKING, 0 );
1869 1976
 }
1870 1977
 
@@ -2020,6 +2127,7 @@ int net80211_prepare_assoc ( struct net80211_device *dev,
2020 2127
 	struct ieee80211_frame *hdr = wlan->beacon->data;
2021 2128
 	struct ieee80211_beacon *beacon =
2022 2129
 		( struct ieee80211_beacon * ) hdr->data;
2130
+	struct net80211_handshaker *handshaker;
2023 2131
 	int rc;
2024 2132
 
2025 2133
 	assert ( dev->netdev->state & NETDEV_OPEN );
@@ -2028,11 +2136,12 @@ int net80211_prepare_assoc ( struct net80211_device *dev,
2028 2136
 	memcpy ( dev->bssid, wlan->bssid, ETH_ALEN );
2029 2137
 	strcpy ( dev->essid, wlan->essid );
2030 2138
 
2139
+	free ( dev->rsn_ie );
2140
+	dev->rsn_ie = NULL;
2141
+
2031 2142
 	dev->last_beacon_timestamp = beacon->timestamp;
2032 2143
 	dev->tx_beacon_interval = 1024 * beacon->beacon_interval;
2033 2144
 
2034
-	/* XXX do crypto setup here */
2035
-
2036 2145
 	/* Barring an IE that tells us the channel outright, assume
2037 2146
 	   the channel we heard this AP best on is the channel it's
2038 2147
 	   communicating on. */
@@ -2051,6 +2160,46 @@ int net80211_prepare_assoc ( struct net80211_device *dev,
2051 2160
 	dev->rate = 0;
2052 2161
 	dev->op->config ( dev, NET80211_CFG_RATE );
2053 2162
 
2163
+	/* Free old handshaker and crypto, if they exist */
2164
+	if ( dev->handshaker && dev->handshaker->stop &&
2165
+	     dev->handshaker->started )
2166
+		dev->handshaker->stop ( dev );
2167
+	free ( dev->handshaker );
2168
+	dev->handshaker = NULL;
2169
+	free ( dev->crypto );
2170
+	free ( dev->gcrypto );
2171
+	dev->crypto = dev->gcrypto = NULL;
2172
+
2173
+	/* Find new security handshaker to use */
2174
+	for_each_table_entry ( handshaker, NET80211_HANDSHAKERS ) {
2175
+		if ( handshaker->protocol == wlan->handshaking ) {
2176
+			dev->handshaker = zalloc ( sizeof ( *handshaker ) +
2177
+						   handshaker->priv_len );
2178
+			if ( ! dev->handshaker )
2179
+				return -ENOMEM;
2180
+
2181
+			memcpy ( dev->handshaker, handshaker,
2182
+				 sizeof ( *handshaker ) );
2183
+			dev->handshaker->priv = ( ( void * ) dev->handshaker +
2184
+						  sizeof ( *handshaker ) );
2185
+			break;
2186
+		}
2187
+	}
2188
+
2189
+	if ( ( wlan->handshaking != NET80211_SECPROT_NONE ) &&
2190
+	     ! dev->handshaker ) {
2191
+		DBGC ( dev, "802.11 %p no support for handshaking scheme %d\n",
2192
+		       dev, wlan->handshaking );
2193
+		return -( ENOTSUP | ( wlan->handshaking << 8 ) );
2194
+	}
2195
+
2196
+	/* Initialize security handshaker */
2197
+	if ( dev->handshaker ) {
2198
+		rc = dev->handshaker->init ( dev );
2199
+		if ( rc < 0 )
2200
+			return rc;
2201
+	}
2202
+
2054 2203
 	return 0;
2055 2204
 }
2056 2205
 
@@ -2091,8 +2240,8 @@ int net80211_send_auth ( struct net80211_device *dev,
2091 2240
  *
2092 2241
  * If the authentication method being used is Shared Key, and the
2093 2242
  * frame that was received included challenge text, the frame is
2094
- * encrypted using the cryptographic algorithm currently in effect and
2095
- * sent back to the AP to complete the authentication.
2243
+ * encrypted using the cryptosystem currently in effect and sent back
2244
+ * to the AP to complete the authentication.
2096 2245
  */
2097 2246
 static void net80211_handle_auth ( struct net80211_device *dev,
2098 2247
 				   struct io_buffer *iob )
@@ -2181,8 +2330,6 @@ int net80211_send_assoc ( struct net80211_device *dev,
2181 2330
 	DBGP ( "802.11 %p about to send association request:\n", dev );
2182 2331
 	DBGP_HD ( iob->data, ( void * ) ie - iob->data );
2183 2332
 
2184
-	/* XXX add RSN ie for WPA support */
2185
-
2186 2333
 	iob_put ( iob, ( void * ) ie - iob->data );
2187 2334
 
2188 2335
 	return net80211_tx_mgmt ( dev, IEEE80211_STYPE_ASSOC_REQ,
@@ -2227,9 +2374,11 @@ static void net80211_handle_assoc_reply ( struct net80211_device *dev,
2227 2374
  *
2228 2375
  * @v dev	802.11 device
2229 2376
  * @v reason	Reason for disassociation
2377
+ * @v deauth	If TRUE, send deauthentication instead of disassociation
2230 2378
  * @ret rc	Return status code
2231 2379
  */
2232
-static int net80211_send_disassoc ( struct net80211_device *dev, int reason )
2380
+static int net80211_send_disassoc ( struct net80211_device *dev, int reason,
2381
+				    int deauth )
2233 2382
 {
2234 2383
 	struct io_buffer *iob = alloc_iob ( 64 );
2235 2384
 	struct ieee80211_disassoc *disassoc;
@@ -2242,8 +2391,28 @@ static int net80211_send_disassoc ( struct net80211_device *dev, int reason )
2242 2391
 	disassoc = iob_put ( iob, sizeof ( *disassoc ) );
2243 2392
 	disassoc->reason = reason;
2244 2393
 
2245
-	return net80211_tx_mgmt ( dev, IEEE80211_STYPE_DISASSOC, dev->bssid,
2246
-				  iob );
2394
+	return net80211_tx_mgmt ( dev, deauth ? IEEE80211_STYPE_DEAUTH :
2395
+				  IEEE80211_STYPE_DISASSOC, dev->bssid, iob );
2396
+}
2397
+
2398
+
2399
+/**
2400
+ * Deauthenticate from current network and try again
2401
+ *
2402
+ * @v dev	802.11 device
2403
+ * @v rc	Return status code indicating reason
2404
+ *
2405
+ * The deauthentication will be sent using an 802.11 "unspecified
2406
+ * reason", as is common, but @a rc will be set as a link-up
2407
+ * error to aid the user in debugging.
2408
+ */
2409
+void net80211_deauthenticate ( struct net80211_device *dev, int rc )
2410
+{
2411
+	net80211_send_disassoc ( dev, IEEE80211_REASON_UNSPECIFIED, 1 );
2412
+	dev->assoc_rc = rc;
2413
+	netdev_link_err ( dev->netdev, rc );
2414
+
2415
+	net80211_autoassociate ( dev );
2247 2416
 }
2248 2417
 
2249 2418
 
@@ -2557,14 +2726,29 @@ void net80211_rx ( struct net80211_device *dev, struct io_buffer *iob,
2557 2726
 		iob_unput ( iob, 4 );
2558 2727
 	}
2559 2728
 
2560
-	if ( hdr->fc & IEEE80211_FC_PROTECTED ) {
2729
+	/* Only decrypt packets from our BSSID, to avoid spurious errors */
2730
+	if ( ( hdr->fc & IEEE80211_FC_PROTECTED ) &&
2731
+	     ! memcmp ( hdr->addr2, dev->bssid, ETH_ALEN ) ) {
2732
+		/* Decrypt packet; record and drop if it fails */
2561 2733
 		struct io_buffer *niob;
2562
-		if ( ! dev->crypto )
2563
-			goto drop;	/* can't decrypt packets on an open network */
2734
+		struct net80211_crypto *crypto = dev->crypto;
2564 2735
 
2565
-		niob = dev->crypto->decrypt ( dev->crypto, iob );
2566
-		if ( ! niob )
2567
-			goto drop;	/* drop failed decryption */
2736
+		if ( ! dev->crypto ) {
2737
+			DBGC ( dev, "802.11 %p cannot decrypt packet "
2738
+			       "without a cryptosystem\n", dev );
2739
+			goto drop_crypt;
2740
+		}
2741
+
2742
+		if ( ( hdr->addr1[0] & 1 ) && dev->gcrypto ) {
2743
+			/* Use group decryption if needed */
2744
+			crypto = dev->gcrypto;
2745
+		}
2746
+
2747
+		niob = crypto->decrypt ( crypto, iob );
2748
+		if ( ! niob ) {
2749
+			DBGC ( dev, "802.11 %p decryption error\n", dev );
2750
+			goto drop_crypt;
2751
+		}
2568 2752
 		free_iob ( iob );
2569 2753
 		iob = niob;
2570 2754
 	}
@@ -2593,11 +2777,16 @@ void net80211_rx ( struct net80211_device *dev, struct io_buffer *iob,
2593 2777
 		rc80211_update_rx ( dev, hdr->fc & IEEE80211_FC_RETRY, rate );
2594 2778
 
2595 2779
 	/* Pass packet onward */
2596
-	if ( netdev_link_ok ( dev->netdev ) ) {
2780
+	if ( dev->state & NET80211_ASSOCIATED ) {
2597 2781
 		netdev_rx ( dev->netdev, iob );
2598 2782
 		return;
2599 2783
 	}
2600 2784
 
2785
+	/* No association? Drop it. */
2786
+	goto drop;
2787
+
2788
+ drop_crypt:
2789
+	netdev_rx_err ( dev->netdev, NULL, EINVAL_CRYPTO_REQUEST );
2601 2790
  drop:
2602 2791
 	DBGC2 ( dev, "802.11 %p dropped packet fc=%04x seq=%04x\n", dev,
2603 2792
 		hdr->fc, hdr->seq );

+ 503
- 0
src/net/80211/sec80211.c View File

@@ -0,0 +1,503 @@
1
+/*
2
+ * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ */
18
+
19
+FILE_LICENCE ( GPL2_OR_LATER );
20
+
21
+#include <stdlib.h>
22
+#include <string.h>
23
+#include <errno.h>
24
+#include <gpxe/ieee80211.h>
25
+#include <gpxe/net80211.h>
26
+#include <gpxe/sec80211.h>
27
+
28
+/** @file
29
+ *
30
+ * General secured-network routines required whenever any secure
31
+ * network support at all is compiled in. This involves things like
32
+ * installing keys, determining the type of security used by a probed
33
+ * network, and some small helper functions that take advantage of
34
+ * static data in this file.
35
+ */
36
+
37
+/** Mapping from net80211 crypto/secprot types to RSN OUI descriptors */
38
+struct descriptor_map {
39
+	/** Value of net80211_crypto_alg or net80211_security_proto */
40
+	u32 net80211_type;
41
+
42
+	/** OUI+type in appropriate byte order, masked to exclude vendor */
43
+	u32 oui_type;
44
+};
45
+
46
+/** Magic number in @a oui_type showing end of list */
47
+#define END_MAGIC	0xFFFFFFFF
48
+
49
+/** Mapping between net80211 cryptosystems and 802.11i cipher IDs */
50
+static struct descriptor_map rsn_cipher_map[] = {
51
+	{ .net80211_type = NET80211_CRYPT_WEP,
52
+	  .oui_type = IEEE80211_RSN_CTYPE_WEP40 },
53
+
54
+	{ .net80211_type = NET80211_CRYPT_WEP,
55
+	  .oui_type = IEEE80211_RSN_CTYPE_WEP104 },
56
+
57
+	{ .net80211_type = NET80211_CRYPT_TKIP,
58
+	  .oui_type = IEEE80211_RSN_CTYPE_TKIP },
59
+
60
+	{ .net80211_type = NET80211_CRYPT_CCMP,
61
+	  .oui_type = IEEE80211_RSN_CTYPE_CCMP },
62
+
63
+	{ .net80211_type = NET80211_CRYPT_UNKNOWN,
64
+	  .oui_type = END_MAGIC },
65
+};
66
+
67
+/** Mapping between net80211 handshakers and 802.11i AKM IDs */
68
+static struct descriptor_map rsn_akm_map[] = {
69
+	{ .net80211_type = NET80211_SECPROT_EAP,
70
+	  .oui_type = IEEE80211_RSN_ATYPE_8021X },
71
+
72
+	{ .net80211_type = NET80211_SECPROT_PSK,
73
+	  .oui_type = IEEE80211_RSN_ATYPE_PSK },
74
+
75
+	{ .net80211_type = NET80211_SECPROT_UNKNOWN,
76
+	  .oui_type = END_MAGIC },
77
+};
78
+
79
+
80
+/**
81
+ * Install 802.11 cryptosystem
82
+ *
83
+ * @v which	Pointer to the cryptosystem structure to install in
84
+ * @v crypt	Cryptosystem ID number
85
+ * @v key	Encryption key to use
86
+ * @v len	Length of encryption key
87
+ * @v rsc	Initial receive sequence counter, if applicable
88
+ * @ret rc	Return status code
89
+ *
90
+ * The encryption key will not be accessed via the provided pointer
91
+ * after this function returns, so you may keep it on the stack.
92
+ *
93
+ * @a which must point to either @c dev->crypto (for the normal case
94
+ * of installing a unicast cryptosystem) or @c dev->gcrypto (to
95
+ * install a cryptosystem that will be used only for decrypting
96
+ * group-source frames).
97
+ */
98
+int sec80211_install ( struct net80211_crypto **which,
99
+		       enum net80211_crypto_alg crypt,
100
+		       const void *key, int len, const void *rsc )
101
+{
102
+	struct net80211_crypto *crypto = *which;
103
+	struct net80211_crypto *tbl_crypto;
104
+
105
+	/* Remove old crypto if it exists */
106
+	free ( *which );
107
+	*which = NULL;
108
+
109
+	if ( crypt == NET80211_CRYPT_NONE ) {
110
+		DBG ( "802.11-Sec not installing null cryptography\n" );
111
+		return 0;
112
+	}
113
+
114
+	/* Find cryptosystem to use */
115
+	for_each_table_entry ( tbl_crypto, NET80211_CRYPTOS ) {
116
+		if ( tbl_crypto->algorithm == crypt ) {
117
+			crypto = zalloc ( sizeof ( *crypto ) +
118
+					  tbl_crypto->priv_len );
119
+			if ( ! crypto ) {
120
+				DBG ( "802.11-Sec out of memory\n" );
121
+				return -ENOMEM;
122
+			}
123
+
124
+			memcpy ( crypto, tbl_crypto, sizeof ( *crypto ) );
125
+			crypto->priv = ( ( void * ) crypto +
126
+					 sizeof ( *crypto ) );
127
+			break;
128
+		}
129
+	}
130
+
131
+	if ( ! crypto ) {
132
+		DBG ( "802.11-Sec no support for cryptosystem %d\n", crypt );
133
+		return -( ENOTSUP | EUNIQ_10 | ( crypt << 8 ) );
134
+	}
135
+
136
+	*which = crypto;
137
+
138
+	DBG ( "802.11-Sec installing cryptosystem %d as %p with key of "
139
+	      "length %d\n", crypt, crypto, len );
140
+
141
+	return crypto->init ( crypto, key, len, rsc );
142
+}
143
+
144
+
145
+/**
146
+ * Determine net80211 crypto or handshaking type value to return for RSN info
147
+ *
148
+ * @v rsnp		Pointer to next descriptor count field in RSN IE
149
+ * @v rsn_end		Pointer to end of RSN IE
150
+ * @v map		Descriptor map to use
151
+ * @v tbl_start		Start of linker table to examine for gPXE support
152
+ * @v tbl_end		End of linker table to examine for gPXE support
153
+ * @ret rsnp		Updated to point to first byte after descriptors
154
+ * @ret map_ent		Descriptor map entry of translation to use
155
+ *
156
+ * The entries in the linker table must be either net80211_crypto or
157
+ * net80211_handshaker structures, and @a tbl_stride must be set to
158
+ * sizeof() the appropriate one.
159
+ *
160
+ * This function expects @a rsnp to point at a two-byte descriptor
161
+ * count followed by a list of four-byte cipher or AKM descriptors; it
162
+ * will return @c NULL if the input packet is malformed, and otherwise
163
+ * set @a rsnp to the first byte it has not looked at. It will return
164
+ * the first cipher in the list that is supported by the current build
165
+ * of gPXE, or the first of all if none are supported.
166
+ *
167
+ * We play rather fast and loose with type checking, because this
168
+ * function is only called from two well-defined places in the
169
+ * RSN-checking code. Don't try to use it for anything else.
170
+ */
171
+static struct descriptor_map * rsn_pick_desc ( u8 **rsnp, u8 *rsn_end,
172
+					       struct descriptor_map *map,
173
+					       void *tbl_start, void *tbl_end )
174
+{
175
+	int ndesc;
176
+	int ok = 0;
177
+	struct descriptor_map *map_ent, *map_ret = NULL;
178
+	u8 *rsn = *rsnp;
179
+	void *tblp;
180
+	size_t tbl_stride = ( map == rsn_cipher_map ?
181
+			      sizeof ( struct net80211_crypto ) :
182
+			      sizeof ( struct net80211_handshaker ) );
183
+
184
+	if ( map != rsn_cipher_map && map != rsn_akm_map )
185
+		return NULL;
186
+
187
+	/* Determine which types we support */
188
+	for ( tblp = tbl_start; tblp < tbl_end; tblp += tbl_stride ) {
189
+		struct net80211_crypto *crypto = tblp;
190
+		struct net80211_handshaker *hs = tblp;
191
+
192
+		if ( map == rsn_cipher_map )
193
+			ok |= ( 1 << crypto->algorithm );
194
+		else
195
+			ok |= ( 1 << hs->protocol );
196
+	}
197
+
198
+	/* RSN sanity checks */
199
+	if ( rsn + 2 > rsn_end ) {
200
+		DBG ( "RSN detect: malformed descriptor count\n" );
201
+		return NULL;
202
+	}
203
+
204
+	ndesc = *( u16 * ) rsn;
205
+	rsn += 2;
206
+
207
+	if ( ! ndesc ) {
208
+		DBG ( "RSN detect: no descriptors\n" );
209
+		return NULL;
210
+	}
211
+
212
+	/* Determine which net80211 crypto types are listed */
213
+	while ( ndesc-- ) {
214
+		u32 desc;
215
+
216
+		if ( rsn + 4 > rsn_end ) {
217
+			DBG ( "RSN detect: malformed descriptor (%d left)\n",
218
+			      ndesc );
219
+			return NULL;
220
+		}
221
+
222
+		desc = *( u32 * ) rsn;
223
+		rsn += 4;
224
+
225
+		for ( map_ent = map; map_ent->oui_type != END_MAGIC; map_ent++ )
226
+			if ( map_ent->oui_type == ( desc & OUI_TYPE_MASK ) )
227
+				break;
228
+
229
+		/* Use first cipher as a fallback */
230
+		if ( ! map_ret )
231
+			map_ret = map_ent;
232
+
233
+		/* Once we find one we support, use it */
234
+		if ( ok & ( 1 << map_ent->net80211_type ) ) {
235
+			map_ret = map_ent;
236
+			break;
237
+		}
238
+	}
239
+
240
+	if ( ndesc > 0 )
241
+		rsn += 4 * ndesc;
242
+
243
+	*rsnp = rsn;
244
+	return map_ret;
245
+}
246
+
247
+
248
+/**
249
+ * Find the RSN or WPA information element in the provided beacon frame
250
+ *
251
+ * @v ie	Pointer to first information element to check
252
+ * @v ie_end	Pointer to end of information element space
253
+ * @ret is_rsn	TRUE if returned IE is RSN, FALSE if it's WPA
254
+ * @ret end	Pointer to byte immediately after last byte of data
255
+ * @ret data	Pointer to first byte of data (the `version' field)
256
+ *
257
+ * If both an RSN and a WPA information element are found, this
258
+ * function will return the first one seen, which by ordering rules
259
+ * should always prefer the newer RSN IE.
260
+ *
261
+ * If no RSN or WPA infomration element is found, returns @c NULL and
262
+ * leaves @a is_rsn and @a end in an undefined state.
263
+ *
264
+ * This function will not return a pointer to an information element
265
+ * that states it extends past the tail of the io_buffer, or whose @a
266
+ * version field is incorrect.
267
+ */
268
+u8 * sec80211_find_rsn ( union ieee80211_ie *ie, void *ie_end,
269
+			 int *is_rsn, u8 **end )
270
+{
271
+	u8 *rsn = NULL;
272
+
273
+	if ( ! ieee80211_ie_bound ( ie, ie_end ) )
274
+		return NULL;
275
+
276
+	while ( ie ) {
277
+		if ( ie->id == IEEE80211_IE_VENDOR &&
278
+		     ie->vendor.oui == IEEE80211_WPA_OUI_VEN ) {
279
+			DBG ( "RSN detect: old-style WPA IE found\n" );
280
+			rsn = &ie->vendor.data[0];
281
+			*end = rsn + ie->len - 4;
282
+			*is_rsn = 0;
283
+		} else if ( ie->id == IEEE80211_IE_RSN ) {
284
+			DBG ( "RSN detect: 802.11i RSN IE found\n" );
285
+			rsn = ( u8 * ) &ie->rsn.version;
286
+			*end = rsn + ie->len;
287
+			*is_rsn = 1;
288
+		}
289
+
290
+		if ( rsn && ( *end > ( u8 * ) ie_end || rsn >= *end ||
291
+			      *( u16 * ) rsn != IEEE80211_RSN_VERSION ) ) {
292
+			DBG ( "RSN detect: malformed RSN IE or unknown "
293
+			      "version, keep trying\n" );
294
+			rsn = NULL;
295
+		}
296
+
297
+		if ( rsn )
298
+			break;
299
+
300
+		ie = ieee80211_next_ie ( ie, ie_end );
301
+	}
302
+
303
+	if ( ! ie ) {
304
+		DBG ( "RSN detect: no RSN IE found\n" );
305
+		return NULL;
306
+	}
307
+
308
+	return rsn;
309
+}
310
+
311
+
312
+/**
313
+ * Detect crypto and AKM types from RSN information element
314
+ *
315
+ * @v is_rsn	If TRUE, IE is a new-style RSN information element
316
+ * @v start	Pointer to first byte of @a version field
317
+ * @v end	Pointer to first byte not in the RSN IE
318
+ * @ret secprot	Security handshaking protocol used by network
319
+ * @ret crypt	Cryptosystem used by network
320
+ * @ret rc	Return status code
321
+ *
322
+ * If the IE cannot be parsed, returns an error indication and leaves
323
+ * @a secprot and @a crypt unchanged.
324
+ */
325
+int sec80211_detect_ie ( int is_rsn, u8 *start, u8 *end,
326
+			 enum net80211_security_proto *secprot,
327
+			 enum net80211_crypto_alg *crypt )
328
+{
329
+	enum net80211_security_proto sp;
330
+	enum net80211_crypto_alg cr;
331
+	struct descriptor_map *map;
332
+	u8 *rsn = start;
333
+
334
+	/* Set some defaults */
335
+	cr = ( is_rsn ? NET80211_CRYPT_CCMP : NET80211_CRYPT_TKIP );
336
+	sp = NET80211_SECPROT_EAP;
337
+
338
+	rsn += 2;		/* version - already checked */
339
+	rsn += 4;		/* group cipher - we don't use it here */
340
+
341
+	if ( rsn >= end )
342
+		goto done;
343
+
344
+	/* Pick crypto algorithm */
345
+	map = rsn_pick_desc ( &rsn, end, rsn_cipher_map,
346
+			      table_start ( NET80211_CRYPTOS ),
347
+			      table_end ( NET80211_CRYPTOS ) );
348
+	if ( ! map )
349
+		goto invalid_rsn;
350
+
351
+	cr = map->net80211_type;
352
+
353
+	if ( rsn >= end )
354
+		goto done;
355
+
356
+	/* Pick handshaking algorithm */
357
+	map = rsn_pick_desc ( &rsn, end, rsn_akm_map,
358
+			      table_start ( NET80211_HANDSHAKERS ),
359
+			      table_end ( NET80211_HANDSHAKERS ) );
360
+	if ( ! map )
361
+		goto invalid_rsn;
362
+
363
+	sp = map->net80211_type;
364
+
365
+ done:
366
+	DBG ( "RSN detect: OK, crypto type %d, secprot type %d\n", cr, sp );
367
+	*secprot = sp;
368
+	*crypt = cr;
369
+	return 0;
370
+
371
+ invalid_rsn:
372
+	DBG ( "RSN detect: invalid RSN IE\n" );
373
+	return -EINVAL;
374
+}
375
+
376
+
377
+/**
378
+ * Detect the cryptosystem and handshaking protocol used by an 802.11 network
379
+ *
380
+ * @v iob	I/O buffer containing beacon frame
381
+ * @ret secprot	Security handshaking protocol used by network
382
+ * @ret crypt	Cryptosystem used by network
383
+ * @ret rc	Return status code
384
+ *
385
+ * This function uses weak linkage, as it must be called from generic
386
+ * contexts but should only be linked in if some encryption is
387
+ * supported; you must test its address against @c NULL before calling
388
+ * it. If it does not exist, any network with the PRIVACY bit set in
389
+ * beacon->capab should be considered unknown.
390
+ */
391
+int _sec80211_detect ( struct io_buffer *iob,
392
+		       enum net80211_security_proto *secprot,
393
+		       enum net80211_crypto_alg *crypt )
394
+{
395
+	struct ieee80211_frame *hdr = iob->data;
396
+	struct ieee80211_beacon *beacon =
397
+		( struct ieee80211_beacon * ) hdr->data;
398
+	u8 *rsn, *rsn_end;
399
+	int is_rsn, rc;
400
+
401
+	*crypt = NET80211_CRYPT_UNKNOWN;
402
+	*secprot = NET80211_SECPROT_UNKNOWN;
403
+
404
+	/* Find RSN or WPA IE */
405
+	if ( ! ( rsn = sec80211_find_rsn ( beacon->info_element, iob->tail,
406
+					   &is_rsn, &rsn_end ) ) ) {
407
+		/* No security IE at all; either WEP or no security. */
408
+		*secprot = NET80211_SECPROT_NONE;
409
+
410
+		if ( beacon->capability & IEEE80211_CAPAB_PRIVACY )
411
+			*crypt = NET80211_CRYPT_WEP;
412
+		else
413
+			*crypt = NET80211_CRYPT_NONE;
414
+
415
+		return 0;
416
+	}
417
+
418
+	/* Determine type of security */
419
+	if ( ( rc = sec80211_detect_ie ( is_rsn, rsn, rsn_end, secprot,
420
+					 crypt ) ) == 0 )
421
+		return 0;
422
+
423
+	/* If we get here, the RSN IE was invalid */
424
+
425
+	*crypt = NET80211_CRYPT_UNKNOWN;
426
+	*secprot = NET80211_SECPROT_UNKNOWN;
427
+	DBG ( "Failed to handle RSN IE:\n" );
428
+	DBG_HD ( rsn, rsn_end - rsn );
429
+	return rc;
430
+}
431
+
432
+
433
+/**
434
+ * Determine RSN descriptor for specified net80211 ID
435
+ *
436
+ * @v id	net80211 ID value
437
+ * @v rsnie	Whether to return a new-format (RSN IE) descriptor
438
+ * @v map	Map to use in translation
439
+ * @ret desc	RSN descriptor, or 0 on error
440
+ *
441
+ * If @a rsnie is false, returns an old-format (WPA vendor IE)
442
+ * descriptor.
443
+ */
444
+static u32 rsn_get_desc ( unsigned id, int rsnie, struct descriptor_map *map )
445
+{
446
+	u32 vendor = ( rsnie ? IEEE80211_RSN_OUI : IEEE80211_WPA_OUI );
447
+
448
+	for ( ; map->oui_type != END_MAGIC; map++ ) {
449
+		if ( map->net80211_type == id )
450
+			return map->oui_type | vendor;
451
+	}
452
+
453
+	return 0;
454
+}
455
+
456
+/**
457
+ * Determine RSN descriptor for specified net80211 cryptosystem number
458
+ *
459
+ * @v crypt	Cryptosystem number
460
+ * @v rsnie	Whether to return a new-format (RSN IE) descriptor
461
+ * @ret desc	RSN descriptor
462
+ *
463
+ * If @a rsnie is false, returns an old-format (WPA vendor IE)
464
+ * descriptor.
465
+ */
466
+u32 sec80211_rsn_get_crypto_desc ( enum net80211_crypto_alg crypt, int rsnie )
467
+{
468
+	return rsn_get_desc ( crypt, rsnie, rsn_cipher_map );
469
+}
470
+
471
+/**
472
+ * Determine RSN descriptor for specified net80211 handshaker number
473
+ *
474
+ * @v secprot	Handshaker number
475
+ * @v rsnie	Whether to return a new-format (RSN IE) descriptor
476
+ * @ret desc	RSN descriptor
477
+ *
478
+ * If @a rsnie is false, returns an old-format (WPA vendor IE)
479
+ * descriptor.
480
+ */
481
+u32 sec80211_rsn_get_akm_desc ( enum net80211_security_proto secprot,
482
+				int rsnie )
483
+{
484
+	return rsn_get_desc ( secprot, rsnie, rsn_akm_map );
485
+}
486
+
487
+/**
488
+ * Determine net80211 cryptosystem number from RSN descriptor
489
+ *
490
+ * @v desc	RSN descriptor
491
+ * @ret crypt	net80211 cryptosystem enumeration value
492
+ */
493
+enum net80211_crypto_alg sec80211_rsn_get_net80211_crypt ( u32 desc )
494
+{
495
+	struct descriptor_map *map = rsn_cipher_map;
496
+
497
+	for ( ; map->oui_type != END_MAGIC; map++ ) {
498
+		if ( map->oui_type == ( desc & OUI_TYPE_MASK ) )
499
+			break;
500
+	}
501
+
502
+	return map->net80211_type;
503
+}

Loading…
Cancel
Save