mirror of
				https://git.kernel.org/pub/scm/network/wireless/iwd.git
				synced 2025-10-31 21:27:30 +01:00 
			
		
		
		
	adhoc: implement setting TX GTK
Adhoc requires 2 GTK's to be set, a single TX GTK and a per-mac RX GTK. The per-mac RX GTK already gets set via netdev_set_gtk. The single TX GTK is created the same as AP, where, upon the first station connecting a GTK is generated and set in the kernel. Then any subsequent stations use GET_KEY to retrieve the GTK and set it in the handshake.
This commit is contained in:
		
							parent
							
								
									2123d613fc
								
							
						
					
					
						commit
						70d6c9c692
					
				
							
								
								
									
										182
									
								
								src/adhoc.c
									
									
									
									
									
								
							
							
						
						
									
										182
									
								
								src/adhoc.c
									
									
									
									
									
								
							| @ -26,6 +26,8 @@ | ||||
| 
 | ||||
| #include <ell/ell.h> | ||||
| 
 | ||||
| #include "linux/nl80211.h" | ||||
| 
 | ||||
| #include "src/iwd.h" | ||||
| #include "src/device.h" | ||||
| #include "src/netdev.h" | ||||
| @ -38,6 +40,7 @@ | ||||
| #include "src/mpdu.h" | ||||
| #include "src/adhoc.h" | ||||
| #include "src/dbus.h" | ||||
| #include "src/nl80211_util.h" | ||||
| 
 | ||||
| struct adhoc_state { | ||||
| 	struct netdev *netdev; | ||||
| @ -47,8 +50,13 @@ struct adhoc_state { | ||||
| 	uint32_t sta_watch_id; | ||||
| 	uint32_t netdev_watch_id; | ||||
| 	struct l_dbus_message *pending; | ||||
| 	uint32_t ciphers; | ||||
| 	uint32_t group_cipher; | ||||
| 	uint8_t gtk[CRYPTO_MAX_GTK_LEN]; | ||||
| 	uint8_t gtk_index; | ||||
| 	bool started : 1; | ||||
| 	bool open : 1; | ||||
| 	bool gtk_set : 1; | ||||
| }; | ||||
| 
 | ||||
| struct sta_state { | ||||
| @ -58,10 +66,12 @@ struct sta_state { | ||||
| 	struct handshake_state *hs_sta; | ||||
| 	struct eapol_sm *sm_a; | ||||
| 	struct handshake_state *hs_auth; | ||||
| 	uint32_t gtk_query_cmd_id; | ||||
| 
 | ||||
| 	bool authenticated : 1; | ||||
| }; | ||||
| 
 | ||||
| static struct l_genl_family *nl80211 = NULL; | ||||
| static uint32_t netdev_watch; | ||||
| 
 | ||||
| static void adhoc_sta_free(void *data) | ||||
| @ -71,6 +81,9 @@ static void adhoc_sta_free(void *data) | ||||
| 	if (sta->adhoc->open) | ||||
| 		goto end; | ||||
| 
 | ||||
| 	if (sta->gtk_query_cmd_id) | ||||
| 		l_genl_family_cancel(nl80211, sta->gtk_query_cmd_id); | ||||
| 
 | ||||
| 	if (sta->sm) | ||||
| 		eapol_sm_free(sta->sm); | ||||
| 
 | ||||
| @ -94,6 +107,11 @@ static void adhoc_remove_sta(struct sta_state *sta) | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (sta->gtk_query_cmd_id) { | ||||
| 		l_genl_family_cancel(nl80211, sta->gtk_query_cmd_id); | ||||
| 		sta->gtk_query_cmd_id = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* signal station has been removed */ | ||||
| 	if (sta->authenticated) { | ||||
| 		l_dbus_property_changed(dbus_get_bus(), | ||||
| @ -125,12 +143,10 @@ static void adhoc_reset(struct adhoc_state *adhoc) | ||||
| static void adhoc_set_rsn_info(struct adhoc_state *adhoc, | ||||
| 						struct ie_rsn_info *rsn) | ||||
| { | ||||
| 	struct wiphy *wiphy = netdev_get_wiphy(adhoc->netdev); | ||||
| 
 | ||||
| 	memset(rsn, 0, sizeof(*rsn)); | ||||
| 	rsn->akm_suites = IE_RSN_AKM_SUITE_PSK; | ||||
| 	rsn->pairwise_ciphers = wiphy_select_cipher(wiphy, 0xffff); | ||||
| 	rsn->group_cipher = IE_RSN_CIPHER_SUITE_NO_GROUP_TRAFFIC; | ||||
| 	rsn->pairwise_ciphers = adhoc->ciphers; | ||||
| 	rsn->group_cipher = adhoc->group_cipher; | ||||
| } | ||||
| 
 | ||||
| static bool ap_sta_match_addr(const void *a, const void *b) | ||||
| @ -180,7 +196,8 @@ static void adhoc_handshake_event(struct handshake_state *hs, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static struct eapol_sm *adhoc_new_sm(struct sta_state *sta, bool authenticator) | ||||
| static struct eapol_sm *adhoc_new_sm(struct sta_state *sta, bool authenticator, | ||||
| 					const uint8_t *gtk_rsc) | ||||
| { | ||||
| 	struct adhoc_state *adhoc = sta->adhoc; | ||||
| 	struct netdev *netdev = adhoc->netdev; | ||||
| @ -216,6 +233,10 @@ static struct eapol_sm *adhoc_new_sm(struct sta_state *sta, bool authenticator) | ||||
| 		handshake_state_set_supplicant_address(hs, own_addr); | ||||
| 	} | ||||
| 
 | ||||
| 	if (gtk_rsc) | ||||
| 		handshake_state_set_gtk(hs, adhoc->gtk, adhoc->gtk_index, | ||||
| 					gtk_rsc); | ||||
| 
 | ||||
| 	sm = eapol_sm_new(hs); | ||||
| 	if (!sm) { | ||||
| 		l_error("could not create sm object"); | ||||
| @ -239,9 +260,65 @@ static void adhoc_free(struct adhoc_state *adhoc) | ||||
| 	l_free(adhoc); | ||||
| } | ||||
| 
 | ||||
| static void adhoc_start_rsna(struct sta_state *sta, const uint8_t *gtk_rsc) | ||||
| { | ||||
| 	sta->sm_a = adhoc_new_sm(sta, true, gtk_rsc); | ||||
| 	if (!sta->sm_a) { | ||||
| 		l_error("could not create authenticator state machine"); | ||||
| 		goto failed; | ||||
| 	} | ||||
| 
 | ||||
| 	sta->sm = adhoc_new_sm(sta, false, NULL); | ||||
| 	if (!sta->sm) { | ||||
| 		l_error("could not create station state machine"); | ||||
| 		goto failed; | ||||
| 	} | ||||
| 
 | ||||
| 	eapol_register(sta->sm); | ||||
| 	eapol_register(sta->sm_a); | ||||
| 
 | ||||
| 	eapol_start(sta->sm); | ||||
| 
 | ||||
| 	return; | ||||
| 
 | ||||
| failed: | ||||
| 	adhoc_remove_sta(sta); | ||||
| } | ||||
| 
 | ||||
| static void adhoc_gtk_op_cb(struct l_genl_msg *msg, void *user_data) | ||||
| { | ||||
| 	if (l_genl_msg_get_error(msg) < 0) { | ||||
| 		uint8_t cmd = l_genl_msg_get_command(msg); | ||||
| 		const char *cmd_name = | ||||
| 			cmd == NL80211_CMD_NEW_KEY ? "NEW_KEY" : "SET_KEY"; | ||||
| 
 | ||||
| 		l_error("%s failed for the GTK: %i", | ||||
| 			cmd_name, l_genl_msg_get_error(msg)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void adhoc_gtk_query_cb(struct l_genl_msg *msg, void *user_data) | ||||
| { | ||||
| 	struct sta_state *sta = user_data; | ||||
| 	const void *gtk_rsc; | ||||
| 
 | ||||
| 	sta->gtk_query_cmd_id = 0; | ||||
| 
 | ||||
| 	gtk_rsc = nl80211_parse_get_key_seq(msg); | ||||
| 	if (!gtk_rsc) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	adhoc_start_rsna(sta, gtk_rsc); | ||||
| 	return; | ||||
| 
 | ||||
| error: | ||||
| 	adhoc_remove_sta(sta); | ||||
| } | ||||
| 
 | ||||
| static void adhoc_new_station(struct adhoc_state *adhoc, const uint8_t *mac) | ||||
| { | ||||
| 	struct sta_state *sta; | ||||
| 	struct l_genl_msg *msg; | ||||
| 
 | ||||
| 	sta = l_queue_find(adhoc->sta_states, ap_sta_match_addr, mac); | ||||
| 	if (sta) { | ||||
| @ -249,6 +326,54 @@ static void adhoc_new_station(struct adhoc_state *adhoc, const uint8_t *mac) | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Follows same logic as AP. If this is the first station we create and | ||||
| 	 * set a group key. Any subsequent connections will use GET_KEY for this | ||||
| 	 * tx GTK. | ||||
| 	 */ | ||||
| 	if (adhoc->group_cipher != IE_RSN_CIPHER_SUITE_NO_GROUP_TRAFFIC && | ||||
| 			!adhoc->gtk_set && !adhoc->open) { | ||||
| 		enum crypto_cipher group_cipher = | ||||
| 			ie_rsn_cipher_suite_to_cipher(adhoc->group_cipher); | ||||
| 		int gtk_len = crypto_cipher_key_len(group_cipher); | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Generate our GTK.  Not following the example derivation | ||||
| 		 * method in 802.11-2016 section 12.7.1.4 because a simple | ||||
| 		 * l_getrandom is just as good. | ||||
| 		 */ | ||||
| 		l_getrandom(adhoc->gtk, gtk_len); | ||||
| 		adhoc->gtk_index = 1; | ||||
| 
 | ||||
| 		msg = nl80211_build_new_key_group( | ||||
| 					netdev_get_ifindex(adhoc->netdev), | ||||
| 					group_cipher, adhoc->gtk_index, | ||||
| 					adhoc->gtk, gtk_len, NULL, | ||||
| 					0, NULL); | ||||
| 
 | ||||
| 		if (!l_genl_family_send(nl80211, msg, adhoc_gtk_op_cb, NULL, | ||||
| 					NULL)) { | ||||
| 			l_genl_msg_unref(msg); | ||||
| 			l_error("Issuing NEW_KEY failed"); | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		msg = nl80211_build_set_key(netdev_get_ifindex(adhoc->netdev), | ||||
| 						adhoc->gtk_index); | ||||
| 		if (!l_genl_family_send(nl80211, msg, adhoc_gtk_op_cb, NULL, | ||||
| 					NULL)) { | ||||
| 			l_genl_msg_unref(msg); | ||||
| 			l_error("Issuing SET_KEY failed"); | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * Set the flag now because any new associating STA will | ||||
| 		 * just use NL80211_CMD_GET_KEY from now. | ||||
| 		 */ | ||||
| 		adhoc->gtk_set = true; | ||||
| 	} | ||||
| 
 | ||||
| 	sta = l_new(struct sta_state, 1); | ||||
| 
 | ||||
| 	memset(sta, 0, sizeof(struct sta_state)); | ||||
| @ -269,27 +394,22 @@ static void adhoc_new_station(struct adhoc_state *adhoc, const uint8_t *mac) | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	sta->sm_a = adhoc_new_sm(sta, true); | ||||
| 	if (!sta->sm_a) { | ||||
| 		l_error("could not create authenticator state machine"); | ||||
| 		goto failed; | ||||
| 	if (adhoc->group_cipher == IE_RSN_CIPHER_SUITE_NO_GROUP_TRAFFIC) | ||||
| 		adhoc_start_rsna(sta, NULL); | ||||
| 	else { | ||||
| 		msg = nl80211_build_get_key(netdev_get_ifindex(adhoc->netdev), | ||||
| 					adhoc->gtk_index); | ||||
| 		sta->gtk_query_cmd_id = l_genl_family_send(nl80211, msg, | ||||
| 							adhoc_gtk_query_cb, | ||||
| 							sta, NULL); | ||||
| 		if (!sta->gtk_query_cmd_id) { | ||||
| 			l_genl_msg_unref(msg); | ||||
| 			l_error("Issuing GET_KEY failed"); | ||||
| 
 | ||||
| 			adhoc_remove_sta(sta); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	sta->sm = adhoc_new_sm(sta, false); | ||||
| 	if (!sta->sm) { | ||||
| 		l_error("could not create station state machine"); | ||||
| 		goto failed; | ||||
| 	} | ||||
| 
 | ||||
| 	eapol_register(sta->sm); | ||||
| 	eapol_register(sta->sm_a); | ||||
| 
 | ||||
| 	eapol_start(sta->sm); | ||||
| 
 | ||||
| 	return; | ||||
| 
 | ||||
| failed: | ||||
| 	adhoc_remove_sta(sta); | ||||
| } | ||||
| 
 | ||||
| static void adhoc_del_station(struct adhoc_state *adhoc, const uint8_t *mac) | ||||
| @ -363,11 +483,10 @@ static struct l_dbus_message *adhoc_dbus_start(struct l_dbus *dbus, | ||||
| 	adhoc->ssid = l_strdup(ssid); | ||||
| 	adhoc->pending = l_dbus_message_ref(message); | ||||
| 	adhoc->sta_states = l_queue_new(); | ||||
| 	adhoc->ciphers = wiphy_select_cipher(wiphy, 0xffff); | ||||
| 	adhoc->group_cipher = wiphy_select_cipher(wiphy, 0xffff); | ||||
| 
 | ||||
| 	memset(&rsn, 0, sizeof(rsn)); | ||||
| 	rsn.akm_suites = IE_RSN_AKM_SUITE_PSK; | ||||
| 	rsn.pairwise_ciphers = wiphy_select_cipher(wiphy, 0xffff); | ||||
| 	rsn.group_cipher = IE_RSN_CIPHER_SUITE_NO_GROUP_TRAFFIC; | ||||
| 	adhoc_set_rsn_info(adhoc, &rsn); | ||||
| 	ie_build_rsne(&rsn, ie_elems); | ||||
| 
 | ||||
| 	rsn_ie.iov_base = ie_elems; | ||||
| @ -556,11 +675,14 @@ static void adhoc_netdev_watch(struct netdev *netdev, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| bool adhoc_init(void) | ||||
| bool adhoc_init(struct l_genl_family *nl) | ||||
| { | ||||
| 	netdev_watch = netdev_watch_add(adhoc_netdev_watch, NULL, NULL); | ||||
| 	l_dbus_register_interface(dbus_get_bus(), IWD_ADHOC_INTERFACE, | ||||
| 			adhoc_setup_interface, adhoc_destroy_interface, false); | ||||
| 
 | ||||
| 	nl80211 = nl; | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -22,5 +22,5 @@ | ||||
| 
 | ||||
| struct device; | ||||
| 
 | ||||
| bool adhoc_init(void); | ||||
| bool adhoc_init(struct l_genl_family *nl); | ||||
| void adhoc_exit(void); | ||||
|  | ||||
| @ -159,6 +159,7 @@ static void nl80211_appeared(void *user_data) | ||||
| 		l_error("Unable to init scan functionality"); | ||||
| 
 | ||||
| 	ap_init(nl80211); | ||||
| 	adhoc_init(nl80211); | ||||
| } | ||||
| 
 | ||||
| static void nl80211_vanished(void *user_data) | ||||
| @ -166,6 +167,7 @@ static void nl80211_vanished(void *user_data) | ||||
| 	l_debug("Lost nl80211 interface"); | ||||
| 
 | ||||
| 	ap_exit(); | ||||
| 	adhoc_exit(); | ||||
| 	scan_exit(); | ||||
| 	wiphy_exit(); | ||||
| } | ||||
| @ -477,7 +479,6 @@ int main(int argc, char *argv[]) | ||||
| 	if (!device_init()) | ||||
| 		goto fail_device; | ||||
| 
 | ||||
| 	adhoc_init(); | ||||
| 	station_init(); | ||||
| 	wsc_init(); | ||||
| 	network_init(); | ||||
| @ -494,7 +495,6 @@ int main(int argc, char *argv[]) | ||||
| 	network_exit(); | ||||
| 	wsc_exit(); | ||||
| 	station_exit(); | ||||
| 	adhoc_exit(); | ||||
| 	device_exit(); | ||||
| fail_device: | ||||
| 	netdev_exit(); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 James Prestwood
						James Prestwood