mirror of
				https://git.kernel.org/pub/scm/network/wireless/iwd.git
				synced 2025-10-31 04:57:25 +01:00 
			
		
		
		
	monitor: Add initial version of iwmon utitlity
This commit is contained in:
		
							parent
							
								
									e724c166fe
								
							
						
					
					
						commit
						db60e4d48f
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -20,6 +20,7 @@ autom4te.cache | ||||
| ell | ||||
| src/iwd | ||||
| client/iwctl | ||||
| monitor/iwmon | ||||
| unit/test-pbkdf2-sha1 | ||||
| unit/test-prf-sha1 | ||||
| unit/*.log | ||||
|  | ||||
| @ -34,7 +34,7 @@ ell_sources = ell/ell.h ell/private.h \ | ||||
| 
 | ||||
| ell_libell_internal_la_SOURCES = $(ell_sources) | ||||
| 
 | ||||
| bin_PROGRAMS = src/iwd client/iwctl | ||||
| bin_PROGRAMS = src/iwd client/iwctl monitor/iwmon | ||||
| 
 | ||||
| src_iwd_SOURCES = src/main.c linux/nl80211.h linux/kdbus.h \
 | ||||
| 					src/kdbus.h src/kdbus.c \
 | ||||
| @ -48,6 +48,10 @@ client_iwctl_SOURCES = client/main.c linux/kdbus.h \ | ||||
| 					src/kdbus.h src/kdbus.c | ||||
| client_iwctl_LDADD = ell/libell-internal.la | ||||
| 
 | ||||
| monitor_iwmon_SOURCES = monitor/main.c linux/nl80211.h \
 | ||||
| 					monitor/nlmon.h monitor/nlmon.c | ||||
| monitor_iwmon_LDADD = ell/libell-internal.la | ||||
| 
 | ||||
| noinst_PROGRAMS = | ||||
| 
 | ||||
| unit_tests = unit/test-pbkdf2-sha1 unit/test-prf-sha1 unit/test-ie | ||||
|  | ||||
							
								
								
									
										165
									
								
								monitor/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								monitor/main.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,165 @@ | ||||
| /*
 | ||||
|  * | ||||
|  *  Wireless daemon for Linux | ||||
|  * | ||||
|  *  Copyright (C) 2013-2014  Intel Corporation. All rights reserved. | ||||
|  * | ||||
|  *  This library is free software; you can redistribute it and/or | ||||
|  *  modify it under the terms of the GNU Lesser General Public | ||||
|  *  License as published by the Free Software Foundation; either | ||||
|  *  version 2.1 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  *  This library is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  *  Lesser General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU Lesser General Public | ||||
|  *  License along with this library; if not, write to the Free Software | ||||
|  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include <config.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <linux/genetlink.h> | ||||
| #include <ell/ell.h> | ||||
| 
 | ||||
| #include "linux/nl80211.h" | ||||
| #include "monitor/nlmon.h" | ||||
| 
 | ||||
| static struct nlmon *nlmon = NULL; | ||||
| 
 | ||||
| #define NLA_OK(nla,len)         ((len) >= (int) sizeof(struct nlattr) && \ | ||||
| 				(nla)->nla_len >= sizeof(struct nlattr) && \ | ||||
| 				(nla)->nla_len <= (len)) | ||||
| #define NLA_NEXT(nla,attrlen)	((attrlen) -= NLA_ALIGN((nla)->nla_len), \ | ||||
| 				(struct nlattr*)(((char*)(nla)) + \ | ||||
| 				NLA_ALIGN((nla)->nla_len))) | ||||
| 
 | ||||
| #define NLA_LENGTH(len)		(NLA_ALIGN(sizeof(struct nlattr)) + (len)) | ||||
| #define NLA_DATA(nla)		((void*)(((char*)(nla)) + NLA_LENGTH(0))) | ||||
| #define NLA_PAYLOAD(nla)	((int)((nla)->nla_len - NLA_LENGTH(0))) | ||||
| 
 | ||||
| static void genl_parse(uint16_t type, const void *data, uint32_t len) | ||||
| { | ||||
| 	const struct genlmsghdr *genlmsg = data; | ||||
| 	const struct nlattr *nla; | ||||
| 	char name[GENL_NAMSIZ]; | ||||
| 	uint16_t id = GENL_ID_GENERATE; | ||||
| 
 | ||||
| 	if (nlmon) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (type != GENL_ID_CTRL) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (genlmsg->cmd != CTRL_CMD_NEWFAMILY) | ||||
| 		return; | ||||
| 
 | ||||
| 	for (nla = data + GENL_HDRLEN; NLA_OK(nla, len); | ||||
| 						nla = NLA_NEXT(nla, len)) { | ||||
| 		switch (nla->nla_type & NLA_TYPE_MASK) { | ||||
| 		case CTRL_ATTR_FAMILY_ID: | ||||
| 			id = *((uint16_t *) NLA_DATA(nla)); | ||||
| 			break; | ||||
| 		case CTRL_ATTR_FAMILY_NAME: | ||||
| 			strncpy(name, NLA_DATA(nla), GENL_NAMSIZ); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (id == GENL_ID_GENERATE) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (!strcmp(name, NL80211_GENL_NAME)) | ||||
| 		nlmon = nlmon_open(id); | ||||
| } | ||||
| 
 | ||||
| static void genl_notify(uint16_t type, const void *data, | ||||
| 						uint32_t len, void *user_data) | ||||
| { | ||||
| 	genl_parse(type, data, len); | ||||
| } | ||||
| 
 | ||||
| static void genl_callback(int error, uint16_t type, const void *data, | ||||
| 						uint32_t len, void *user_data) | ||||
| { | ||||
| 	if (error < 0) { | ||||
| 		fprintf(stderr, "Failed to lookup nl80211 family\n"); | ||||
| 		l_main_quit(); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	genl_parse(type, data, len); | ||||
| } | ||||
| 
 | ||||
| static struct l_netlink *genl_lookup(void) | ||||
| { | ||||
| 	struct l_netlink *genl; | ||||
| 	char buf[GENL_HDRLEN + NLA_HDRLEN + GENL_NAMSIZ]; | ||||
| 	struct genlmsghdr *genlmsg; | ||||
| 	struct nlattr *nla; | ||||
| 
 | ||||
| 	genl = l_netlink_new(NETLINK_GENERIC); | ||||
| 
 | ||||
| 	l_netlink_register(genl, GENL_ID_CTRL, genl_notify, NULL, NULL); | ||||
| 
 | ||||
| 	genlmsg = (struct genlmsghdr *) buf; | ||||
| 	genlmsg->cmd = CTRL_CMD_GETFAMILY; | ||||
| 	genlmsg->version = 0; | ||||
| 	genlmsg->reserved = 0; | ||||
| 
 | ||||
| 	nla = (struct nlattr *) (buf + GENL_HDRLEN); | ||||
| 	nla->nla_len = NLA_HDRLEN + GENL_NAMSIZ; | ||||
| 	nla->nla_type = CTRL_ATTR_FAMILY_NAME; | ||||
| 	strncpy(buf + GENL_HDRLEN + NLA_HDRLEN, | ||||
| 					NL80211_GENL_NAME, GENL_NAMSIZ); | ||||
| 
 | ||||
| 	l_netlink_send(genl, GENL_ID_CTRL, 0, buf, sizeof(buf), | ||||
| 						genl_callback, NULL, NULL); | ||||
| 
 | ||||
| 	return genl; | ||||
| } | ||||
| 
 | ||||
| static void signal_handler(struct l_signal *signal, uint32_t signo, | ||||
| 							void *user_data) | ||||
| { | ||||
| 	switch (signo) { | ||||
| 	case SIGINT: | ||||
| 	case SIGTERM: | ||||
| 		l_main_quit(); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
| 	struct l_signal *signal; | ||||
| 	struct l_netlink *genl; | ||||
| 	sigset_t mask; | ||||
| 	int exit_status; | ||||
| 
 | ||||
| 	sigemptyset(&mask); | ||||
| 	sigaddset(&mask, SIGINT); | ||||
| 	sigaddset(&mask, SIGTERM); | ||||
| 
 | ||||
| 	signal = l_signal_create(&mask, signal_handler, NULL, NULL); | ||||
| 
 | ||||
| 	genl = genl_lookup(); | ||||
| 
 | ||||
| 	l_main_run(); | ||||
| 
 | ||||
| 	l_netlink_destroy(genl); | ||||
| 	nlmon_close(nlmon); | ||||
| 
 | ||||
| 	exit_status = EXIT_SUCCESS; | ||||
| 
 | ||||
| 	l_signal_remove(signal); | ||||
| 
 | ||||
| 	return exit_status; | ||||
| } | ||||
							
								
								
									
										951
									
								
								monitor/nlmon.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										951
									
								
								monitor/nlmon.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,951 @@ | ||||
| /*
 | ||||
|  * | ||||
|  *  Wireless daemon for Linux | ||||
|  * | ||||
|  *  Copyright (C) 2013-2014  Intel Corporation. All rights reserved. | ||||
|  * | ||||
|  *  This library is free software; you can redistribute it and/or | ||||
|  *  modify it under the terms of the GNU Lesser General Public | ||||
|  *  License as published by the Free Software Foundation; either | ||||
|  *  version 2.1 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  *  This library is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  *  Lesser General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU Lesser General Public | ||||
|  *  License along with this library; if not, write to the Free Software | ||||
|  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #ifdef HAVE_CONFIG_H | ||||
| #include <config.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <sys/socket.h> | ||||
| #include <arpa/inet.h> | ||||
| #include <linux/if.h> | ||||
| #include <linux/if_packet.h> | ||||
| #include <linux/if_ether.h> | ||||
| #include <linux/netlink.h> | ||||
| #include <linux/genetlink.h> | ||||
| #include <ell/ell.h> | ||||
| 
 | ||||
| #include "linux/nl80211.h" | ||||
| #include "monitor/nlmon.h" | ||||
| 
 | ||||
| struct nlmon { | ||||
| 	uint16_t id; | ||||
| 	struct l_io *io; | ||||
| 	struct l_queue *req_list; | ||||
| }; | ||||
| 
 | ||||
| struct nlmon_req { | ||||
| 	uint32_t seq; | ||||
| 	uint32_t pid; | ||||
| 	uint16_t flags; | ||||
| }; | ||||
| 
 | ||||
| static void nlmon_req_free(void *data) | ||||
| { | ||||
| 	struct nlmon_req *req = data; | ||||
| 
 | ||||
| 	l_free(req); | ||||
| } | ||||
| 
 | ||||
| enum attr_type { | ||||
| 	ATTR_UNSPEC, | ||||
| 	ATTR_FLAG, | ||||
| 	ATTR_U8, | ||||
| 	ATTR_U16, | ||||
| 	ATTR_U32, | ||||
| 	ATTR_U64, | ||||
| 	ATTR_STRING, | ||||
| 	ATTR_ADDRESS, | ||||
| 	ATTR_BINARY, | ||||
| }; | ||||
| 
 | ||||
| struct attr_entry { | ||||
| 	uint16_t attr; | ||||
| 	const char *str; | ||||
| 	enum attr_type type; | ||||
| }; | ||||
| 
 | ||||
| static const struct attr_entry attr_table[] = { | ||||
| 	{ NL80211_ATTR_WIPHY, | ||||
| 			"Wiphy", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_WIPHY_NAME, | ||||
| 			"Wiphy Name", ATTR_STRING }, | ||||
| 	{ NL80211_ATTR_IFINDEX, | ||||
| 			"Interface Index", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_IFNAME, | ||||
| 			"Interface Name", ATTR_STRING }, | ||||
| 	{ NL80211_ATTR_IFTYPE, | ||||
| 			"Interface Type", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_MAC, | ||||
| 			"MAC Address", ATTR_ADDRESS }, | ||||
| 	{ NL80211_ATTR_KEY_DATA, | ||||
| 			"Key Data", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_KEY_IDX, | ||||
| 			"Key Index", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_KEY_CIPHER, | ||||
| 			"Key Cipher", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_KEY_SEQ, | ||||
| 			"Key Sequence", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_KEY_DEFAULT, | ||||
| 			"Key Default", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_BEACON_INTERVAL, | ||||
| 			"Beacon Interval", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_DTIM_PERIOD, | ||||
| 			"DTIM Period", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_BEACON_HEAD, | ||||
| 			"Beacon Head", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_BEACON_TAIL, | ||||
| 			"Beacon Tail", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_STA_AID, | ||||
| 			"Station AID", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_STA_FLAGS, | ||||
| 			"Station Flags" }, | ||||
| 	{ NL80211_ATTR_STA_LISTEN_INTERVAL, | ||||
| 			"Station Listen Interval", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_STA_SUPPORTED_RATES, | ||||
| 			"Station Supported Rates", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_STA_VLAN, | ||||
| 			"Station VLAN", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_STA_INFO, | ||||
| 			"Station Info" }, | ||||
| 	{ NL80211_ATTR_WIPHY_BANDS, | ||||
| 			"Wiphy Bands" }, | ||||
| 	{ NL80211_ATTR_MNTR_FLAGS, | ||||
| 			"MNTR Flags" }, | ||||
| 	{ NL80211_ATTR_MESH_ID, | ||||
| 			"Mesh ID", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_STA_PLINK_ACTION, | ||||
| 			"Station P-Link Action", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_MPATH_NEXT_HOP, | ||||
| 			"Mesh Path Next Hop", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_MPATH_INFO, | ||||
| 			"Mesh Path Info" }, | ||||
| 	{ NL80211_ATTR_BSS_CTS_PROT, | ||||
| 			"BSS CTS Protection", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_BSS_SHORT_PREAMBLE, | ||||
| 			"BSS Short Preamble", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_BSS_SHORT_SLOT_TIME, | ||||
| 			"BSS Short Slot Time", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_HT_CAPABILITY, | ||||
| 			"HT Capability" }, | ||||
| 	{ NL80211_ATTR_SUPPORTED_IFTYPES, | ||||
| 			"Supported Interface Types" }, | ||||
| 	{ NL80211_ATTR_REG_ALPHA2, | ||||
| 			"Regulatory Alpha2", ATTR_STRING }, | ||||
| 	{ NL80211_ATTR_REG_RULES, | ||||
| 			"Regulatory Rules" }, | ||||
| 	{ NL80211_ATTR_MESH_CONFIG, | ||||
| 			"Mesh Configuration" }, | ||||
| 	{ NL80211_ATTR_BSS_BASIC_RATES, | ||||
| 			"BSS Basic Rates", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_WIPHY_TXQ_PARAMS, | ||||
| 			"Wiphy TXQ Parameters" }, | ||||
| 	{ NL80211_ATTR_WIPHY_FREQ, | ||||
| 			"Wiphy Frequency", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_WIPHY_CHANNEL_TYPE, | ||||
| 			"Wiphy Channel Type", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_KEY_DEFAULT_MGMT, | ||||
| 			"Key Default Management", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_MGMT_SUBTYPE, | ||||
| 			"Management Subtype", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_IE, | ||||
| 			"Information Elements", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_MAX_NUM_SCAN_SSIDS, | ||||
| 			"Max Number Scan SSIDs", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_SCAN_FREQUENCIES, | ||||
| 			"Scan Frequencies" }, | ||||
| 	{ NL80211_ATTR_SCAN_SSIDS, | ||||
| 			"Scan SSIDs" }, | ||||
| 	{ NL80211_ATTR_GENERATION, | ||||
| 			"Generation", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_BSS, | ||||
| 			"BSS" }, | ||||
| 	{ NL80211_ATTR_REG_INITIATOR, | ||||
| 			"Regulatory Initiator" }, | ||||
| 	{ NL80211_ATTR_REG_TYPE, | ||||
| 			"Regulatory Type" }, | ||||
| 	{ NL80211_ATTR_SUPPORTED_COMMANDS, | ||||
| 			"Supported Commands" }, | ||||
| 	{ NL80211_ATTR_FRAME, | ||||
| 			"Frame", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_SSID, | ||||
| 			"SSID", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_AUTH_TYPE, | ||||
| 			"Auth Type", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_REASON_CODE, | ||||
| 			"Reason Code", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_KEY_TYPE, | ||||
| 			"Key Type", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_MAX_SCAN_IE_LEN, | ||||
| 			"Max Scan IE Length", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_CIPHER_SUITES, | ||||
| 			"Cipher Suites" }, | ||||
| 	{ NL80211_ATTR_FREQ_BEFORE, | ||||
| 			"Frequency Before" }, | ||||
| 	{ NL80211_ATTR_FREQ_AFTER, | ||||
| 			"Frequency After" }, | ||||
| 	{ NL80211_ATTR_FREQ_FIXED, | ||||
| 			"Frequency Fixed", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_WIPHY_RETRY_SHORT, | ||||
| 			"Wiphy Retry Short", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_WIPHY_RETRY_LONG, | ||||
| 			"Wiphy Retry Long", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_WIPHY_FRAG_THRESHOLD, | ||||
| 			"Wiphy Frag Threshold", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_WIPHY_RTS_THRESHOLD, | ||||
| 			"Wiphy RTS Threshold", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_TIMED_OUT, | ||||
| 			"Timed Out", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_USE_MFP, | ||||
| 			"Use MFP", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_STA_FLAGS2, | ||||
| 			"Station Flags 2" }, | ||||
| 	{ NL80211_ATTR_CONTROL_PORT, | ||||
| 			"Control Port", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_TESTDATA, | ||||
| 			"Test Data" }, | ||||
| 	{ NL80211_ATTR_PRIVACY, | ||||
| 			"Privacy", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_DISCONNECTED_BY_AP, | ||||
| 			"Disconnect by AP", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_STATUS_CODE, | ||||
| 			"Status Code", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_CIPHER_SUITES_PAIRWISE, | ||||
| 			"Cipher Suites Pairwise" }, | ||||
| 	{ NL80211_ATTR_CIPHER_SUITE_GROUP, | ||||
| 			"Cipher Suite Group", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_WPA_VERSIONS, | ||||
| 			"WPA Versions", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_AKM_SUITES, | ||||
| 			"AKM Suites" }, | ||||
| 	{ NL80211_ATTR_REQ_IE, | ||||
| 			"Request IE" }, | ||||
| 	{ NL80211_ATTR_RESP_IE, | ||||
| 			"Response IE" }, | ||||
| 	{ NL80211_ATTR_PREV_BSSID, | ||||
| 			"Previous BSSID", ATTR_ADDRESS }, | ||||
| 	{ NL80211_ATTR_KEY, | ||||
| 			"Key" }, | ||||
| 	{ NL80211_ATTR_KEYS, | ||||
| 			"Keys" }, | ||||
| 	{ NL80211_ATTR_PID, | ||||
| 			"PID", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_4ADDR, | ||||
| 			"4-Address", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_SURVEY_INFO, | ||||
| 			"Survey Info" }, | ||||
| 	{ NL80211_ATTR_PMKID, | ||||
| 			"PMKID", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_MAX_NUM_PMKIDS, | ||||
| 			"Max Number PMKIDs", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_DURATION, | ||||
| 			"Duration", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_COOKIE, | ||||
| 			"Cookie", ATTR_U64 }, | ||||
| 	{ NL80211_ATTR_WIPHY_COVERAGE_CLASS, | ||||
| 			"Wiphy Coverage Class", ATTR_U8	}, | ||||
| 	{ NL80211_ATTR_TX_RATES, | ||||
| 			"TX Rates" }, | ||||
| 	{ NL80211_ATTR_FRAME_MATCH, | ||||
| 			"Frame Match", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_ACK, | ||||
| 			"ACK", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_PS_STATE, | ||||
| 			"PS State", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_CQM, | ||||
| 			"CQM" }, | ||||
| 	{ NL80211_ATTR_LOCAL_STATE_CHANGE, | ||||
| 			"Local State Change", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_AP_ISOLATE, | ||||
| 			"AP Isolate", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_WIPHY_TX_POWER_SETTING, | ||||
| 			"Wiphy TX Power Setting", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_WIPHY_TX_POWER_LEVEL, | ||||
| 			"Wiphy TX Power Level", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_TX_FRAME_TYPES, | ||||
| 			"TX Frame Types" }, | ||||
| 	{ NL80211_ATTR_RX_FRAME_TYPES, | ||||
| 			"RX Frame Types" }, | ||||
| 	{ NL80211_ATTR_FRAME_TYPE, | ||||
| 			"Frame Type", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_CONTROL_PORT_ETHERTYPE, | ||||
| 			"Control Port Ethertype", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, | ||||
| 			"Control Port No Encrypt", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_SUPPORT_IBSS_RSN, | ||||
| 			"Support IBSS RSN", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_WIPHY_ANTENNA_TX, | ||||
| 			"Wiphy Antenna TX", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_WIPHY_ANTENNA_RX, | ||||
| 			"Wiphy Antenna RX", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_MCAST_RATE, | ||||
| 			"Multicast Rate", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_OFFCHANNEL_TX_OK, | ||||
| 			"Offchannel TX OK", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_BSS_HT_OPMODE, | ||||
| 			"BSS HT Operation Mode", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_KEY_DEFAULT_TYPES, | ||||
| 			"Key Default Types" }, | ||||
| 	{ NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION, | ||||
| 			"Remain on Channel Duration " }, | ||||
| 	{ NL80211_ATTR_MESH_SETUP, | ||||
| 			"Mesh Setup" }, | ||||
| 	{ NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX, | ||||
| 			"Wiphy Antenna Avail TX" }, | ||||
| 	{ NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX, | ||||
| 			"Wiphy Antenna Avail RX" }, | ||||
| 	{ NL80211_ATTR_SUPPORT_MESH_AUTH, | ||||
| 			"Support Mesh Auth", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_STA_PLINK_STATE, | ||||
| 			"Station P-Link State" }, | ||||
| 	{ NL80211_ATTR_WOWLAN_TRIGGERS, | ||||
| 			"WoWLAN Triggers" }, | ||||
| 	{ NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, | ||||
| 			"WoWLAN Triggers Supported" }, | ||||
| 	{ NL80211_ATTR_SCHED_SCAN_INTERVAL, | ||||
| 			"Scheduled Scan Interval", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_INTERFACE_COMBINATIONS, | ||||
| 			"Interface Combinations" }, | ||||
| 	{ NL80211_ATTR_SOFTWARE_IFTYPES, | ||||
| 			"Software Interface Types" }, | ||||
| 	{ NL80211_ATTR_REKEY_DATA, | ||||
| 			"Rekey Data" }, | ||||
| 	{ NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS, | ||||
| 			"Max Num Sched Scan SSIDs", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN, | ||||
| 			"Max Sched Scan IE Len", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_SCAN_SUPP_RATES, | ||||
| 			"Scan Supported Rates" }, | ||||
| 	{ NL80211_ATTR_HIDDEN_SSID, | ||||
| 			"Hidden SSID", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_IE_PROBE_RESP, | ||||
| 			"IE Probe Response" }, | ||||
| 	{ NL80211_ATTR_IE_ASSOC_RESP, | ||||
| 			"IE Assoc Response" }, | ||||
| 	{ NL80211_ATTR_STA_WME, | ||||
| 			"Station WME" }, | ||||
| 	{ NL80211_ATTR_SUPPORT_AP_UAPSD, | ||||
| 			"Support AP UAPSD", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_ROAM_SUPPORT, | ||||
| 			"Roaming Support", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_SCHED_SCAN_MATCH, | ||||
| 			"Scheduled Scan Match" }, | ||||
| 	{ NL80211_ATTR_MAX_MATCH_SETS, | ||||
| 			"Max Match Sets", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_PMKSA_CANDIDATE, | ||||
| 			"PMKSA Candidate" }, | ||||
| 	{ NL80211_ATTR_TX_NO_CCK_RATE, | ||||
| 			"TX No CCK Rate", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_TDLS_ACTION, | ||||
| 			"TDLS Action", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_TDLS_DIALOG_TOKEN, | ||||
| 			"TDLS Dialog Token", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_TDLS_OPERATION, | ||||
| 			"TDLS Operation", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_TDLS_SUPPORT, | ||||
| 			"TDLS Support", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_TDLS_EXTERNAL_SETUP, | ||||
| 			"TDLS External Setup", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_DEVICE_AP_SME, | ||||
| 			"Device AP SME" }, | ||||
| 	{ NL80211_ATTR_DONT_WAIT_FOR_ACK, | ||||
| 			"Don't Wait for Ack", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_FEATURE_FLAGS, | ||||
| 			"Feature Flags" }, | ||||
| 	{ NL80211_ATTR_PROBE_RESP_OFFLOAD, | ||||
| 			"Probe Response Offload" }, | ||||
| 	{ NL80211_ATTR_PROBE_RESP, | ||||
| 			"Probe Response" }, | ||||
| 	{ NL80211_ATTR_DFS_REGION, | ||||
| 			"DFS Region", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_DISABLE_HT, | ||||
| 			"Diable HT", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_HT_CAPABILITY_MASK, | ||||
| 			"HT Capability Mask" }, | ||||
| 	{ NL80211_ATTR_NOACK_MAP, | ||||
| 			"No-Ack Map", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_INACTIVITY_TIMEOUT, | ||||
| 			"Inactivity Timeout", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_RX_SIGNAL_DBM, | ||||
| 			"RX Signal dBm", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_BG_SCAN_PERIOD, | ||||
| 			"Background Scan Period", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_WDEV, | ||||
| 			"Wireless Device", ATTR_U64 }, | ||||
| 	{ NL80211_ATTR_USER_REG_HINT_TYPE, | ||||
| 			"User Regulatroy Hint Type", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_CONN_FAILED_REASON, | ||||
| 			"Connection Failed Reason" }, | ||||
| 	{ NL80211_ATTR_SAE_DATA, | ||||
| 			"SAE Data" }, | ||||
| 	{ NL80211_ATTR_VHT_CAPABILITY, | ||||
| 			"VHT Capability" }, | ||||
| 	{ NL80211_ATTR_SCAN_FLAGS, | ||||
| 			"Scan Flags", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_CHANNEL_WIDTH, | ||||
| 			"Channel Width", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_CENTER_FREQ1, | ||||
| 			"Center Frequency 1", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_CENTER_FREQ2, | ||||
| 			"Center Frequency 2", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_P2P_CTWINDOW, | ||||
| 			"P2P CT Window", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_P2P_OPPPS, | ||||
| 			"P2P OP PPS", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_LOCAL_MESH_POWER_MODE, | ||||
| 			"Local Mesh Power Mode" }, | ||||
| 	{ NL80211_ATTR_ACL_POLICY, | ||||
| 			"ACL Policy", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_MAC_ADDRS, | ||||
| 			"MAC Addresses" }, | ||||
| 	{ NL80211_ATTR_MAC_ACL_MAX, | ||||
| 			"MAC ACL Max" }, | ||||
| 	{ NL80211_ATTR_RADAR_EVENT, | ||||
| 			"Radar Event" }, | ||||
| 	{ NL80211_ATTR_EXT_CAPA, | ||||
| 			"Extended Capabilities" }, | ||||
| 	{ NL80211_ATTR_EXT_CAPA_MASK, | ||||
| 			"Extended Capabilities Mask" }, | ||||
| 	{ NL80211_ATTR_STA_CAPABILITY, | ||||
| 			"Station Capability", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_STA_EXT_CAPABILITY, | ||||
| 			"Station Extended Capability" }, | ||||
| 	{ NL80211_ATTR_PROTOCOL_FEATURES, | ||||
| 			"Protocol Features", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_SPLIT_WIPHY_DUMP, | ||||
| 			"Split Wiphy Dump", ATTR_FLAG}, | ||||
| 	{ NL80211_ATTR_DISABLE_VHT, | ||||
| 			"Disable VHT" }, | ||||
| 	{ NL80211_ATTR_VHT_CAPABILITY_MASK, | ||||
| 			"VHT Capability Mask" }, | ||||
| 	{ NL80211_ATTR_MDID, | ||||
| 			"MDID", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_IE_RIC, | ||||
| 			"IE RIC", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_CRIT_PROT_ID, | ||||
| 			"Critical Protocol ID" }, | ||||
| 	{ NL80211_ATTR_MAX_CRIT_PROT_DURATION, | ||||
| 			"Max Criticial Protocol Duration" }, | ||||
| 	{ NL80211_ATTR_PEER_AID, | ||||
| 			"Peer AID", ATTR_U16 }, | ||||
| 	{ NL80211_ATTR_COALESCE_RULE, | ||||
| 			"Coalesce Rule" }, | ||||
| 	{ NL80211_ATTR_CH_SWITCH_COUNT, | ||||
| 			"Channel Switch Count", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_CH_SWITCH_BLOCK_TX, | ||||
| 			"Channel Switch Block TX", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_CSA_IES, | ||||
| 			"CSA IEs" }, | ||||
| 	{ NL80211_ATTR_CSA_C_OFF_BEACON, | ||||
| 			"CSA C Off Beacon" }, | ||||
| 	{ NL80211_ATTR_CSA_C_OFF_PRESP, | ||||
| 			"CSA C Off Response" }, | ||||
| 	{ NL80211_ATTR_RXMGMT_FLAGS, | ||||
| 			"RX Management Flags", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_STA_SUPPORTED_CHANNELS, | ||||
| 			"Station Supported Channels" }, | ||||
| 	{ NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES, | ||||
| 			"Station Supported Operation Classes" }, | ||||
| 	{ NL80211_ATTR_HANDLE_DFS, | ||||
| 			"Handle DFS", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_SUPPORT_5_MHZ, | ||||
| 			"Support 5 MHz" }, | ||||
| 	{ NL80211_ATTR_SUPPORT_10_MHZ, | ||||
| 			"Support 10 MHz" }, | ||||
| 	{ NL80211_ATTR_OPMODE_NOTIF, | ||||
| 			"Operation Mode Notification", ATTR_U8 }, | ||||
| 	{ NL80211_ATTR_VENDOR_ID, | ||||
| 			"Vendor ID", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_VENDOR_SUBCMD, | ||||
| 			"Vendor Subcommand", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_VENDOR_DATA, | ||||
| 			"Vendor Data", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_VENDOR_EVENTS, | ||||
| 			"Vendor Events" }, | ||||
| 	{ NL80211_ATTR_QOS_MAP, | ||||
| 			"QoS Map", ATTR_BINARY }, | ||||
| 	{ NL80211_ATTR_MAC_HINT, | ||||
| 			"MAC Hint", ATTR_ADDRESS }, | ||||
| 	{ NL80211_ATTR_WIPHY_FREQ_HINT, | ||||
| 			"Wiphy Frequency Hint", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_MAX_AP_ASSOC_STA, | ||||
| 			"Max AP Assoc Station" }, | ||||
| 	{ NL80211_ATTR_TDLS_PEER_CAPABILITY, | ||||
| 			"TDLS Peer Capability", ATTR_U32 }, | ||||
| 	{ NL80211_ATTR_IFACE_SOCKET_OWNER, | ||||
| 			"Interface Socket Owner", ATTR_FLAG }, | ||||
| 	{ NL80211_ATTR_CSA_C_OFFSETS_TX, | ||||
| 			"CSA C Offsets TX" }, | ||||
| 	{ NL80211_ATTR_MAX_CSA_COUNTERS, | ||||
| 			"Max CSA Counters" }, | ||||
| 	{ } | ||||
| }; | ||||
| 
 | ||||
| #define NLA_OK(nla,len)         ((len) >= (int) sizeof(struct nlattr) && \ | ||||
| 				(nla)->nla_len >= sizeof(struct nlattr) && \ | ||||
| 				(nla)->nla_len <= (len)) | ||||
| #define NLA_NEXT(nla,attrlen)	((attrlen) -= NLA_ALIGN((nla)->nla_len), \ | ||||
| 				(struct nlattr*)(((char*)(nla)) + \ | ||||
| 				NLA_ALIGN((nla)->nla_len))) | ||||
| 
 | ||||
| #define NLA_LENGTH(len)		(NLA_ALIGN(sizeof(struct nlattr)) + (len)) | ||||
| #define NLA_DATA(nla)		((void*)(((char*)(nla)) + NLA_LENGTH(0))) | ||||
| #define NLA_PAYLOAD(nla)	((int)((nla)->nla_len - NLA_LENGTH(0))) | ||||
| 
 | ||||
| static void print_attributes(int indent, const void *buf, uint32_t len) | ||||
| { | ||||
| 	const struct nlattr *nla; | ||||
| 	const char *str; | ||||
| 	int i; | ||||
| 
 | ||||
| 	for (nla = buf ; NLA_OK(nla, len); nla = NLA_NEXT(nla, len)) { | ||||
| 		uint16_t nla_type = nla->nla_type & NLA_TYPE_MASK; | ||||
| 		enum attr_type type; | ||||
| 		uint64_t val64; | ||||
| 		uint32_t val32; | ||||
| 		uint16_t val16; | ||||
| 		uint8_t val8; | ||||
| 
 | ||||
| 		str = "Reserved"; | ||||
| 		type = ATTR_UNSPEC; | ||||
| 
 | ||||
| 		for (i = 0; attr_table[i].str; i++) { | ||||
| 			if (nla_type == attr_table[i].attr) { | ||||
| 				str = attr_table[i].str; | ||||
| 				type = attr_table[i].type; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		switch (type) { | ||||
| 		case ATTR_UNSPEC: | ||||
| 			printf("%*c%s: len %u\n", indent, ' ', str, | ||||
| 						NLA_PAYLOAD(nla)); | ||||
| 			break; | ||||
| 		case ATTR_FLAG: | ||||
| 			printf("%*c%s: true\n", indent, ' ', str); | ||||
| 			if (NLA_PAYLOAD(nla) != 0) | ||||
| 				printf("malformed packet\n"); | ||||
| 			break; | ||||
| 		case ATTR_U8: | ||||
| 			val8 = *((uint32_t *) NLA_DATA(nla)); | ||||
| 			printf("%*c%s: %u (0x%02x)\n", indent, ' ', str, | ||||
| 								val8, val8); | ||||
| 			if (NLA_PAYLOAD(nla) != 1) | ||||
| 				printf("malformed packet\n"); | ||||
| 			break; | ||||
| 		case ATTR_U16: | ||||
| 			val16 = *((uint32_t *) NLA_DATA(nla)); | ||||
| 			printf("%*c%s: %u (0x%04x)\n", indent, ' ', str, | ||||
| 								val16, val16); | ||||
| 			if (NLA_PAYLOAD(nla) != 2) | ||||
| 				printf("malformed packet\n"); | ||||
| 			break; | ||||
| 		case ATTR_U32: | ||||
| 			val32 = *((uint32_t *) NLA_DATA(nla)); | ||||
| 			printf("%*c%s: %u (0x%08x)\n", indent, ' ', str, | ||||
| 								val32, val32); | ||||
| 			if (NLA_PAYLOAD(nla) != 4) | ||||
| 				printf("malformed packet\n"); | ||||
| 			break; | ||||
| 		case ATTR_U64: | ||||
| 			val64 = *((uint64_t *) NLA_DATA(nla)); | ||||
| 			printf("%*c%s: %lu (0x%016lx)\n", indent, ' ', str, | ||||
| 								val64, val64); | ||||
| 			if (NLA_PAYLOAD(nla) != 8) | ||||
| 				printf("malformed packet\n"); | ||||
| 			break; | ||||
| 		case ATTR_STRING: | ||||
| 			printf("%*c%s: %s\n", indent, ' ', str, | ||||
| 						(char *) NLA_DATA(nla)); | ||||
| 			break; | ||||
| 		case ATTR_ADDRESS: | ||||
| 			printf("%*c%s: len %u\n", indent, ' ', str, | ||||
| 						NLA_PAYLOAD(nla)); | ||||
| 			if (NLA_PAYLOAD(nla) != 6) | ||||
| 				printf("malformed packet\n"); | ||||
| 			break; | ||||
| 		case ATTR_BINARY: | ||||
| 			printf("%*c%s: len %u\n", indent, ' ', str, | ||||
| 						NLA_PAYLOAD(nla)); | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		if (nla->nla_type & NLA_F_NESTED) | ||||
| 			print_attributes(indent + 2, NLA_DATA(nla), | ||||
| 							NLA_PAYLOAD(nla)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static const struct { | ||||
| 	uint8_t cmd; | ||||
| 	const char *str; | ||||
| } cmd_table[] = { | ||||
| 	{ NL80211_CMD_GET_WIPHY,		"Get Wiphy"		}, | ||||
| 	{ NL80211_CMD_SET_WIPHY,		"Set Wiphy"		}, | ||||
| 	{ NL80211_CMD_NEW_WIPHY,		"New Wiphy"		}, | ||||
| 	{ NL80211_CMD_DEL_WIPHY,		"Del Wiphy"		}, | ||||
| 	{ NL80211_CMD_GET_INTERFACE,		"Get Interface"		}, | ||||
| 	{ NL80211_CMD_SET_INTERFACE,		"Set Interface"		}, | ||||
| 	{ NL80211_CMD_NEW_INTERFACE,		"New Interface"		}, | ||||
| 	{ NL80211_CMD_DEL_INTERFACE,		"Del Interface"		}, | ||||
| 	{ NL80211_CMD_GET_KEY,			"Get Key"		}, | ||||
| 	{ NL80211_CMD_SET_KEY,			"Set Key"		}, | ||||
| 	{ NL80211_CMD_NEW_KEY,			"New Key"		}, | ||||
| 	{ NL80211_CMD_DEL_KEY,			"Del Key"		}, | ||||
| 	{ NL80211_CMD_GET_BEACON,		"Get Beacon"		}, | ||||
| 	{ NL80211_CMD_SET_BEACON,		"Set Beacon"		}, | ||||
| 	{ NL80211_CMD_START_AP,			"Start AP"		}, | ||||
| 	{ NL80211_CMD_STOP_AP,			"Stop AP"		}, | ||||
| 	{ NL80211_CMD_GET_STATION,		"Get Station"		}, | ||||
| 	{ NL80211_CMD_SET_STATION,		"Set Station"		}, | ||||
| 	{ NL80211_CMD_NEW_STATION,		"New Station"		}, | ||||
| 	{ NL80211_CMD_DEL_STATION,		"Del Station"		}, | ||||
| 	{ NL80211_CMD_GET_MPATH,		"Get Mesh Path"		}, | ||||
| 	{ NL80211_CMD_SET_MPATH,		"Set Mesh Path"		}, | ||||
| 	{ NL80211_CMD_NEW_MPATH,		"New Mesh Path"		}, | ||||
| 	{ NL80211_CMD_DEL_MPATH,		"Del Mesh Path"		}, | ||||
| 	{ NL80211_CMD_SET_BSS,			"Set BSS"		}, | ||||
| 	{ NL80211_CMD_SET_REG,			"Set Reg"		}, | ||||
| 	{ NL80211_CMD_REQ_SET_REG,		"Req Set Reg"		}, | ||||
| 	{ NL80211_CMD_GET_MESH_CONFIG,		"Get Mesh Config"	}, | ||||
| 	{ NL80211_CMD_SET_MESH_CONFIG,		"Set Mesh Config"	}, | ||||
| 	{ NL80211_CMD_SET_MGMT_EXTRA_IE,	"Mgmt Extra IE"		}, | ||||
| 	{ NL80211_CMD_GET_REG,			"Get Reg"		}, | ||||
| 	{ NL80211_CMD_GET_SCAN,			"Get Scan"		}, | ||||
| 	{ NL80211_CMD_TRIGGER_SCAN,		"Trigger Scan"		}, | ||||
| 	{ NL80211_CMD_NEW_SCAN_RESULTS,		"New Scan Results"	}, | ||||
| 	{ NL80211_CMD_SCAN_ABORTED,		"Scan Aborted"		}, | ||||
| 	{ NL80211_CMD_REG_CHANGE,		"Reg Change"		}, | ||||
| 	{ NL80211_CMD_AUTHENTICATE,		"Authenticate"		}, | ||||
| 	{ NL80211_CMD_ASSOCIATE,		"Associate"		}, | ||||
| 	{ NL80211_CMD_DEAUTHENTICATE,		"Deauthenticate"	}, | ||||
| 	{ NL80211_CMD_DISASSOCIATE,		"Disassociate"		}, | ||||
| 	{ NL80211_CMD_MICHAEL_MIC_FAILURE,	"Michael MIC Failure"	}, | ||||
| 	{ NL80211_CMD_REG_BEACON_HINT,		"Reg Beacon Hint"	}, | ||||
| 	{ NL80211_CMD_JOIN_IBSS,		"Join IBSS"		}, | ||||
| 	{ NL80211_CMD_LEAVE_IBSS,		"Leave IBSS"		}, | ||||
| 	{ NL80211_CMD_TESTMODE,			"Test Mode"		}, | ||||
| 	{ NL80211_CMD_CONNECT,			"Connect"		}, | ||||
| 	{ NL80211_CMD_ROAM,			"Roam"			}, | ||||
| 	{ NL80211_CMD_DISCONNECT,		"Disconnect"		}, | ||||
| 	{ NL80211_CMD_SET_WIPHY_NETNS,		"Set Wiphy Netns"	}, | ||||
| 	{ NL80211_CMD_GET_SURVEY,		"Get Survey"		}, | ||||
| 	{ NL80211_CMD_NEW_SURVEY_RESULTS,	"New Survey Results"	}, | ||||
| 	{ NL80211_CMD_SET_PMKSA,		"Set PMKSA"		}, | ||||
| 	{ NL80211_CMD_DEL_PMKSA,		"Del PMKSA"		}, | ||||
| 	{ NL80211_CMD_FLUSH_PMKSA,		"Flush PMKSA"		}, | ||||
| 	{ NL80211_CMD_REMAIN_ON_CHANNEL,	"Remain on Channel"	}, | ||||
| 	{ NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,	"Cancel Remain on Channel"}, | ||||
| 	{ NL80211_CMD_SET_TX_BITRATE_MASK,	"Set TX Bitrate Mask"	}, | ||||
| 	{ NL80211_CMD_REGISTER_FRAME,		"Register Frame"	}, | ||||
| 	{ NL80211_CMD_FRAME,			"Frame"			}, | ||||
| 	{ NL80211_CMD_FRAME_TX_STATUS,		"Frame TX Status"	}, | ||||
| 	{ NL80211_CMD_SET_POWER_SAVE,		"Set Power Save"	}, | ||||
| 	{ NL80211_CMD_GET_POWER_SAVE,		"Get Power Save"	}, | ||||
| 	{ NL80211_CMD_SET_CQM,			"Set CQM"		}, | ||||
| 	{ NL80211_CMD_NOTIFY_CQM,		"Notify CQM"		}, | ||||
| 	{ NL80211_CMD_SET_CHANNEL,		"Set Channel"		}, | ||||
| 	{ NL80211_CMD_SET_WDS_PEER,		"Set WDS Peer"		}, | ||||
| 	{ NL80211_CMD_FRAME_WAIT_CANCEL,	"Frame Wait Cancel"	}, | ||||
| 	{ NL80211_CMD_JOIN_MESH,		"Join Mesh"		}, | ||||
| 	{ NL80211_CMD_LEAVE_MESH,		"Leave Mesh"		}, | ||||
| 	{ NL80211_CMD_UNPROT_DEAUTHENTICATE,	"Unprot Deauthenticate"	}, | ||||
| 	{ NL80211_CMD_UNPROT_DISASSOCIATE,	"Unprot Disassociate"	}, | ||||
| 	{ NL80211_CMD_NEW_PEER_CANDIDATE,	"New Peer Candidate"	}, | ||||
| 	{ NL80211_CMD_GET_WOWLAN,		"Get WoWLAN"		}, | ||||
| 	{ NL80211_CMD_SET_WOWLAN,		"Set WoWLAN"		}, | ||||
| 	{ NL80211_CMD_START_SCHED_SCAN,		"Start Sched Scan"	}, | ||||
| 	{ NL80211_CMD_STOP_SCHED_SCAN,		"Stop Sched Scan"	}, | ||||
| 	{ NL80211_CMD_SCHED_SCAN_RESULTS,	"Sched Scan Results"	}, | ||||
| 	{ NL80211_CMD_SCHED_SCAN_STOPPED,	"Sched Scan Stopped"	}, | ||||
| 	{ NL80211_CMD_SET_REKEY_OFFLOAD,	"Set Rekey Offload"	}, | ||||
| 	{ NL80211_CMD_PMKSA_CANDIDATE,		"PMKSA Candidate"	}, | ||||
| 	{ NL80211_CMD_TDLS_OPER,		"TDLS Oper"		}, | ||||
| 	{ NL80211_CMD_TDLS_MGMT,		"TDLS Mgmt"		}, | ||||
| 	{ NL80211_CMD_UNEXPECTED_FRAME,		"Unexpected Frame"	}, | ||||
| 	{ NL80211_CMD_PROBE_CLIENT,		"Probe Client"		}, | ||||
| 	{ NL80211_CMD_REGISTER_BEACONS,		"Register Beacons"	}, | ||||
| 	{ NL80211_CMD_UNEXPECTED_4ADDR_FRAME,	"Unexpected 4addr Frame"}, | ||||
| 	{ NL80211_CMD_SET_NOACK_MAP,		"Set NoAck Map"		}, | ||||
| 	{ NL80211_CMD_CH_SWITCH_NOTIFY,		"Channel Switch Notify"	}, | ||||
| 	{ NL80211_CMD_START_P2P_DEVICE,		"Start P2P Device"	}, | ||||
| 	{ NL80211_CMD_STOP_P2P_DEVICE,		"Stop P2P Device"	}, | ||||
| 	{ NL80211_CMD_CONN_FAILED,		"Conn Failed"		}, | ||||
| 	{ NL80211_CMD_SET_MCAST_RATE,		"Set Mcast Rate"	}, | ||||
| 	{ NL80211_CMD_SET_MAC_ACL,		"Set MAC ACL"		}, | ||||
| 	{ NL80211_CMD_RADAR_DETECT,		"Radar Detect"		}, | ||||
| 	{ NL80211_CMD_GET_PROTOCOL_FEATURES,	"Get Protocol Features"	}, | ||||
| 	{ NL80211_CMD_UPDATE_FT_IES,		"Update FT IEs"		}, | ||||
| 	{ NL80211_CMD_FT_EVENT,			"FT Event"		}, | ||||
| 	{ NL80211_CMD_CRIT_PROTOCOL_START,	"Crit Protocol Start"	}, | ||||
| 	{ NL80211_CMD_CRIT_PROTOCOL_STOP,	"Crit Protocol Stop"	}, | ||||
| 	{ NL80211_CMD_GET_COALESCE,		"Get Coalesce"		}, | ||||
| 	{ NL80211_CMD_SET_COALESCE,		"Set Coalesce"		}, | ||||
| 	{ NL80211_CMD_CHANNEL_SWITCH,		"Channel Switch"	}, | ||||
| 	{ NL80211_CMD_VENDOR,			"Vendor"		}, | ||||
| 	{ NL80211_CMD_SET_QOS_MAP,		"Set QoS Map"		}, | ||||
| 	{ } | ||||
| }; | ||||
| 
 | ||||
| static void print_message(const struct nlmsghdr *nlmsg) | ||||
| { | ||||
| 	const struct genlmsghdr *genlmsg; | ||||
| 	const char *str; | ||||
| 	bool out; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (nlmsg->nlmsg_seq && (nlmsg->nlmsg_flags & NLM_F_REQUEST)) | ||||
| 		out = true; | ||||
| 	else | ||||
| 		out = false; | ||||
| 
 | ||||
| 	if (nlmsg->nlmsg_type < NLMSG_MIN_TYPE) { | ||||
| 		switch (nlmsg->nlmsg_type) { | ||||
| 		case NLMSG_NOOP: | ||||
| 			str = "Noop"; | ||||
| 			break; | ||||
| 		case NLMSG_ERROR: | ||||
| 			str = "Error"; | ||||
| 			break; | ||||
| 		case NLMSG_DONE: | ||||
| 			str = "Done"; | ||||
| 			break; | ||||
| 		case NLMSG_OVERRUN: | ||||
| 			str = "Overrun"; | ||||
| 			break; | ||||
| 		default: | ||||
| 			str = "Reserved"; | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		printf("%c %s (%u) flags 0x%04x len %u\n", | ||||
| 						out ? '<' : '>', str, | ||||
| 						nlmsg->nlmsg_type, | ||||
| 						nlmsg->nlmsg_flags, | ||||
| 						NLMSG_PAYLOAD(nlmsg, 0)); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	genlmsg = NLMSG_DATA(nlmsg); | ||||
| 
 | ||||
| 	str = "Reserved"; | ||||
| 
 | ||||
| 	for (i = 0; cmd_table[i].str; i++) { | ||||
| 		if (genlmsg->cmd == cmd_table[i].cmd) { | ||||
| 			str = cmd_table[i].str; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	printf("%c %s (%u) flags 0x%04x len %u\n", | ||||
| 					out ? '<' : '>', str, | ||||
| 					genlmsg->cmd, | ||||
| 					nlmsg->nlmsg_flags, | ||||
| 					NLMSG_PAYLOAD(nlmsg, 0)); | ||||
| 
 | ||||
| 	print_attributes(4, NLMSG_DATA(nlmsg) + GENL_HDRLEN, | ||||
| 					NLMSG_PAYLOAD(nlmsg, GENL_HDRLEN)); | ||||
| } | ||||
| 
 | ||||
| struct nlmon_req_match { | ||||
| 	uint32_t seq; | ||||
| 	uint32_t pid; | ||||
| }; | ||||
| 
 | ||||
| static bool nlmon_req_match(const void *a, const void *b) | ||||
| { | ||||
| 	const struct nlmon_req *req = a; | ||||
| 	const struct nlmon_req_match *match = b; | ||||
| 
 | ||||
| 	return (req->seq == match->seq && req->pid == match->pid); | ||||
| } | ||||
| 
 | ||||
| static void nlmon_message(struct nlmon *nlmon, const struct nlmsghdr *nlmsg) | ||||
| { | ||||
| 	struct nlmon_req *req; | ||||
| 
 | ||||
| 	if (nlmsg->nlmsg_type < NLMSG_MIN_TYPE) { | ||||
| 		struct nlmon_req_match match = { | ||||
| 			.seq = nlmsg->nlmsg_seq, | ||||
| 			.pid = nlmsg->nlmsg_pid | ||||
| 		}; | ||||
| 
 | ||||
| 		req = l_queue_remove_if(nlmon->req_list, | ||||
| 						nlmon_req_match, &match); | ||||
| 		if (req) { | ||||
| 			nlmon_req_free(req); | ||||
| 			print_message(nlmsg); | ||||
| 		} | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (nlmsg->nlmsg_type != nlmon->id) | ||||
| 		return; | ||||
| 
 | ||||
| 	if (nlmsg->nlmsg_flags & NLM_F_REQUEST) { | ||||
| 		req = l_new(struct nlmon_req, 1); | ||||
| 
 | ||||
| 		req->seq = nlmsg->nlmsg_seq; | ||||
| 		req->pid = nlmsg->nlmsg_pid; | ||||
| 		req->flags = nlmsg->nlmsg_flags; | ||||
| 
 | ||||
| 		l_queue_push_tail(nlmon->req_list, req); | ||||
| 		print_message(nlmsg); | ||||
| 	} else { | ||||
| 		struct nlmon_req_match match = { | ||||
| 			.seq = nlmsg->nlmsg_seq, | ||||
| 			.pid = nlmsg->nlmsg_pid | ||||
| 		}; | ||||
| 
 | ||||
| 		req = l_queue_find(nlmon->req_list, nlmon_req_match, &match); | ||||
| 		if (req) { | ||||
| 			if (!(req->flags & NLM_F_ACK)) { | ||||
| 				l_queue_remove(nlmon->req_list, req); | ||||
| 				nlmon_req_free(req); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		print_message(nlmsg); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static bool nlmon_receive(struct l_io *io, void *user_data) | ||||
| { | ||||
| 	struct nlmon *nlmon = user_data; | ||||
| 	struct nlmsghdr *nlmsg; | ||||
| 	struct msghdr msg; | ||||
| 	struct sockaddr_ll sll; | ||||
| 	struct iovec iov; | ||||
| 	struct cmsghdr *cmsg; | ||||
| 	unsigned char buf[8192]; | ||||
| 	unsigned char control[32]; | ||||
| 	ssize_t bytes_read; | ||||
| 	int fd; | ||||
| 
 | ||||
| 	fd = l_io_get_fd(io); | ||||
| 	if (fd < 0) | ||||
| 		return false; | ||||
| 
 | ||||
| 	memset(&sll, 0, sizeof(sll)); | ||||
| 
 | ||||
| 	memset(&iov, 0, sizeof(iov)); | ||||
| 	iov.iov_base = buf; | ||||
| 	iov.iov_len = sizeof(buf); | ||||
| 
 | ||||
| 	memset(&msg, 0, sizeof(msg)); | ||||
| 	msg.msg_name = &sll; | ||||
| 	msg.msg_namelen = sizeof(sll); | ||||
| 	msg.msg_iov = &iov; | ||||
| 	msg.msg_iovlen = 1; | ||||
| 	msg.msg_control = control; | ||||
| 	msg.msg_controllen = sizeof(control); | ||||
| 
 | ||||
| 	bytes_read = recvmsg(fd, &msg, 0); | ||||
| 	if (bytes_read < 0) { | ||||
| 		if (errno != EAGAIN && errno != EINTR) | ||||
| 			return false; | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ntohs(sll.sll_protocol) != NETLINK_GENERIC) | ||||
| 		return true; | ||||
| 
 | ||||
| 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; | ||||
| 				cmsg = CMSG_NXTHDR(&msg, cmsg)) { | ||||
| 		struct tpacket_auxdata tp; | ||||
| 
 | ||||
| 		if (cmsg->cmsg_level != SOL_PACKET) | ||||
| 			continue; | ||||
| 
 | ||||
| 		if (cmsg->cmsg_type != PACKET_AUXDATA) | ||||
| 			continue; | ||||
| 
 | ||||
| 		memcpy(&tp, CMSG_DATA(cmsg), sizeof(tp)); | ||||
| 	} | ||||
| 
 | ||||
| 	for (nlmsg = iov.iov_base; NLMSG_OK(nlmsg, bytes_read); | ||||
| 				nlmsg = NLMSG_NEXT(nlmsg, bytes_read)) { | ||||
| 		nlmon_message(nlmon, nlmsg); | ||||
| 	} | ||||
| 
 | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static struct l_io *open_packet(const char *name) | ||||
| { | ||||
| 	struct l_io *io; | ||||
| 	struct sockaddr_ll sll; | ||||
| 	struct ifreq ifr; | ||||
| 	int fd; | ||||
| 
 | ||||
| 	fd = socket(PF_PACKET, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); | ||||
| 	if (fd < 0) { | ||||
| 		perror("Failed to create packet socket"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	strncpy(ifr.ifr_name, name, IFNAMSIZ); | ||||
| 
 | ||||
| 	if (ioctl(fd, SIOCGIFINDEX, &ifr) < 0) { | ||||
| 		perror("Failed to get monitor index"); | ||||
| 		close(fd); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	memset(&sll, 0, sizeof(sll)); | ||||
| 	sll.sll_family = AF_PACKET; | ||||
| 	sll.sll_protocol = htons(ETH_P_ALL); | ||||
| 	sll.sll_ifindex = ifr.ifr_ifindex; | ||||
| 
 | ||||
| 	if (bind(fd, (struct sockaddr *) &sll, sizeof(sll)) < 0) { | ||||
| 		perror("Failed to bind packet socket"); | ||||
| 		close(fd); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	io = l_io_new(fd); | ||||
| 
 | ||||
| 	l_io_set_close_on_destroy(io, true); | ||||
| 
 | ||||
| 	return io; | ||||
| } | ||||
| 
 | ||||
| struct nlmon *nlmon_open(uint16_t id) | ||||
| { | ||||
| 	struct nlmon *nlmon; | ||||
| 
 | ||||
| 	nlmon = l_new(struct nlmon, 1); | ||||
| 
 | ||||
| 	nlmon->id = id; | ||||
| 	nlmon->io = open_packet("nlmon"); | ||||
| 	nlmon->req_list = l_queue_new(); | ||||
| 
 | ||||
| 	l_io_set_read_handler(nlmon->io, nlmon_receive, nlmon, NULL); | ||||
| 
 | ||||
| 	return nlmon; | ||||
| } | ||||
| 
 | ||||
| void nlmon_close(struct nlmon *nlmon) | ||||
| { | ||||
| 	if (!nlmon) | ||||
| 		return; | ||||
| 
 | ||||
| 	l_io_destroy(nlmon->io); | ||||
| 	l_queue_destroy(nlmon->req_list, nlmon_req_free); | ||||
| 
 | ||||
| 	l_free(nlmon); | ||||
| } | ||||
							
								
								
									
										28
									
								
								monitor/nlmon.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								monitor/nlmon.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| /*
 | ||||
|  * | ||||
|  *  Wireless daemon for Linux | ||||
|  * | ||||
|  *  Copyright (C) 2013-2014  Intel Corporation. All rights reserved. | ||||
|  * | ||||
|  *  This library is free software; you can redistribute it and/or | ||||
|  *  modify it under the terms of the GNU Lesser General Public | ||||
|  *  License as published by the Free Software Foundation; either | ||||
|  *  version 2.1 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  *  This library is distributed in the hope that it will be useful, | ||||
|  *  but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  *  Lesser General Public License for more details. | ||||
|  * | ||||
|  *  You should have received a copy of the GNU Lesser General Public | ||||
|  *  License along with this library; if not, write to the Free Software | ||||
|  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| struct nlmon; | ||||
| 
 | ||||
| struct nlmon *nlmon_open(uint16_t id); | ||||
| void nlmon_close(struct nlmon *nlmon); | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Marcel Holtmann
						Marcel Holtmann