mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-10-30 18:07:52 +00:00 
			
		
		
		
	cleanup: drop obselete code
Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
		| @@ -12,6 +12,5 @@ patch_folders: | ||||
|   - patches/ipq40xx | ||||
|   - patches/ipq806x | ||||
|   - patches/ipq807x | ||||
|   - patches/rtkmipsel | ||||
|   - patches/rest | ||||
|   - patches/x86 | ||||
|   | ||||
| @@ -1,25 +0,0 @@ | ||||
| include $(TOPDIR)/rules.mk | ||||
|  | ||||
| PKG_NAME:=realtek-poe | ||||
| PKG_RELEASE:=1 | ||||
|  | ||||
| PKG_LICENSE:=GPL-2.0 | ||||
| PKG_MAINTAINER:=John Crispin <john@phrozen.org> | ||||
|  | ||||
| include $(INCLUDE_DIR)/package.mk | ||||
| include $(INCLUDE_DIR)/cmake.mk | ||||
|  | ||||
| define Package/realtek-poe | ||||
|   SECTION:=net | ||||
|   CATEGORY:=Network | ||||
|   TITLE:=Realtek PoE Switch Port daemon | ||||
|   DEPENDS:=+libubox +libubus +libuci | ||||
| endef | ||||
|  | ||||
| define Package/realtek-poe/install | ||||
| 	$(INSTALL_DIR) $(1)/usr/bin | ||||
| 	$(INSTALL_BIN) $(PKG_BUILD_DIR)/realtek-poe $(1)/usr/bin/ | ||||
| 	$(CP) ./files/* $(1) | ||||
| endef | ||||
|  | ||||
| $(eval $(call BuildPackage,realtek-poe)) | ||||
| @@ -1,58 +0,0 @@ | ||||
| config global | ||||
| 	option budget	'65' | ||||
|  | ||||
| config port | ||||
| 	option enable	'1' | ||||
| 	option id	'1' | ||||
| 	option name	'lan1' | ||||
| 	option poe_plus	'1' | ||||
| 	option priority	'3' | ||||
|  | ||||
| config port | ||||
| 	option enable	'1' | ||||
| 	option id	'2' | ||||
| 	option name	'lan2' | ||||
| 	option poe_plus	'1' | ||||
| 	option priority	'3' | ||||
|  | ||||
| config port | ||||
| 	option enable	'1' | ||||
| 	option id	'3' | ||||
| 	option name	'lan3' | ||||
| 	option poe_plus	'1' | ||||
| 	option priority	'2' | ||||
|  | ||||
| config port | ||||
| 	option enable	'1' | ||||
| 	option id	'4' | ||||
| 	option name	'lan4' | ||||
| 	option poe_plus	'1' | ||||
| 	option priority	'2' | ||||
|  | ||||
| config port | ||||
| 	option enable	'1' | ||||
| 	option id	'5' | ||||
| 	option name	'lan5' | ||||
| 	option poe_plus	'1' | ||||
| 	option priority	'1' | ||||
|  | ||||
| config port | ||||
| 	option enable	'1' | ||||
| 	option id	'6' | ||||
| 	option name	'lan6' | ||||
| 	option poe_plus	'1' | ||||
| 	option priority	'1' | ||||
|  | ||||
| config port | ||||
| 	option enable	'1' | ||||
| 	option id	'7' | ||||
| 	option name	'lan7' | ||||
| 	option poe_plus	'1' | ||||
| 	option priority	'0' | ||||
|  | ||||
| config port | ||||
| 	option enable	'1' | ||||
| 	option id	'8' | ||||
| 	option name	'lan8' | ||||
| 	option poe_plus	'1' | ||||
| 	option priority	'0' | ||||
| @@ -1,20 +0,0 @@ | ||||
| #!/bin/sh /etc/rc.common | ||||
|  | ||||
| START=80 | ||||
| USE_PROCD=1 | ||||
| PROG=/usr/bin/realtek-poe | ||||
|  | ||||
| reload_service() { | ||||
| 	ubus call poe reload | ||||
| } | ||||
|  | ||||
| service_triggers() {                                 | ||||
|         procd_add_config_trigger "config.change" "poe" ubus call poe reload | ||||
| } | ||||
|  | ||||
| start_service() { | ||||
| 	procd_open_instance | ||||
| 	procd_set_param command "$PROG" | ||||
| 	procd_set_param respawn | ||||
| 	procd_close_instance | ||||
| } | ||||
| @@ -1,28 +0,0 @@ | ||||
| cmake_minimum_required(VERSION 2.6) | ||||
|  | ||||
| PROJECT(realtek-poe C) | ||||
| ADD_DEFINITIONS(-Os -ggdb -Wextra -Wall -Werror --std=gnu99 -Wmissing-declarations -Wno-unused-parameter) | ||||
|  | ||||
| SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") | ||||
|  | ||||
| SET(SOURCES main.c) | ||||
|  | ||||
| IF(DEBUG) | ||||
|   ADD_DEFINITIONS(-DDEBUG -g3) | ||||
| ENDIF() | ||||
|  | ||||
| FIND_LIBRARY(ubus NAMES ubus) | ||||
| FIND_LIBRARY(uci NAMES uci) | ||||
| FIND_LIBRARY(ubox NAMES ubox) | ||||
| FIND_PATH(uci_include_dir NAMES uci.h) | ||||
| FIND_PATH(ubus_include_dir NAMES libubus.h) | ||||
| FIND_PATH(ubox_include_dir NAMES libubox/usock.h) | ||||
| INCLUDE_DIRECTORIES(${ubox_include_dir} ${ubus_include_dir} ${uci_include_dir}) | ||||
|  | ||||
| ADD_EXECUTABLE(realtek-poe ${SOURCES}) | ||||
|  | ||||
| TARGET_LINK_LIBRARIES(realtek-poe ${ubox} ${ubus} ${uci}) | ||||
|  | ||||
| INSTALL(TARGETS realtek-poe | ||||
| 	RUNTIME DESTINATION sbin | ||||
| ) | ||||
| @@ -1,845 +0,0 @@ | ||||
| /* SPDX-License-Identifier: GPL-2.0 */ | ||||
|  | ||||
| #include <string.h> | ||||
| #include <stdint.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| #include <termios.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/stat.h> | ||||
| #include <fcntl.h> | ||||
| #include <getopt.h> | ||||
|  | ||||
| #include <libubox/ustream.h> | ||||
| #include <libubox/uloop.h> | ||||
| #include <libubox/list.h> | ||||
| #include <libubox/ulog.h> | ||||
| #include <libubus.h> | ||||
|  | ||||
| #include <uci.h> | ||||
| #include <uci_blob.h> | ||||
|  | ||||
| #define ULOG_DBG(fmt, ...) ulog(LOG_DEBUG, fmt, ## __VA_ARGS__) | ||||
|  | ||||
| typedef int (*poe_reply_handler)(unsigned char *reply); | ||||
|  | ||||
| #define MAX_PORT	8 | ||||
| #define GET_STR(a, b)	(a < ARRAY_SIZE(b) ? b[a] : NULL) | ||||
|  | ||||
| struct port_config { | ||||
| 	char name[16]; | ||||
| 	unsigned char enable; | ||||
| 	unsigned char priority; | ||||
| 	unsigned char power_up_mode; | ||||
| 	unsigned char power_budget; | ||||
| }; | ||||
|  | ||||
| struct config { | ||||
| 	int debug; | ||||
|  | ||||
| 	int budget; | ||||
| 	int budget_guard; | ||||
|  | ||||
| 	int port_count; | ||||
| 	struct port_config ports[MAX_PORT]; | ||||
| }; | ||||
|  | ||||
| struct port_state { | ||||
| 	char *status; | ||||
| 	float watt; | ||||
| 	char *poe_mode; | ||||
| }; | ||||
|  | ||||
| struct state { | ||||
| 	char *sys_mode; | ||||
| 	unsigned char sys_version; | ||||
| 	char *sys_mcu; | ||||
| 	char *sys_status; | ||||
| 	unsigned char sys_ext_version; | ||||
| 	float power_consumption; | ||||
|  | ||||
| 	struct port_state ports[MAX_PORT]; | ||||
| }; | ||||
|  | ||||
| struct cmd { | ||||
| 	struct list_head list; | ||||
| 	unsigned char cmd[12]; | ||||
| }; | ||||
|  | ||||
| static struct uloop_timeout state_timeout; | ||||
| static struct ubus_auto_conn conn; | ||||
| static struct ustream_fd stream; | ||||
| static LIST_HEAD(cmd_pending); | ||||
| static unsigned char cmd_seq; | ||||
| static struct state state; | ||||
| static struct blob_buf b; | ||||
|  | ||||
| static struct config config = { | ||||
| 	.budget = 65, | ||||
| 	.budget_guard = 7, | ||||
| 	.port_count = 8, | ||||
| }; | ||||
|  | ||||
| static void | ||||
| config_load_port(struct uci_section *s) | ||||
| { | ||||
| 	enum { | ||||
| 		PORT_ATTR_ID, | ||||
| 		PORT_ATTR_NAME, | ||||
| 		PORT_ATTR_ENABLE, | ||||
| 		PORT_ATTR_PRIO, | ||||
| 		PORT_ATTR_POE_PLUS, | ||||
| 		__PORT_ATTR_MAX, | ||||
| 	}; | ||||
|  | ||||
| 	static const struct blobmsg_policy port_attrs[__PORT_ATTR_MAX] = { | ||||
| 		[PORT_ATTR_ID] = { .name = "id", .type = BLOBMSG_TYPE_INT32 }, | ||||
| 		[PORT_ATTR_NAME] = { .name = "name", .type = BLOBMSG_TYPE_STRING }, | ||||
| 		[PORT_ATTR_ENABLE] = { .name = "enable", .type = BLOBMSG_TYPE_INT32 }, | ||||
| 		[PORT_ATTR_PRIO] = { .name = "priority", .type = BLOBMSG_TYPE_INT32 }, | ||||
| 		[PORT_ATTR_POE_PLUS] = { .name = "poe_plus", .type = BLOBMSG_TYPE_INT32 }, | ||||
| 	}; | ||||
|  | ||||
| 	const struct uci_blob_param_list port_attr_list = { | ||||
| 		.n_params = __PORT_ATTR_MAX, | ||||
| 		.params = port_attrs, | ||||
| 	}; | ||||
|  | ||||
| 	struct blob_attr *tb[__PORT_ATTR_MAX] = { 0 }; | ||||
| 	unsigned int id; | ||||
|  | ||||
| 	blob_buf_init(&b, 0); | ||||
| 	uci_to_blob(&b, s, &port_attr_list); | ||||
| 	blobmsg_parse(port_attrs, __PORT_ATTR_MAX, tb, blob_data(b.head), blob_len(b.head)); | ||||
|  | ||||
| 	if (!tb[PORT_ATTR_ID] || !tb[PORT_ATTR_NAME]) { | ||||
| 		ULOG_ERR("invalid port settings"); | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	id = blobmsg_get_u32(tb[PORT_ATTR_ID]); | ||||
| 	if (!id || id > MAX_PORT) { | ||||
| 		ULOG_ERR("invalid port id"); | ||||
| 		return; | ||||
| 	} | ||||
| 	id--; | ||||
|  | ||||
| 	strncpy(config.ports[id].name, blobmsg_get_string(tb[PORT_ATTR_NAME]), 16); | ||||
|  | ||||
| 	if (tb[PORT_ATTR_ENABLE]) | ||||
| 		config.ports[id].enable = !!blobmsg_get_u32(tb[PORT_ATTR_ENABLE]); | ||||
|  | ||||
| 	if (tb[PORT_ATTR_PRIO]) | ||||
| 		config.ports[id].priority = blobmsg_get_u32(tb[PORT_ATTR_PRIO]); | ||||
| 	if (config.ports[id].priority > 3) | ||||
| 		config.ports[id].priority = 3; | ||||
|  | ||||
| 	if (tb[PORT_ATTR_POE_PLUS] && blobmsg_get_u32(tb[PORT_ATTR_POE_PLUS])) | ||||
| 		config.ports[id].power_up_mode = 3; | ||||
| } | ||||
|  | ||||
| static void | ||||
| config_load_global(struct uci_section *s) | ||||
| { | ||||
| 	enum { | ||||
| 		GLOBAL_ATTR_BUDGET, | ||||
| 		GLOBAL_ATTR_GUARD, | ||||
| 		__GLOBAL_ATTR_MAX, | ||||
| 	}; | ||||
|  | ||||
| 	static const struct blobmsg_policy global_attrs[__GLOBAL_ATTR_MAX] = { | ||||
| 		[GLOBAL_ATTR_BUDGET] = { .name = "budget", .type = BLOBMSG_TYPE_INT32 }, | ||||
| 		[GLOBAL_ATTR_GUARD] = { .name = "guard", .type = BLOBMSG_TYPE_INT32 }, | ||||
| 	}; | ||||
|  | ||||
| 	const struct uci_blob_param_list global_attr_list = { | ||||
| 		.n_params = __GLOBAL_ATTR_MAX, | ||||
| 		.params = global_attrs, | ||||
| 	}; | ||||
|  | ||||
| 	struct blob_attr *tb[__GLOBAL_ATTR_MAX] = { 0 }; | ||||
|  | ||||
| 	blob_buf_init(&b, 0); | ||||
| 	uci_to_blob(&b, s, &global_attr_list); | ||||
| 	blobmsg_parse(global_attrs, __GLOBAL_ATTR_MAX, tb, blob_data(b.head), blob_len(b.head)); | ||||
|  | ||||
| 	config.budget = 65; | ||||
| 	if (tb[GLOBAL_ATTR_BUDGET]) | ||||
| 		config.budget = blobmsg_get_u32(tb[GLOBAL_ATTR_BUDGET]); | ||||
|  | ||||
| 	if (tb[GLOBAL_ATTR_GUARD]) | ||||
| 		config.budget_guard = blobmsg_get_u32(tb[GLOBAL_ATTR_GUARD]); | ||||
| 	else | ||||
| 		config.budget_guard = config.budget / 10; | ||||
| } | ||||
|  | ||||
| static void | ||||
| config_load(int init) | ||||
| { | ||||
| 	struct uci_context *uci = uci_alloc_context(); | ||||
|         struct uci_package *package = NULL; | ||||
|  | ||||
| 	memset(config.ports, 0, sizeof(config.ports)); | ||||
|  | ||||
| 	if (!uci_load(uci, "poe", &package)) { | ||||
| 		struct uci_element *e; | ||||
|  | ||||
| 		if (init) | ||||
| 			uci_foreach_element(&package->sections, e) { | ||||
| 				struct uci_section *s = uci_to_section(e); | ||||
|  | ||||
| 				if (!strcmp(s->type, "global")) | ||||
| 					config_load_global(s); | ||||
| 			} | ||||
| 		uci_foreach_element(&package->sections, e) { | ||||
| 			struct uci_section *s = uci_to_section(e); | ||||
|  | ||||
| 			if (!strcmp(s->type, "port")) | ||||
| 				config_load_port(s); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	uci_unload(uci, package); | ||||
| 	uci_free_context(uci); | ||||
| } | ||||
|  | ||||
| static void | ||||
| poe_cmd_dump(char *type, unsigned char *data) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	if (!config.debug) | ||||
| 		return; | ||||
|  | ||||
| 	fprintf(stderr, "%s ->", type); | ||||
| 	for (i = 0; i < 12; i++) | ||||
| 		fprintf(stderr, " 0x%02x", data[i]); | ||||
| 	fprintf(stderr, "\n"); | ||||
| } | ||||
|  | ||||
| static int | ||||
| poe_cmd_send(struct cmd *cmd) | ||||
| { | ||||
| 	poe_cmd_dump("TX", cmd->cmd); | ||||
| 	ustream_write(&stream.stream, (char *)cmd->cmd, 12, false); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| poe_cmd_next(void) | ||||
| { | ||||
| 	struct cmd *cmd; | ||||
|  | ||||
| 	if (list_empty(&cmd_pending)) | ||||
| 		return -1; | ||||
|  | ||||
| 	cmd = list_first_entry(&cmd_pending, struct cmd, list); | ||||
|  | ||||
| 	return poe_cmd_send(cmd); | ||||
| } | ||||
|  | ||||
| static int | ||||
| poe_cmd_queue(unsigned char *_cmd, int len) | ||||
| { | ||||
| 	int i, empty = list_empty(&cmd_pending); | ||||
| 	struct cmd *cmd = malloc(sizeof(*cmd)); | ||||
|  | ||||
| 	memset(cmd, 0, sizeof(*cmd)); | ||||
| 	memset(cmd->cmd, 0xff, 12); | ||||
| 	memcpy(cmd->cmd, _cmd, len); | ||||
|  | ||||
| 	cmd_seq++; | ||||
| 	cmd->cmd[1] = cmd_seq; | ||||
| 	cmd->cmd[11] = 0; | ||||
|  | ||||
| 	for (i = 0; i < 11; i++) | ||||
| 		cmd->cmd[11] += cmd->cmd[i]; | ||||
|  | ||||
| 	list_add_tail(&cmd->list, &cmd_pending); | ||||
|  | ||||
| 	if (empty) | ||||
| 		return poe_cmd_send(cmd); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* 0x00 - Set port enable | ||||
|  *	0: Disable | ||||
|  *	1: Enable | ||||
|  */ | ||||
| static int | ||||
| poe_cmd_port_enable(unsigned char port, unsigned char enable) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x00, 0x00, port, enable }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| /* 0x06 - Set global port enable | ||||
|  *	0: Disable PSE Functionality on all Ports | ||||
|  *	1: Enable PSE Functionality on all Ports | ||||
|  *	2: Enable Force power Functionality on all ports | ||||
|  *	3: Enable Force Power with Disconnect Functionality on all Ports | ||||
|  */ | ||||
| static int | ||||
| poe_cmd_global_port_enable(unsigned char enable) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x06, 0x00, enable }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| /* 0x10 - Set port detection type | ||||
|  *	1: Legacy Capacitive Detection only | ||||
|  *	2: IEEE 802.3af 4-Point Detection only (Default) | ||||
|  *	3: IEEE 802.3af 4-Point followed by Legacy | ||||
|  *	4: IEEE 802.3af 2-Point detection (Not Supported) | ||||
|  *	5: IEEE 802.3af 2-Point followed by Legacy | ||||
|  */ | ||||
| static int | ||||
| poe_cmd_port_detection_type(unsigned char port, unsigned char type) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x10, 0x00, port, type }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| /* 0x11 - Set port classification | ||||
|  *	0: Disable | ||||
|  *	1: Enable | ||||
|  */ | ||||
| static int | ||||
| poe_cmd_port_classification(unsigned char port, unsigned char classification) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x11, 0x00, port, classification }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| /* 0x13 - Set port disconnect type | ||||
|  *	0: none | ||||
|  *	1: AC-disconnect | ||||
|  *	2: DC-disconnect | ||||
|  *	3: DC with delay | ||||
|  */ | ||||
| static int | ||||
| poe_cmd_port_disconnect_type(unsigned char port, unsigned char type) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x13, 0x00, port, type }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| /* 0x15 - Set port power limit type | ||||
|  *	0: None. Power limit is 16.2W if the connected device is “low power”, | ||||
|  *	   or the set high power limit if the device is “high power”. | ||||
|  *	1: Class based. The power limit for class 4 devices is determined by the high power limit. | ||||
|  *	2: User defined | ||||
|  */ | ||||
| static int | ||||
| poe_cmd_port_power_limit_type(unsigned char port, unsigned char type) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x15, 0x00, port, type }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| /* 0x16 - Set port power budget | ||||
|  *	values in 0.2W increments | ||||
|  */ | ||||
| static int | ||||
| poe_cmd_port_power_budget(unsigned char port, unsigned char budget) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x16, 0x00, port, budget }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| /* 0x17 - Set power management mode | ||||
|  *	0: None (No Power Management mode) (Default in Semi-Auto mode) | ||||
|  *	1: Static Power Management with Port Priority(Default in Automode) | ||||
|  *	2: Dynamic Power Management with Port Priority | ||||
|  *	3: Static Power Management without Port Priority | ||||
|  *	4: Dynamic Power Management without Port Priority | ||||
|  */ | ||||
| static int | ||||
| poe_cmd_power_mgmt_mode(unsigned char mode) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x17, 0x00, mode }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| /* 0x18 - Set global power budget */ | ||||
| static int | ||||
| poe_cmd_global_power_budget(int budget, int guard) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||||
|  | ||||
| 	cmd[3] = budget * 10 / 256; | ||||
| 	cmd[4] = budget * 10 % 256; | ||||
| 	cmd[5] = guard * 10 / 256; | ||||
| 	cmd[6] = guard * 10 % 256; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| /* 0x1a - Set port priority | ||||
|  *	0: Low | ||||
|  *	1: Normal | ||||
|  *	2: High | ||||
|  *	3: Critical | ||||
|  */ | ||||
| static int | ||||
| poe_set_port_priority(unsigned char port, unsigned char priority) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x1a, 0x00, port, priority }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| /* 0x1c - Set port power-up mode | ||||
|  *	0: PoE | ||||
|  *	1: legacy | ||||
|  *	2: pre-PoE+ | ||||
|  *	3: PoE+ | ||||
|  */ | ||||
| static int | ||||
| poe_set_port_power_up_mode(unsigned char port, unsigned char mode) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x1c, 0x00, port, mode }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| /* 0x20 - Get system info */ | ||||
| static int | ||||
| poe_cmd_status(void) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x20 }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| static int | ||||
| poe_reply_status(unsigned char *reply) | ||||
| { | ||||
| 	static char *mode[]={ | ||||
| 		"Semi-auto I2C", | ||||
| 		"Semi-auto UART", | ||||
| 		"Auto I2C", | ||||
| 		"Auto UART" | ||||
| 	}; | ||||
| 	static char *mcu[]={ | ||||
| 		"ST Micro ST32F100 Microcontroller", | ||||
| 		"Nuvoton M05xx LAN Microcontroller", | ||||
| 		"ST Micro STF030C8 Microcontroller", | ||||
| 		"Nuvoton M058SAN Microcontroller", | ||||
| 		"Nuvoton NUC122 Microcontroller" | ||||
| 	}; | ||||
| 	static char *status[]={ | ||||
| 		"Global Disable pin is de-asserted:No system reset from the previous query cmd:Configuration saved", | ||||
| 		"Global Disable pin is de-asserted:No system reset from the previous query cmd:Configuration Dirty", | ||||
| 		"Global Disable pin is de-asserted:System reseted:Configuration saved", | ||||
| 		"Global Disable pin is de-asserted:System reseted:Configuration Dirty", | ||||
| 		"Global Disable Pin is asserted:No system reset from the previous query cmd:Configuration saved", | ||||
| 		"Global Disable Pin is asserted:No system reset from the previous query cmd:Configuration Dirty", | ||||
| 		"Global Disable Pin is asserted:System reseted:Configuration saved", | ||||
| 		"Global Disable Pin is asserted:System reseted:Configuration Dirty" | ||||
| 	}; | ||||
|  | ||||
| 	state.sys_mode = GET_STR(reply[2], mode); | ||||
| 	config.port_count = reply[3]; | ||||
| 	state.sys_version = reply[7]; | ||||
| 	state.sys_mcu = GET_STR(reply[8], mcu); | ||||
| 	state.sys_status = GET_STR(reply[9], status); | ||||
| 	state.sys_ext_version = reply[10]; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* 0x23 - Get power statistics */ | ||||
| static int | ||||
| poe_cmd_power_stats(void) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x23 }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| static int | ||||
| poe_reply_power_stats(unsigned char *reply) | ||||
| { | ||||
| 	state.power_consumption = reply[2]; | ||||
| 	state.power_consumption *= 256; | ||||
| 	state.power_consumption += reply[3]; | ||||
| 	state.power_consumption /= 10; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* 0x26 - Get extended port config */ | ||||
| static int | ||||
| poe_cmd_port_ext_config(unsigned char port) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x26, 0x00, port }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| static int | ||||
| poe_reply_port_ext_config(unsigned char *reply) | ||||
| { | ||||
| 	static char *mode[] = { | ||||
| 		"PoE", | ||||
| 		"Legacy", | ||||
| 		"pre-PoE+", | ||||
| 		"PoE+" | ||||
| 	}; | ||||
|  | ||||
| 	state.ports[reply[2]].poe_mode = GET_STR(reply[3], mode); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* 0x2a - Get all port status */ | ||||
| static int | ||||
| poe_cmd_port_overview(void) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x2a, 0x00, 0x00 }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| static int | ||||
| poe_reply_port_overview(unsigned char *reply) | ||||
| { | ||||
| 	static char *status[]={ | ||||
| 		"Disabled", | ||||
| 		"Searching", | ||||
| 		"Delivering power", | ||||
| 		"Fault", | ||||
| 		"Other fault", | ||||
| 		"Requesting power", | ||||
| 	}; | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < 8; i++) | ||||
| 		state.ports[i].status = GET_STR((reply[3 + i] & 0xf), status); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* 0x30 - Get port power statistics */ | ||||
| static int | ||||
| poe_cmd_port_power_stats(unsigned char port) | ||||
| { | ||||
| 	unsigned char cmd[] = { 0x30, 0x00, port }; | ||||
|  | ||||
| 	return poe_cmd_queue(cmd, sizeof(cmd)); | ||||
| } | ||||
|  | ||||
| static int | ||||
| poe_reply_port_power_stats(unsigned char *reply) | ||||
| { | ||||
| 	float watt; | ||||
|  | ||||
| 	watt = reply[9]; | ||||
| 	watt *= 256; | ||||
| 	watt += reply[10]; | ||||
| 	watt /= 10; | ||||
|  | ||||
| 	state.ports[reply[2]].watt = watt; | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static poe_reply_handler reply_handler[] = { | ||||
| 	[0x20] = poe_reply_status, | ||||
| 	[0x23] = poe_reply_power_stats, | ||||
| 	[0x26] = poe_reply_port_ext_config, | ||||
| 	[0x2a] = poe_reply_port_overview, | ||||
| 	[0x30] = poe_reply_port_power_stats, | ||||
| }; | ||||
|  | ||||
| static int | ||||
| poe_reply_consume(unsigned char *reply) | ||||
| { | ||||
| 	struct cmd *cmd = NULL; | ||||
| 	unsigned char sum = 0, i; | ||||
|  | ||||
| 	poe_cmd_dump("RX", reply); | ||||
|  | ||||
| 	if (list_empty(&cmd_pending)) { | ||||
| 		ULOG_ERR("received unsolicited reply\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	cmd = list_first_entry(&cmd_pending, struct cmd, list); | ||||
| 	list_del(&cmd->list); | ||||
|  | ||||
| 	for (i = 0; i < 11; i++) | ||||
| 		sum += reply[i]; | ||||
|  | ||||
| 	if (reply[11] != sum) { | ||||
| 		ULOG_DBG("received reply with bad checksum\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (reply[0] != cmd->cmd[0]) { | ||||
| 		ULOG_DBG("received reply with bad command id\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (reply[1] != cmd->cmd[1]) { | ||||
| 		ULOG_DBG("received reply with bad sequence number\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	free(cmd); | ||||
|  | ||||
| 	if (reply_handler[reply[0]]) | ||||
| 		return reply_handler[reply[0]](reply); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void | ||||
| poe_stream_msg_cb(struct ustream *s, int bytes) | ||||
| { | ||||
| 	int len; | ||||
| 	unsigned char *reply = (unsigned char *)ustream_get_read_buf(s, &len); | ||||
|  | ||||
| 	if (len < 12) | ||||
| 		return; | ||||
|  | ||||
| 	poe_reply_consume(reply); | ||||
| 	ustream_consume(s, 12); | ||||
| 	poe_cmd_next(); | ||||
| } | ||||
|  | ||||
| static void | ||||
| poe_stream_notify_cb(struct ustream *s) | ||||
| { | ||||
| 	if (!s->eof) | ||||
| 		return; | ||||
|  | ||||
| 	ULOG_ERR("tty error, shutting down\n"); | ||||
| 	exit(-1); | ||||
| } | ||||
|  | ||||
| static int | ||||
| poe_stream_open(char *dev, struct ustream_fd *s, speed_t speed) | ||||
| { | ||||
| 	struct termios tio; | ||||
| 	int tty; | ||||
|  | ||||
| 	tty = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK); | ||||
| 	if (tty < 0) { | ||||
| 		ULOG_ERR("%s: device open failed: %s\n", dev, strerror(errno)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	tcgetattr(tty, &tio); | ||||
| 	tio.c_cflag |= CREAD; | ||||
| 	tio.c_cflag |= CS8; | ||||
| 	tio.c_iflag |= IGNPAR; | ||||
| 	tio.c_lflag &= ~(ICANON); | ||||
| 	tio.c_lflag &= ~(ECHO); | ||||
| 	tio.c_lflag &= ~(ECHOE); | ||||
| 	tio.c_lflag &= ~(ISIG); | ||||
| 	tio.c_iflag &= ~(IXON | IXOFF | IXANY); | ||||
| 	tio.c_cflag &= ~CRTSCTS; | ||||
| 	tio.c_cc[VMIN] = 1; | ||||
| 	tio.c_cc[VTIME] = 0; | ||||
| 	cfsetispeed(&tio, speed); | ||||
| 	cfsetospeed(&tio, speed); | ||||
| 	tcsetattr(tty, TCSANOW, &tio); | ||||
|  | ||||
| 	s->stream.string_data = false; | ||||
| 	s->stream.notify_read = poe_stream_msg_cb; | ||||
| 	s->stream.notify_state = poe_stream_notify_cb; | ||||
|  | ||||
| 	ustream_fd_init(s, tty); | ||||
| 	tcflush(tty, TCIFLUSH); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| poe_port_setup(void) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for (i = 0; i < config.port_count; i++) { | ||||
| 		if (!config.ports[i].enable) { | ||||
| 			poe_cmd_port_enable(i, 0); | ||||
| 			continue; | ||||
| 		} | ||||
|  | ||||
| 		poe_set_port_priority(i, config.ports[i].priority); | ||||
| 		poe_set_port_power_up_mode(i, config.ports[i].power_up_mode); | ||||
| 		if (config.ports[i].power_budget) { | ||||
| 			poe_cmd_port_power_budget(i, config.ports[i].power_budget); | ||||
| 			poe_cmd_port_power_limit_type(i, 2); | ||||
| 		} else { | ||||
| 			poe_cmd_port_power_limit_type(i, 1); | ||||
| 		} | ||||
| 		poe_cmd_port_disconnect_type(i, 2); | ||||
| 		poe_cmd_port_classification(i, 1); | ||||
| 		poe_cmd_port_detection_type(i, 3); | ||||
| 		poe_cmd_port_enable(i, 1); | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| poe_initial_setup(void) | ||||
| { | ||||
| 	poe_cmd_status(); | ||||
| 	poe_cmd_power_mgmt_mode(2); | ||||
| 	poe_cmd_global_power_budget(0, 0); | ||||
| 	poe_cmd_global_port_enable(0); | ||||
| 	poe_cmd_global_power_budget(config.budget, config.budget_guard); | ||||
|  | ||||
| 	poe_port_setup(); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static void | ||||
| state_timeout_cb(struct uloop_timeout *t) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	poe_cmd_power_stats(); | ||||
| 	poe_cmd_port_overview(); | ||||
|  | ||||
| 	for (i = 0; i < config.port_count; i++) { | ||||
| 		poe_cmd_port_ext_config(i); | ||||
| 		poe_cmd_port_power_stats(i); | ||||
| 	} | ||||
|  | ||||
| 	uloop_timeout_set(&state_timeout, 2 * 1000); | ||||
| } | ||||
|  | ||||
| static int | ||||
| ubus_poe_info_cb(struct ubus_context *ctx, struct ubus_object *obj, | ||||
| 		 struct ubus_request_data *req, const char *method, | ||||
| 		 struct blob_attr *msg) | ||||
| { | ||||
| 	char tmp[16]; | ||||
| 	void *c; | ||||
| 	int i; | ||||
|  | ||||
| 	blob_buf_init(&b, 0); | ||||
|  | ||||
| 	snprintf(tmp, sizeof(tmp), "v%u.%u.%u.%u", | ||||
| 		 state.sys_version >> 4, state.sys_version & 0xf, | ||||
| 		 state.sys_ext_version >> 4, state.sys_ext_version & 0xf); | ||||
| 	blobmsg_add_string(&b, "firmware", tmp); | ||||
| 	if (state.sys_mcu) | ||||
| 		blobmsg_add_string(&b, "mcu", state.sys_mcu); | ||||
| 	blobmsg_add_double(&b, "budget", config.budget); | ||||
| 	blobmsg_add_double(&b, "consumption", state.power_consumption); | ||||
|  | ||||
| 	c = blobmsg_open_table(&b, "ports"); | ||||
| 	for (i = 0; i < config.port_count; i++) { | ||||
| 		void *p; | ||||
|  | ||||
| 		if (!config.ports[i].enable) | ||||
| 			continue; | ||||
|  | ||||
| 		p = blobmsg_open_table(&b, config.ports[i].name); | ||||
|  | ||||
| 		blobmsg_add_u32(&b, "priority", config.ports[i].priority); | ||||
|  | ||||
| 		if (state.ports[i].poe_mode) | ||||
| 			blobmsg_add_string(&b, "mode", state.ports[i].poe_mode); | ||||
| 		if (state.ports[i].status) | ||||
| 			blobmsg_add_string(&b, "status", state.ports[i].status); | ||||
| 		else | ||||
| 			blobmsg_add_string(&b, "status", "unknown"); | ||||
| 		if (state.ports[i].watt) | ||||
| 			blobmsg_add_double(&b, "consumption", state.ports[i].watt); | ||||
|  | ||||
| 		blobmsg_close_table(&b, p); | ||||
| 	} | ||||
| 	blobmsg_close_table(&b, c); | ||||
|  | ||||
| 	ubus_send_reply(ctx, req, b.head); | ||||
|  | ||||
| 	return UBUS_STATUS_OK; | ||||
| } | ||||
|  | ||||
| static int | ||||
| ubus_poe_reload_cb(struct ubus_context *ctx, struct ubus_object *obj, | ||||
| 		   struct ubus_request_data *req, const char *method, | ||||
| 		   struct blob_attr *msg) | ||||
| { | ||||
| 	config_load(0); | ||||
| 	poe_port_setup(); | ||||
|  | ||||
| 	return UBUS_STATUS_OK; | ||||
| } | ||||
|  | ||||
| static const struct ubus_method ubus_poe_methods[] = { | ||||
| 	UBUS_METHOD_NOARG("info", ubus_poe_info_cb), | ||||
| 	UBUS_METHOD_NOARG("reload", ubus_poe_reload_cb), | ||||
| }; | ||||
|  | ||||
| static struct ubus_object_type ubus_poe_object_type = | ||||
| 	UBUS_OBJECT_TYPE("poe", ubus_poe_methods); | ||||
|  | ||||
| static struct ubus_object ubus_poe_object = { | ||||
| 	.name = "poe", | ||||
| 	.type = &ubus_poe_object_type, | ||||
| 	.methods = ubus_poe_methods, | ||||
| 	.n_methods = ARRAY_SIZE(ubus_poe_methods), | ||||
| }; | ||||
|  | ||||
| static void | ||||
| ubus_connect_handler(struct ubus_context *ctx) | ||||
| { | ||||
| 	int ret; | ||||
|  | ||||
| 	ret = ubus_add_object(ctx, &ubus_poe_object); | ||||
| 	if (ret) | ||||
| 		fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret)); | ||||
| } | ||||
|  | ||||
| int | ||||
| main(int argc, char ** argv) | ||||
| { | ||||
| 	int ch; | ||||
|  | ||||
| 	ulog_open(ULOG_STDIO | ULOG_SYSLOG, LOG_DAEMON, "realtek-poe"); | ||||
| 	ulog_threshold(LOG_INFO); | ||||
|  | ||||
| 	while ((ch = getopt(argc, argv, "d")) != -1) { | ||||
| 		switch (ch) { | ||||
| 		case 'd': | ||||
| 			config.debug = 1; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	config_load(1); | ||||
|  | ||||
| 	uloop_init(); | ||||
| 	conn.cb = ubus_connect_handler; | ||||
| 	ubus_auto_connect(&conn); | ||||
|  | ||||
| 	if (poe_stream_open("/dev/ttyS1", &stream, B19200) < 0) | ||||
| 		return -1; | ||||
|  | ||||
| 	poe_initial_setup(); | ||||
| 	state_timeout.cb = state_timeout_cb; | ||||
| 	uloop_timeout_set(&state_timeout, 1000); | ||||
| 	uloop_run(); | ||||
| 	uloop_done(); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
| @@ -1,29 +0,0 @@ | ||||
| include $(TOPDIR)/rules.mk | ||||
|  | ||||
| PKG_NAME:=rtl83xx-poe | ||||
| PKG_RELEASE:=2 | ||||
|  | ||||
| PKG_LICENSE:=GPL-2.0+ | ||||
|  | ||||
| include $(INCLUDE_DIR)/package.mk | ||||
|  | ||||
| define Package/rtl83xx-poe | ||||
|   SECTION:=utils | ||||
|   CATEGORY:=Utilities | ||||
|   DEPENDS:=+libubox-lua +libubus-lua +libuci-lua +lua-rs232 | ||||
|   TITLE:=PoE daemon for realtek switches | ||||
| endef | ||||
|  | ||||
| define Package/rtl83xx-poe/description | ||||
|  This package contains an utility to allow triggering the PoE state of realtek switch ports. | ||||
| endef | ||||
|  | ||||
| define Build/Compile | ||||
|  | ||||
| endef | ||||
|  | ||||
| define Package/rtl83xx-poe/install | ||||
| 	$(CP) ./files/* $(1)/ | ||||
| endef | ||||
|  | ||||
| $(eval $(call BuildPackage,rtl83xx-poe)) | ||||
| @@ -1,316 +0,0 @@ | ||||
| #!/usr/bin/lua | ||||
| local rs = require "luars232" | ||||
|  | ||||
| port_name = "/dev/ttyS1" | ||||
| out = io.stderr | ||||
| nseq = 0 | ||||
|  | ||||
| budget = 65.0 | ||||
| port_power = {0, 0, 0, 0, 0, 0, 0, 0 } | ||||
|  | ||||
| if arg[1] ~= nil then | ||||
| 	budget = tonumber(arg[1]) | ||||
| end | ||||
| for i = 1, 8 do | ||||
| 	port_power[i] = arg[i + 1] | ||||
| end | ||||
|  | ||||
| function initSerial(p) | ||||
| 	local e, p = rs.open(p) | ||||
| 	if e ~= rs.RS232_ERR_NOERROR then | ||||
| 		-- handle error | ||||
| 		out:write(string.format("can't open serial port '%s', error: '%s'\n", | ||||
| 				port_name, rs.error_tostring(e))) | ||||
| 		return | ||||
| 	end | ||||
|  | ||||
| 	assert(p:set_baud_rate(rs.RS232_BAUD_19200) == rs.RS232_ERR_NOERROR) | ||||
| 	assert(p:set_data_bits(rs.RS232_DATA_8) == rs.RS232_ERR_NOERROR) | ||||
| 	assert(p:set_parity(rs.RS232_PARITY_NONE) == rs.RS232_ERR_NOERROR) | ||||
| 	assert(p:set_stop_bits(rs.RS232_STOP_1) == rs.RS232_ERR_NOERROR) | ||||
| 	assert(p:set_flow_control(rs.RS232_FLOW_OFF)  == rs.RS232_ERR_NOERROR) | ||||
|  | ||||
| 	out:write(string.format("OK, port open with values '%s'\n", tostring(p))) | ||||
|  | ||||
| 	return p | ||||
| end | ||||
|  | ||||
| function receive(pCon) | ||||
| 	local reply = {} | ||||
| 	local retries = 0 | ||||
|  | ||||
| 	while table.getn(reply) < 12 and retries < 4 do | ||||
| 		-- Read up to 12 byte response, timeout 400ms | ||||
| 		err, data_read, size = pCon:read(12, 400) | ||||
| 		assert(err == rs.RS232_ERR_NOERROR) | ||||
| --		io.write(string.format("-> [%2d]:", string.len(data_read))) | ||||
| 		for i = 1, string.len(data_read) do | ||||
| 			table.insert(reply, string.byte(string.sub(data_read, i, i))) | ||||
| --			io.write(string.format(" %02x", reply[i])) | ||||
| 		end | ||||
| --		io.write("\n") | ||||
| 		retries = retries + 1 | ||||
| 	end | ||||
| 	if table.getn(reply) ~= 12 then | ||||
| 		print ("Unexpected length!") | ||||
| 		return(nil) | ||||
| 	end | ||||
| 	local sum = 0 | ||||
| 	for i = 1, 11 do | ||||
| 		sum = sum + reply[i] | ||||
| 	end | ||||
| 	if sum % 256 ~= reply[12] then | ||||
| 		print ("Checksum error!") | ||||
| 		return(nil) | ||||
| 	end | ||||
| 	return(reply) | ||||
| end | ||||
|  | ||||
| function sendCommand(pCon, cmd) | ||||
| 	nseq = nseq + 1 | ||||
| 	cmd[2] = nseq % 256 | ||||
|  | ||||
| 	while table.getn(cmd) < 11 do | ||||
| 		table.insert(cmd, 0xff) | ||||
| 	end | ||||
| 	local c_string = "" | ||||
| 	local sum = 0 | ||||
| --	io.write("send  ") | ||||
| 	for i = 1, 11 do | ||||
| 		sum = sum + cmd[i] | ||||
| --		io.write(string.format(" %02x", cmd[i])) | ||||
| 		c_string = c_string .. string.char(cmd[i]) | ||||
| 	end | ||||
| --	io.write(string.format(" %02x\n", sum % 256)) | ||||
| 	c_string = c_string .. string.char(sum % 256) | ||||
| 	err, len_written = pCon:write(c_string) | ||||
| 	assert(err == rs.RS232_ERR_NOERROR) | ||||
|  | ||||
| 	local reply = receive(pCon) | ||||
| 	if reply then | ||||
| --		io.write("recv  ") | ||||
| --		dumpReply(reply) | ||||
| 		if (reply[1] == cmd[1] and reply[2] == cmd[2]) then | ||||
| 			return(reply) | ||||
| 		else | ||||
| 			if reply[1] == 0xfd then | ||||
| 				print ("An incomplete request was received!") | ||||
| 			elseif reply[1] == 0xfe then | ||||
| 				print ("Request frame checksum was incorrect!") | ||||
| 			elseif reply[1] == 0xff then | ||||
| 				print ("Controller was not ready to respond !") | ||||
| 			else | ||||
| 				print ("Sequence number mismatch!") | ||||
| 			end | ||||
| 		end | ||||
| 	else | ||||
| 		print ("Missing reply!") | ||||
| 	end | ||||
| 	return(nil) | ||||
| end | ||||
|  | ||||
| function dumpReply(reply) | ||||
| 	for i,v in ipairs(reply) do | ||||
| 		io.write(string.format(" %02x", v)) | ||||
| 	end | ||||
| 	io.write("\n"); | ||||
| end | ||||
|  | ||||
| function getStatus(pCon) | ||||
| 	local cmd = {0x20, 0x01} | ||||
| 	local reply = sendCommand(pCon, cmd) | ||||
| 	if not reply then return(nil) end | ||||
| 	-- returns status, PoEExtVersion, PoEVersion, state2 | ||||
| 	return({reply[5], reply[6], reply[7], reply[10]}) | ||||
| end | ||||
|  | ||||
| function disablePort(pCon, port) | ||||
| 	local cmd = {0x00, port, port, 0x00} | ||||
| 	-- disable command is always sent twice | ||||
| 	sendCommand(pCon, cmd) | ||||
| 	sendCommand(pCon, cmd) | ||||
| end | ||||
|  | ||||
| function enablePort(pCon, port) | ||||
| 	local cmd = {0x00, port, port, 0x01} | ||||
| 	sendCommand(pCon, cmd) | ||||
| end | ||||
|  | ||||
| function setPortRelPrio(pCon, port, prio) | ||||
| 	local cmd = {0x1d, 0x00, port, prio} | ||||
| 	sendCommand(pCon, cmd) | ||||
| end | ||||
|  | ||||
| function setGlobalPowerBudget(pCon, maxPower, guard) | ||||
| 	-- maxPower and guard Watts | ||||
| 	local cmd = {0x18, 0x01, 0x00} | ||||
| 	table.insert(cmd, math.floor(maxPower * 10 / 256)) | ||||
| 	table.insert(cmd, math.floor(maxPower * 10) % 256) | ||||
| 	table.insert(cmd, math.floor(guard * 10 / 256)) | ||||
| 	table.insert(cmd, math.floor(guard * 10) % 256) | ||||
| 	sendCommand(pCon, cmd) | ||||
| end | ||||
|  | ||||
| function setPowerLowAction(pCon, disableNext) | ||||
| 	local cmd = {0x17, 0x00} | ||||
| 	if disableNext then | ||||
| 		table.insert(cmd, 0x04) | ||||
| 	else | ||||
| 		table.insert(cmd, 0x02) | ||||
| 	end | ||||
| 	sendCommand(pCon, cmd) | ||||
| end | ||||
|  | ||||
| function getPowerStat(pCon) | ||||
| 	local cmd = {0x23, 0x01} | ||||
| 	local reply = sendCommand(pCon, cmd) | ||||
| 	if not reply then return(nil) end | ||||
| 	local watts = (reply[3] * 256 + reply[4]) / 10.0 | ||||
| 	return watts | ||||
| end | ||||
|  | ||||
| function getPortPower(pCon, port) | ||||
| 	local cmd = {0x30, 0x01, port} | ||||
| 	local reply = sendCommand(pCon, cmd) | ||||
| 	if not reply then return(nil) end | ||||
| 	local watts = (reply[10] * 256 + reply[11]) / 10.0 | ||||
| 	local mamps = reply[6] * 256 + reply[7] | ||||
| 	return({watts, mamps}) | ||||
| end | ||||
|  | ||||
| function getPortOverview(pCon) | ||||
| 	local cmd = {0x2a, 0x01, 0x00} | ||||
| 	local reply = sendCommand(pCon, cmd) | ||||
| 	if not reply then return(nil) end | ||||
| 	local s = { } | ||||
| 	for i = 4, 11 do | ||||
| 		if reply[i] == 0x10 then | ||||
| 			s[i-3] = "off" | ||||
| 		elseif reply[i] == 0x11 then | ||||
| 			s[i-3] = "enabled" | ||||
| 		elseif reply[i] > 0x11 then | ||||
| 			s[i-3] = "active" | ||||
| 		else | ||||
| 			s[i-3] = "unknown" | ||||
| 		end | ||||
| 	end | ||||
| 	return(s) | ||||
| end | ||||
|  | ||||
| -- Priority for power: 3: High, 2: Normal, 1: Low? | ||||
| function setPortPriority(pCon, port, prio) | ||||
| 	local cmd = {0x1a, port, port, prio} | ||||
| 	local reply = sendCommand(pCon, cmd) | ||||
| 	if not reply then return(nil) end | ||||
| 	return(unpack(reply, 4, 11)) | ||||
| end | ||||
|  | ||||
| function getPortPowerLimits(pCon, port) | ||||
| 	local cmd = {0x26, 0x01, port} | ||||
| 	local reply = sendCommand(pCon, cmd) | ||||
| 	if not reply then return(nil) end | ||||
| 	return(reply) | ||||
| end | ||||
|  | ||||
| function startupPoE(pCon) | ||||
| 	local reply = nil | ||||
| 	reply = getStatus(pCon) | ||||
|  | ||||
| 	setGlobalPowerBudget(pCon, 0, 0) | ||||
| 	setPowerLowAction(pCon, nil) | ||||
| 	-- do something unknown | ||||
| 	sendCommand(pCon, {0x06, 0x00, 0x01}) | ||||
| 	for i = 0, 7 do | ||||
| 		if port_power[i + 1] ~= "1" then | ||||
| 			disablePort(pCon, i) | ||||
| 		end | ||||
| 	end | ||||
| 	-- do something unknown | ||||
| 	sendCommand(pCon, {0x02, 0x00, 0x01}) | ||||
|  | ||||
| 	for i = 0, 7 do | ||||
| 		if port_power[i + 1] ~= "1" then | ||||
| 			disablePort(pCon, i) | ||||
| 		end | ||||
| 	end | ||||
| 	-- do something unknown | ||||
| 	sendCommand(pCon, {0x02, 0x00, 0x01}) | ||||
|  | ||||
| 	-- use monitor command 25 | ||||
| 	sendCommand(pCon, {0x25, 0x01}) | ||||
|  | ||||
| 	setGlobalPowerBudget(pCon, 65.0, 7.0) | ||||
| 	getPowerStat(pCon) | ||||
| 	-- -> 23 01 00 00 02 44 00 02 ff ff 00 6a | ||||
|  | ||||
| 	-- Set 4 unknown port properties: | ||||
| 	for i = 0, 7 do | ||||
| 		sendCommand(pCon, {0x11, i, i, 0x01}) | ||||
| 		sendCommand(pCon, {0x13, i, i, 0x02}) | ||||
| 		sendCommand(pCon, {0x15, i, i, 0x01}) | ||||
| 		sendCommand(pCon, {0x10, i, i, 0x03}) | ||||
| 	end | ||||
| 	for i = 0, 7 do | ||||
| 		if port_power[i + 1] == "1" then | ||||
| 			enablePort(pCon, i) | ||||
| 		end | ||||
| 	end | ||||
|  | ||||
| end | ||||
|  | ||||
| local p = initSerial(port_name) | ||||
| startupPoE(p) | ||||
|  | ||||
| require "ubus" | ||||
| require "uloop" | ||||
|  | ||||
| uloop.init() | ||||
|  | ||||
| local conn = ubus.connect() | ||||
| if not conn then | ||||
|         error("Failed to connect to ubus") | ||||
| end | ||||
|  | ||||
| local my_method = { | ||||
| 	poe = { | ||||
| 		info = { | ||||
| 			function(req, msg) | ||||
| 				local reply = {} | ||||
|  | ||||
| 				reply.power_consumption = tostring(getPowerStat(p)).."W" | ||||
| 				reply.power_budget = tostring(budget).."W" | ||||
|  | ||||
| 				reply.ports = {} | ||||
| 				local s = getPortOverview(p) | ||||
| 				for i = 1, 8 do | ||||
| 					if s[i] == "active" then | ||||
| 						local r = getPortPower(p, i - 1) | ||||
| 						reply.ports[i] = tostring(r[1]).."W" | ||||
| 					else | ||||
| 						reply.ports[i] = s[i] | ||||
| 					end | ||||
| 				end | ||||
| 				conn:reply(req, reply); | ||||
| 			end, {} | ||||
| 		}, | ||||
| 		port = { | ||||
| 			function(req, msg) | ||||
| 				local reply = {} | ||||
| 				if msg.port < 1 or msg.port > 8 then | ||||
| 					conn:reply(req, false); | ||||
| 					return -1 | ||||
| 				end | ||||
| 				if msg.enable == true then | ||||
| 					enablePort(p, msg.port - 1) | ||||
| 				else | ||||
| 					disablePort(p, msg.port - 1) | ||||
| 				end | ||||
| 				conn:reply(req, reply); | ||||
| 			end, {port = ubus.INT32, enable = ubus.BOOLEAN } | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| conn:add(my_method) | ||||
|  | ||||
| uloop.run() | ||||
| @@ -1,10 +0,0 @@ | ||||
| config poe poe | ||||
| 	option budget	65 | ||||
| 	option port1	0 | ||||
| 	option port2	0 | ||||
| 	option port3	0 | ||||
| 	option port4	0 | ||||
| 	option port5	0 | ||||
| 	option port6	0 | ||||
| 	option port7	0 | ||||
| 	option port8	0 | ||||
| @@ -1,24 +0,0 @@ | ||||
| #!/bin/sh /etc/rc.common | ||||
| START=40 | ||||
|  | ||||
| USE_PROCD=1 | ||||
| PROG=/bin/poe.lua | ||||
|  | ||||
| service_triggers() { | ||||
| 	procd_add_reload_trigger poe | ||||
| } | ||||
|  | ||||
| start_service() { | ||||
| 	[ "$(uci get poe.poe.enable)" -eq 1 ] || return 0 | ||||
|  | ||||
| 	local budget=$(uci get poe.poe.budget) | ||||
|  | ||||
| 	procd_open_instance | ||||
| 	procd_set_param command "$PROG" | ||||
| 	procd_append_param command ${budget:-65} | ||||
| 	for p in `seq 1 8`; do | ||||
| 		local pwr=$(uci get poe.poe.port$p) | ||||
| 		procd_append_param command  ${pwr:-0} | ||||
| 	done | ||||
| 	procd_close_instance | ||||
| } | ||||
| @@ -1,21 +0,0 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| . /lib/functions.sh | ||||
|  | ||||
| board=$(board_name) | ||||
|  | ||||
| budget=0 | ||||
| case "$board" in | ||||
| d-link,dgs-1210-10p) | ||||
| 	budget=65 | ||||
| 	;; | ||||
| netgear,gs110tpp-v1|\ | ||||
| zyxel,gs1900-10hp) | ||||
| 	budget=130 | ||||
| 	;; | ||||
| *) | ||||
| 	exit 0 | ||||
| 	;; | ||||
| esac | ||||
| uci set poe.poe.enable=1 | ||||
| uci set poe.poe.budget=$budget | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,754 +0,0 @@ | ||||
| #!/bin/sh | ||||
| . /lib/netifd/netifd-wireless.sh | ||||
| . /lib/netifd/hostapd.sh | ||||
|  | ||||
| init_wireless_driver "$@" | ||||
|  | ||||
| MP_CONFIG_INT="mesh_retry_timeout mesh_confirm_timeout mesh_holding_timeout mesh_max_peer_links | ||||
| 	       mesh_max_retries mesh_ttl mesh_element_ttl mesh_hwmp_max_preq_retries | ||||
| 	       mesh_path_refresh_time mesh_min_discovery_timeout mesh_hwmp_active_path_timeout | ||||
| 	       mesh_hwmp_preq_min_interval mesh_hwmp_net_diameter_traversal_time mesh_hwmp_rootmode | ||||
| 	       mesh_hwmp_rann_interval mesh_gate_announcements mesh_sync_offset_max_neighor | ||||
| 	       mesh_rssi_threshold mesh_hwmp_active_path_to_root_timeout mesh_hwmp_root_interval | ||||
| 	       mesh_hwmp_confirmation_interval mesh_awake_window mesh_plink_timeout" | ||||
| MP_CONFIG_BOOL="mesh_auto_open_plinks mesh_fwding" | ||||
| MP_CONFIG_STRING="mesh_power_mode" | ||||
|  | ||||
| drv_mac80211_init_device_config() { | ||||
| 	hostapd_common_add_device_config | ||||
|  | ||||
| 	config_add_string path phy 'macaddr:macaddr' | ||||
| 	config_add_string hwmode | ||||
| 	config_add_int beacon_int chanbw frag rts | ||||
| 	config_add_int rxantenna txantenna antenna_gain txpower distance | ||||
| 	config_add_boolean noscan ht_coex | ||||
| 	config_add_array ht_capab | ||||
| 	config_add_boolean \ | ||||
| 		rxldpc \ | ||||
| 		short_gi_80 \ | ||||
| 		short_gi_160 \ | ||||
| 		tx_stbc_2by1 \ | ||||
| 		su_beamformer \ | ||||
| 		su_beamformee \ | ||||
| 		mu_beamformer \ | ||||
| 		mu_beamformee \ | ||||
| 		vht_txop_ps \ | ||||
| 		htc_vht \ | ||||
| 		rx_antenna_pattern \ | ||||
| 		tx_antenna_pattern | ||||
| 	config_add_int vht_max_a_mpdu_len_exp vht_max_mpdu vht_link_adapt vht160 rx_stbc tx_stbc | ||||
| 	config_add_boolean \ | ||||
| 		ldpc \ | ||||
| 		greenfield \ | ||||
| 		short_gi_20 \ | ||||
| 		short_gi_40 \ | ||||
| 		max_amsdu \ | ||||
| 		dsss_cck_40 | ||||
| } | ||||
|  | ||||
| drv_mac80211_init_iface_config() { | ||||
| 	hostapd_common_add_bss_config | ||||
|  | ||||
| 	config_add_string 'macaddr:macaddr' ifname | ||||
|  | ||||
| 	config_add_boolean wds powersave | ||||
| 	config_add_int maxassoc | ||||
| 	config_add_int max_listen_int | ||||
| 	config_add_int dtim_period | ||||
| 	config_add_int start_disabled | ||||
|  | ||||
| 	# mesh | ||||
| 	config_add_string mesh_id | ||||
| 	config_add_int $MP_CONFIG_INT | ||||
| 	config_add_boolean $MP_CONFIG_BOOL | ||||
| 	config_add_string $MP_CONFIG_STRING | ||||
| } | ||||
|  | ||||
| mac80211_add_capabilities() { | ||||
| 	local __var="$1"; shift | ||||
| 	local __mask="$1"; shift | ||||
| 	local __out= oifs | ||||
|  | ||||
| 	oifs="$IFS" | ||||
| 	IFS=: | ||||
| 	for capab in "$@"; do | ||||
| 		set -- $capab | ||||
|  | ||||
| 		[ "$(($4))" -gt 0 ] || continue | ||||
| 		[ "$(($__mask & $2))" -eq "$((${3:-$2}))" ] || continue | ||||
| 		__out="$__out[$1]" | ||||
| 	done | ||||
| 	IFS="$oifs" | ||||
|  | ||||
| 	export -n -- "$__var=$__out" | ||||
| } | ||||
|  | ||||
| mac80211_hostapd_setup_base() { | ||||
| 	local phy="$1" | ||||
|  | ||||
| 	json_select config | ||||
|  | ||||
| 	[ "$auto_channel" -gt 0 ] && channel=acs_survey | ||||
|  | ||||
| 	json_get_vars noscan ht_coex | ||||
| 	json_get_values ht_capab_list ht_capab | ||||
|  | ||||
| 	ieee80211n=1 | ||||
| 	ht_capab= | ||||
| 	case "$htmode" in | ||||
| 		VHT20|HT20) ;; | ||||
| 		HT40*|VHT40|VHT80|VHT160) | ||||
| 			case "$hwmode" in | ||||
| 				a) | ||||
| 					case "$(( ($channel / 4) % 2 ))" in | ||||
| 						1) ht_capab="[HT40+]";; | ||||
| 						0) ht_capab="[HT40-]";; | ||||
| 					esac | ||||
| 				;; | ||||
| 				*) | ||||
| 					case "$htmode" in | ||||
| 						HT40+) ht_capab="[HT40+]";; | ||||
| 						HT40-) ht_capab="[HT40-]";; | ||||
| 						*) | ||||
| 							if [ "$channel" -lt 7 ]; then | ||||
| 								ht_capab="[HT40+]" | ||||
| 							else | ||||
| 								ht_capab="[HT40-]" | ||||
| 							fi | ||||
| 						;; | ||||
| 					esac | ||||
| 				;; | ||||
| 			esac | ||||
| 			[ "$auto_channel" -gt 0 ] && ht_capab="[HT40+]" | ||||
| 		;; | ||||
| 		*) ieee80211n= ;; | ||||
| 	esac | ||||
|  | ||||
| 	[ -n "$ieee80211n" ] && { | ||||
| 		append base_cfg "ieee80211n=1" "$N" | ||||
|  | ||||
| 		set_default ht_coex 0 | ||||
| 		append base_cfg "ht_coex=$ht_coex" "$N" | ||||
|  | ||||
| 		json_get_vars \ | ||||
| 			ldpc:1 \ | ||||
| 			greenfield:0 \ | ||||
| 			short_gi_20:1 \ | ||||
| 			short_gi_40:1 \ | ||||
| 			tx_stbc:1 \ | ||||
| 			rx_stbc:3 \ | ||||
| 			max_amsdu:1 \ | ||||
| 			dsss_cck_40:1 | ||||
|  | ||||
| 		ht_cap_mask=0 | ||||
| 		for cap in $(iw phy "$phy" info | grep 'Capabilities:' | cut -d: -f2); do | ||||
| 			ht_cap_mask="$(($ht_cap_mask | $cap))" | ||||
| 		done | ||||
|  | ||||
| 		cap_rx_stbc=$((($ht_cap_mask >> 8) & 3)) | ||||
| 		[ "$rx_stbc" -lt "$cap_rx_stbc" ] && cap_rx_stbc="$rx_stbc" | ||||
| 		ht_cap_mask="$(( ($ht_cap_mask & ~(0x300)) | ($cap_rx_stbc << 8) ))" | ||||
|  | ||||
| 		mac80211_add_capabilities ht_capab_flags $ht_cap_mask \ | ||||
| 			LDPC:0x1::$ldpc \ | ||||
| 			GF:0x10::$greenfield \ | ||||
| 			SHORT-GI-20:0x20::$short_gi_20 \ | ||||
| 			SHORT-GI-40:0x40::$short_gi_40 \ | ||||
| 			TX-STBC:0x80::$tx_stbc \ | ||||
| 			RX-STBC1:0x300:0x100:1 \ | ||||
| 			RX-STBC12:0x300:0x200:1 \ | ||||
| 			RX-STBC123:0x300:0x300:1 \ | ||||
| 			MAX-AMSDU-7935:0x800::$max_amsdu \ | ||||
| 			DSSS_CCK-40:0x1000::$dsss_cck_40 | ||||
|  | ||||
| 		ht_capab="$ht_capab$ht_capab_flags" | ||||
| 		[ -n "$ht_capab" ] && append base_cfg "ht_capab=$ht_capab" "$N" | ||||
| 	} | ||||
|  | ||||
| 	# 802.11ac | ||||
| 	enable_ac=0 | ||||
| 	idx="$channel" | ||||
| 	case "$htmode" in | ||||
| 		VHT20) enable_ac=1;; | ||||
| 		VHT40) | ||||
| 			case "$(( ($channel / 4) % 2 ))" in | ||||
| 				1) idx=$(($channel + 2));; | ||||
| 				0) idx=$(($channel - 2));; | ||||
| 			esac | ||||
| 			enable_ac=1 | ||||
| 			append base_cfg "vht_oper_chwidth=0" "$N" | ||||
| 			append base_cfg "vht_oper_centr_freq_seg0_idx=$idx" "$N" | ||||
| 		;; | ||||
| 		VHT80) | ||||
| 			case "$(( ($channel / 4) % 4 ))" in | ||||
| 				1) idx=$(($channel + 6));; | ||||
| 				2) idx=$(($channel + 2));; | ||||
| 				3) idx=$(($channel - 2));; | ||||
| 				0) idx=$(($channel - 6));; | ||||
| 			esac | ||||
| 			enable_ac=1 | ||||
| 			append base_cfg "vht_oper_chwidth=1" "$N" | ||||
| 			append base_cfg "vht_oper_centr_freq_seg0_idx=$idx" "$N" | ||||
| 		;; | ||||
| 		VHT160) | ||||
| 			case "$channel" in | ||||
| 				36|40|44|48|52|56|60|64) idx=50;; | ||||
| 				100|104|108|112|116|120|124|128) idx=114;; | ||||
| 			esac | ||||
| 			enable_ac=1 | ||||
| 			append base_cfg "vht_oper_chwidth=2" "$N" | ||||
| 			append base_cfg "vht_oper_centr_freq_seg0_idx=$idx" "$N" | ||||
| 		;; | ||||
| 	esac | ||||
|  | ||||
| 	if [ "$enable_ac" != "0" ]; then | ||||
| 		json_get_vars \ | ||||
| 			rxldpc:1 \ | ||||
| 			short_gi_80:1 \ | ||||
| 			short_gi_160:1 \ | ||||
| 			tx_stbc_2by1:1 \ | ||||
| 			su_beamformer:1 \ | ||||
| 			su_beamformee:1 \ | ||||
| 			mu_beamformer:1 \ | ||||
| 			mu_beamformee:1 \ | ||||
| 			vht_txop_ps:1 \ | ||||
| 			htc_vht:1 \ | ||||
| 			rx_antenna_pattern:1 \ | ||||
| 			tx_antenna_pattern:1 \ | ||||
| 			vht_max_a_mpdu_len_exp:7 \ | ||||
| 			vht_max_mpdu:11454 \ | ||||
| 			rx_stbc:4 \ | ||||
| 			tx_stbc:4 \ | ||||
| 			vht_link_adapt:3 \ | ||||
| 			vht160:2 | ||||
|  | ||||
| 		append base_cfg "ieee80211ac=1" "$N" | ||||
| 		vht_cap=0 | ||||
| 		for cap in $(iw phy "$phy" info | awk -F "[()]" '/VHT Capabilities/ { print $2 }'); do | ||||
| 			vht_cap="$(($vht_cap | $cap))" | ||||
| 		done | ||||
|  | ||||
| 		cap_rx_stbc=$((($vht_cap >> 8) & 7)) | ||||
| 		[ "$rx_stbc" -lt "$cap_rx_stbc" ] && cap_rx_stbc="$rx_stbc" | ||||
| 		ht_cap_mask="$(( ($vht_cap & ~(0x700)) | ($cap_rx_stbc << 8) ))" | ||||
|  | ||||
| 		mac80211_add_capabilities vht_capab $vht_cap \ | ||||
| 			RXLDPC:0x10::$rxldpc \ | ||||
| 			SHORT-GI-80:0x20::$short_gi_80 \ | ||||
| 			SHORT-GI-160:0x40::$short_gi_160 \ | ||||
| 			TX-STBC-2BY1:0x80::$tx_stbc \ | ||||
| 			SU-BEAMFORMER:0x800::$su_beamformer \ | ||||
| 			SU-BEAMFORMEE:0x1000::$su_beamformee \ | ||||
| 			MU-BEAMFORMER:0x80000::$mu_beamformer \ | ||||
| 			MU-BEAMFORMEE:0x100000::$mu_beamformee \ | ||||
| 			VHT-TXOP-PS:0x200000::$vht_txop_ps \ | ||||
| 			HTC-VHT:0x400000::$htc_vht \ | ||||
| 			RX-ANTENNA-PATTERN:0x10000000::$rx_antenna_pattern \ | ||||
| 			TX-ANTENNA-PATTERN:0x20000000::$tx_antenna_pattern \ | ||||
| 			RX-STBC1:0x700:0x100:1 \ | ||||
| 			RX-STBC12:0x700:0x200:1 \ | ||||
| 			RX-STBC123:0x700:0x300:1 \ | ||||
| 			RX-STBC1234:0x700:0x400:1 \ | ||||
|  | ||||
| 		# supported Channel widths | ||||
| 		vht160_hw=0 | ||||
| 		[ "$(($vht_cap & 12))" -eq 4 -a 1 -le "$vht160" ] && \ | ||||
| 			vht160_hw=1 | ||||
| 		[ "$(($vht_cap & 12))" -eq 8 -a 2 -le "$vht160" ] && \ | ||||
| 			vht160_hw=2 | ||||
| 		[ "$vht160_hw" = 1 ] && vht_capab="$vht_capab[VHT160]" | ||||
| 		[ "$vht160_hw" = 2 ] && vht_capab="$vht_capab[VHT160-80PLUS80]" | ||||
|  | ||||
| 		# maximum MPDU length | ||||
| 		vht_max_mpdu_hw=3895 | ||||
| 		[ "$(($vht_cap & 3))" -ge 1 -a 7991 -le "$vht_max_mpdu" ] && \ | ||||
| 			vht_max_mpdu_hw=7991 | ||||
| 		[ "$(($vht_cap & 3))" -ge 2 -a 11454 -le "$vht_max_mpdu" ] && \ | ||||
| 			vht_max_mpdu_hw=11454 | ||||
| 		[ "$vht_max_mpdu_hw" != 3895 ] && \ | ||||
| 			vht_capab="$vht_capab[MAX-MPDU-$vht_max_mpdu_hw]" | ||||
| 			 | ||||
| 		# maximum A-MPDU length exponent | ||||
| 		vht_max_a_mpdu_len_exp_hw=0 | ||||
| 		[ "$(($vht_cap & 58720256))" -ge 8388608 -a 1 -le "$vht_max_a_mpdu_len_exp" ] && \ | ||||
| 			vht_max_a_mpdu_len_exp_hw=1 | ||||
| 		[ "$(($vht_cap & 58720256))" -ge 16777216 -a 2 -le "$vht_max_a_mpdu_len_exp" ] && \ | ||||
| 			vht_max_a_mpdu_len_exp_hw=2 | ||||
| 		[ "$(($vht_cap & 58720256))" -ge 25165824 -a 3 -le "$vht_max_a_mpdu_len_exp" ] && \ | ||||
| 			vht_max_a_mpdu_len_exp_hw=3 | ||||
| 		[ "$(($vht_cap & 58720256))" -ge 33554432 -a 4 -le "$vht_max_a_mpdu_len_exp" ] && \ | ||||
| 			vht_max_a_mpdu_len_exp_hw=4 | ||||
| 		[ "$(($vht_cap & 58720256))" -ge 41943040 -a 5 -le "$vht_max_a_mpdu_len_exp" ] && \ | ||||
| 			vht_max_a_mpdu_len_exp_hw=5 | ||||
| 		[ "$(($vht_cap & 58720256))" -ge 50331648 -a 6 -le "$vht_max_a_mpdu_len_exp" ] && \ | ||||
| 			vht_max_a_mpdu_len_exp_hw=6 | ||||
| 		[ "$(($vht_cap & 58720256))" -ge 58720256 -a 7 -le "$vht_max_a_mpdu_len_exp" ] && \ | ||||
| 			vht_max_a_mpdu_len_exp_hw=7 | ||||
| 		vht_capab="$vht_capab[MAX-A-MPDU-LEN-EXP$vht_max_a_mpdu_len_exp_hw]" | ||||
|  | ||||
| 		# whether or not the STA supports link adaptation using VHT variant | ||||
| 		vht_link_adapt_hw=0 | ||||
| 		[ "$(($vht_cap & 201326592))" -ge 134217728 -a 2 -le "$vht_link_adapt" ] && \ | ||||
| 			vht_link_adapt_hw=2 | ||||
| 		[ "$(($vht_cap & 201326592))" -ge 201326592 -a 3 -le "$vht_link_adapt" ] && \ | ||||
| 			vht_link_adapt_hw=3 | ||||
| 		[ "$vht_link_adapt_hw" != 0 ] && \ | ||||
| 			vht_capab="$vht_capab[VHT-LINK-ADAPT-$vht_link_adapt_hw]" | ||||
|  | ||||
| 		[ -n "$vht_capab" ] && append base_cfg "vht_capab=$vht_capab" "$N" | ||||
| 	fi | ||||
|  | ||||
| 	hostapd_prepare_device_config "$hostapd_conf_file" nl80211 | ||||
| 	cat >> "$hostapd_conf_file" <<EOF | ||||
| ${channel:+channel=$channel} | ||||
| ${noscan:+noscan=$noscan} | ||||
| $base_cfg | ||||
|  | ||||
| EOF | ||||
| 	json_select .. | ||||
| } | ||||
|  | ||||
| mac80211_hostapd_setup_bss() { | ||||
| 	local phy="$1" | ||||
| 	local ifname="$2" | ||||
| 	local macaddr="$3" | ||||
| 	local type="$4" | ||||
|  | ||||
| 	hostapd_cfg= | ||||
| 	append hostapd_cfg "$type=$ifname" "$N" | ||||
|  | ||||
| 	hostapd_set_bss_options hostapd_cfg "$vif" || return 1 | ||||
| 	json_get_vars wds dtim_period max_listen_int start_disabled | ||||
|  | ||||
| 	set_default wds 0 | ||||
| 	set_default start_disabled 0 | ||||
|  | ||||
| 	[ "$wds" -gt 0 ] && append hostapd_cfg "wds_sta=1" "$N" | ||||
| 	[ "$staidx" -gt 0 -o "$start_disabled" -eq 1 ] && append hostapd_cfg "start_disabled=1" "$N" | ||||
|  | ||||
| 	cat >> /var/run/hostapd-$phy.conf <<EOF | ||||
| $hostapd_cfg | ||||
| bssid=$macaddr | ||||
| ${dtim_period:+dtim_period=$dtim_period} | ||||
| ${max_listen_int:+max_listen_interval=$max_listen_int} | ||||
| EOF | ||||
| } | ||||
|  | ||||
| mac80211_get_addr() { | ||||
| 	local phy="$1" | ||||
| 	local idx="$(($2 + 1))" | ||||
|  | ||||
| 	head -n $(($macidx + 1)) /sys/class/ieee80211/${phy}/addresses | tail -n1 | ||||
| } | ||||
|  | ||||
| mac80211_generate_mac() { | ||||
| 	local phy="$1" | ||||
| 	local id="${macidx:-0}" | ||||
|  | ||||
| 	local ref="$(cat /sys/class/ieee80211/${phy}/macaddress)" | ||||
| 	local mask="$(cat /sys/class/ieee80211/${phy}/address_mask)" | ||||
|  | ||||
| 	[ "$mask" = "00:00:00:00:00:00" ] && { | ||||
| 		mask="ff:ff:ff:ff:ff:ff"; | ||||
|  | ||||
| 		[ "$(wc -l < /sys/class/ieee80211/${phy}/addresses)" -gt 1 ] && { | ||||
| 			addr="$(mac80211_get_addr "$phy" "$id")" | ||||
| 			[ -n "$addr" ] && { | ||||
| 				echo "$addr" | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	local oIFS="$IFS"; IFS=":"; set -- $mask; IFS="$oIFS" | ||||
|  | ||||
| 	local mask1=$1 | ||||
| 	local mask6=$6 | ||||
|  | ||||
| 	local oIFS="$IFS"; IFS=":"; set -- $ref; IFS="$oIFS" | ||||
|  | ||||
| 	macidx=$(($id + 1)) | ||||
| 	[ "$((0x$mask1))" -gt 0 ] && { | ||||
| 		b1="0x$1" | ||||
| 		[ "$id" -gt 0 ] && \ | ||||
| 			b1=$(($b1 ^ ((($id - 1) << 2) | 0x2))) | ||||
| 		printf "%02x:%s:%s:%s:%s:%s" $b1 $2 $3 $4 $5 $6 | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	[ "$((0x$mask6))" -lt 255 ] && { | ||||
| 		printf "%s:%s:%s:%s:%s:%02x" $1 $2 $3 $4 $5 $(( 0x$6 ^ $id )) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	off2=$(( (0x$6 + $id) / 0x100 )) | ||||
| 	printf "%s:%s:%s:%s:%02x:%02x" \ | ||||
| 		$1 $2 $3 $4 \ | ||||
| 		$(( (0x$5 + $off2) % 0x100 )) \ | ||||
| 		$(( (0x$6 + $id) % 0x100 )) | ||||
| } | ||||
|  | ||||
| find_phy() { | ||||
| 	[ -n "$phy" -a -d /sys/class/ieee80211/$phy ] && return 0 | ||||
| 	[ -n "$path" ] && { | ||||
| 		for phy in /sys/devices/$path/ieee80211/phy*; do | ||||
| 			[ -e "$phy" ] && { | ||||
| 				phy="${phy##*/}" | ||||
| 				return 0 | ||||
| 			} | ||||
| 		done | ||||
| 	} | ||||
| 	[ -n "$macaddr" ] && { | ||||
| 		for phy in $(ls /sys/class/ieee80211 2>/dev/null); do | ||||
| 			grep -i -q "$macaddr" "/sys/class/ieee80211/${phy}/macaddress" && return 0 | ||||
| 		done | ||||
| 	} | ||||
| 	return 1 | ||||
| } | ||||
|  | ||||
| mac80211_check_ap() { | ||||
| 	has_ap=1 | ||||
| } | ||||
|  | ||||
| mac80211_prepare_vif() { | ||||
| 	json_select config | ||||
|  | ||||
| 	json_get_vars ifname mode ssid wds powersave macaddr | ||||
|  | ||||
| 	[ -n "$ifname" ] || ifname="wlan${phy#phy}${if_idx:+-$if_idx}" | ||||
| 	if_idx=$((${if_idx:-0} + 1)) | ||||
|  | ||||
| 	set_default wds 0 | ||||
| 	set_default powersave 0 | ||||
|  | ||||
| 	json_select .. | ||||
|  | ||||
| 	[ -n "$macaddr" ] || { | ||||
| 		macaddr="$(mac80211_generate_mac $phy)" | ||||
| 		macidx="$(($macidx + 1))" | ||||
| 	} | ||||
|  | ||||
| 	json_add_object data | ||||
| 	json_add_string ifname "$ifname" | ||||
| 	json_close_object | ||||
| 	json_select config | ||||
|  | ||||
| 	# It is far easier to delete and create the desired interface | ||||
| 	case "$mode" in | ||||
| 		adhoc) | ||||
| 			iw phy "$phy" interface add "$ifname" type adhoc | ||||
| 		;; | ||||
| 		ap) | ||||
| 			# Hostapd will handle recreating the interface and | ||||
| 			# subsequent virtual APs belonging to the same PHY | ||||
| 			if [ -n "$hostapd_ctrl" ]; then | ||||
| 				type=bss | ||||
| 			else | ||||
| 				type=interface | ||||
| 			fi | ||||
|  | ||||
| 			mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" "$type" || return | ||||
|  | ||||
| 			[ -n "$hostapd_ctrl" ] || { | ||||
| 				iw phy "$phy" interface add "$ifname" type __ap | ||||
| 				hostapd_ctrl="${hostapd_ctrl:-/var/run/hostapd/$ifname}" | ||||
| 			} | ||||
| 		;; | ||||
| 		mesh) | ||||
| 			iw phy "$phy" interface add "$ifname" type mp | ||||
| 		;; | ||||
| 		monitor) | ||||
| 			iw phy "$phy" interface add "$ifname" type monitor | ||||
| 		;; | ||||
| 		sta) | ||||
| 			local wdsflag= | ||||
| 			staidx="$(($staidx + 1))" | ||||
| 			[ "$wds" -gt 0 ] && wdsflag="4addr on" | ||||
| 			iw phy "$phy" interface add "$ifname" type managed $wdsflag | ||||
| 			[ "$powersave" -gt 0 ] && powersave="on" || powersave="off" | ||||
| 			iw "$ifname" set power_save "$powersave" | ||||
| 		;; | ||||
| 	esac | ||||
|  | ||||
| 	case "$mode" in | ||||
| 		monitor|mesh) | ||||
| 			[ "$auto_channel" -gt 0 ] || iw dev "$ifname" set channel "$channel" $htmode | ||||
| 		;; | ||||
| 	esac | ||||
|  | ||||
| 	if [ "$mode" != "ap" ]; then | ||||
| 		# ALL ap functionality will be passed to hostapd | ||||
| 		# All interfaces must have unique mac addresses | ||||
| 		# which can either be explicitly set in the device | ||||
| 		# section, or automatically generated | ||||
| 		ifconfig "$ifname" hw ether "$macaddr" | ||||
| 	fi | ||||
|  | ||||
| 	json_select .. | ||||
| } | ||||
|  | ||||
| mac80211_setup_supplicant() { | ||||
| 	wpa_supplicant_prepare_interface "$ifname" nl80211 || return 1 | ||||
| 	wpa_supplicant_add_network "$ifname" | ||||
| 	wpa_supplicant_run "$ifname" ${hostapd_ctrl:+-H $hostapd_ctrl} | ||||
| } | ||||
|  | ||||
| mac80211_setup_adhoc_htmode() { | ||||
| 	case "$htmode" in | ||||
| 		VHT20|HT20) ibss_htmode=HT20;; | ||||
| 		HT40*|VHT40|VHT80|VHT160) | ||||
| 			case "$hwmode" in | ||||
| 				a) | ||||
| 					case "$(( ($channel / 4) % 2 ))" in | ||||
| 						1) ibss_htmode="HT40+" ;; | ||||
| 						0) ibss_htmode="HT40-";; | ||||
| 					esac | ||||
| 				;; | ||||
| 				*) | ||||
| 					case "$htmode" in | ||||
| 						HT40+) ibss_htmode="HT40+";; | ||||
| 						HT40-) ibss_htmode="HT40-";; | ||||
| 						*) | ||||
| 							if [ "$channel" -lt 7 ]; then | ||||
| 								ibss_htmode="HT40+" | ||||
| 							else | ||||
| 								ibss_htmode="HT40-" | ||||
| 							fi | ||||
| 						;; | ||||
| 					esac | ||||
| 				;; | ||||
| 			esac | ||||
| 			[ "$auto_channel" -gt 0 ] && ibss_htmode="HT40+" | ||||
| 		;; | ||||
| 		NONE|NOHT) | ||||
| 			ibss_htmode="NOHT" | ||||
| 		;; | ||||
| 		*) ibss_htmode="" ;; | ||||
| 	esac | ||||
|  | ||||
| } | ||||
|  | ||||
| mac80211_setup_adhoc() { | ||||
| 	json_get_vars bssid ssid key mcast_rate | ||||
|  | ||||
| 	keyspec= | ||||
| 	[ "$auth_type" = "wep" ] && { | ||||
| 		set_default key 1 | ||||
| 		case "$key" in | ||||
| 			[1234]) | ||||
| 				local idx | ||||
| 				for idx in 1 2 3 4; do | ||||
| 					json_get_var ikey "key$idx" | ||||
|  | ||||
| 					[ -n "$ikey" ] && { | ||||
| 						ikey="$(($idx - 1)):$(prepare_key_wep "$ikey")" | ||||
| 						[ $idx -eq $key ] && ikey="d:$ikey" | ||||
| 						append keyspec "$ikey" | ||||
| 					} | ||||
| 				done | ||||
| 			;; | ||||
| 			*) | ||||
| 				append keyspec "d:0:$(prepare_key_wep "$key")" | ||||
| 			;; | ||||
| 		esac | ||||
| 	} | ||||
|  | ||||
| 	brstr= | ||||
| 	for br in $basic_rate_list; do | ||||
| 		wpa_supplicant_add_rate brstr "$br" | ||||
| 	done | ||||
|  | ||||
| 	mcval= | ||||
| 	[ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate" | ||||
|  | ||||
| 	iw dev "$ifname" ibss join "$ssid" $freq $ibss_htmode fixed-freq $bssid \ | ||||
| 		${beacon_int:+beacon-interval $beacon_int} \ | ||||
| 		${brstr:+basic-rates $brstr} \ | ||||
| 		${mcval:+mcast-rate $mcval} \ | ||||
| 		${keyspec:+keys $keyspec} | ||||
| } | ||||
|  | ||||
| mac80211_setup_vif() { | ||||
| 	local name="$1" | ||||
| 	local failed | ||||
|  | ||||
| 	json_select data | ||||
| 	json_get_vars ifname | ||||
| 	json_select .. | ||||
|  | ||||
| 	json_select config | ||||
| 	json_get_vars mode | ||||
| 	json_get_var vif_txpower txpower | ||||
|  | ||||
| 	ifconfig "$ifname" up || { | ||||
| 		wireless_setup_vif_failed IFUP_ERROR | ||||
| 		json_select .. | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	set_default vif_txpower "$txpower" | ||||
| 	[ -z "$vif_txpower" ] || iw dev "$ifname" set txpower fixed "${vif_txpower%%.*}00" | ||||
|  | ||||
| 	case "$mode" in | ||||
| 		mesh) | ||||
| 			# authsae or wpa_supplicant | ||||
| 			json_get_vars key | ||||
| 			if [ -n "$key" ]; then | ||||
| 				if [ -e "/lib/wifi/authsae.sh" ]; then | ||||
| 					. /lib/wifi/authsae.sh | ||||
| 					authsae_start_interface || failed=1 | ||||
| 				else | ||||
| 					wireless_vif_parse_encryption | ||||
| 					mac80211_setup_supplicant || failed=1 | ||||
| 				fi | ||||
| 			else | ||||
| 				json_get_vars mesh_id mcast_rate | ||||
|  | ||||
| 				mcval= | ||||
| 				[ -n "$mcast_rate" ] && wpa_supplicant_add_rate mcval "$mcast_rate" | ||||
|  | ||||
| 				iw dev "$ifname" mesh join "$mesh_id" ${mcval:+mcast-rate $mcval} | ||||
| 			fi | ||||
|  | ||||
| 			for var in $MP_CONFIG_INT $MP_CONFIG_BOOL $MP_CONFIG_STRING; do | ||||
| 				json_get_var mp_val "$var" | ||||
| 				[ -n "$mp_val" ] && iw dev "$ifname" set mesh_param "$var" "$mp_val" | ||||
| 			done | ||||
| 		;; | ||||
| 		adhoc) | ||||
| 			wireless_vif_parse_encryption | ||||
| 			mac80211_setup_adhoc_htmode | ||||
| 			if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ]; then | ||||
| 				mac80211_setup_supplicant || failed=1 | ||||
| 			else | ||||
| 				mac80211_setup_adhoc | ||||
| 			fi | ||||
| 		;; | ||||
| 		sta) | ||||
| 			mac80211_setup_supplicant || failed=1 | ||||
| 		;; | ||||
| 	esac | ||||
|  | ||||
| 	json_select .. | ||||
| 	[ -n "$failed" ] || wireless_add_vif "$name" "$ifname" | ||||
| } | ||||
|  | ||||
| get_freq() { | ||||
| 	local phy="$1" | ||||
| 	local chan="$2" | ||||
| 	iw "$phy" info | grep -E -m1 "(\* ${chan:-....} MHz${chan:+|\\[$chan\\]})" | grep MHz | awk '{print $2}' | ||||
| } | ||||
|  | ||||
| mac80211_interface_cleanup() { | ||||
| 	local phy="$1" | ||||
|  | ||||
| 	for wdev in $(list_phy_interfaces "$phy"); do | ||||
| 		ifconfig "$wdev" down 2>/dev/null | ||||
| 		iw dev "$wdev" del | ||||
| 	done | ||||
| } | ||||
|  | ||||
| drv_mac80211_cleanup() { | ||||
| 	hostapd_common_cleanup | ||||
| } | ||||
|  | ||||
| drv_mac80211_setup() { | ||||
| 	json_select config | ||||
| 	json_get_vars \ | ||||
| 		phy macaddr path \ | ||||
| 		country chanbw distance \ | ||||
| 		txpower antenna_gain \ | ||||
| 		rxantenna txantenna \ | ||||
| 		frag rts beacon_int htmode | ||||
| 	json_get_values basic_rate_list basic_rate | ||||
| 	json_select .. | ||||
|  | ||||
| 	find_phy || { | ||||
| 		echo "Could not find PHY for device '$1'" | ||||
| 		wireless_set_retry 0 | ||||
| 		return 1 | ||||
| 	} | ||||
|  | ||||
| 	wireless_set_data phy="$phy" | ||||
| 	mac80211_interface_cleanup "$phy" | ||||
|  | ||||
| 	# convert channel to frequency | ||||
| 	[ "$auto_channel" -gt 0 ] || freq="$(get_freq "$phy" "$channel")" | ||||
|  | ||||
| 	[ -n "$country" ] && { | ||||
| 		iw reg get | grep -q "^country $country:" || { | ||||
| 			iw reg set "$country" | ||||
| 			sleep 1 | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	hostapd_conf_file="/var/run/hostapd-$phy.conf" | ||||
|  | ||||
| 	no_ap=1 | ||||
| 	macidx=0 | ||||
| 	staidx=0 | ||||
|  | ||||
| 	[ -n "$chanbw" ] && { | ||||
| 		for file in /sys/kernel/debug/ieee80211/$phy/ath9k/chanbw /sys/kernel/debug/ieee80211/$phy/ath5k/bwmode; do | ||||
| 			[ -f "$file" ] && echo "$chanbw" > "$file" | ||||
| 		done | ||||
| 	} | ||||
|  | ||||
| 	set_default rxantenna all | ||||
| 	set_default txantenna all | ||||
| 	set_default distance 0 | ||||
| 	set_default antenna_gain 0 | ||||
|  | ||||
| 	iw phy "$phy" set antenna $txantenna $rxantenna >/dev/null 2>&1 | ||||
| 	iw phy "$phy" set antenna_gain $antenna_gain | ||||
| 	iw phy "$phy" set distance "$distance" | ||||
|  | ||||
| 	[ -n "$frag" ] && iw phy "$phy" set frag "${frag%%.*}" | ||||
| 	[ -n "$rts" ] && iw phy "$phy" set rts "${rts%%.*}" | ||||
|  | ||||
| 	has_ap= | ||||
| 	hostapd_ctrl= | ||||
| 	for_each_interface "ap" mac80211_check_ap | ||||
|  | ||||
| 	rm -f "$hostapd_conf_file" | ||||
| 	[ -n "$has_ap" ] && mac80211_hostapd_setup_base "$phy" | ||||
| #	rtk : reoder the prepare_vif flow to workaround | ||||
| 	for_each_interface "ap" mac80211_prepare_vif | ||||
| 	for_each_interface "sta adhoc mesh monitor" mac80211_prepare_vif | ||||
| #	for_each_interface "ap" mac80211_prepare_vif | ||||
|  | ||||
| 	[ -n "$hostapd_ctrl" ] && { | ||||
| 		/usr/sbin/hostapd -P /var/run/wifi-$phy.pid -B "$hostapd_conf_file" | ||||
| 		ret="$?" | ||||
| 		wireless_add_process "$(cat /var/run/wifi-$phy.pid)" "/usr/sbin/hostapd" 1 | ||||
| 		[ "$ret" != 0 ] && { | ||||
| 			wireless_setup_failed HOSTAPD_START_FAILED | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for_each_interface "ap sta adhoc mesh monitor" mac80211_setup_vif | ||||
|  | ||||
| 	wireless_set_up | ||||
| } | ||||
|  | ||||
| list_phy_interfaces() { | ||||
| 	local phy="$1" | ||||
| 	if [ -d "/sys/class/ieee80211/${phy}/device/net" ]; then | ||||
| 		ls "/sys/class/ieee80211/${phy}/device/net" 2>/dev/null; | ||||
| 	else | ||||
| 		ls "/sys/class/ieee80211/${phy}/device" 2>/dev/null | grep net: | sed -e 's,net:,,g' | ||||
| 	fi | ||||
| } | ||||
|  | ||||
| drv_mac80211_teardown() { | ||||
| 	wireless_process_kill_all | ||||
|  | ||||
| 	json_select data | ||||
| 	json_get_vars phy | ||||
| 	json_select .. | ||||
|  | ||||
| 	mac80211_interface_cleanup "$phy" | ||||
| } | ||||
|  | ||||
| add_driver mac80211 | ||||
| @@ -1,190 +0,0 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| append DRIVERS "mac80211" | ||||
|  | ||||
| lookup_phy() { | ||||
| 	[ -n "$phy" ] && { | ||||
| 		[ -d /sys/class/ieee80211/$phy ] && return | ||||
| 	} | ||||
|  | ||||
| 	local devpath | ||||
| 	config_get devpath "$device" path | ||||
| 	[ -n "$devpath" ] && { | ||||
| 		phy="$(iwinfo nl80211 phyname "path=$devpath")" | ||||
| 		[ -n "$phy" ] && return | ||||
| 	} | ||||
|  | ||||
| 	local macaddr="$(config_get "$device" macaddr | tr 'A-Z' 'a-z')" | ||||
| 	[ -n "$macaddr" ] && { | ||||
| 		for _phy in /sys/class/ieee80211/*; do | ||||
| 			[ -e "$_phy" ] || continue | ||||
|  | ||||
| 			[ "$macaddr" = "$(cat ${_phy}/macaddress)" ] || continue | ||||
| 			phy="${_phy##*/}" | ||||
| 			return | ||||
| 		done | ||||
| 	} | ||||
| 	phy= | ||||
| 	return | ||||
| } | ||||
|  | ||||
| find_mac80211_phy() { | ||||
| 	local device="$1" | ||||
|  | ||||
| 	config_get phy "$device" phy | ||||
| 	lookup_phy | ||||
| 	[ -n "$phy" -a -d "/sys/class/ieee80211/$phy" ] || { | ||||
| 		echo "PHY for wifi device $1 not found" | ||||
| 		return 1 | ||||
| 	} | ||||
| 	config_set "$device" phy "$phy" | ||||
|  | ||||
| 	config_get macaddr "$device" macaddr | ||||
| 	[ -z "$macaddr" ] && { | ||||
| 		config_set "$device" macaddr "$(cat /sys/class/ieee80211/${phy}/macaddress)" | ||||
| 	} | ||||
|  | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| check_mac80211_device() { | ||||
| 	config_get phy "$1" phy | ||||
| 	[ -z "$phy" ] && { | ||||
| 		find_mac80211_phy "$1" >/dev/null || return 0 | ||||
| 		config_get phy "$1" phy | ||||
| 	} | ||||
| 	[ "$phy" = "$dev" ] && found=1 | ||||
| } | ||||
|  | ||||
|  | ||||
| __get_band_defaults() { | ||||
| 	local phy="$1" | ||||
|  | ||||
| 	( iw phy "$phy" info; echo ) | awk ' | ||||
| BEGIN { | ||||
|         bands = "" | ||||
| } | ||||
|  | ||||
| ($1 == "Band" || $1 == "") && band { | ||||
|         if (channel) { | ||||
| 		mode="NOHT" | ||||
| 		if (ht) mode="HT20" | ||||
| 		if (vht && band != "1:") mode="VHT80" | ||||
| 		if (he) mode="HE80" | ||||
| 		if (he && band == "1:") mode="HE20" | ||||
|                 sub("\\[", "", channel) | ||||
|                 sub("\\]", "", channel) | ||||
|                 bands = bands band channel ":" mode " " | ||||
|         } | ||||
|         band="" | ||||
| } | ||||
|  | ||||
| $1 == "Band" { | ||||
|         band = $2 | ||||
|         channel = "" | ||||
| 	vht = "" | ||||
| 	ht = "" | ||||
| 	he = "" | ||||
| } | ||||
|  | ||||
| $0 ~ "Capabilities:" { | ||||
| 	ht=1 | ||||
| } | ||||
|  | ||||
| $0 ~ "VHT Capabilities" { | ||||
| 	vht=1 | ||||
| } | ||||
|  | ||||
| $0 ~ "HE Iftypes" { | ||||
| 	he=1 | ||||
| } | ||||
|  | ||||
| $1 == "*" && $3 == "MHz" && $0 !~ /disabled/ && band && !channel { | ||||
|         channel = $4 | ||||
| } | ||||
|  | ||||
| END { | ||||
|         print bands | ||||
| }' | ||||
| } | ||||
|  | ||||
| get_band_defaults() { | ||||
| 	local phy="$1" | ||||
|  | ||||
| 	for c in $(__get_band_defaults "$phy"); do | ||||
| 		local band="${c%%:*}" | ||||
| 		c="${c#*:}" | ||||
| 		local chan="${c%%:*}" | ||||
| 		c="${c#*:}" | ||||
| 		local mode="${c%%:*}" | ||||
|  | ||||
| 		case "$band" in | ||||
| 			1) band=2g;; | ||||
| 			2) band=5g;; | ||||
| 			3) band=60g;; | ||||
| 			4) band=6g;; | ||||
| 			*) band="";; | ||||
| 		esac | ||||
|  | ||||
| 		[ -n "$band" ] || continue | ||||
| 		[ -n "$mode_band" -a "$band" = "6g" ] && return | ||||
|  | ||||
| 		mode_band="$band" | ||||
| 		channel="$chan" | ||||
| 		htmode="$mode" | ||||
| 	done | ||||
| } | ||||
|  | ||||
| detect_mac80211() { | ||||
| 	devidx=0 | ||||
| 	config_load wireless | ||||
| 	while :; do | ||||
| 		config_get type "radio$devidx" type | ||||
| 		[ -n "$type" ] || break | ||||
| 		devidx=$(($devidx + 1)) | ||||
| 	done | ||||
|  | ||||
| 	for _dev in /sys/class/ieee80211/*; do | ||||
| 		[ -e "$_dev" ] || continue | ||||
|  | ||||
| 		dev="${_dev##*/}" | ||||
|  | ||||
| 		found=0 | ||||
| 		config_foreach check_mac80211_device wifi-device | ||||
| 		[ "$found" -gt 0 ] && continue | ||||
|  | ||||
| 		mode_band="" | ||||
| 		channel="" | ||||
| 		htmode="" | ||||
| 		ht_capab="" | ||||
|  | ||||
| 		get_band_defaults "$dev" | ||||
|  | ||||
| 		path="$(iwinfo nl80211 path "$dev")" | ||||
| 		if [ -n "$path" ]; then | ||||
| 			dev_id="set wireless.radio${devidx}.path='$path'" | ||||
| 		else | ||||
| 			dev_id="set wireless.radio${devidx}.macaddr=$(cat /sys/class/ieee80211/${dev}/macaddress)" | ||||
| 		fi | ||||
|  | ||||
| 		uci -q batch <<-EOF | ||||
| 			set wireless.radio${devidx}=wifi-device | ||||
| 			set wireless.radio${devidx}.type=mac80211 | ||||
| 			${dev_id} | ||||
| 			set wireless.radio${devidx}.channel=${channel} | ||||
| 			set wireless.radio${devidx}.band=${mode_band} | ||||
| 			set wireless.radio${devidx}.htmode=$htmode | ||||
| 			set wireless.radio${devidx}.disabled=0 | ||||
|  | ||||
| 			set wireless.default_radio${devidx}=wifi-iface | ||||
| 			set wireless.default_radio${devidx}.device=radio${devidx} | ||||
| 			set wireless.default_radio${devidx}.network=lan | ||||
| 			set wireless.default_radio${devidx}.mode=ap | ||||
| 			set wireless.default_radio${devidx}.ssid=OpenWrt | ||||
| 			set wireless.default_radio${devidx}.encryption=none | ||||
| EOF | ||||
| 		uci -q commit wireless | ||||
|  | ||||
| 		devidx=$(($devidx + 1)) | ||||
| 	done | ||||
| } | ||||
| @@ -1,5 +0,0 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| [ "${ACTION}" = "add" ] && { | ||||
| 	/sbin/wifi config | ||||
| } | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,14 +0,0 @@ | ||||
| --- a/kconf/Makefile | ||||
| +++ b/kconf/Makefile | ||||
| @@ -1,9 +1,9 @@ | ||||
| -CFLAGS=-Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer | ||||
| +CFLAGS=-Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -DKBUILD_NO_NLS | ||||
|   | ||||
|  LXDIALOG := lxdialog/checklist.o lxdialog/inputbox.o lxdialog/menubox.o lxdialog/textbox.o lxdialog/util.o lxdialog/yesno.o | ||||
|   | ||||
|  conf: conf.o zconf.tab.o | ||||
| -mconf_CFLAGS := $(shell ./lxdialog/check-lxdialog.sh -ccflags) -DLOCALE | ||||
| +mconf_CFLAGS := $(shell ./lxdialog/check-lxdialog.sh -ccflags) | ||||
|  mconf_LDFLAGS := $(shell ./lxdialog/check-lxdialog.sh -ldflags $(CC)) | ||||
|  mconf: CFLAGS += $(mconf_CFLAGS) | ||||
|   | ||||
| @@ -1,167 +0,0 @@ | ||||
| --- a/Makefile | ||||
| +++ b/Makefile | ||||
| @@ -5,7 +5,7 @@ | ||||
|  ifeq ($(KERNELRELEASE),) | ||||
|   | ||||
|  MAKEFLAGS += --no-print-directory | ||||
| -SHELL := /bin/bash | ||||
| +SHELL := /usr/bin/env bash | ||||
|  BACKPORT_DIR := $(shell pwd) | ||||
|   | ||||
|  KMODDIR ?= updates | ||||
| @@ -19,6 +19,7 @@ KLIB_BUILD ?= $(KLIB)/build/ | ||||
|  KERNEL_CONFIG := $(KLIB_BUILD)/.config | ||||
|  KERNEL_MAKEFILE := $(KLIB_BUILD)/Makefile | ||||
|  CONFIG_MD5 := $(shell md5sum $(KERNEL_CONFIG) 2>/dev/null | sed 's/\s.*//') | ||||
| +STAMP_KERNEL_CONFIG := .kernel_config_md5_$(CONFIG_MD5) | ||||
|   | ||||
|  export KLIB KLIB_BUILD BACKPORT_DIR KMODDIR KMODPATH_ARG | ||||
|   | ||||
| @@ -36,7 +37,8 @@ mrproper: | ||||
|  	@rm -f .kernel_config_md5 Kconfig.versions Kconfig.kernel | ||||
|  	@rm -f backport-include/backport/autoconf.h | ||||
|   | ||||
| -.DEFAULT: | ||||
| +.SILENT: $(STAMP_KERNEL_CONFIG) | ||||
| +$(STAMP_KERNEL_CONFIG): | ||||
|  	@set -e ; test -f .local-symbols || (						\ | ||||
|  	echo "/--------------"								;\ | ||||
|  	echo "| You shouldn't run make in the backports tree, but only in"		;\ | ||||
| @@ -60,57 +62,61 @@ mrproper: | ||||
|  	echo "| (that isn't currently running.)"					;\ | ||||
|  	echo "\\--"									;\ | ||||
|  	false) | ||||
| -	@set -e ; if [ "$$(cat .kernel_config_md5 2>/dev/null)" != "$(CONFIG_MD5)" ]	;\ | ||||
| -	then 										\ | ||||
| -		echo -n "Generating local configuration database from kernel ..."	;\ | ||||
| -		grep -v -f .local-symbols $(KERNEL_CONFIG) | grep = | (			\ | ||||
| -			while read l ; do						\ | ||||
| -				if [ "$${l:0:7}" != "CONFIG_" ] ; then			\ | ||||
| -					continue					;\ | ||||
| -				fi							;\ | ||||
| -				l=$${l:7}						;\ | ||||
| -				n=$${l%%=*}						;\ | ||||
| -				v=$${l#*=}						;\ | ||||
| -				if [ "$$v" = "m" ] ; then				\ | ||||
| -					echo config $$n					;\ | ||||
| -					echo '    tristate' 				;\ | ||||
| -				elif [ "$$v" = "y" ] ; then				\ | ||||
| -					echo config $$n					;\ | ||||
| -					echo '    bool'					;\ | ||||
| -				else							\ | ||||
| -					continue					;\ | ||||
| -				fi							;\ | ||||
| -				echo "    default $$v"					;\ | ||||
| -				echo ""							;\ | ||||
| -			done								\ | ||||
| -		) > Kconfig.kernel							;\ | ||||
| -		kver=$$($(MAKE) --no-print-directory -C $(KLIB_BUILD) kernelversion |	\ | ||||
| -			sed 's/^\(\([3-4]\|2\.6\)\.[0-9]\+\).*/\1/;t;d')		;\ | ||||
| -		test "$$kver" != "" || echo "Kernel version parse failed!"		;\ | ||||
| -		test "$$kver" != ""							;\ | ||||
| -		kvers="$$(seq 14 39 | sed 's/^/2.6./')"					;\ | ||||
| -		kvers="$$kvers $$(seq 0 19 | sed 's/^/3./')"				;\ | ||||
| -		kvers="$$kvers $$(seq 0 99 | sed 's/^/4./')"				;\ | ||||
| -		print=0									;\ | ||||
| -		for v in $$kvers ; do							\ | ||||
| -			if [ "$$print" = "1" ] ; then					\ | ||||
| -				echo config KERNEL_$$(echo $$v | tr . _)	;\ | ||||
| -				echo "    def_bool y"					;\ | ||||
| -			fi								;\ | ||||
| -			if [ "$$v" = "$$kver" ] ; then print=1 ; fi			;\ | ||||
| -		done > Kconfig.versions							;\ | ||||
| -		# RHEL as well, sadly we need to grep for it				;\ | ||||
| -		RHEL_MAJOR=$$(grep '^RHEL_MAJOR' $(KERNEL_MAKEFILE) | 			\ | ||||
| -					sed 's/.*=\s*\([0-9]*\)/\1/;t;d')		;\ | ||||
| -		RHEL_MINOR=$$(grep '^RHEL_MINOR' $(KERNEL_MAKEFILE) | 			\ | ||||
| -					sed 's/.*=\s*\([0-9]*\)/\1/;t;d')		;\ | ||||
| -		for v in $$(seq 0 $$RHEL_MINOR) ; do 					\ | ||||
| -			echo config BACKPORT_RHEL_KERNEL_$${RHEL_MAJOR}_$$v		;\ | ||||
| -			echo "    def_bool y"						;\ | ||||
| -		done >> Kconfig.versions						;\ | ||||
| -		echo " done."								;\ | ||||
| -	fi										;\ | ||||
| -	echo "$(CONFIG_MD5)" > .kernel_config_md5 | ||||
| +	@rm -f .kernel_config_md5_* | ||||
| +	@touch $@ | ||||
| + | ||||
| +Kconfig.kernel: $(STAMP_KERNEL_CONFIG) .local-symbols | ||||
| +	@printf "Generating local configuration database from kernel ..." | ||||
| +	@grep -v -f .local-symbols $(KERNEL_CONFIG) | grep = | (			\ | ||||
| +		while read l ; do						\ | ||||
| +			if [ "$${l:0:7}" != "CONFIG_" ] ; then			\ | ||||
| +				continue					;\ | ||||
| +			fi							;\ | ||||
| +			l=$${l:7}						;\ | ||||
| +			n=$${l%%=*}						;\ | ||||
| +			v=$${l#*=}						;\ | ||||
| +			if [ "$$v" = "m" ] ; then				\ | ||||
| +				echo config $$n					;\ | ||||
| +				echo '    tristate' 				;\ | ||||
| +			elif [ "$$v" = "y" ] ; then				\ | ||||
| +				echo config $$n					;\ | ||||
| +				echo '    bool'					;\ | ||||
| +			else							\ | ||||
| +				continue					;\ | ||||
| +			fi							;\ | ||||
| +			echo "    default $$v"					;\ | ||||
| +			echo ""							;\ | ||||
| +		done								\ | ||||
| +	) > $@ | ||||
| +	@echo " done." | ||||
| + | ||||
| +Kconfig.versions: Kconfig.kernel | ||||
| +	@kver=$$($(MAKE) --no-print-directory -C $(KLIB_BUILD) kernelversion |	\ | ||||
| +		sed 's/^\(\([3-4]\|2\.6\)\.[0-9]\+\).*/\1/;t;d')		;\ | ||||
| +	test "$$kver" != "" || echo "Kernel version parse failed!"		;\ | ||||
| +	test "$$kver" != ""							;\ | ||||
| +	kvers="$$(seq 14 39 | sed 's/^/2.6./')"					;\ | ||||
| +	kvers="$$kvers $$(seq 0 19 | sed 's/^/3./')"				;\ | ||||
| +	kvers="$$kvers $$(seq 0 99 | sed 's/^/4./')"				;\ | ||||
| +	print=0									;\ | ||||
| +	for v in $$kvers ; do							\ | ||||
| +		if [ "$$print" = "1" ] ; then					\ | ||||
| +			echo config KERNEL_$$(echo $$v | tr . _)	;\ | ||||
| +			echo "    def_bool y"					;\ | ||||
| +		fi								;\ | ||||
| +		if [ "$$v" = "$$kver" ] ; then print=1 ; fi			;\ | ||||
| +	done > $@ | ||||
| +	@RHEL_MAJOR=$$(grep '^RHEL_MAJOR' $(KERNEL_MAKEFILE) | 			\ | ||||
| +				sed 's/.*=\s*\([0-9]*\)/\1/;t;d')		;\ | ||||
| +	RHEL_MINOR=$$(grep '^RHEL_MINOR' $(KERNEL_MAKEFILE) | 			\ | ||||
| +				sed 's/.*=\s*\([0-9]*\)/\1/;t;d')		;\ | ||||
| +	for v in $$(seq 0 $$RHEL_MINOR) ; do 					\ | ||||
| +		echo config BACKPORT_RHEL_KERNEL_$${RHEL_MAJOR}_$$v		;\ | ||||
| +		echo "    def_bool y"						;\ | ||||
| +	done >> $@ | ||||
| + | ||||
| +.DEFAULT: | ||||
| +	@$(MAKE) Kconfig.versions | ||||
|  	@$(MAKE) -f Makefile.real "$@" | ||||
|   | ||||
|  .PHONY: defconfig-help | ||||
| --- a/Makefile.real | ||||
| +++ b/Makefile.real | ||||
| @@ -59,7 +59,7 @@ defconfig-%:: | ||||
|   | ||||
|  backport-include/backport/autoconf.h: .config Kconfig.versions Kconfig.kernel | ||||
|  	@$(MAKE) oldconfig | ||||
| -	@echo -n "Building backport-include/backport/autoconf.h ..." | ||||
| +	@printf "Building backport-include/backport/autoconf.h ..." | ||||
|  	@grep -f .local-symbols .config | (				\ | ||||
|  		echo "#ifndef COMPAT_AUTOCONF_INCLUDED"			;\ | ||||
|  		echo "#define COMPAT_AUTOCONF_INCLUDED"			;\ | ||||
| @@ -80,7 +80,12 @@ backport-include/backport/autoconf.h: .c | ||||
|  			esac						;\ | ||||
|  		done							;\ | ||||
|  		echo "#endif /* COMPAT_AUTOCONF_INCLUDED */"		;\ | ||||
| -	) > backport-include/backport/autoconf.h | ||||
| +	) > $@.new | ||||
| +	@if cmp -s $@ $@.new; then \ | ||||
| +		rm -f $@.new; \ | ||||
| +	else \ | ||||
| +		mv $@.new $@; \ | ||||
| +	fi | ||||
|  	@echo " done." | ||||
|   | ||||
|  .PHONY: modules | ||||
| @@ -1,64 +0,0 @@ | ||||
| --- a/kconf/conf.c | ||||
| +++ b/kconf/conf.c | ||||
| @@ -593,40 +593,12 @@ int main(int ac, char **av) | ||||
|  	case oldconfig: | ||||
|  	case listnewconfig: | ||||
|  	case olddefconfig: | ||||
| -		conf_read(NULL); | ||||
| -		break; | ||||
|  	case allnoconfig: | ||||
|  	case allyesconfig: | ||||
|  	case allmodconfig: | ||||
|  	case alldefconfig: | ||||
|  	case randconfig: | ||||
| -		name = getenv("KCONFIG_ALLCONFIG"); | ||||
| -		if (!name) | ||||
| -			break; | ||||
| -		if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { | ||||
| -			if (conf_read_simple(name, S_DEF_USER)) { | ||||
| -				fprintf(stderr, | ||||
| -					_("*** Can't read seed configuration \"%s\"!\n"), | ||||
| -					name); | ||||
| -				exit(1); | ||||
| -			} | ||||
| -			break; | ||||
| -		} | ||||
| -		switch (input_mode) { | ||||
| -		case allnoconfig:	name = "allno.config"; break; | ||||
| -		case allyesconfig:	name = "allyes.config"; break; | ||||
| -		case allmodconfig:	name = "allmod.config"; break; | ||||
| -		case alldefconfig:	name = "alldef.config"; break; | ||||
| -		case randconfig:	name = "allrandom.config"; break; | ||||
| -		default: break; | ||||
| -		} | ||||
| -		if (conf_read_simple(name, S_DEF_USER) && | ||||
| -		    conf_read_simple("all.config", S_DEF_USER)) { | ||||
| -			fprintf(stderr, | ||||
| -				_("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), | ||||
| -				name); | ||||
| -			exit(1); | ||||
| -		} | ||||
| +		conf_read(NULL); | ||||
|  		break; | ||||
|  	default: | ||||
|  		break; | ||||
| --- a/kconf/confdata.c | ||||
| +++ b/kconf/confdata.c | ||||
| @@ -1169,6 +1169,8 @@ bool conf_set_all_new_symbols(enum conf_ | ||||
|  	} | ||||
|  	bool has_changed = false; | ||||
|   | ||||
| +	sym_clear_all_valid(); | ||||
| + | ||||
|  	for_all_symbols(i, sym) { | ||||
|  		if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) | ||||
|  			continue; | ||||
| @@ -1212,8 +1214,6 @@ bool conf_set_all_new_symbols(enum conf_ | ||||
|   | ||||
|  	} | ||||
|   | ||||
| -	sym_clear_all_valid(); | ||||
| - | ||||
|  	/* | ||||
|  	 * We have different type of choice blocks. | ||||
|  	 * If curr.tri equals to mod then we can select several | ||||
| @@ -1,34 +0,0 @@ | ||||
| --- a/compat/main.c | ||||
| +++ b/compat/main.c | ||||
| @@ -20,31 +20,6 @@ MODULE_LICENSE("GPL"); | ||||
|  #error "You need a CPTCFG_VERSION" | ||||
|  #endif | ||||
|   | ||||
| -static char *backported_kernel_name = CPTCFG_KERNEL_NAME; | ||||
| - | ||||
| -module_param(backported_kernel_name, charp, 0400); | ||||
| -MODULE_PARM_DESC(backported_kernel_name, | ||||
| -		 "The kernel tree name that was used for this backport (" CPTCFG_KERNEL_NAME ")"); | ||||
| - | ||||
| -#ifdef BACKPORTS_GIT_TRACKED | ||||
| -static char *backports_tracker_id = BACKPORTS_GIT_TRACKED; | ||||
| -module_param(backports_tracker_id, charp, 0400); | ||||
| -MODULE_PARM_DESC(backports_tracker_id, | ||||
| -		 "The version of the tree containing this backport (" BACKPORTS_GIT_TRACKED ")"); | ||||
| -#else | ||||
| -static char *backported_kernel_version = CPTCFG_KERNEL_VERSION; | ||||
| -static char *backports_version = CPTCFG_VERSION; | ||||
| - | ||||
| -module_param(backported_kernel_version, charp, 0400); | ||||
| -MODULE_PARM_DESC(backported_kernel_version, | ||||
| -		 "The kernel version that was used for this backport (" CPTCFG_KERNEL_VERSION ")"); | ||||
| - | ||||
| -module_param(backports_version, charp, 0400); | ||||
| -MODULE_PARM_DESC(backports_version, | ||||
| -		 "The git version of the backports tree used to generate this backport (" CPTCFG_VERSION ")"); | ||||
| - | ||||
| -#endif | ||||
| - | ||||
|  void backport_dependency_symbol(void) | ||||
|  { | ||||
|  } | ||||
| @@ -1,21 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Thu, 28 Jan 2016 15:16:35 +0100 | ||||
| Subject: [PATCH] backports: add skb_free_frag() | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/backport-include/linux/skbuff.h | ||||
| +++ b/backport-include/linux/skbuff.h | ||||
| @@ -300,4 +300,11 @@ int skb_ensure_writable(struct sk_buff * | ||||
|   | ||||
|  #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0) */ | ||||
|   | ||||
| +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,2,0) | ||||
| +static inline void skb_free_frag(void *data) | ||||
| +{ | ||||
| +	put_page(virt_to_head_page(data)); | ||||
| +} | ||||
| +#endif | ||||
| + | ||||
|  #endif /* __BACKPORT_SKBUFF_H */ | ||||
| @@ -1,20 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Thu, 28 Jan 2016 15:19:22 +0100 | ||||
| Subject: [PATCH] backports: add napi_alloc_frag | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/backport-include/linux/netdevice.h | ||||
| +++ b/backport-include/linux/netdevice.h | ||||
| @@ -232,6 +232,10 @@ static inline void backport_unregister_n | ||||
|  #define unregister_netdevice_many LINUX_BACKPORT(unregister_netdevice_many) | ||||
|  #endif | ||||
|   | ||||
| +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0) | ||||
| +#define napi_alloc_frag netdev_alloc_frag | ||||
| +#endif | ||||
| + | ||||
|  /* | ||||
|   * Complicated way of saying: We only backport netdev_rss_key stuff on kernels | ||||
|   * that either already have net_get_random_once() (>= 3.13) or where we've been | ||||
| @@ -1,13 +0,0 @@ | ||||
| --- a/backport-include/linux/rfkill.h | ||||
| +++ b/backport-include/linux/rfkill.h | ||||
| @@ -2,6 +2,10 @@ | ||||
|  #define __COMPAT_RFKILL_H | ||||
|  #include <linux/version.h> | ||||
|   | ||||
| +#undef CONFIG_RFKILL | ||||
| +#undef CONFIG_RFKILL_LEDS | ||||
| +#undef CONFIG_RFKILL_MODULE | ||||
| + | ||||
|  #if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) | ||||
|  #include_next <linux/rfkill.h> | ||||
|  #else | ||||
| @@ -1,47 +0,0 @@ | ||||
| --- a/drivers/net/wireless/ralink/rt2x00/Kconfig | ||||
| +++ b/drivers/net/wireless/ralink/rt2x00/Kconfig | ||||
| @@ -225,36 +225,37 @@ config RT2800SOC | ||||
|   | ||||
|   | ||||
|  config RT2800_LIB | ||||
| -	tristate | ||||
| +	tristate "RT2800 USB/PCI support" | ||||
|  	depends on m | ||||
|   | ||||
|  config RT2800_LIB_MMIO | ||||
| -	tristate | ||||
| +	tristate "RT2800 MMIO support" | ||||
|  	depends on m | ||||
|  	select RT2X00_LIB_MMIO | ||||
|  	select RT2800_LIB | ||||
|   | ||||
|  config RT2X00_LIB_MMIO | ||||
| -	tristate | ||||
| +	tristate "RT2x00 MMIO support" | ||||
|  	depends on m | ||||
|   | ||||
|  config RT2X00_LIB_PCI | ||||
| -	tristate | ||||
| +	tristate "RT2x00 PCI support" | ||||
|  	depends on m | ||||
|  	select RT2X00_LIB | ||||
|   | ||||
|  config RT2X00_LIB_SOC | ||||
| -	tristate | ||||
| +	tristate "RT2x00 SoC support" | ||||
| +	depends on SOC_RT288X || SOC_RT305X | ||||
|  	depends on m | ||||
|  	select RT2X00_LIB | ||||
|   | ||||
|  config RT2X00_LIB_USB | ||||
| -	tristate | ||||
| +	tristate "RT2x00 USB support" | ||||
|  	depends on m | ||||
|  	select RT2X00_LIB | ||||
|   | ||||
|  config RT2X00_LIB | ||||
| -	tristate | ||||
| +	tristate "RT2x00 support" | ||||
|  	depends on m | ||||
|   | ||||
|  config RT2X00_LIB_FIRMWARE | ||||
| @@ -1,9 +0,0 @@ | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/Kconfig | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/Kconfig | ||||
| @@ -1,5 +1,5 @@ | ||||
|  config BRCMUTIL | ||||
| -	tristate | ||||
| +	tristate "Broadcom 802.11 driver utility functions" | ||||
|  	depends on m | ||||
|   | ||||
|  config BRCMSMAC | ||||
| @@ -1,30 +0,0 @@ | ||||
| --- a/net/wireless/Kconfig | ||||
| +++ b/net/wireless/Kconfig | ||||
| @@ -171,7 +171,7 @@ config CFG80211_WEXT_EXPORT | ||||
|  	  wext compatibility symbols to be exported. | ||||
|   | ||||
|  config LIB80211 | ||||
| -	tristate | ||||
| +	tristate "lib80211" | ||||
|  	depends on m | ||||
|  	default n | ||||
|  	help | ||||
| @@ -181,15 +181,15 @@ config LIB80211 | ||||
|  	  Drivers should select this themselves if needed. | ||||
|   | ||||
|  config LIB80211_CRYPT_WEP | ||||
| -	tristate | ||||
| +	tristate "lib80211 WEP support" | ||||
|  	depends on m | ||||
|   | ||||
|  config LIB80211_CRYPT_CCMP | ||||
| -	tristate | ||||
| +	tristate "lib80211 CCMP support" | ||||
|  	depends on m | ||||
|   | ||||
|  config LIB80211_CRYPT_TKIP | ||||
| -	tristate | ||||
| +	tristate "lib80211 TKIP support" | ||||
|  	depends on m | ||||
|   | ||||
|  config LIB80211_DEBUG | ||||
| @@ -1,131 +0,0 @@ | ||||
| --- a/.local-symbols | ||||
| +++ b/.local-symbols | ||||
| @@ -476,44 +476,6 @@ USB_IPHETH= | ||||
|  USB_SIERRA_NET= | ||||
|  USB_VL600= | ||||
|  USB_NET_CH9200= | ||||
| -SSB_POSSIBLE= | ||||
| -SSB= | ||||
| -SSB_SPROM= | ||||
| -SSB_BLOCKIO= | ||||
| -SSB_PCIHOST_POSSIBLE= | ||||
| -SSB_PCIHOST= | ||||
| -SSB_B43_PCI_BRIDGE= | ||||
| -SSB_PCMCIAHOST_POSSIBLE= | ||||
| -SSB_PCMCIAHOST= | ||||
| -SSB_SDIOHOST_POSSIBLE= | ||||
| -SSB_SDIOHOST= | ||||
| -SSB_HOST_SOC= | ||||
| -SSB_SILENT= | ||||
| -SSB_DEBUG= | ||||
| -SSB_SERIAL= | ||||
| -SSB_DRIVER_PCICORE_POSSIBLE= | ||||
| -SSB_DRIVER_PCICORE= | ||||
| -SSB_PCICORE_HOSTMODE= | ||||
| -SSB_DRIVER_MIPS= | ||||
| -SSB_SFLASH= | ||||
| -SSB_EMBEDDED= | ||||
| -SSB_DRIVER_EXTIF= | ||||
| -SSB_DRIVER_GIGE= | ||||
| -SSB_DRIVER_GPIO= | ||||
| -BCMA_POSSIBLE= | ||||
| -BCMA= | ||||
| -BCMA_BLOCKIO= | ||||
| -BCMA_HOST_PCI_POSSIBLE= | ||||
| -BCMA_HOST_PCI= | ||||
| -BCMA_HOST_SOC= | ||||
| -BCMA_DRIVER_PCI= | ||||
| -BCMA_DRIVER_PCI_HOSTMODE= | ||||
| -BCMA_DRIVER_MIPS= | ||||
| -BCMA_SFLASH= | ||||
| -BCMA_NFLASH= | ||||
| -BCMA_DRIVER_GMAC_CMN= | ||||
| -BCMA_DRIVER_GPIO= | ||||
| -BCMA_DEBUG= | ||||
|  NFC= | ||||
|  NFC_DIGITAL= | ||||
|  NFC_NCI= | ||||
| --- a/drivers/net/wireless/broadcom/b43/main.c | ||||
| +++ b/drivers/net/wireless/broadcom/b43/main.c | ||||
| @@ -2866,7 +2866,7 @@ static struct ssb_device *b43_ssb_gpio_d | ||||
|  { | ||||
|  	struct ssb_bus *bus = dev->dev->sdev->bus; | ||||
|   | ||||
| -#ifdef CPTCFG_SSB_DRIVER_PCICORE | ||||
| +#ifdef CONFIG_SSB_DRIVER_PCICORE | ||||
|  	return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev); | ||||
|  #else | ||||
|  	return bus->chipco.dev; | ||||
| @@ -4903,7 +4903,7 @@ static int b43_wireless_core_init(struct | ||||
|  	} | ||||
|  	if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW) | ||||
|  		hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */ | ||||
| -#if defined(CPTCFG_B43_SSB) && defined(CPTCFG_SSB_DRIVER_PCICORE) | ||||
| +#if defined(CPTCFG_B43_SSB) && defined(CONFIG_SSB_DRIVER_PCICORE) | ||||
|  	if (dev->dev->bus_type == B43_BUS_SSB && | ||||
|  	    dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI && | ||||
|  	    dev->dev->sdev->bus->pcicore.dev->id.revision <= 10) | ||||
| --- a/drivers/net/wireless/broadcom/b43legacy/main.c | ||||
| +++ b/drivers/net/wireless/broadcom/b43legacy/main.c | ||||
| @@ -1937,7 +1937,7 @@ static int b43legacy_gpio_init(struct b4 | ||||
|  	if (dev->dev->id.revision >= 2) | ||||
|  		mask  |= 0x0010; /* FIXME: This is redundant. */ | ||||
|   | ||||
| -#ifdef CPTCFG_SSB_DRIVER_PCICORE | ||||
| +#ifdef CONFIG_SSB_DRIVER_PCICORE | ||||
|  	pcidev = bus->pcicore.dev; | ||||
|  #endif | ||||
|  	gpiodev = bus->chipco.dev ? : pcidev; | ||||
| @@ -1956,7 +1956,7 @@ static void b43legacy_gpio_cleanup(struc | ||||
|  	struct ssb_bus *bus = dev->dev->bus; | ||||
|  	struct ssb_device *gpiodev, *pcidev = NULL; | ||||
|   | ||||
| -#ifdef CPTCFG_SSB_DRIVER_PCICORE | ||||
| +#ifdef CONFIG_SSB_DRIVER_PCICORE | ||||
|  	pcidev = bus->pcicore.dev; | ||||
|  #endif | ||||
|  	gpiodev = bus->chipco.dev ? : pcidev; | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile | ||||
| @@ -43,6 +43,6 @@ brcmsmac-y := \ | ||||
|  	brcms_trace_events.o \ | ||||
|  	debug.o | ||||
|   | ||||
| -brcmsmac-$(CPTCFG_BCMA_DRIVER_GPIO) += led.o | ||||
| +brcmsmac-$(CONFIG_BCMA_DRIVER_GPIO) += led.o | ||||
|   | ||||
|  obj-$(CPTCFG_BRCMSMAC)	+= brcmsmac.o | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h | ||||
| @@ -22,7 +22,7 @@ struct brcms_led { | ||||
|  	bool active_low; | ||||
|  }; | ||||
|   | ||||
| -#ifdef CPTCFG_BCMA_DRIVER_GPIO | ||||
| +#ifdef CONFIG_BCMA_DRIVER_GPIO | ||||
|  void brcms_led_unregister(struct brcms_info *wl); | ||||
|  int brcms_led_register(struct brcms_info *wl); | ||||
|  #else | ||||
| --- a/Kconfig.sources | ||||
| +++ b/Kconfig.sources | ||||
| @@ -9,9 +9,6 @@ source "$BACKPORT_DIR/drivers/net/wirele | ||||
|  source "$BACKPORT_DIR/drivers/net/ethernet/Kconfig" | ||||
|  source "$BACKPORT_DIR/drivers/net/usb/Kconfig" | ||||
|   | ||||
| -source "$BACKPORT_DIR/drivers/ssb/Kconfig" | ||||
| -source "$BACKPORT_DIR/drivers/bcma/Kconfig" | ||||
| - | ||||
|  source "$BACKPORT_DIR/net/nfc/Kconfig" | ||||
|   | ||||
|  source "$BACKPORT_DIR/drivers/media/Kconfig" | ||||
| --- a/Makefile.kernel | ||||
| +++ b/Makefile.kernel | ||||
| @@ -38,8 +38,6 @@ obj-$(CPTCFG_MAC80211) += net/mac80211/ | ||||
|  obj-$(CPTCFG_WLAN) += drivers/net/wireless/ | ||||
|  obj-$(CPTCFG_BT) += net/bluetooth/ | ||||
|  obj-$(CPTCFG_BT) += drivers/bluetooth/ | ||||
| -obj-$(CPTCFG_SSB) += drivers/ssb/ | ||||
| -obj-$(CPTCFG_BCMA) += drivers/bcma/ | ||||
|  obj-$(CPTCFG_ETHERNET) += drivers/net/ethernet/ | ||||
|  obj-$(CPTCFG_USB_NET_RNDIS_WLAN) += drivers/net/usb/ | ||||
|  obj-$(CPTCFG_NFC) += net/nfc/ | ||||
| @@ -1,9 +0,0 @@ | ||||
| --- a/drivers/net/wireless/ath/Kconfig | ||||
| +++ b/drivers/net/wireless/ath/Kconfig | ||||
| @@ -1,5 +1,5 @@ | ||||
|  config ATH_COMMON | ||||
| -	tristate | ||||
| +	tristate "ath.ko" | ||||
|  	depends on m | ||||
|   | ||||
|  config WLAN_VENDOR_ATH | ||||
| @@ -1,20 +0,0 @@ | ||||
| --- a/compat/compat-3.6.c | ||||
| +++ b/compat/compat-3.6.c | ||||
| @@ -147,17 +147,3 @@ int sg_alloc_table_from_pages(struct sg_ | ||||
|  	return 0; | ||||
|  } | ||||
|  EXPORT_SYMBOL_GPL(sg_alloc_table_from_pages); | ||||
| - | ||||
| -/* whoopsie ! */ | ||||
| -#ifndef CONFIG_COMMON_CLK | ||||
| -int clk_enable(struct clk *clk) | ||||
| -{ | ||||
| -	return 0; | ||||
| -} | ||||
| -EXPORT_SYMBOL_GPL(clk_enable); | ||||
| - | ||||
| -void clk_disable(struct clk *clk) | ||||
| -{ | ||||
| -} | ||||
| -EXPORT_SYMBOL_GPL(clk_disable); | ||||
| -#endif | ||||
| @@ -1,376 +0,0 @@ | ||||
| --- a/net/mac80211/Kconfig | ||||
| +++ b/net/mac80211/Kconfig | ||||
| @@ -5,8 +5,6 @@ config MAC80211 | ||||
|  	depends on CRYPTO | ||||
|  	depends on CRYPTO_ARC4 | ||||
|  	depends on CRYPTO_AES | ||||
| -	select BPAUTO_CRYPTO_CCM | ||||
| -	depends on CRYPTO_GCM | ||||
|  	depends on CRC32 | ||||
|  	---help--- | ||||
|  	  This option enables the hardware independent IEEE 802.11 | ||||
| --- a/net/mac80211/Makefile | ||||
| +++ b/net/mac80211/Makefile | ||||
| @@ -16,9 +16,7 @@ mac80211-y := \ | ||||
|  	michael.o \ | ||||
|  	tkip.o \ | ||||
|  	aes_ccm.o \ | ||||
| -	aes_gcm.o \ | ||||
|  	aes_cmac.o \ | ||||
| -	aes_gmac.o \ | ||||
|  	cfg.o \ | ||||
|  	ethtool.o \ | ||||
|  	rx.o \ | ||||
| --- a/net/mac80211/aes_ccm.c | ||||
| +++ b/net/mac80211/aes_ccm.c | ||||
| @@ -13,89 +13,132 @@ | ||||
|  #include <linux/types.h> | ||||
|  #include <linux/err.h> | ||||
|  #include <crypto/aead.h> | ||||
| +#include <crypto/aes.h> | ||||
|   | ||||
|  #include <net/mac80211.h> | ||||
|  #include "key.h" | ||||
|  #include "aes_ccm.h" | ||||
|   | ||||
| -void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, | ||||
| -			       u8 *data, size_t data_len, u8 *mic, | ||||
| -			       size_t mic_len) | ||||
| +static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, u8 *s_0, | ||||
| +			    u8 *a, u8 *b) | ||||
|  { | ||||
| -	struct scatterlist sg[3]; | ||||
| +	int i; | ||||
| + | ||||
| +	crypto_cipher_encrypt_one(tfm, b, b_0); | ||||
| + | ||||
| +	/* Extra Authenticate-only data (always two AES blocks) */ | ||||
| +	for (i = 0; i < AES_BLOCK_SIZE; i++) | ||||
| +		aad[i] ^= b[i]; | ||||
| +	crypto_cipher_encrypt_one(tfm, b, aad); | ||||
| + | ||||
| +	aad += AES_BLOCK_SIZE; | ||||
| + | ||||
| +	for (i = 0; i < AES_BLOCK_SIZE; i++) | ||||
| +		aad[i] ^= b[i]; | ||||
| +	crypto_cipher_encrypt_one(tfm, a, aad); | ||||
|   | ||||
| -	char aead_req_data[sizeof(struct aead_request) + | ||||
| -			   crypto_aead_reqsize(tfm)] | ||||
| -		__aligned(__alignof__(struct aead_request)); | ||||
| -	struct aead_request *aead_req = (void *) aead_req_data; | ||||
| +	/* Mask out bits from auth-only-b_0 */ | ||||
| +	b_0[0] &= 0x07; | ||||
|   | ||||
| -	memset(aead_req, 0, sizeof(aead_req_data)); | ||||
| +	/* S_0 is used to encrypt T (= MIC) */ | ||||
| +	b_0[14] = 0; | ||||
| +	b_0[15] = 0; | ||||
| +	crypto_cipher_encrypt_one(tfm, s_0, b_0); | ||||
| +} | ||||
|   | ||||
| -	sg_init_table(sg, 3); | ||||
| -	sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad)); | ||||
| -	sg_set_buf(&sg[1], data, data_len); | ||||
| -	sg_set_buf(&sg[2], mic, mic_len); | ||||
|   | ||||
| -	aead_request_set_tfm(aead_req, tfm); | ||||
| -	aead_request_set_crypt(aead_req, sg, sg, data_len, b_0); | ||||
| -	aead_request_set_ad(aead_req, sg[0].length); | ||||
| +void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, | ||||
| +			       u8 *data, size_t data_len, u8 *mic, | ||||
| +			       size_t mic_len) | ||||
| +{ | ||||
| +	int i, j, last_len, num_blocks; | ||||
| +	u8 b[AES_BLOCK_SIZE]; | ||||
| +	u8 s_0[AES_BLOCK_SIZE]; | ||||
| +	u8 e[AES_BLOCK_SIZE]; | ||||
| +	u8 *pos, *cpos; | ||||
| + | ||||
| +	num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE); | ||||
| +	last_len = data_len % AES_BLOCK_SIZE; | ||||
| +	aes_ccm_prepare(tfm, b_0, aad, s_0, b, b); | ||||
| + | ||||
| +	/* Process payload blocks */ | ||||
| +	pos = data; | ||||
| +	cpos = data; | ||||
| +	for (j = 1; j <= num_blocks; j++) { | ||||
| +		int blen = (j == num_blocks && last_len) ? | ||||
| +			last_len : AES_BLOCK_SIZE; | ||||
| + | ||||
| +		/* Authentication followed by encryption */ | ||||
| +		for (i = 0; i < blen; i++) | ||||
| +			b[i] ^= pos[i]; | ||||
| +		crypto_cipher_encrypt_one(tfm, b, b); | ||||
| + | ||||
| +		b_0[14] = (j >> 8) & 0xff; | ||||
| +		b_0[15] = j & 0xff; | ||||
| +		crypto_cipher_encrypt_one(tfm, e, b_0); | ||||
| +		for (i = 0; i < blen; i++) | ||||
| +			*cpos++ = *pos++ ^ e[i]; | ||||
| +	} | ||||
|   | ||||
| -	crypto_aead_encrypt(aead_req); | ||||
| +	for (i = 0; i < mic_len; i++) | ||||
| +		mic[i] = b[i] ^ s_0[i]; | ||||
|  } | ||||
|   | ||||
| -int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, | ||||
| +int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, | ||||
|  			      u8 *data, size_t data_len, u8 *mic, | ||||
|  			      size_t mic_len) | ||||
|  { | ||||
| -	struct scatterlist sg[3]; | ||||
| -	char aead_req_data[sizeof(struct aead_request) + | ||||
| -			   crypto_aead_reqsize(tfm)] | ||||
| -		__aligned(__alignof__(struct aead_request)); | ||||
| -	struct aead_request *aead_req = (void *) aead_req_data; | ||||
| - | ||||
| -	if (data_len == 0) | ||||
| -		return -EINVAL; | ||||
| - | ||||
| -	memset(aead_req, 0, sizeof(aead_req_data)); | ||||
| - | ||||
| -	sg_init_table(sg, 3); | ||||
| -	sg_set_buf(&sg[0], &aad[2], be16_to_cpup((__be16 *)aad)); | ||||
| -	sg_set_buf(&sg[1], data, data_len); | ||||
| -	sg_set_buf(&sg[2], mic, mic_len); | ||||
| - | ||||
| -	aead_request_set_tfm(aead_req, tfm); | ||||
| -	aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0); | ||||
| -	aead_request_set_ad(aead_req, sg[0].length); | ||||
| +	int i, j, last_len, num_blocks; | ||||
| +	u8 *pos, *cpos; | ||||
| +	u8 a[AES_BLOCK_SIZE]; | ||||
| +	u8 b[AES_BLOCK_SIZE]; | ||||
| +	u8 s_0[AES_BLOCK_SIZE]; | ||||
| + | ||||
| +	num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE); | ||||
| +	last_len = data_len % AES_BLOCK_SIZE; | ||||
| +	aes_ccm_prepare(tfm, b_0, aad, s_0, a, b); | ||||
| + | ||||
| +	/* Process payload blocks */ | ||||
| +	cpos = data; | ||||
| +	pos = data; | ||||
| +	for (j = 1; j <= num_blocks; j++) { | ||||
| +		int blen = (j == num_blocks && last_len) ? | ||||
| +			last_len : AES_BLOCK_SIZE; | ||||
| + | ||||
| +		/* Decryption followed by authentication */ | ||||
| +		b_0[14] = (j >> 8) & 0xff; | ||||
| +		b_0[15] = j & 0xff; | ||||
| +		crypto_cipher_encrypt_one(tfm, b, b_0); | ||||
| +		for (i = 0; i < blen; i++) { | ||||
| +			*pos = *cpos++ ^ b[i]; | ||||
| +			a[i] ^= *pos++; | ||||
| +		} | ||||
| +		crypto_cipher_encrypt_one(tfm, a, a); | ||||
| +	} | ||||
| + | ||||
| +	for (i = 0; i < mic_len; i++) { | ||||
| +		if ((mic[i] ^ s_0[i]) != a[i]) | ||||
| +			return -1; | ||||
| +	} | ||||
|   | ||||
| -	return crypto_aead_decrypt(aead_req); | ||||
| +	return 0; | ||||
|  } | ||||
|   | ||||
| -struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[], | ||||
| -						    size_t key_len, | ||||
| -						    size_t mic_len) | ||||
| +struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[], | ||||
| +						      size_t key_len, | ||||
| +						      size_t mic_len) | ||||
|  { | ||||
| -	struct crypto_aead *tfm; | ||||
| -	int err; | ||||
| +	struct crypto_cipher *tfm; | ||||
|   | ||||
| -	tfm = crypto_alloc_aead("ccm(aes)", 0, CRYPTO_ALG_ASYNC); | ||||
| -	if (IS_ERR(tfm)) | ||||
| -		return tfm; | ||||
| - | ||||
| -	err = crypto_aead_setkey(tfm, key, key_len); | ||||
| -	if (err) | ||||
| -		goto free_aead; | ||||
| -	err = crypto_aead_setauthsize(tfm, mic_len); | ||||
| -	if (err) | ||||
| -		goto free_aead; | ||||
| +	tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); | ||||
| +	if (!IS_ERR(tfm)) | ||||
| +		crypto_cipher_setkey(tfm, key, key_len); | ||||
|   | ||||
|  	return tfm; | ||||
| - | ||||
| -free_aead: | ||||
| -	crypto_free_aead(tfm); | ||||
| -	return ERR_PTR(err); | ||||
|  } | ||||
|   | ||||
| -void ieee80211_aes_key_free(struct crypto_aead *tfm) | ||||
| + | ||||
| +void ieee80211_aes_key_free(struct crypto_cipher *tfm) | ||||
|  { | ||||
| -	crypto_free_aead(tfm); | ||||
| +	crypto_free_cipher(tfm); | ||||
|  } | ||||
| --- a/net/mac80211/aes_ccm.h | ||||
| +++ b/net/mac80211/aes_ccm.h | ||||
| @@ -12,15 +12,15 @@ | ||||
|   | ||||
|  #include <linux/crypto.h> | ||||
|   | ||||
| -struct crypto_aead *ieee80211_aes_key_setup_encrypt(const u8 key[], | ||||
| -						    size_t key_len, | ||||
| -						    size_t mic_len); | ||||
| -void ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, | ||||
| +struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[], | ||||
| +						      size_t key_len, | ||||
| +						      size_t mic_len); | ||||
| +void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, | ||||
|  			       u8 *data, size_t data_len, u8 *mic, | ||||
|  			       size_t mic_len); | ||||
| -int ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, | ||||
| +int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, | ||||
|  			      u8 *data, size_t data_len, u8 *mic, | ||||
|  			      size_t mic_len); | ||||
| -void ieee80211_aes_key_free(struct crypto_aead *tfm); | ||||
| +void ieee80211_aes_key_free(struct crypto_cipher *tfm); | ||||
|   | ||||
|  #endif /* AES_CCM_H */ | ||||
| --- a/net/mac80211/aes_gcm.h | ||||
| +++ b/net/mac80211/aes_gcm.h | ||||
| @@ -11,12 +11,28 @@ | ||||
|   | ||||
|  #include <linux/crypto.h> | ||||
|   | ||||
| -void ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, | ||||
| -			       u8 *data, size_t data_len, u8 *mic); | ||||
| -int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, | ||||
| -			      u8 *data, size_t data_len, u8 *mic); | ||||
| -struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], | ||||
| -							size_t key_len); | ||||
| -void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm); | ||||
| +static inline void | ||||
| +ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, | ||||
| +			  u8 *data, size_t data_len, u8 *mic) | ||||
| +{ | ||||
| +} | ||||
| + | ||||
| +static inline int | ||||
| +ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, | ||||
| +			  u8 *data, size_t data_len, u8 *mic) | ||||
| +{ | ||||
| +    return -EOPNOTSUPP; | ||||
| +} | ||||
| + | ||||
| +static inline struct crypto_aead * | ||||
| +ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], size_t key_len) | ||||
| +{ | ||||
| +    return NULL; | ||||
| +} | ||||
| + | ||||
| +static inline void | ||||
| +ieee80211_aes_gcm_key_free(struct crypto_aead *tfm) | ||||
| +{ | ||||
| +} | ||||
|   | ||||
|  #endif /* AES_GCM_H */ | ||||
| --- a/net/mac80211/aes_gmac.h | ||||
| +++ b/net/mac80211/aes_gmac.h | ||||
| @@ -11,10 +11,22 @@ | ||||
|   | ||||
|  #include <linux/crypto.h> | ||||
|   | ||||
| -struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[], | ||||
| -						 size_t key_len); | ||||
| -int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce, | ||||
| -		       const u8 *data, size_t data_len, u8 *mic); | ||||
| -void ieee80211_aes_gmac_key_free(struct crypto_aead *tfm); | ||||
| +static inline struct crypto_aead * | ||||
| +ieee80211_aes_gmac_key_setup(const u8 key[], size_t key_len) | ||||
| +{ | ||||
| +	return NULL; | ||||
| +} | ||||
| + | ||||
| +static inline int | ||||
| +ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce, | ||||
| +		   const u8 *data, size_t data_len, u8 *mic) | ||||
| +{ | ||||
| +	return -EOPNOTSUPP; | ||||
| +} | ||||
| + | ||||
| +static inline void | ||||
| +ieee80211_aes_gmac_key_free(struct crypto_aead *tfm) | ||||
| +{ | ||||
| +} | ||||
|   | ||||
|  #endif /* AES_GMAC_H */ | ||||
| --- a/net/mac80211/key.h | ||||
| +++ b/net/mac80211/key.h | ||||
| @@ -84,7 +84,7 @@ struct ieee80211_key { | ||||
|  			 * Management frames. | ||||
|  			 */ | ||||
|  			u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN]; | ||||
| -			struct crypto_aead *tfm; | ||||
| +			struct crypto_cipher *tfm; | ||||
|  			u32 replays; /* dot11RSNAStatsCCMPReplays */ | ||||
|  		} ccmp; | ||||
|  		struct { | ||||
| --- a/net/mac80211/wpa.c | ||||
| +++ b/net/mac80211/wpa.c | ||||
| @@ -307,7 +307,8 @@ ieee80211_crypto_tkip_decrypt(struct iee | ||||
|  } | ||||
|   | ||||
|   | ||||
| -static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad) | ||||
| +static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad, | ||||
| +				u16 data_len) | ||||
|  { | ||||
|  	__le16 mask_fc; | ||||
|  	int a4_included, mgmt; | ||||
| @@ -337,14 +338,8 @@ static void ccmp_special_blocks(struct s | ||||
|  	else | ||||
|  		qos_tid = 0; | ||||
|   | ||||
| -	/* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC | ||||
| -	 * mode authentication are not allowed to collide, yet both are derived | ||||
| -	 * from this vector b_0. We only set L := 1 here to indicate that the | ||||
| -	 * data size can be represented in (L+1) bytes. The CCM layer will take | ||||
| -	 * care of storing the data length in the top (L+1) bytes and setting | ||||
| -	 * and clearing the other bits as is required to derive the two IVs. | ||||
| -	 */ | ||||
| -	b_0[0] = 0x1; | ||||
| +	/* First block, b_0 */ | ||||
| +	b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */ | ||||
|   | ||||
|  	/* Nonce: Nonce Flags | A2 | PN | ||||
|  	 * Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7) | ||||
| @@ -352,6 +347,8 @@ static void ccmp_special_blocks(struct s | ||||
|  	b_0[1] = qos_tid | (mgmt << 4); | ||||
|  	memcpy(&b_0[2], hdr->addr2, ETH_ALEN); | ||||
|  	memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN); | ||||
| +	/* l(m) */ | ||||
| +	put_unaligned_be16(data_len, &b_0[14]); | ||||
|   | ||||
|  	/* AAD (extra authenticate-only data) / masked 802.11 header | ||||
|  	 * FC | A1 | A2 | A3 | SC | [A4] | [QC] */ | ||||
| @@ -463,7 +460,7 @@ static int ccmp_encrypt_skb(struct ieee8 | ||||
|  		return 0; | ||||
|   | ||||
|  	pos += IEEE80211_CCMP_HDR_LEN; | ||||
| -	ccmp_special_blocks(skb, pn, b_0, aad); | ||||
| +	ccmp_special_blocks(skb, pn, b_0, aad, len); | ||||
|  	ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len, | ||||
|  				  skb_put(skb, mic_len), mic_len); | ||||
|   | ||||
| @@ -534,7 +531,7 @@ ieee80211_crypto_ccmp_decrypt(struct iee | ||||
|  			u8 aad[2 * AES_BLOCK_SIZE]; | ||||
|  			u8 b_0[AES_BLOCK_SIZE]; | ||||
|  			/* hardware didn't decrypt/verify MIC */ | ||||
| -			ccmp_special_blocks(skb, pn, b_0, aad); | ||||
| +			ccmp_special_blocks(skb, pn, b_0, aad, data_len); | ||||
|   | ||||
|  			if (ieee80211_aes_ccm_decrypt( | ||||
|  				    key->u.ccmp.tfm, b_0, aad, | ||||
| @@ -1,12 +0,0 @@ | ||||
| Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnects | ||||
|  | ||||
| --- a/net/mac80211/cfg.c | ||||
| +++ b/net/mac80211/cfg.c | ||||
| @@ -846,7 +846,6 @@ static int ieee80211_stop_ap(struct wiph | ||||
|  	sdata->u.ap.driver_smps_mode = IEEE80211_SMPS_OFF; | ||||
|   | ||||
|  	__sta_info_flush(sdata, true); | ||||
| -	ieee80211_free_keys(sdata, true); | ||||
|   | ||||
|  	sdata->vif.bss_conf.enable_beacon = false; | ||||
|  	sdata->vif.bss_conf.ssid_len = 0; | ||||
| @@ -1,43 +0,0 @@ | ||||
| --- a/net/wireless/sysfs.c | ||||
| +++ b/net/wireless/sysfs.c | ||||
| @@ -24,18 +24,35 @@ static inline struct cfg80211_registered | ||||
|  	return container_of(dev, struct cfg80211_registered_device, wiphy.dev); | ||||
|  } | ||||
|   | ||||
| -#define SHOW_FMT(name, fmt, member)					\ | ||||
| +#define SHOW_FMT(name, fmt, member, mode)				\ | ||||
|  static ssize_t name ## _show(struct device *dev,			\ | ||||
|  			      struct device_attribute *attr,		\ | ||||
|  			      char *buf)				\ | ||||
|  {									\ | ||||
|  	return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member);	\ | ||||
|  }									\ | ||||
| -static DEVICE_ATTR_RO(name) | ||||
| +static DEVICE_ATTR_##mode(name) | ||||
|   | ||||
| -SHOW_FMT(index, "%d", wiphy_idx); | ||||
| -SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); | ||||
| -SHOW_FMT(address_mask, "%pM", wiphy.addr_mask); | ||||
| +static ssize_t macaddress_store(struct device *dev, | ||||
| +				struct device_attribute *attr, | ||||
| +				const char *buf, size_t len) | ||||
| +{ | ||||
| +	u8 mac[ETH_ALEN]; | ||||
| + | ||||
| +	if (!mac_pton(buf, mac)) | ||||
| +		return -EINVAL; | ||||
| + | ||||
| +	if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n') | ||||
| +		return -EINVAL; | ||||
| + | ||||
| +	memcpy(dev_to_rdev(dev)->wiphy.perm_addr, mac, ETH_ALEN); | ||||
| + | ||||
| +	return strnlen(buf, len); | ||||
| +} | ||||
| + | ||||
| +SHOW_FMT(index, "%d", wiphy_idx, RO); | ||||
| +SHOW_FMT(macaddress, "%pM", wiphy.perm_addr, RW); | ||||
| +SHOW_FMT(address_mask, "%pM", wiphy.addr_mask, RO); | ||||
|   | ||||
|  static ssize_t name_show(struct device *dev, | ||||
|  			 struct device_attribute *attr, | ||||
| @@ -1,67 +0,0 @@ | ||||
| --- a/net/mac80211/main.c | ||||
| +++ b/net/mac80211/main.c | ||||
| @@ -291,7 +291,7 @@ void ieee80211_restart_hw(struct ieee802 | ||||
|  } | ||||
|  EXPORT_SYMBOL(ieee80211_restart_hw); | ||||
|   | ||||
| -#ifdef CONFIG_INET | ||||
| +#ifdef __disabled__CONFIG_INET | ||||
|  static int ieee80211_ifa_changed(struct notifier_block *nb, | ||||
|  				 unsigned long data, void *arg) | ||||
|  { | ||||
| @@ -350,7 +350,7 @@ static int ieee80211_ifa_changed(struct | ||||
|  } | ||||
|  #endif | ||||
|   | ||||
| -#if IS_ENABLED(CONFIG_IPV6) | ||||
| +#if IS_ENABLED(__disabled__CONFIG_IPV6) | ||||
|  static int ieee80211_ifa6_changed(struct notifier_block *nb, | ||||
|  				  unsigned long data, void *arg) | ||||
|  { | ||||
| @@ -1087,14 +1087,14 @@ int ieee80211_register_hw(struct ieee802 | ||||
|   | ||||
|  	rtnl_unlock(); | ||||
|   | ||||
| -#ifdef CONFIG_INET | ||||
| +#ifdef __disabled__CONFIG_INET | ||||
|  	local->ifa_notifier.notifier_call = ieee80211_ifa_changed; | ||||
|  	result = register_inetaddr_notifier(&local->ifa_notifier); | ||||
|  	if (result) | ||||
|  		goto fail_ifa; | ||||
|  #endif | ||||
|   | ||||
| -#if IS_ENABLED(CONFIG_IPV6) | ||||
| +#if IS_ENABLED(__disabled__CONFIG_IPV6) | ||||
|  	local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed; | ||||
|  	result = register_inet6addr_notifier(&local->ifa6_notifier); | ||||
|  	if (result) | ||||
| @@ -1103,13 +1103,13 @@ int ieee80211_register_hw(struct ieee802 | ||||
|   | ||||
|  	return 0; | ||||
|   | ||||
| -#if IS_ENABLED(CONFIG_IPV6) | ||||
| +#if IS_ENABLED(__disabled__CONFIG_IPV6) | ||||
|   fail_ifa6: | ||||
| -#ifdef CONFIG_INET | ||||
| +#ifdef __disabled__CONFIG_INET | ||||
|  	unregister_inetaddr_notifier(&local->ifa_notifier); | ||||
|  #endif | ||||
|  #endif | ||||
| -#if defined(CONFIG_INET) || defined(CONFIG_IPV6) | ||||
| +#if defined(__disabled__CONFIG_INET) || defined(__disabled__CONFIG_IPV6) | ||||
|   fail_ifa: | ||||
|  #endif | ||||
|  	rtnl_lock(); | ||||
| @@ -1137,10 +1137,10 @@ void ieee80211_unregister_hw(struct ieee | ||||
|  	tasklet_kill(&local->tx_pending_tasklet); | ||||
|  	tasklet_kill(&local->tasklet); | ||||
|   | ||||
| -#ifdef CONFIG_INET | ||||
| +#ifdef __disabled__CONFIG_INET | ||||
|  	unregister_inetaddr_notifier(&local->ifa_notifier); | ||||
|  #endif | ||||
| -#if IS_ENABLED(CONFIG_IPV6) | ||||
| +#if IS_ENABLED(__disabled__CONFIG_IPV6) | ||||
|  	unregister_inet6addr_notifier(&local->ifa6_notifier); | ||||
|  #endif | ||||
|   | ||||
| @@ -1,38 +0,0 @@ | ||||
| --- a/drivers/net/wireless/ath/ath5k/initvals.c | ||||
| +++ b/drivers/net/wireless/ath/ath5k/initvals.c | ||||
| @@ -62,8 +62,14 @@ static const struct ath5k_ini ar5210_ini | ||||
|  	{ AR5K_IMR,		0 }, | ||||
|  	{ AR5K_IER,		AR5K_IER_DISABLE }, | ||||
|  	{ AR5K_BSR,		0, AR5K_INI_READ }, | ||||
| +#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79) | ||||
|  	{ AR5K_TXCFG,		AR5K_DMASIZE_128B }, | ||||
|  	{ AR5K_RXCFG,		AR5K_DMASIZE_128B }, | ||||
| +#else | ||||
| +	/* WAR for AR71xx PCI bug */ | ||||
| +	{ AR5K_TXCFG,		AR5K_DMASIZE_128B }, | ||||
| +	{ AR5K_RXCFG,		AR5K_DMASIZE_4B }, | ||||
| +#endif | ||||
|  	{ AR5K_CFG,		AR5K_INIT_CFG }, | ||||
|  	{ AR5K_TOPS,		8 }, | ||||
|  	{ AR5K_RXNOFRM,		8 }, | ||||
| --- a/drivers/net/wireless/ath/ath5k/dma.c | ||||
| +++ b/drivers/net/wireless/ath/ath5k/dma.c | ||||
| @@ -869,10 +869,18 @@ ath5k_hw_dma_init(struct ath5k_hw *ah) | ||||
|  	 * guess we can tweak it and see how it goes ;-) | ||||
|  	 */ | ||||
|  	if (ah->ah_version != AR5K_AR5210) { | ||||
| +#if !defined(CONFIG_ATHEROS_AR71XX) && !defined(CONFIG_ATH79) | ||||
|  		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, | ||||
|  			AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B); | ||||
|  		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, | ||||
|  			AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B); | ||||
| +#else | ||||
| +		/* WAR for AR71xx PCI bug */ | ||||
| +		AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG, | ||||
| +			AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B); | ||||
| +		AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG, | ||||
| +			AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_4B); | ||||
| +#endif | ||||
|  	} | ||||
|   | ||||
|  	/* Pre-enable interrupts on 5211/5212*/ | ||||
| @@ -1,11 +0,0 @@ | ||||
| --- a/net/mac80211/cfg.c | ||||
| +++ b/net/mac80211/cfg.c | ||||
| @@ -1999,7 +1999,7 @@ static int ieee80211_scan(struct wiphy * | ||||
|  		 * the  frames sent while scanning on other channel will be | ||||
|  		 * lost) | ||||
|  		 */ | ||||
| -		if (sdata->u.ap.beacon && | ||||
| +		if (0 && sdata->u.ap.beacon && | ||||
|  		    (!(wiphy->features & NL80211_FEATURE_AP_SCAN) || | ||||
|  		     !(req->flags & NL80211_SCAN_FLAG_AP))) | ||||
|  			return -EOPNOTSUPP; | ||||
| @@ -1,31 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Sun, 7 Jun 2015 13:53:35 +0200 | ||||
| Subject: [PATCH] ath9k: force rx_clear when disabling rx | ||||
|  | ||||
| This makes stopping Rx more reliable and should reduce the frequency of | ||||
| Rx related DMA stop warnings | ||||
|  | ||||
| Cc: stable@vger.kernel.org | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/ath/ath9k/mac.c | ||||
| +++ b/drivers/net/wireless/ath/ath9k/mac.c | ||||
| @@ -677,13 +677,15 @@ void ath9k_hw_startpcureceive(struct ath | ||||
|   | ||||
|  	ath9k_ani_reset(ah, is_scanning); | ||||
|   | ||||
| -	REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); | ||||
| +	REG_CLR_BIT(ah, AR_DIAG_SW, | ||||
| +		    AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR); | ||||
|  } | ||||
|  EXPORT_SYMBOL(ath9k_hw_startpcureceive); | ||||
|   | ||||
|  void ath9k_hw_abortpcurecv(struct ath_hw *ah) | ||||
|  { | ||||
| -	REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_ABORT | AR_DIAG_RX_DIS); | ||||
| +	REG_SET_BIT(ah, AR_DIAG_SW, | ||||
| +		    AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT | AR_DIAG_FORCE_RX_CLEAR); | ||||
|   | ||||
|  	ath9k_hw_disable_mib_counters(ah); | ||||
|  } | ||||
| @@ -1,121 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Thu, 2 Jul 2015 15:20:56 +0200 | ||||
| Subject: [PATCH] ath9k: limit retries for powersave response frames | ||||
|  | ||||
| In some cases, the channel might be busy enough that an ath9k AP's | ||||
| response to PS-Poll frames might be too slow and the station has already | ||||
| gone to sleep. To avoid wasting too much airtime on this, limit the | ||||
| number of retries on such frames and ensure that no sample rate gets | ||||
| used. | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/ath/ath9k/xmit.c | ||||
| +++ b/drivers/net/wireless/ath/ath9k/xmit.c | ||||
| @@ -136,10 +136,25 @@ static void ath_send_bar(struct ath_atx_ | ||||
|  } | ||||
|   | ||||
|  static void ath_set_rates(struct ieee80211_vif *vif, struct ieee80211_sta *sta, | ||||
| -			  struct ath_buf *bf) | ||||
| +			  struct ath_buf *bf, bool ps) | ||||
|  { | ||||
| +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(bf->bf_mpdu); | ||||
| + | ||||
| +	if (ps) { | ||||
| +		/* Clear the first rate to avoid using a sample rate for PS frames */ | ||||
| +		info->control.rates[0].idx = -1; | ||||
| +		info->control.rates[0].count = 0; | ||||
| +	} | ||||
| + | ||||
|  	ieee80211_get_tx_rates(vif, sta, bf->bf_mpdu, bf->rates, | ||||
|  			       ARRAY_SIZE(bf->rates)); | ||||
| +	if (!ps) | ||||
| +		return; | ||||
| + | ||||
| +	if (bf->rates[0].count > 2) | ||||
| +		bf->rates[0].count = 2; | ||||
| + | ||||
| +	bf->rates[1].idx = -1; | ||||
|  } | ||||
|   | ||||
|  static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, | ||||
| @@ -1419,7 +1434,7 @@ ath_tx_form_burst(struct ath_softc *sc, | ||||
|  		if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) | ||||
|  			break; | ||||
|   | ||||
| -		ath_set_rates(tid->an->vif, tid->an->sta, bf); | ||||
| +		ath_set_rates(tid->an->vif, tid->an->sta, bf, false); | ||||
|  	} while (1); | ||||
|  } | ||||
|   | ||||
| @@ -1450,7 +1465,7 @@ static bool ath_tx_sched_aggr(struct ath | ||||
|  		return false; | ||||
|  	} | ||||
|   | ||||
| -	ath_set_rates(tid->an->vif, tid->an->sta, bf); | ||||
| +	ath_set_rates(tid->an->vif, tid->an->sta, bf, false); | ||||
|  	if (aggr) | ||||
|  		last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf, | ||||
|  					tid_q, &aggr_len); | ||||
| @@ -1647,7 +1662,7 @@ void ath9k_release_buffered_frames(struc | ||||
|   | ||||
|  			__skb_unlink(bf->bf_mpdu, tid_q); | ||||
|  			list_add_tail(&bf->list, &bf_q); | ||||
| -			ath_set_rates(tid->an->vif, tid->an->sta, bf); | ||||
| +			ath_set_rates(tid->an->vif, tid->an->sta, bf, true); | ||||
|  			if (bf_isampdu(bf)) { | ||||
|  				ath_tx_addto_baw(sc, tid, bf); | ||||
|  				bf->bf_state.bf_type &= ~BUF_AGGR; | ||||
| @@ -2293,7 +2308,7 @@ int ath_tx_start(struct ieee80211_hw *hw | ||||
|  	struct ath_txq *txq = txctl->txq; | ||||
|  	struct ath_atx_tid *tid = NULL; | ||||
|  	struct ath_buf *bf; | ||||
| -	bool queue, skip_uapsd = false, ps_resp; | ||||
| +	bool queue, ps_resp; | ||||
|  	int q, ret; | ||||
|   | ||||
|  	if (vif) | ||||
| @@ -2346,13 +2361,13 @@ int ath_tx_start(struct ieee80211_hw *hw | ||||
|  		if (!txctl->an) | ||||
|  			txctl->an = &avp->mcast_node; | ||||
|  		queue = true; | ||||
| -		skip_uapsd = true; | ||||
| +		ps_resp = false; | ||||
|  	} | ||||
|   | ||||
|  	if (txctl->an && queue) | ||||
|  		tid = ath_get_skb_tid(sc, txctl->an, skb); | ||||
|   | ||||
| -	if (!skip_uapsd && ps_resp) { | ||||
| +	if (ps_resp) { | ||||
|  		ath_txq_unlock(sc, txq); | ||||
|  		txq = sc->tx.uapsdq; | ||||
|  		ath_txq_lock(sc, txq); | ||||
| @@ -2390,7 +2405,7 @@ int ath_tx_start(struct ieee80211_hw *hw | ||||
|  	if (txctl->paprd) | ||||
|  		bf->bf_state.bfs_paprd_timestamp = jiffies; | ||||
|   | ||||
| -	ath_set_rates(vif, sta, bf); | ||||
| +	ath_set_rates(vif, sta, bf, ps_resp); | ||||
|  	ath_tx_send_normal(sc, txq, tid, skb); | ||||
|   | ||||
|  out: | ||||
| @@ -2429,7 +2444,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw | ||||
|  			break; | ||||
|   | ||||
|  		bf->bf_lastbf = bf; | ||||
| -		ath_set_rates(vif, NULL, bf); | ||||
| +		ath_set_rates(vif, NULL, bf, false); | ||||
|  		ath_buf_set_rate(sc, bf, &info, fi->framelen, false); | ||||
|  		duration += info.rates[0].PktDuration; | ||||
|  		if (bf_tail) | ||||
| @@ -2932,7 +2947,7 @@ int ath9k_tx99_send(struct ath_softc *sc | ||||
|  		return -EINVAL; | ||||
|  	} | ||||
|   | ||||
| -	ath_set_rates(sc->tx99_vif, NULL, bf); | ||||
| +	ath_set_rates(sc->tx99_vif, NULL, bf, false); | ||||
|   | ||||
|  	ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, bf->bf_daddr); | ||||
|  	ath9k_hw_tx99_start(sc->sc_ah, txctl->txq->axq_qnum); | ||||
| @@ -1,95 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Thu, 14 Jan 2016 03:14:03 +0100 | ||||
| Subject: [PATCH] ath9k_hw: add low power tx gain table for AR953x | ||||
|  | ||||
| Used in some newer TP-Link AR9533 devices. | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c | ||||
| +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c | ||||
| @@ -698,6 +698,9 @@ static void ar9003_tx_gain_table_mode2(s | ||||
|  	else if (AR_SREV_9340(ah)) | ||||
|  		INIT_INI_ARRAY(&ah->iniModesTxGain, | ||||
|  			ar9340Modes_low_ob_db_tx_gain_table_1p0); | ||||
| +	else if (AR_SREV_9531_11(ah)) | ||||
| +		INIT_INI_ARRAY(&ah->iniModesTxGain, | ||||
| +			       qca953x_1p1_modes_no_xpa_low_power_tx_gain_table); | ||||
|  	else if (AR_SREV_9485_11_OR_LATER(ah)) | ||||
|  		INIT_INI_ARRAY(&ah->iniModesTxGain, | ||||
|  			ar9485Modes_low_ob_db_tx_gain_1_1); | ||||
| --- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h | ||||
| +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h | ||||
| @@ -757,6 +757,71 @@ static const u32 qca953x_1p1_modes_xpa_t | ||||
|  	{0x00016448, 0x6c927a70}, | ||||
|  }; | ||||
|   | ||||
| +static const u32 qca953x_1p1_modes_no_xpa_low_power_tx_gain_table[][2] = { | ||||
| +	/* Addr      allmodes  */ | ||||
| +	{0x0000a2dc, 0xfff55592}, | ||||
| +	{0x0000a2e0, 0xfff99924}, | ||||
| +	{0x0000a2e4, 0xfffe1e00}, | ||||
| +	{0x0000a2e8, 0xffffe000}, | ||||
| +	{0x0000a410, 0x000050d6}, | ||||
| +	{0x0000a500, 0x00000069}, | ||||
| +	{0x0000a504, 0x0400006b}, | ||||
| +	{0x0000a508, 0x0800006d}, | ||||
| +	{0x0000a50c, 0x0c000269}, | ||||
| +	{0x0000a510, 0x1000026b}, | ||||
| +	{0x0000a514, 0x1400026d}, | ||||
| +	{0x0000a518, 0x18000669}, | ||||
| +	{0x0000a51c, 0x1c00066b}, | ||||
| +	{0x0000a520, 0x1d000a68}, | ||||
| +	{0x0000a524, 0x21000a6a}, | ||||
| +	{0x0000a528, 0x25000a6c}, | ||||
| +	{0x0000a52c, 0x29000a6e}, | ||||
| +	{0x0000a530, 0x2d0012a9}, | ||||
| +	{0x0000a534, 0x310012ab}, | ||||
| +	{0x0000a538, 0x350012ad}, | ||||
| +	{0x0000a53c, 0x39001b0a}, | ||||
| +	{0x0000a540, 0x3d001b0c}, | ||||
| +	{0x0000a544, 0x41001b0e}, | ||||
| +	{0x0000a548, 0x43001bae}, | ||||
| +	{0x0000a54c, 0x45001914}, | ||||
| +	{0x0000a550, 0x47001916}, | ||||
| +	{0x0000a554, 0x49001b96}, | ||||
| +	{0x0000a558, 0x49001b96}, | ||||
| +	{0x0000a55c, 0x49001b96}, | ||||
| +	{0x0000a560, 0x49001b96}, | ||||
| +	{0x0000a564, 0x49001b96}, | ||||
| +	{0x0000a568, 0x49001b96}, | ||||
| +	{0x0000a56c, 0x49001b96}, | ||||
| +	{0x0000a570, 0x49001b96}, | ||||
| +	{0x0000a574, 0x49001b96}, | ||||
| +	{0x0000a578, 0x49001b96}, | ||||
| +	{0x0000a57c, 0x49001b96}, | ||||
| +	{0x0000a600, 0x00000000}, | ||||
| +	{0x0000a604, 0x00000000}, | ||||
| +	{0x0000a608, 0x00000000}, | ||||
| +	{0x0000a60c, 0x00000000}, | ||||
| +	{0x0000a610, 0x00000000}, | ||||
| +	{0x0000a614, 0x00000000}, | ||||
| +	{0x0000a618, 0x00804201}, | ||||
| +	{0x0000a61c, 0x01408201}, | ||||
| +	{0x0000a620, 0x01408502}, | ||||
| +	{0x0000a624, 0x01408502}, | ||||
| +	{0x0000a628, 0x01408502}, | ||||
| +	{0x0000a62c, 0x01408502}, | ||||
| +	{0x0000a630, 0x01408502}, | ||||
| +	{0x0000a634, 0x01408502}, | ||||
| +	{0x0000a638, 0x01408502}, | ||||
| +	{0x0000a63c, 0x01408502}, | ||||
| +	{0x0000b2dc, 0xfff55592}, | ||||
| +	{0x0000b2e0, 0xfff99924}, | ||||
| +	{0x0000b2e4, 0xfffe1e00}, | ||||
| +	{0x0000b2e8, 0xffffe000}, | ||||
| +	{0x00016044, 0x044922db}, | ||||
| +	{0x00016048, 0x6c927a70}, | ||||
| +	{0x00016444, 0x044922db}, | ||||
| +	{0x00016448, 0x6c927a70}, | ||||
| +}; | ||||
| + | ||||
|  static const u32 qca953x_2p0_baseband_core[][2] = { | ||||
|  	/* Addr      allmodes  */ | ||||
|  	{0x00009800, 0xafe68e30}, | ||||
| @@ -1,156 +0,0 @@ | ||||
| From: Eli Cooper <elicooper@gmx.com> | ||||
| Date: Thu, 14 Jan 2016 00:07:12 +0800 | ||||
| Subject: [PATCH] rt2x00: fix monitor mode regression | ||||
|  | ||||
| Since commit df1404650ccbfeb76a84f301f22316be0d00a864 monitor mode for rt2x00 | ||||
| has been made effectively useless because the hardware filter is configured to | ||||
| drop packets whose intended recipient is not the device, regardless of the | ||||
| presence of monitor mode interfaces. | ||||
|  | ||||
| This patch fixes this regression by adding explicit monitor mode support, and | ||||
| configuring the hardware filter accordingly. | ||||
|  | ||||
| Signed-off-by: Eli Cooper <elicooper@gmx.com> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/ralink/rt2x00/rt2400pci.c | ||||
| +++ b/drivers/net/wireless/ralink/rt2x00/rt2400pci.c | ||||
| @@ -273,8 +273,10 @@ static void rt2400pci_config_filter(stru | ||||
|  			   !(filter_flags & FIF_PLCPFAIL)); | ||||
|  	rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, | ||||
|  			   !(filter_flags & FIF_CONTROL)); | ||||
| -	rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, 1); | ||||
| +	rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, | ||||
| +			   !rt2x00dev->is_monitoring); | ||||
|  	rt2x00_set_field32(®, RXCSR0_DROP_TODS, | ||||
| +			   !rt2x00dev->is_monitoring && | ||||
|  			   !rt2x00dev->intf_ap_count); | ||||
|  	rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); | ||||
|  	rt2x00mmio_register_write(rt2x00dev, RXCSR0, reg); | ||||
| --- a/drivers/net/wireless/ralink/rt2x00/rt2500pci.c | ||||
| +++ b/drivers/net/wireless/ralink/rt2x00/rt2500pci.c | ||||
| @@ -274,8 +274,10 @@ static void rt2500pci_config_filter(stru | ||||
|  			   !(filter_flags & FIF_PLCPFAIL)); | ||||
|  	rt2x00_set_field32(®, RXCSR0_DROP_CONTROL, | ||||
|  			   !(filter_flags & FIF_CONTROL)); | ||||
| -	rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, 1); | ||||
| +	rt2x00_set_field32(®, RXCSR0_DROP_NOT_TO_ME, | ||||
| +			   !rt2x00dev->is_monitoring); | ||||
|  	rt2x00_set_field32(®, RXCSR0_DROP_TODS, | ||||
| +			   !rt2x00dev->is_monitoring && | ||||
|  			   !rt2x00dev->intf_ap_count); | ||||
|  	rt2x00_set_field32(®, RXCSR0_DROP_VERSION_ERROR, 1); | ||||
|  	rt2x00_set_field32(®, RXCSR0_DROP_MCAST, | ||||
| --- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c | ||||
| +++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c | ||||
| @@ -437,8 +437,10 @@ static void rt2500usb_config_filter(stru | ||||
|  			   !(filter_flags & FIF_PLCPFAIL)); | ||||
|  	rt2x00_set_field16(®, TXRX_CSR2_DROP_CONTROL, | ||||
|  			   !(filter_flags & FIF_CONTROL)); | ||||
| -	rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, 1); | ||||
| +	rt2x00_set_field16(®, TXRX_CSR2_DROP_NOT_TO_ME, | ||||
| +			   !rt2x00dev->is_monitoring); | ||||
|  	rt2x00_set_field16(®, TXRX_CSR2_DROP_TODS, | ||||
| +			   !rt2x00dev->is_monitoring && | ||||
|  			   !rt2x00dev->intf_ap_count); | ||||
|  	rt2x00_set_field16(®, TXRX_CSR2_DROP_VERSION_ERROR, 1); | ||||
|  	rt2x00_set_field16(®, TXRX_CSR2_DROP_MULTICAST, | ||||
| --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c | ||||
| +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c | ||||
| @@ -1490,7 +1490,8 @@ void rt2800_config_filter(struct rt2x00_ | ||||
|  			   !(filter_flags & FIF_FCSFAIL)); | ||||
|  	rt2x00_set_field32(®, RX_FILTER_CFG_DROP_PHY_ERROR, | ||||
|  			   !(filter_flags & FIF_PLCPFAIL)); | ||||
| -	rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, 1); | ||||
| +	rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_TO_ME, | ||||
| +			   !rt2x00dev->is_monitoring); | ||||
|  	rt2x00_set_field32(®, RX_FILTER_CFG_DROP_NOT_MY_BSSD, 0); | ||||
|  	rt2x00_set_field32(®, RX_FILTER_CFG_DROP_VER_ERROR, 1); | ||||
|  	rt2x00_set_field32(®, RX_FILTER_CFG_DROP_MULTICAST, | ||||
| --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h | ||||
| +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h | ||||
| @@ -844,11 +844,13 @@ struct rt2x00_dev { | ||||
|  	 *  - Open sta interface count. | ||||
|  	 *  - Association count. | ||||
|  	 *  - Beaconing enabled count. | ||||
| +	 *  - Whether the device is monitoring. | ||||
|  	 */ | ||||
|  	unsigned int intf_ap_count; | ||||
|  	unsigned int intf_sta_count; | ||||
|  	unsigned int intf_associated; | ||||
|  	unsigned int intf_beaconing; | ||||
| +	bool is_monitoring; | ||||
|   | ||||
|  	/* | ||||
|  	 * Interface combinations | ||||
| --- a/drivers/net/wireless/ralink/rt2x00/rt2x00config.c | ||||
| +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00config.c | ||||
| @@ -244,6 +244,16 @@ void rt2x00lib_config(struct rt2x00_dev | ||||
|  	    (ieee80211_flags & IEEE80211_CONF_CHANGE_PS)) | ||||
|  		cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); | ||||
|   | ||||
| +	if (ieee80211_flags & IEEE80211_CONF_CHANGE_MONITOR) { | ||||
| +		if (conf->flags & IEEE80211_CONF_MONITOR) { | ||||
| +			rt2x00_dbg(rt2x00dev, "Monitor mode is enabled\n"); | ||||
| +			rt2x00dev->is_monitoring = true; | ||||
| +		} else { | ||||
| +			rt2x00_dbg(rt2x00dev, "Monitor mode is disabled\n"); | ||||
| +			rt2x00dev->is_monitoring = false; | ||||
| +		} | ||||
| +	} | ||||
| + | ||||
|  	/* | ||||
|  	 * Start configuration. | ||||
|  	 */ | ||||
| --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | ||||
| +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | ||||
| @@ -1204,6 +1204,7 @@ int rt2x00lib_start(struct rt2x00_dev *r | ||||
|  	rt2x00dev->intf_ap_count = 0; | ||||
|  	rt2x00dev->intf_sta_count = 0; | ||||
|  	rt2x00dev->intf_associated = 0; | ||||
| +	rt2x00dev->is_monitoring = false; | ||||
|   | ||||
|  	/* Enable the radio */ | ||||
|  	retval = rt2x00lib_enable_radio(rt2x00dev); | ||||
| --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | ||||
| +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | ||||
| @@ -385,11 +385,6 @@ void rt2x00mac_configure_filter(struct i | ||||
|  			*total_flags |= FIF_PSPOLL; | ||||
|  	} | ||||
|   | ||||
| -	/* | ||||
| -	 * Check if there is any work left for us. | ||||
| -	 */ | ||||
| -	if (rt2x00dev->packet_filter == *total_flags) | ||||
| -		return; | ||||
|  	rt2x00dev->packet_filter = *total_flags; | ||||
|   | ||||
|  	rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); | ||||
| --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c | ||||
| +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c | ||||
| @@ -530,8 +530,10 @@ static void rt61pci_config_filter(struct | ||||
|  			   !(filter_flags & FIF_PLCPFAIL)); | ||||
|  	rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, | ||||
|  			   !(filter_flags & (FIF_CONTROL | FIF_PSPOLL))); | ||||
| -	rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, 1); | ||||
| +	rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, | ||||
| +			   !rt2x00dev->is_monitoring); | ||||
|  	rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, | ||||
| +			   !rt2x00dev->is_monitoring && | ||||
|  			   !rt2x00dev->intf_ap_count); | ||||
|  	rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); | ||||
|  	rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, | ||||
| --- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c | ||||
| +++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c | ||||
| @@ -480,8 +480,10 @@ static void rt73usb_config_filter(struct | ||||
|  			   !(filter_flags & FIF_PLCPFAIL)); | ||||
|  	rt2x00_set_field32(®, TXRX_CSR0_DROP_CONTROL, | ||||
|  			   !(filter_flags & (FIF_CONTROL | FIF_PSPOLL))); | ||||
| -	rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, 1); | ||||
| +	rt2x00_set_field32(®, TXRX_CSR0_DROP_NOT_TO_ME, | ||||
| +			   !rt2x00dev->is_monitoring); | ||||
|  	rt2x00_set_field32(®, TXRX_CSR0_DROP_TO_DS, | ||||
| +			   !rt2x00dev->is_monitoring && | ||||
|  			   !rt2x00dev->intf_ap_count); | ||||
|  	rt2x00_set_field32(®, TXRX_CSR0_DROP_VERSION_ERROR, 1); | ||||
|  	rt2x00_set_field32(®, TXRX_CSR0_DROP_MULTICAST, | ||||
| @@ -1,32 +0,0 @@ | ||||
| From: Miaoqing Pan <miaoqing@codeaurora.org> | ||||
| Date: Fri, 15 Jan 2016 18:17:17 +0800 | ||||
| Subject: [PATCH] ath9k: avoid ANI restart if no trigger | ||||
|  | ||||
| Fixes commit 54da20d83f0e ("ath9k_hw: improve ANI processing and rx desensitizing parameters") | ||||
|  | ||||
| Call ath9k_ani_restart() only when the phy error rate reach the | ||||
| ANI immunity threshold. Sync the logic with internal code base. | ||||
|  | ||||
| Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/ath/ath9k/ani.c | ||||
| +++ b/drivers/net/wireless/ath/ath9k/ani.c | ||||
| @@ -444,14 +444,16 @@ void ath9k_hw_ani_monitor(struct ath_hw | ||||
|  		    ofdmPhyErrRate < ah->config.ofdm_trig_low) { | ||||
|  			ath9k_hw_ani_lower_immunity(ah); | ||||
|  			aniState->ofdmsTurn = !aniState->ofdmsTurn; | ||||
| +			ath9k_ani_restart(ah); | ||||
|  		} else if (ofdmPhyErrRate > ah->config.ofdm_trig_high) { | ||||
|  			ath9k_hw_ani_ofdm_err_trigger(ah); | ||||
|  			aniState->ofdmsTurn = false; | ||||
| +			ath9k_ani_restart(ah); | ||||
|  		} else if (cckPhyErrRate > ah->config.cck_trig_high) { | ||||
|  			ath9k_hw_ani_cck_err_trigger(ah); | ||||
|  			aniState->ofdmsTurn = true; | ||||
| +			ath9k_ani_restart(ah); | ||||
|  		} | ||||
| -		ath9k_ani_restart(ah); | ||||
|  	} | ||||
|  } | ||||
|  EXPORT_SYMBOL(ath9k_hw_ani_monitor); | ||||
| @@ -1,91 +0,0 @@ | ||||
| From: Miaoqing Pan <miaoqing@codeaurora.org> | ||||
| Date: Fri, 15 Jan 2016 18:17:18 +0800 | ||||
| Subject: [PATCH] ath9k: clean up ANI per-channel pointer checking | ||||
|  | ||||
| commit c24bd3620c50 ("ath9k: Do not maintain ANI state per-channel") | ||||
| removed per-channel handling, the code to check 'curchan' also | ||||
| should be removed as never used. | ||||
|  | ||||
| Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/ath/ath9k/ani.c | ||||
| +++ b/drivers/net/wireless/ath/ath9k/ani.c | ||||
| @@ -126,12 +126,8 @@ static void ath9k_hw_update_mibstats(str | ||||
|   | ||||
|  static void ath9k_ani_restart(struct ath_hw *ah) | ||||
|  { | ||||
| -	struct ar5416AniState *aniState; | ||||
| - | ||||
| -	if (!ah->curchan) | ||||
| -		return; | ||||
| +	struct ar5416AniState *aniState = &ah->ani; | ||||
|   | ||||
| -	aniState = &ah->ani; | ||||
|  	aniState->listenTime = 0; | ||||
|   | ||||
|  	ENABLE_REGWRITE_BUFFER(ah); | ||||
| @@ -221,12 +217,7 @@ static void ath9k_hw_set_ofdm_nil(struct | ||||
|   | ||||
|  static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) | ||||
|  { | ||||
| -	struct ar5416AniState *aniState; | ||||
| - | ||||
| -	if (!ah->curchan) | ||||
| -		return; | ||||
| - | ||||
| -	aniState = &ah->ani; | ||||
| +	struct ar5416AniState *aniState = &ah->ani; | ||||
|   | ||||
|  	if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL) | ||||
|  		ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false); | ||||
| @@ -281,12 +272,7 @@ static void ath9k_hw_set_cck_nil(struct | ||||
|   | ||||
|  static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) | ||||
|  { | ||||
| -	struct ar5416AniState *aniState; | ||||
| - | ||||
| -	if (!ah->curchan) | ||||
| -		return; | ||||
| - | ||||
| -	aniState = &ah->ani; | ||||
| +	struct ar5416AniState *aniState = &ah->ani; | ||||
|   | ||||
|  	if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL) | ||||
|  		ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1, | ||||
| @@ -299,9 +285,7 @@ static void ath9k_hw_ani_cck_err_trigger | ||||
|   */ | ||||
|  static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) | ||||
|  { | ||||
| -	struct ar5416AniState *aniState; | ||||
| - | ||||
| -	aniState = &ah->ani; | ||||
| +	struct ar5416AniState *aniState = &ah->ani; | ||||
|   | ||||
|  	/* lower OFDM noise immunity */ | ||||
|  	if (aniState->ofdmNoiseImmunityLevel > 0 && | ||||
| @@ -329,7 +313,7 @@ void ath9k_ani_reset(struct ath_hw *ah, | ||||
|  	struct ath_common *common = ath9k_hw_common(ah); | ||||
|  	int ofdm_nil, cck_nil; | ||||
|   | ||||
| -	if (!ah->curchan) | ||||
| +	if (!chan) | ||||
|  		return; | ||||
|   | ||||
|  	BUG_ON(aniState == NULL); | ||||
| @@ -416,14 +400,10 @@ static bool ath9k_hw_ani_read_counters(s | ||||
|   | ||||
|  void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) | ||||
|  { | ||||
| -	struct ar5416AniState *aniState; | ||||
| +	struct ar5416AniState *aniState = &ah->ani; | ||||
|  	struct ath_common *common = ath9k_hw_common(ah); | ||||
|  	u32 ofdmPhyErrRate, cckPhyErrRate; | ||||
|   | ||||
| -	if (!ah->curchan) | ||||
| -		return; | ||||
| - | ||||
| -	aniState = &ah->ani; | ||||
|  	if (!ath9k_hw_ani_read_counters(ah)) | ||||
|  		return; | ||||
|   | ||||
| @@ -1,31 +0,0 @@ | ||||
| From: Miaoqing Pan <miaoqing@codeaurora.org> | ||||
| Date: Fri, 15 Jan 2016 18:17:19 +0800 | ||||
| Subject: [PATCH] ath9k: do not reset while BB panic(0x4000409) on ar9561 | ||||
|  | ||||
| BB panic(0x4000409) observed while AP enabling/disabling | ||||
| bursting. | ||||
|  | ||||
| Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c | ||||
| +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c | ||||
| @@ -2071,7 +2071,8 @@ void ar9003_hw_attach_phy_ops(struct ath | ||||
|   *             to be disabled. | ||||
|   * | ||||
|   * 0x04000409: Packet stuck on receive. | ||||
| - *             Full chip reset is required for all chips except AR9340. | ||||
| + *             Full chip reset is required for all chips except | ||||
| + *	       AR9340, AR9531 and AR9561. | ||||
|   */ | ||||
|   | ||||
|  /* | ||||
| @@ -2100,7 +2101,7 @@ bool ar9003_hw_bb_watchdog_check(struct | ||||
|  	case 0x04000b09: | ||||
|  		return true; | ||||
|  	case 0x04000409: | ||||
| -		if (AR_SREV_9340(ah) || AR_SREV_9531(ah)) | ||||
| +		if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) | ||||
|  			return false; | ||||
|  		else | ||||
|  			return true; | ||||
| @@ -1,27 +0,0 @@ | ||||
| From: Miaoqing Pan <miaoqing@codeaurora.org> | ||||
| Date: Fri, 15 Jan 2016 18:17:20 +0800 | ||||
| Subject: [PATCH] ath9k: fix inconsistent use of tab and space in | ||||
|  indentation | ||||
|  | ||||
| Minor changes for indenting. | ||||
|  | ||||
| Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | ||||
| +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | ||||
| @@ -5485,11 +5485,11 @@ unsigned int ar9003_get_paprd_scale_fact | ||||
|  			  AR9300_PAPRD_SCALE_1); | ||||
|  	else { | ||||
|  		if (chan->channel >= 5700) | ||||
| -		return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20), | ||||
| -			  AR9300_PAPRD_SCALE_1); | ||||
| +			return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20), | ||||
| +				  AR9300_PAPRD_SCALE_1); | ||||
|  		else if (chan->channel >= 5400) | ||||
|  			return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40), | ||||
| -				   AR9300_PAPRD_SCALE_2); | ||||
| +				  AR9300_PAPRD_SCALE_2); | ||||
|  		else | ||||
|  			return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40), | ||||
|  				  AR9300_PAPRD_SCALE_1); | ||||
| @@ -1,65 +0,0 @@ | ||||
| From: Miaoqing Pan <miaoqing@codeaurora.org> | ||||
| Date: Fri, 15 Jan 2016 18:17:21 +0800 | ||||
| Subject: [PATCH] ath9k: fix data bus error on ar9300 and ar9580 | ||||
|  | ||||
| One crash issue be found on ar9300: RTC_RC reg read leads crash, leading | ||||
| the data bus error, due to RTC_RC reg write not happen properly. | ||||
|  | ||||
| Warm Reset trigger in continuous beacon stuck for one of the customer for | ||||
| other chip, noticed the MAC was stuck in RTC reset. After analysis noticed | ||||
| DMA did not complete when RTC was put in reset. | ||||
|  | ||||
| So, before resetting the MAC need to make sure there are no pending DMA | ||||
| transactions because this reset does not reset all parts of the chip. | ||||
|  | ||||
| The 12th and 11th bit of MAC _DMA_CFG register used to do that. | ||||
| 	12 cfg_halt_ack 0x0 | ||||
| 		0 DMA has not yet halted | ||||
| 		1 DMA has halted | ||||
| 	11 cfg_halt_req 0x0 | ||||
| 		0 DMA logic operates normally | ||||
| 		1 Request DMA logic to stop so software can reset the MAC | ||||
|  | ||||
| The Bit [12] of this register indicates when the halt has taken effect or | ||||
| not. the DMA halt IS NOT recoverable; once software sets bit [11] to | ||||
| request a DMA halt, software must wait for bit [12] to be set and reset | ||||
| the MAC. | ||||
|  | ||||
| So, the same thing we implemented for ar9580 chip. | ||||
|  | ||||
| Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/ath/ath9k/hw.c | ||||
| +++ b/drivers/net/wireless/ath/ath9k/hw.c | ||||
| @@ -1368,6 +1368,16 @@ static bool ath9k_hw_set_reset(struct at | ||||
|  	if (ath9k_hw_mci_is_enabled(ah)) | ||||
|  		ar9003_mci_check_gpm_offset(ah); | ||||
|   | ||||
| +	/* DMA HALT added to resolve ar9300 and ar9580 bus error during | ||||
| +	 * RTC_RC reg read | ||||
| +	 */ | ||||
| +	if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) { | ||||
| +		REG_SET_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); | ||||
| +		ath9k_hw_wait(ah, AR_CFG, AR_CFG_HALT_ACK, AR_CFG_HALT_ACK, | ||||
| +			      20 * AH_WAIT_TIMEOUT); | ||||
| +		REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); | ||||
| +	} | ||||
| + | ||||
|  	REG_WRITE(ah, AR_RTC_RC, rst_flags); | ||||
|   | ||||
|  	REGWRITE_BUFFER_FLUSH(ah); | ||||
| --- a/drivers/net/wireless/ath/ath9k/reg.h | ||||
| +++ b/drivers/net/wireless/ath/ath9k/reg.h | ||||
| @@ -34,8 +34,10 @@ | ||||
|  #define AR_CFG_SWRG          0x00000010 | ||||
|  #define AR_CFG_AP_ADHOC_INDICATION 0x00000020 | ||||
|  #define AR_CFG_PHOK          0x00000100 | ||||
| -#define AR_CFG_CLK_GATE_DIS  0x00000400 | ||||
|  #define AR_CFG_EEBS          0x00000200 | ||||
| +#define AR_CFG_CLK_GATE_DIS  0x00000400 | ||||
| +#define AR_CFG_HALT_REQ	     0x00000800 | ||||
| +#define AR_CFG_HALT_ACK	     0x00001000 | ||||
|  #define AR_CFG_PCI_MASTER_REQ_Q_THRESH         0x00060000 | ||||
|  #define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S       17 | ||||
|   | ||||
| @@ -1,19 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Fri, 15 Jan 2016 15:59:45 +0100 | ||||
| Subject: [PATCH] brcmfmac: add missing include | ||||
|  | ||||
| linux/module.h is required for defining module parameters | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c | ||||
| @@ -17,6 +17,7 @@ | ||||
|  #include <linux/kernel.h> | ||||
|  #include <linux/string.h> | ||||
|  #include <linux/netdevice.h> | ||||
| +#include <linux/module.h> | ||||
|  #include <brcmu_wifi.h> | ||||
|  #include <brcmu_utils.h> | ||||
|  #include "core.h" | ||||
| @@ -1,118 +0,0 @@ | ||||
| From: Hante Meuleman <meuleman@broadcom.com> | ||||
| Date: Tue, 19 Jan 2016 12:39:24 +0100 | ||||
| Subject: [PATCH] brcmfmac: fix sdio sg table alloc crash | ||||
|  | ||||
| With commit 7d34b0560567 ("brcmfmac: Move all module parameters to | ||||
| one place") a bug was introduced causing a null pointer exception. | ||||
| This patch fixes the bug by initializing the sg table till after | ||||
| the settings have been initialized. | ||||
|  | ||||
| Fixes: 7d34b0560567 ("brcmfmac: Move all module parameters to one place") | ||||
| Reported-by: Marc Zyngier <marc.zyngier@arm.com> | ||||
| Tested-by: Marc Zyngier <marc.zyngier@arm.com> | ||||
| Reviewed-by: Arend Van Spriel <arend@broadcom.com> | ||||
| Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> | ||||
| Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> | ||||
| Signed-off-by: Hante Meuleman <meuleman@broadcom.com> | ||||
| Signed-off-by: Arend van Spriel <arend@broadcom.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | ||||
| @@ -879,11 +879,24 @@ int brcmf_sdiod_abort(struct brcmf_sdio_ | ||||
|  	return 0; | ||||
|  } | ||||
|   | ||||
| -static void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev) | ||||
| +void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev) | ||||
|  { | ||||
| +	struct sdio_func *func; | ||||
| +	struct mmc_host *host; | ||||
| +	uint max_blocks; | ||||
|  	uint nents; | ||||
|  	int err; | ||||
|   | ||||
| +	func = sdiodev->func[2]; | ||||
| +	host = func->card->host; | ||||
| +	sdiodev->sg_support = host->max_segs > 1; | ||||
| +	max_blocks = min_t(uint, host->max_blk_count, 511u); | ||||
| +	sdiodev->max_request_size = min_t(uint, host->max_req_size, | ||||
| +					  max_blocks * func->cur_blksize); | ||||
| +	sdiodev->max_segment_count = min_t(uint, host->max_segs, | ||||
| +					   SG_MAX_SINGLE_ALLOC); | ||||
| +	sdiodev->max_segment_size = host->max_seg_size; | ||||
| + | ||||
|  	if (!sdiodev->sg_support) | ||||
|  		return; | ||||
|   | ||||
| @@ -1021,9 +1034,6 @@ static void brcmf_sdiod_host_fixup(struc | ||||
|   | ||||
|  static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) | ||||
|  { | ||||
| -	struct sdio_func *func; | ||||
| -	struct mmc_host *host; | ||||
| -	uint max_blocks; | ||||
|  	int ret = 0; | ||||
|   | ||||
|  	sdiodev->num_funcs = 2; | ||||
| @@ -1054,26 +1064,6 @@ static int brcmf_sdiod_probe(struct brcm | ||||
|  		goto out; | ||||
|  	} | ||||
|   | ||||
| -	/* | ||||
| -	 * determine host related variables after brcmf_sdiod_probe() | ||||
| -	 * as func->cur_blksize is properly set and F2 init has been | ||||
| -	 * completed successfully. | ||||
| -	 */ | ||||
| -	func = sdiodev->func[2]; | ||||
| -	host = func->card->host; | ||||
| -	sdiodev->sg_support = host->max_segs > 1; | ||||
| -	max_blocks = min_t(uint, host->max_blk_count, 511u); | ||||
| -	sdiodev->max_request_size = min_t(uint, host->max_req_size, | ||||
| -					  max_blocks * func->cur_blksize); | ||||
| -	sdiodev->max_segment_count = min_t(uint, host->max_segs, | ||||
| -					   SG_MAX_SINGLE_ALLOC); | ||||
| -	sdiodev->max_segment_size = host->max_seg_size; | ||||
| - | ||||
| -	/* allocate scatter-gather table. sg support | ||||
| -	 * will be disabled upon allocation failure. | ||||
| -	 */ | ||||
| -	brcmf_sdiod_sgtable_alloc(sdiodev); | ||||
| - | ||||
|  	ret = brcmf_sdiod_freezer_attach(sdiodev); | ||||
|  	if (ret) | ||||
|  		goto out; | ||||
| @@ -1084,7 +1074,7 @@ static int brcmf_sdiod_probe(struct brcm | ||||
|  		ret = -ENODEV; | ||||
|  		goto out; | ||||
|  	} | ||||
| -	brcmf_sdiod_host_fixup(host); | ||||
| +	brcmf_sdiod_host_fixup(sdiodev->func[2]->card->host); | ||||
|  out: | ||||
|  	if (ret) | ||||
|  		brcmf_sdiod_remove(sdiodev); | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | ||||
| @@ -4114,6 +4114,11 @@ struct brcmf_sdio *brcmf_sdio_probe(stru | ||||
|  		goto fail; | ||||
|  	} | ||||
|   | ||||
| +	/* allocate scatter-gather table. sg support | ||||
| +	 * will be disabled upon allocation failure. | ||||
| +	 */ | ||||
| +	brcmf_sdiod_sgtable_alloc(bus->sdiodev); | ||||
| + | ||||
|  	/* Query the F2 block size, set roundup accordingly */ | ||||
|  	bus->blocksize = bus->sdiodev->func[2]->cur_blksize; | ||||
|  	bus->roundup = min(max_roundup, bus->blocksize); | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h | ||||
| @@ -342,6 +342,7 @@ int brcmf_sdiod_ramrw(struct brcmf_sdio_ | ||||
|   | ||||
|  /* Issue an abort to the specified function */ | ||||
|  int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn); | ||||
| +void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev); | ||||
|  void brcmf_sdiod_change_state(struct brcmf_sdio_dev *sdiodev, | ||||
|  			      enum brcmf_sdiod_state state); | ||||
|  #ifdef CONFIG_PM_SLEEP | ||||
| @@ -1,38 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Thu, 21 Jan 2016 16:28:44 +0100 | ||||
| Subject: [PATCH] ath9k_hw: ignore eeprom magic mismatch on flash based devices | ||||
|  | ||||
| Many AR913x based devices (maybe others too) do not have a valid EEPROM | ||||
| magic in their calibration data partition. | ||||
|  | ||||
| Fixes: 6fa658fd5ab2 ("ath9k: Simplify and fix eeprom endianness swapping") | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/ath/ath9k/eeprom.c | ||||
| +++ b/drivers/net/wireless/ath/ath9k/eeprom.c | ||||
| @@ -150,18 +150,18 @@ int ath9k_hw_nvram_swap_data(struct ath_ | ||||
|  		return -EIO; | ||||
|  	} | ||||
|   | ||||
| -	if (magic == AR5416_EEPROM_MAGIC) { | ||||
| -		*swap_needed = false; | ||||
| -	} else if (swab16(magic) == AR5416_EEPROM_MAGIC) { | ||||
| +	*swap_needed = false; | ||||
| +	if (swab16(magic) == AR5416_EEPROM_MAGIC) { | ||||
|  		if (ah->ah_flags & AH_NO_EEP_SWAP) { | ||||
|  			ath_info(common, | ||||
|  				 "Ignoring endianness difference in EEPROM magic bytes.\n"); | ||||
| - | ||||
| -			*swap_needed = false; | ||||
|  		} else { | ||||
|  			*swap_needed = true; | ||||
|  		} | ||||
| -	} else { | ||||
| +	} else if (magic != AR5416_EEPROM_MAGIC) { | ||||
| +		if (ath9k_hw_use_flash(ah)) | ||||
| +			return 0; | ||||
| + | ||||
|  		ath_err(common, | ||||
|  			"Invalid EEPROM Magic (0x%04x).\n", magic); | ||||
|  		return -EINVAL; | ||||
| @@ -1,55 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Fri, 22 Jan 2016 01:05:56 +0100 | ||||
| Subject: [PATCH] ath9k: do not limit the number of DFS interfaces to 1 | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/ath/ath9k/init.c | ||||
| +++ b/drivers/net/wireless/ath/ath9k/init.c | ||||
| @@ -751,14 +751,6 @@ static const struct ieee80211_iface_comb | ||||
|   | ||||
|  #endif /* CPTCFG_ATH9K_CHANNEL_CONTEXT */ | ||||
|   | ||||
| -static const struct ieee80211_iface_limit if_dfs_limits[] = { | ||||
| -	{ .max = 1,	.types = BIT(NL80211_IFTYPE_AP) | | ||||
| -#ifdef CPTCFG_MAC80211_MESH | ||||
| -				 BIT(NL80211_IFTYPE_MESH_POINT) | | ||||
| -#endif | ||||
| -				 BIT(NL80211_IFTYPE_ADHOC) }, | ||||
| -}; | ||||
| - | ||||
|  static const struct ieee80211_iface_combination if_comb[] = { | ||||
|  	{ | ||||
|  		.limits = if_limits, | ||||
| @@ -766,6 +758,11 @@ static const struct ieee80211_iface_comb | ||||
|  		.max_interfaces = 2048, | ||||
|  		.num_different_channels = 1, | ||||
|  		.beacon_int_infra_match = true, | ||||
| +#ifdef CPTCFG_ATH9K_DFS_CERTIFIED | ||||
| +		.radar_detect_widths =	BIT(NL80211_CHAN_WIDTH_20_NOHT) | | ||||
| +					BIT(NL80211_CHAN_WIDTH_20) | | ||||
| +					BIT(NL80211_CHAN_WIDTH_40), | ||||
| +#endif | ||||
|  	}, | ||||
|  	{ | ||||
|  		.limits = wds_limits, | ||||
| @@ -774,18 +771,6 @@ static const struct ieee80211_iface_comb | ||||
|  		.num_different_channels = 1, | ||||
|  		.beacon_int_infra_match = true, | ||||
|  	}, | ||||
| -#ifdef CPTCFG_ATH9K_DFS_CERTIFIED | ||||
| -	{ | ||||
| -		.limits = if_dfs_limits, | ||||
| -		.n_limits = ARRAY_SIZE(if_dfs_limits), | ||||
| -		.max_interfaces = 1, | ||||
| -		.num_different_channels = 1, | ||||
| -		.beacon_int_infra_match = true, | ||||
| -		.radar_detect_widths =	BIT(NL80211_CHAN_WIDTH_20_NOHT) | | ||||
| -					BIT(NL80211_CHAN_WIDTH_20) | | ||||
| -					BIT(NL80211_CHAN_WIDTH_40), | ||||
| -	} | ||||
| -#endif | ||||
|  }; | ||||
|   | ||||
|  #ifdef CPTCFG_ATH9K_CHANNEL_CONTEXT | ||||
| @@ -1,27 +0,0 @@ | ||||
| From: Michal Kazior <michal.kazior@tieto.com> | ||||
| Date: Thu, 21 Jan 2016 14:23:07 +0100 | ||||
| Subject: [PATCH] mac80211: fix txq queue related crashes | ||||
|  | ||||
| The driver can access the queue simultanously | ||||
| while mac80211 tears down the interface. Without | ||||
| spinlock protection this could lead to corrupting | ||||
| sk_buff_head and subsequently to an invalid | ||||
| pointer dereference. | ||||
|  | ||||
| Fixes: ba8c3d6f16a1 ("mac80211: add an intermediate software queue implementation") | ||||
| Signed-off-by: Michal Kazior <michal.kazior@tieto.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/iface.c | ||||
| +++ b/net/mac80211/iface.c | ||||
| @@ -977,7 +977,10 @@ static void ieee80211_do_stop(struct iee | ||||
|  	if (sdata->vif.txq) { | ||||
|  		struct txq_info *txqi = to_txq_info(sdata->vif.txq); | ||||
|   | ||||
| +		spin_lock_bh(&txqi->queue.lock); | ||||
|  		ieee80211_purge_tx_queue(&local->hw, &txqi->queue); | ||||
| +		spin_unlock_bh(&txqi->queue.lock); | ||||
| + | ||||
|  		atomic_set(&sdata->txqs_len[txqi->txq.ac], 0); | ||||
|  	} | ||||
|   | ||||
| @@ -1,57 +0,0 @@ | ||||
| From: Michal Kazior <michal.kazior@tieto.com> | ||||
| Date: Mon, 25 Jan 2016 14:43:24 +0100 | ||||
| Subject: [PATCH] mac80211: fix unnecessary frame drops in mesh fwding | ||||
|  | ||||
| The ieee80211_queue_stopped() expects hw queue | ||||
| number but it was given raw WMM AC number instead. | ||||
|  | ||||
| This could cause frame drops and problems with | ||||
| traffic in some cases - most notably if driver | ||||
| doesn't map AC numbers to queue numbers 1:1 and | ||||
| uses ieee80211_stop_queues() and | ||||
| ieee80211_wake_queue() only without ever calling | ||||
| ieee80211_wake_queues(). | ||||
|  | ||||
| On ath10k it was possible to hit this problem in | ||||
| the following case: | ||||
|  | ||||
|   1. wlan0 uses queue 0 | ||||
|      (ath10k maps queues per vif) | ||||
|   2. offchannel uses queue 15 | ||||
|   3. queues 1-14 are unused | ||||
|   4. ieee80211_stop_queues() | ||||
|   5. ieee80211_wake_queue(q=0) | ||||
|   6. ieee80211_wake_queue(q=15) | ||||
|      (other queues are not woken up because both | ||||
|       driver and mac80211 know other queues are | ||||
|       unused) | ||||
|   7. ieee80211_rx_h_mesh_fwding() | ||||
|   8. ieee80211_select_queue_80211() returns 2 | ||||
|   9. ieee80211_queue_stopped(q=2) returns true | ||||
|  10. frame is dropped (oops!) | ||||
|  | ||||
| Fixes: d3c1597b8d1b ("mac80211: fix forwarded mesh frame queue mapping") | ||||
| Signed-off-by: Michal Kazior <michal.kazior@tieto.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/rx.c | ||||
| +++ b/net/mac80211/rx.c | ||||
| @@ -2235,7 +2235,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80 | ||||
|  	struct ieee80211_local *local = rx->local; | ||||
|  	struct ieee80211_sub_if_data *sdata = rx->sdata; | ||||
|  	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; | ||||
| -	u16 q, hdrlen; | ||||
| +	u16 ac, q, hdrlen; | ||||
|   | ||||
|  	hdr = (struct ieee80211_hdr *) skb->data; | ||||
|  	hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||||
| @@ -2304,7 +2304,8 @@ ieee80211_rx_h_mesh_fwding(struct ieee80 | ||||
|  	    ether_addr_equal(sdata->vif.addr, hdr->addr3)) | ||||
|  		return RX_CONTINUE; | ||||
|   | ||||
| -	q = ieee80211_select_queue_80211(sdata, skb, hdr); | ||||
| +	ac = ieee80211_select_queue_80211(sdata, skb, hdr); | ||||
| +	q = sdata->vif.hw_queue[ac]; | ||||
|  	if (ieee80211_queue_stopped(&local->hw, q)) { | ||||
|  		IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion); | ||||
|  		return RX_DROP_MONITOR; | ||||
| @@ -1,103 +0,0 @@ | ||||
| From: Sachin Kulkarni <Sachin.Kulkarni@imgtec.com> | ||||
| Date: Tue, 12 Jan 2016 14:30:19 +0530 | ||||
| Subject: [PATCH] mac80211: Requeue work after scan complete for all VIF | ||||
|  types. | ||||
|  | ||||
| During a sw scan ieee80211_iface_work ignores work items for all vifs. | ||||
| However after the scan complete work is requeued only for STA, ADHOC | ||||
| and MESH iftypes. | ||||
|  | ||||
| This occasionally results in event processing getting delayed/not | ||||
| processed for iftype AP when it coexists with a STA. This can result | ||||
| in data halt and eventually disconnection on the AP interface. | ||||
|  | ||||
| Signed-off-by: Sachin Kulkarni <Sachin.Kulkarni@imgtec.com> | ||||
| Cc: linux-wireless@vger.kernel.org | ||||
| Cc: johannes@sipsolutions.net | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/ibss.c | ||||
| +++ b/net/mac80211/ibss.c | ||||
| @@ -1731,7 +1731,6 @@ void ieee80211_ibss_notify_scan_complete | ||||
|  		if (sdata->vif.type != NL80211_IFTYPE_ADHOC) | ||||
|  			continue; | ||||
|  		sdata->u.ibss.last_scan_completed = jiffies; | ||||
| -		ieee80211_queue_work(&local->hw, &sdata->work); | ||||
|  	} | ||||
|  	mutex_unlock(&local->iflist_mtx); | ||||
|  } | ||||
| --- a/net/mac80211/mesh.c | ||||
| +++ b/net/mac80211/mesh.c | ||||
| @@ -1369,17 +1369,6 @@ out: | ||||
|  	sdata_unlock(sdata); | ||||
|  } | ||||
|   | ||||
| -void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) | ||||
| -{ | ||||
| -	struct ieee80211_sub_if_data *sdata; | ||||
| - | ||||
| -	rcu_read_lock(); | ||||
| -	list_for_each_entry_rcu(sdata, &local->interfaces, list) | ||||
| -		if (ieee80211_vif_is_mesh(&sdata->vif) && | ||||
| -		    ieee80211_sdata_running(sdata)) | ||||
| -			ieee80211_queue_work(&local->hw, &sdata->work); | ||||
| -	rcu_read_unlock(); | ||||
| -} | ||||
|   | ||||
|  void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) | ||||
|  { | ||||
| --- a/net/mac80211/mesh.h | ||||
| +++ b/net/mac80211/mesh.h | ||||
| @@ -362,14 +362,10 @@ static inline bool mesh_path_sel_is_hwmp | ||||
|  	return sdata->u.mesh.mesh_pp_id == IEEE80211_PATH_PROTOCOL_HWMP; | ||||
|  } | ||||
|   | ||||
| -void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local); | ||||
| - | ||||
|  void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata); | ||||
|  void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata); | ||||
|  void ieee80211s_stop(void); | ||||
|  #else | ||||
| -static inline void | ||||
| -ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) {} | ||||
|  static inline bool mesh_path_sel_is_hwmp(struct ieee80211_sub_if_data *sdata) | ||||
|  { return false; } | ||||
|  static inline void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) | ||||
| --- a/net/mac80211/mlme.c | ||||
| +++ b/net/mac80211/mlme.c | ||||
| @@ -3978,8 +3978,6 @@ static void ieee80211_restart_sta_timer( | ||||
|  		if (!ieee80211_hw_check(&sdata->local->hw, CONNECTION_MONITOR)) | ||||
|  			ieee80211_queue_work(&sdata->local->hw, | ||||
|  					     &sdata->u.mgd.monitor_work); | ||||
| -		/* and do all the other regular work too */ | ||||
| -		ieee80211_queue_work(&sdata->local->hw, &sdata->work); | ||||
|  	} | ||||
|  } | ||||
|   | ||||
| --- a/net/mac80211/scan.c | ||||
| +++ b/net/mac80211/scan.c | ||||
| @@ -314,6 +314,7 @@ static void __ieee80211_scan_completed(s | ||||
|  	bool was_scanning = local->scanning; | ||||
|  	struct cfg80211_scan_request *scan_req; | ||||
|  	struct ieee80211_sub_if_data *scan_sdata; | ||||
| +	struct ieee80211_sub_if_data *sdata; | ||||
|   | ||||
|  	lockdep_assert_held(&local->mtx); | ||||
|   | ||||
| @@ -373,7 +374,15 @@ static void __ieee80211_scan_completed(s | ||||
|   | ||||
|  	ieee80211_mlme_notify_scan_completed(local); | ||||
|  	ieee80211_ibss_notify_scan_completed(local); | ||||
| -	ieee80211_mesh_notify_scan_completed(local); | ||||
| + | ||||
| +	/* Requeue all the work that might have been ignored while | ||||
| +	 * the scan was in progress | ||||
| +	 */ | ||||
| +	list_for_each_entry_rcu(sdata, &local->interfaces, list) { | ||||
| +		if (ieee80211_sdata_running(sdata)) | ||||
| +			ieee80211_queue_work(&sdata->local->hw, &sdata->work); | ||||
| +	} | ||||
| + | ||||
|  	if (was_scanning) | ||||
|  		ieee80211_start_next_roc(local); | ||||
|  } | ||||
| @@ -1,57 +0,0 @@ | ||||
| From: Sara Sharon <sara.sharon@intel.com> | ||||
| Date: Mon, 25 Jan 2016 15:46:35 +0200 | ||||
| Subject: [PATCH] mac80211: fix ibss scan parameters | ||||
|  | ||||
| When joining IBSS a full scan should be initiated in order to search | ||||
| for existing cell, unless the fixed_channel parameter was set. | ||||
| A default channel to create the IBSS on if no cell was found is | ||||
| provided as well. | ||||
| However - a scan is initiated only on the default channel provided | ||||
| regardless of whether ifibss->fixed_channel is set or not, with the | ||||
| obvious result of the cell not joining existing IBSS cell that is | ||||
| on another channel. | ||||
|  | ||||
| Fixes: 76bed0f43b27 ("mac80211: IBSS fix scan request") | ||||
| Signed-off-by: Sara Sharon <sara.sharon@intel.com> | ||||
| Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/ibss.c | ||||
| +++ b/net/mac80211/ibss.c | ||||
| @@ -7,6 +7,7 @@ | ||||
|   * Copyright 2007, Michael Wu <flamingice@sourmilk.net> | ||||
|   * Copyright 2009, Johannes Berg <johannes@sipsolutions.net> | ||||
|   * Copyright 2013-2014  Intel Mobile Communications GmbH | ||||
| + * Copyright(c) 2016 Intel Deutschland GmbH | ||||
|   * | ||||
|   * This program is free software; you can redistribute it and/or modify | ||||
|   * it under the terms of the GNU General Public License version 2 as | ||||
| @@ -1483,14 +1484,21 @@ static void ieee80211_sta_find_ibss(stru | ||||
|   | ||||
|  		sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); | ||||
|   | ||||
| -		num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy, | ||||
| -							 &ifibss->chandef, | ||||
| -							 channels, | ||||
| -							 ARRAY_SIZE(channels)); | ||||
|  		scan_width = cfg80211_chandef_to_scan_width(&ifibss->chandef); | ||||
| -		ieee80211_request_ibss_scan(sdata, ifibss->ssid, | ||||
| -					    ifibss->ssid_len, channels, num, | ||||
| -					    scan_width); | ||||
| + | ||||
| +		if (ifibss->fixed_channel) { | ||||
| +			num = ieee80211_ibss_setup_scan_channels(local->hw.wiphy, | ||||
| +								 &ifibss->chandef, | ||||
| +								 channels, | ||||
| +								 ARRAY_SIZE(channels)); | ||||
| +			ieee80211_request_ibss_scan(sdata, ifibss->ssid, | ||||
| +						    ifibss->ssid_len, channels, | ||||
| +						    num, scan_width); | ||||
| +		} else { | ||||
| +			ieee80211_request_ibss_scan(sdata, ifibss->ssid, | ||||
| +						    ifibss->ssid_len, NULL, | ||||
| +						    0, scan_width); | ||||
| +		} | ||||
|  	} else { | ||||
|  		int interval = IEEE80211_SCAN_INTERVAL; | ||||
|   | ||||
| @@ -1,50 +0,0 @@ | ||||
| From: Chris Bainbridge <chris.bainbridge@gmail.com> | ||||
| Date: Wed, 27 Jan 2016 15:46:18 +0000 | ||||
| Subject: [PATCH] net/mac80211/agg-rx.c: fix use of uninitialised values | ||||
|  | ||||
| Use kzalloc instead of kmalloc for struct tid_ampdu_rx. Fixes: | ||||
|  | ||||
| [    7.976605] UBSAN: Undefined behaviour in net/mac80211/rx.c:932:29 | ||||
| [    7.976608] load of value 2 is not a valid value for type '_Bool' | ||||
| [    7.976611] CPU: 3 PID: 1134 Comm: kworker/u16:7 Not tainted 4.5.0-rc1+ #265 | ||||
| [    7.976613] Hardware name: Apple Inc. MacBookPro10,2/Mac-AFD8A9D944EA4843, BIOS MBP102.88Z.0106.B0A.1509130955 09/13/2015 | ||||
| [    7.976616] Workqueue: phy0 rt2x00usb_work_rxdone | ||||
| [    7.976619]  0000000000000004 ffff880254a7ba50 ffffffff8181d866 0000000000000007 | ||||
| [    7.976622]  ffff880254a7ba78 ffff880254a7ba68 ffffffff8188422d ffffffff8379b500 | ||||
| [    7.976626]  ffff880254a7bab8 ffffffff81884747 0000000000000202 0000000348620032 | ||||
| [    7.976629] Call Trace: | ||||
| [    7.976633]  [<ffffffff8181d866>] dump_stack+0x45/0x5f | ||||
| [    7.976637]  [<ffffffff8188422d>] ubsan_epilogue+0xd/0x40 | ||||
| [    7.976642]  [<ffffffff81884747>] __ubsan_handle_load_invalid_value+0x67/0x70 | ||||
| [    7.976646]  [<ffffffff82227b4d>] ieee80211_sta_reorder_release.isra.16+0x5ed/0x730 | ||||
| [    7.976650]  [<ffffffff8222ca14>] ieee80211_prepare_and_rx_handle+0xd04/0x1c00 | ||||
| [    7.976654]  [<ffffffff81cb27ce>] ? usb_hcd_map_urb_for_dma+0x65e/0x960 | ||||
| [    7.976659]  [<ffffffff8222db03>] __ieee80211_rx_handle_packet+0x1f3/0x750 | ||||
| [    7.976663]  [<ffffffff8222e4a7>] ieee80211_rx_napi+0x447/0x990 | ||||
| [    7.976667]  [<ffffffff81c5fb85>] rt2x00lib_rxdone+0x305/0xbd0 | ||||
| [    7.976670]  [<ffffffff811ac23f>] ? dequeue_task_fair+0x64f/0x1de0 | ||||
| [    7.976674]  [<ffffffff811a1516>] ? sched_clock_cpu+0xe6/0x150 | ||||
| [    7.976678]  [<ffffffff81c6c45c>] rt2x00usb_work_rxdone+0x7c/0x140 | ||||
| [    7.976682]  [<ffffffff8117aef6>] process_one_work+0x226/0x860 | ||||
| [    7.976686]  [<ffffffff8117b58c>] worker_thread+0x5c/0x680 | ||||
| [    7.976690]  [<ffffffff8117b530>] ? process_one_work+0x860/0x860 | ||||
| [    7.976693]  [<ffffffff81184f86>] kthread+0xf6/0x150 | ||||
| [    7.976697]  [<ffffffff81184e90>] ? kthread_worker_fn+0x310/0x310 | ||||
| [    7.976700]  [<ffffffff822a94df>] ret_from_fork+0x3f/0x70 | ||||
| [    7.976703]  [<ffffffff81184e90>] ? kthread_worker_fn+0x310/0x310 | ||||
|  | ||||
| Link: https://lkml.org/lkml/2016/1/26/230 | ||||
| Signed-off-by: Chris Bainbridge <chris.bainbridge@gmail.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/agg-rx.c | ||||
| +++ b/net/mac80211/agg-rx.c | ||||
| @@ -327,7 +327,7 @@ void __ieee80211_start_rx_ba_session(str | ||||
|  	} | ||||
|   | ||||
|  	/* prepare A-MPDU MLME for Rx aggregation */ | ||||
| -	tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL); | ||||
| +	tid_agg_rx = kzalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL); | ||||
|  	if (!tid_agg_rx) | ||||
|  		goto end; | ||||
|   | ||||
| @@ -1,45 +0,0 @@ | ||||
| From: Konstantin Khlebnikov <koct9i@gmail.com> | ||||
| Date: Fri, 29 Jan 2016 11:35:12 +0300 | ||||
| Subject: [PATCH] mac80211: minstrel_ht: fix out-of-bound in | ||||
|  minstrel_ht_set_best_prob_rate | ||||
|  | ||||
| Patch fixes this splat | ||||
|  | ||||
| BUG: KASAN: slab-out-of-bounds in minstrel_ht_update_stats.isra.7+0x6e1/0x9e0 | ||||
| [mac80211] at addr ffff8800cee640f4 Read of size 4 by task swapper/3/0 | ||||
|  | ||||
| Signed-off-by: Konstantin Khlebnikov <koct9i@gmail.com> | ||||
| Link: http://lkml.kernel.org/r/CALYGNiNyJhSaVnE35qS6UCGaSb2Dx1_i5HcRavuOX14oTz2P+w@mail.gmail.com | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/rc80211_minstrel_ht.c | ||||
| +++ b/net/mac80211/rc80211_minstrel_ht.c | ||||
| @@ -414,15 +414,16 @@ minstrel_ht_set_best_prob_rate(struct mi | ||||
|  	    (max_tp_group != MINSTREL_CCK_GROUP)) | ||||
|  		return; | ||||
|   | ||||
| +	max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES; | ||||
| +	max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; | ||||
| +	max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma; | ||||
| + | ||||
|  	if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) { | ||||
|  		cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, | ||||
|  						    mrs->prob_ewma); | ||||
|  		if (cur_tp_avg > tmp_tp_avg) | ||||
|  			mi->max_prob_rate = index; | ||||
|   | ||||
| -		max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES; | ||||
| -		max_gpr_idx = mg->max_group_prob_rate %	MCS_GROUP_RATES; | ||||
| -		max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma; | ||||
|  		max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group, | ||||
|  							max_gpr_idx, | ||||
|  							max_gpr_prob); | ||||
| @@ -431,7 +432,7 @@ minstrel_ht_set_best_prob_rate(struct mi | ||||
|  	} else { | ||||
|  		if (mrs->prob_ewma > tmp_prob) | ||||
|  			mi->max_prob_rate = index; | ||||
| -		if (mrs->prob_ewma > mg->rates[mg->max_group_prob_rate].prob_ewma) | ||||
| +		if (mrs->prob_ewma > max_gpr_prob) | ||||
|  			mg->max_group_prob_rate = index; | ||||
|  	} | ||||
|  } | ||||
| @@ -1,35 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Tue, 2 Feb 2016 14:39:08 +0100 | ||||
| Subject: [PATCH] mac80211: move A-MSDU skb_linearize call to | ||||
|  ieee80211_amsdu_to_8023s | ||||
|  | ||||
| Prepararation for zero-copy A-MSDU support with page fragment SKBs | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/rx.c | ||||
| +++ b/net/mac80211/rx.c | ||||
| @@ -2203,9 +2203,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx | ||||
|  	skb->dev = dev; | ||||
|  	__skb_queue_head_init(&frame_list); | ||||
|   | ||||
| -	if (skb_linearize(skb)) | ||||
| -		return RX_DROP_UNUSABLE; | ||||
| - | ||||
|  	ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr, | ||||
|  				 rx->sdata->vif.type, | ||||
|  				 rx->local->hw.extra_tx_headroom, true); | ||||
| --- a/net/wireless/util.c | ||||
| +++ b/net/wireless/util.c | ||||
| @@ -657,6 +657,9 @@ void ieee80211_amsdu_to_8023s(struct sk_ | ||||
|  	int remaining, err; | ||||
|  	u8 dst[ETH_ALEN], src[ETH_ALEN]; | ||||
|   | ||||
| +	if (skb_linearize(skb)) | ||||
| +		goto out; | ||||
| + | ||||
|  	if (has_80211_header) { | ||||
|  		err = ieee80211_data_to_8023(skb, addr, iftype); | ||||
|  		if (err) | ||||
| @@ -1,186 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Tue, 2 Feb 2016 14:39:09 +0100 | ||||
| Subject: [PATCH] cfg80211: add function for 802.3 conversion with separate | ||||
|  output buffer | ||||
|  | ||||
| Use skb_copy_bits in preparation for allowing fragmented skbs | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/wireless/util.c | ||||
| +++ b/net/wireless/util.c | ||||
| @@ -393,9 +393,9 @@ unsigned int ieee80211_get_hdrlen_from_s | ||||
|  } | ||||
|  EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); | ||||
|   | ||||
| -unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | ||||
| +static unsigned int __ieee80211_get_mesh_hdrlen(u8 flags) | ||||
|  { | ||||
| -	int ae = meshhdr->flags & MESH_FLAGS_AE; | ||||
| +	int ae = flags & MESH_FLAGS_AE; | ||||
|  	/* 802.11-2012, 8.2.4.7.3 */ | ||||
|  	switch (ae) { | ||||
|  	default: | ||||
| @@ -407,21 +407,31 @@ unsigned int ieee80211_get_mesh_hdrlen(s | ||||
|  		return 18; | ||||
|  	} | ||||
|  } | ||||
| + | ||||
| +unsigned int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) | ||||
| +{ | ||||
| +	return __ieee80211_get_mesh_hdrlen(meshhdr->flags); | ||||
| +} | ||||
|  EXPORT_SYMBOL(ieee80211_get_mesh_hdrlen); | ||||
|   | ||||
| -int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | ||||
| -			   enum nl80211_iftype iftype) | ||||
| +static int __ieee80211_data_to_8023(struct sk_buff *skb, struct ethhdr *ehdr, | ||||
| +				    const u8 *addr, enum nl80211_iftype iftype) | ||||
|  { | ||||
|  	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||||
| -	u16 hdrlen, ethertype; | ||||
| -	u8 *payload; | ||||
| -	u8 dst[ETH_ALEN]; | ||||
| -	u8 src[ETH_ALEN] __aligned(2); | ||||
| +	struct { | ||||
| +		u8 hdr[ETH_ALEN] __aligned(2); | ||||
| +		__be16 proto; | ||||
| +	} payload; | ||||
| +	struct ethhdr tmp; | ||||
| +	u16 hdrlen; | ||||
| +	u8 mesh_flags = 0; | ||||
|   | ||||
|  	if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) | ||||
|  		return -1; | ||||
|   | ||||
|  	hdrlen = ieee80211_hdrlen(hdr->frame_control); | ||||
| +	if (skb->len < hdrlen + 8) | ||||
| +		return -1; | ||||
|   | ||||
|  	/* convert IEEE 802.11 header + possible LLC headers into Ethernet | ||||
|  	 * header | ||||
| @@ -432,8 +442,11 @@ int ieee80211_data_to_8023(struct sk_buf | ||||
|  	 *   1     0   BSSID SA    DA    n/a | ||||
|  	 *   1     1   RA    TA    DA    SA | ||||
|  	 */ | ||||
| -	memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN); | ||||
| -	memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN); | ||||
| +	memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN); | ||||
| +	memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN); | ||||
| + | ||||
| +	if (iftype == NL80211_IFTYPE_MESH_POINT) | ||||
| +		skb_copy_bits(skb, hdrlen, &mesh_flags, 1); | ||||
|   | ||||
|  	switch (hdr->frame_control & | ||||
|  		cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { | ||||
| @@ -450,44 +463,31 @@ int ieee80211_data_to_8023(struct sk_buf | ||||
|  			     iftype != NL80211_IFTYPE_STATION)) | ||||
|  			return -1; | ||||
|  		if (iftype == NL80211_IFTYPE_MESH_POINT) { | ||||
| -			struct ieee80211s_hdr *meshdr = | ||||
| -				(struct ieee80211s_hdr *) (skb->data + hdrlen); | ||||
| -			/* make sure meshdr->flags is on the linear part */ | ||||
| -			if (!pskb_may_pull(skb, hdrlen + 1)) | ||||
| -				return -1; | ||||
| -			if (meshdr->flags & MESH_FLAGS_AE_A4) | ||||
| +			if (mesh_flags & MESH_FLAGS_AE_A4) | ||||
|  				return -1; | ||||
| -			if (meshdr->flags & MESH_FLAGS_AE_A5_A6) { | ||||
| +			if (mesh_flags & MESH_FLAGS_AE_A5_A6) { | ||||
|  				skb_copy_bits(skb, hdrlen + | ||||
|  					offsetof(struct ieee80211s_hdr, eaddr1), | ||||
| -				       	dst, ETH_ALEN); | ||||
| -				skb_copy_bits(skb, hdrlen + | ||||
| -					offsetof(struct ieee80211s_hdr, eaddr2), | ||||
| -				        src, ETH_ALEN); | ||||
| +					tmp.h_dest, 2 * ETH_ALEN); | ||||
|  			} | ||||
| -			hdrlen += ieee80211_get_mesh_hdrlen(meshdr); | ||||
| +			hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags); | ||||
|  		} | ||||
|  		break; | ||||
|  	case cpu_to_le16(IEEE80211_FCTL_FROMDS): | ||||
|  		if ((iftype != NL80211_IFTYPE_STATION && | ||||
|  		     iftype != NL80211_IFTYPE_P2P_CLIENT && | ||||
|  		     iftype != NL80211_IFTYPE_MESH_POINT) || | ||||
| -		    (is_multicast_ether_addr(dst) && | ||||
| -		     ether_addr_equal(src, addr))) | ||||
| +		    (is_multicast_ether_addr(tmp.h_dest) && | ||||
| +		     ether_addr_equal(tmp.h_source, addr))) | ||||
|  			return -1; | ||||
|  		if (iftype == NL80211_IFTYPE_MESH_POINT) { | ||||
| -			struct ieee80211s_hdr *meshdr = | ||||
| -				(struct ieee80211s_hdr *) (skb->data + hdrlen); | ||||
| -			/* make sure meshdr->flags is on the linear part */ | ||||
| -			if (!pskb_may_pull(skb, hdrlen + 1)) | ||||
| -				return -1; | ||||
| -			if (meshdr->flags & MESH_FLAGS_AE_A5_A6) | ||||
| +			if (mesh_flags & MESH_FLAGS_AE_A5_A6) | ||||
|  				return -1; | ||||
| -			if (meshdr->flags & MESH_FLAGS_AE_A4) | ||||
| +			if (mesh_flags & MESH_FLAGS_AE_A4) | ||||
|  				skb_copy_bits(skb, hdrlen + | ||||
|  					offsetof(struct ieee80211s_hdr, eaddr1), | ||||
| -					src, ETH_ALEN); | ||||
| -			hdrlen += ieee80211_get_mesh_hdrlen(meshdr); | ||||
| +					tmp.h_source, ETH_ALEN); | ||||
| +			hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags); | ||||
|  		} | ||||
|  		break; | ||||
|  	case cpu_to_le16(0): | ||||
| @@ -498,33 +498,33 @@ int ieee80211_data_to_8023(struct sk_buf | ||||
|  		break; | ||||
|  	} | ||||
|   | ||||
| -	if (!pskb_may_pull(skb, hdrlen + 8)) | ||||
| -		return -1; | ||||
| - | ||||
| -	payload = skb->data + hdrlen; | ||||
| -	ethertype = (payload[6] << 8) | payload[7]; | ||||
| +	skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)); | ||||
| +	tmp.h_proto = payload.proto; | ||||
|   | ||||
| -	if (likely((ether_addr_equal(payload, rfc1042_header) && | ||||
| -		    ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | ||||
| -		   ether_addr_equal(payload, bridge_tunnel_header))) { | ||||
| +	if (likely((ether_addr_equal(payload.hdr, rfc1042_header) && | ||||
| +		    tmp.h_proto != htons(ETH_P_AARP) && | ||||
| +		    tmp.h_proto != htons(ETH_P_IPX)) || | ||||
| +		   ether_addr_equal(payload.hdr, bridge_tunnel_header))) | ||||
|  		/* remove RFC1042 or Bridge-Tunnel encapsulation and | ||||
|  		 * replace EtherType */ | ||||
| -		skb_pull(skb, hdrlen + 6); | ||||
| -		memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN); | ||||
| -		memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN); | ||||
| -	} else { | ||||
| -		struct ethhdr *ehdr; | ||||
| -		__be16 len; | ||||
| +		hdrlen += ETH_ALEN + 2; | ||||
| +	else | ||||
| +		tmp.h_proto = htons(skb->len); | ||||
|   | ||||
| -		skb_pull(skb, hdrlen); | ||||
| -		len = htons(skb->len); | ||||
| +	pskb_pull(skb, hdrlen); | ||||
| + | ||||
| +	if (!ehdr) | ||||
|  		ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr)); | ||||
| -		memcpy(ehdr->h_dest, dst, ETH_ALEN); | ||||
| -		memcpy(ehdr->h_source, src, ETH_ALEN); | ||||
| -		ehdr->h_proto = len; | ||||
| -	} | ||||
| +	memcpy(ehdr, &tmp, sizeof(tmp)); | ||||
| + | ||||
|  	return 0; | ||||
|  } | ||||
| + | ||||
| +int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | ||||
| +			   enum nl80211_iftype iftype) | ||||
| +{ | ||||
| +	return __ieee80211_data_to_8023(skb, NULL, addr, iftype); | ||||
| +} | ||||
|  EXPORT_SYMBOL(ieee80211_data_to_8023); | ||||
|   | ||||
|  int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | ||||
| @@ -1,159 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Tue, 2 Feb 2016 14:39:10 +0100 | ||||
| Subject: [PATCH] cfg80211: add support for non-linear skbs in | ||||
|  ieee80211_amsdu_to_8023s | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/wireless/util.c | ||||
| +++ b/net/wireless/util.c | ||||
| @@ -644,73 +644,75 @@ int ieee80211_data_from_8023(struct sk_b | ||||
|  } | ||||
|  EXPORT_SYMBOL(ieee80211_data_from_8023); | ||||
|   | ||||
| +static struct sk_buff * | ||||
| +__ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, | ||||
| +		       int offset, int len) | ||||
| +{ | ||||
| +	struct sk_buff *frame; | ||||
| + | ||||
| +	if (skb->len - offset < len) | ||||
| +		return NULL; | ||||
| + | ||||
| +	/* | ||||
| +	 * Allocate and reserve two bytes more for payload | ||||
| +	 * alignment since sizeof(struct ethhdr) is 14. | ||||
| +	 */ | ||||
| +	frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + len); | ||||
| + | ||||
| +	skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); | ||||
| +	skb_copy_bits(skb, offset, skb_put(frame, len), len); | ||||
| + | ||||
| +	return frame; | ||||
| +} | ||||
|   | ||||
|  void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, | ||||
|  			      const u8 *addr, enum nl80211_iftype iftype, | ||||
|  			      const unsigned int extra_headroom, | ||||
|  			      bool has_80211_header) | ||||
|  { | ||||
| +	unsigned int hlen = ALIGN(extra_headroom, 4); | ||||
|  	struct sk_buff *frame = NULL; | ||||
|  	u16 ethertype; | ||||
|  	u8 *payload; | ||||
| -	const struct ethhdr *eth; | ||||
| -	int remaining, err; | ||||
| -	u8 dst[ETH_ALEN], src[ETH_ALEN]; | ||||
| - | ||||
| -	if (skb_linearize(skb)) | ||||
| -		goto out; | ||||
| +	int offset = 0, remaining, err; | ||||
| +	struct ethhdr eth; | ||||
| +	bool reuse_skb = true; | ||||
| +	bool last = false; | ||||
|   | ||||
|  	if (has_80211_header) { | ||||
| -		err = ieee80211_data_to_8023(skb, addr, iftype); | ||||
| +		err = __ieee80211_data_to_8023(skb, ð, addr, iftype); | ||||
|  		if (err) | ||||
|  			goto out; | ||||
| - | ||||
| -		/* skip the wrapping header */ | ||||
| -		eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); | ||||
| -		if (!eth) | ||||
| -			goto out; | ||||
| -	} else { | ||||
| -		eth = (struct ethhdr *) skb->data; | ||||
|  	} | ||||
|   | ||||
| -	while (skb != frame) { | ||||
| +	while (!last) { | ||||
| +		unsigned int subframe_len; | ||||
| +		int len; | ||||
|  		u8 padding; | ||||
| -		__be16 len = eth->h_proto; | ||||
| -		unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len); | ||||
| - | ||||
| -		remaining = skb->len; | ||||
| -		memcpy(dst, eth->h_dest, ETH_ALEN); | ||||
| -		memcpy(src, eth->h_source, ETH_ALEN); | ||||
|   | ||||
| +		skb_copy_bits(skb, offset, ð, sizeof(eth)); | ||||
| +		len = ntohs(eth.h_proto); | ||||
| +		subframe_len = sizeof(struct ethhdr) + len; | ||||
|  		padding = (4 - subframe_len) & 0x3; | ||||
| + | ||||
|  		/* the last MSDU has no padding */ | ||||
| +		remaining = skb->len - offset; | ||||
|  		if (subframe_len > remaining) | ||||
|  			goto purge; | ||||
|   | ||||
| -		skb_pull(skb, sizeof(struct ethhdr)); | ||||
| +		offset += sizeof(struct ethhdr); | ||||
|  		/* reuse skb for the last subframe */ | ||||
| -		if (remaining <= subframe_len + padding) | ||||
| +		last = remaining <= subframe_len + padding; | ||||
| +		if (!skb_is_nonlinear(skb) && last) { | ||||
| +			skb_pull(skb, offset); | ||||
|  			frame = skb; | ||||
| -		else { | ||||
| -			unsigned int hlen = ALIGN(extra_headroom, 4); | ||||
| -			/* | ||||
| -			 * Allocate and reserve two bytes more for payload | ||||
| -			 * alignment since sizeof(struct ethhdr) is 14. | ||||
| -			 */ | ||||
| -			frame = dev_alloc_skb(hlen + subframe_len + 2); | ||||
| +			reuse_skb = true; | ||||
| +		} else { | ||||
| +			frame = __ieee80211_amsdu_copy(skb, hlen, offset, len); | ||||
|  			if (!frame) | ||||
|  				goto purge; | ||||
|   | ||||
| -			skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); | ||||
| -			memcpy(skb_put(frame, ntohs(len)), skb->data, | ||||
| -				ntohs(len)); | ||||
| - | ||||
| -			eth = (struct ethhdr *)skb_pull(skb, ntohs(len) + | ||||
| -							padding); | ||||
| -			if (!eth) { | ||||
| -				dev_kfree_skb(frame); | ||||
| -				goto purge; | ||||
| -			} | ||||
| +			offset += len + padding; | ||||
|  		} | ||||
|   | ||||
|  		skb_reset_network_header(frame); | ||||
| @@ -719,24 +721,20 @@ void ieee80211_amsdu_to_8023s(struct sk_ | ||||
|   | ||||
|  		payload = frame->data; | ||||
|  		ethertype = (payload[6] << 8) | payload[7]; | ||||
| - | ||||
|  		if (likely((ether_addr_equal(payload, rfc1042_header) && | ||||
|  			    ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || | ||||
|  			   ether_addr_equal(payload, bridge_tunnel_header))) { | ||||
| -			/* remove RFC1042 or Bridge-Tunnel | ||||
| -			 * encapsulation and replace EtherType */ | ||||
| -			skb_pull(frame, 6); | ||||
| -			memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); | ||||
| -			memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); | ||||
| -		} else { | ||||
| -			memcpy(skb_push(frame, sizeof(__be16)), &len, | ||||
| -				sizeof(__be16)); | ||||
| -			memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); | ||||
| -			memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); | ||||
| +			eth.h_proto = htons(ethertype); | ||||
| +			skb_pull(frame, ETH_ALEN + 2); | ||||
|  		} | ||||
| + | ||||
| +		memcpy(skb_push(frame, sizeof(eth)), ð, sizeof(eth)); | ||||
|  		__skb_queue_tail(list, frame); | ||||
|  	} | ||||
|   | ||||
| +	if (!reuse_skb) | ||||
| +		dev_kfree_skb(skb); | ||||
| + | ||||
|  	return; | ||||
|   | ||||
|   purge: | ||||
| @@ -1,155 +0,0 @@ | ||||
| From: Sven Eckelmann <sven@narfation.org> | ||||
| Date: Tue, 26 Jan 2016 17:11:13 +0100 | ||||
| Subject: [PATCH] mac80211: Parse legacy and HT rate in injected frames | ||||
|  | ||||
| Drivers/devices without their own rate control algorithm can get the | ||||
| information what rates they should use from either the radiotap header of | ||||
| injected frames or from the rate control algorithm. But the parsing of the | ||||
| legacy rate information from the radiotap header was removed in commit | ||||
| e6a9854b05c1 ("mac80211/drivers: rewrite the rate control API"). | ||||
|  | ||||
| The removal of this feature heavily reduced the usefulness of frame | ||||
| injection when wanting to simulate specific transmission behavior. Having | ||||
| rate parsing together with MCS rates and retry support allows a fine | ||||
| grained selection of the tx behavior of injected frames for these kind of | ||||
| tests. | ||||
|  | ||||
| Signed-off-by: Sven Eckelmann <sven@narfation.org> | ||||
| Cc: Simon Wunderlich <sw@simonwunderlich.de> | ||||
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> | ||||
| --- | ||||
|  | ||||
| --- a/include/net/mac80211.h | ||||
| +++ b/include/net/mac80211.h | ||||
| @@ -708,12 +708,14 @@ enum mac80211_tx_info_flags { | ||||
|   *	protocol frame (e.g. EAP) | ||||
|   * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll | ||||
|   *	frame (PS-Poll or uAPSD). | ||||
| + * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information | ||||
|   * | ||||
|   * These flags are used in tx_info->control.flags. | ||||
|   */ | ||||
|  enum mac80211_tx_control_flags { | ||||
|  	IEEE80211_TX_CTRL_PORT_CTRL_PROTO	= BIT(0), | ||||
|  	IEEE80211_TX_CTRL_PS_RESPONSE		= BIT(1), | ||||
| +	IEEE80211_TX_CTRL_RATE_INJECT		= BIT(2), | ||||
|  }; | ||||
|   | ||||
|  /* | ||||
| --- a/net/mac80211/tx.c | ||||
| +++ b/net/mac80211/tx.c | ||||
| @@ -710,6 +710,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021 | ||||
|   | ||||
|  	info->control.short_preamble = txrc.short_preamble; | ||||
|   | ||||
| +	/* don't ask rate control when rate already injected via radiotap */ | ||||
| +	if (info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT) | ||||
| +		return TX_CONTINUE; | ||||
| + | ||||
|  	if (tx->sta) | ||||
|  		assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC); | ||||
|   | ||||
| @@ -1665,15 +1669,24 @@ void ieee80211_xmit(struct ieee80211_sub | ||||
|  	ieee80211_tx(sdata, sta, skb, false); | ||||
|  } | ||||
|   | ||||
| -static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) | ||||
| +static bool ieee80211_parse_tx_radiotap(struct ieee80211_local *local, | ||||
| +					struct sk_buff *skb) | ||||
|  { | ||||
|  	struct ieee80211_radiotap_iterator iterator; | ||||
|  	struct ieee80211_radiotap_header *rthdr = | ||||
|  		(struct ieee80211_radiotap_header *) skb->data; | ||||
|  	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||
| +	struct ieee80211_supported_band *sband = | ||||
| +		local->hw.wiphy->bands[info->band]; | ||||
|  	int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, | ||||
|  						   NULL); | ||||
|  	u16 txflags; | ||||
| +	u16 rate = 0; | ||||
| +	bool rate_found = false; | ||||
| +	u8 rate_retries = 0; | ||||
| +	u16 rate_flags = 0; | ||||
| +	u8 mcs_known, mcs_flags; | ||||
| +	int i; | ||||
|   | ||||
|  	info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | | ||||
|  		       IEEE80211_TX_CTL_DONTFRAG; | ||||
| @@ -1724,6 +1737,35 @@ static bool ieee80211_parse_tx_radiotap( | ||||
|  				info->flags |= IEEE80211_TX_CTL_NO_ACK; | ||||
|  			break; | ||||
|   | ||||
| +		case IEEE80211_RADIOTAP_RATE: | ||||
| +			rate = *iterator.this_arg; | ||||
| +			rate_flags = 0; | ||||
| +			rate_found = true; | ||||
| +			break; | ||||
| + | ||||
| +		case IEEE80211_RADIOTAP_DATA_RETRIES: | ||||
| +			rate_retries = *iterator.this_arg; | ||||
| +			break; | ||||
| + | ||||
| +		case IEEE80211_RADIOTAP_MCS: | ||||
| +			mcs_known = iterator.this_arg[0]; | ||||
| +			mcs_flags = iterator.this_arg[1]; | ||||
| +			if (!(mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_MCS)) | ||||
| +				break; | ||||
| + | ||||
| +			rate_found = true; | ||||
| +			rate = iterator.this_arg[2]; | ||||
| +			rate_flags = IEEE80211_TX_RC_MCS; | ||||
| + | ||||
| +			if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_GI && | ||||
| +			    mcs_flags & IEEE80211_RADIOTAP_MCS_SGI) | ||||
| +				rate_flags |= IEEE80211_TX_RC_SHORT_GI; | ||||
| + | ||||
| +			if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW && | ||||
| +			    mcs_flags & IEEE80211_RADIOTAP_MCS_BW_40) | ||||
| +				rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||||
| +			break; | ||||
| + | ||||
|  		/* | ||||
|  		 * Please update the file | ||||
|  		 * Documentation/networking/mac80211-injection.txt | ||||
| @@ -1738,6 +1780,32 @@ static bool ieee80211_parse_tx_radiotap( | ||||
|  	if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ | ||||
|  		return false; | ||||
|   | ||||
| +	if (rate_found) { | ||||
| +		info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT; | ||||
| + | ||||
| +		for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { | ||||
| +			info->control.rates[i].idx = -1; | ||||
| +			info->control.rates[i].flags = 0; | ||||
| +			info->control.rates[i].count = 0; | ||||
| +		} | ||||
| + | ||||
| +		if (rate_flags & IEEE80211_TX_RC_MCS) { | ||||
| +			info->control.rates[0].idx = rate; | ||||
| +		} else { | ||||
| +			for (i = 0; i < sband->n_bitrates; i++) { | ||||
| +				if (rate * 5 != sband->bitrates[i].bitrate) | ||||
| +					continue; | ||||
| + | ||||
| +				info->control.rates[0].idx = i; | ||||
| +				break; | ||||
| +			} | ||||
| +		} | ||||
| + | ||||
| +		info->control.rates[0].flags = rate_flags; | ||||
| +		info->control.rates[0].count = min_t(u8, rate_retries + 1, | ||||
| +						     local->hw.max_rate_tries); | ||||
| +	} | ||||
| + | ||||
|  	/* | ||||
|  	 * remove the radiotap header | ||||
|  	 * iterator->_max_length was sanity-checked against | ||||
| @@ -1819,7 +1887,7 @@ netdev_tx_t ieee80211_monitor_start_xmit | ||||
|  		      IEEE80211_TX_CTL_INJECTED; | ||||
|   | ||||
|  	/* process and remove the injection radiotap header */ | ||||
| -	if (!ieee80211_parse_tx_radiotap(skb)) | ||||
| +	if (!ieee80211_parse_tx_radiotap(local, skb)) | ||||
|  		goto fail; | ||||
|   | ||||
|  	rcu_read_lock(); | ||||
| @@ -1,317 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Fri, 5 Feb 2016 01:38:51 +0100 | ||||
| Subject: [PATCH] mac80211: add A-MSDU tx support | ||||
|  | ||||
| Requires software tx queueing support. frag_list support (for zero-copy) | ||||
| is optional. | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/include/net/mac80211.h | ||||
| +++ b/include/net/mac80211.h | ||||
| @@ -709,6 +709,7 @@ enum mac80211_tx_info_flags { | ||||
|   * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll | ||||
|   *	frame (PS-Poll or uAPSD). | ||||
|   * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information | ||||
| + * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame | ||||
|   * | ||||
|   * These flags are used in tx_info->control.flags. | ||||
|   */ | ||||
| @@ -716,6 +717,7 @@ enum mac80211_tx_control_flags { | ||||
|  	IEEE80211_TX_CTRL_PORT_CTRL_PROTO	= BIT(0), | ||||
|  	IEEE80211_TX_CTRL_PS_RESPONSE		= BIT(1), | ||||
|  	IEEE80211_TX_CTRL_RATE_INJECT		= BIT(2), | ||||
| +	IEEE80211_TX_CTRL_AMSDU			= BIT(3), | ||||
|  }; | ||||
|   | ||||
|  /* | ||||
| @@ -1728,6 +1730,7 @@ struct ieee80211_sta_rates { | ||||
|   *		  size is min(max_amsdu_len, 7935) bytes. | ||||
|   *	Both additional HT limits must be enforced by the low level driver. | ||||
|   *	This is defined by the spec (IEEE 802.11-2012 section 8.3.2.2 NOTE 2). | ||||
| + * @max_rc_amsdu_len: Maximum A-MSDU size in bytes recommended by rate control. | ||||
|   * @txq: per-TID data TX queues (if driver uses the TXQ abstraction) | ||||
|   */ | ||||
|  struct ieee80211_sta { | ||||
| @@ -1748,6 +1751,7 @@ struct ieee80211_sta { | ||||
|  	bool mfp; | ||||
|  	u8 max_amsdu_subframes; | ||||
|  	u16 max_amsdu_len; | ||||
| +	u16 max_rc_amsdu_len; | ||||
|   | ||||
|  	struct ieee80211_txq *txq[IEEE80211_NUM_TIDS]; | ||||
|   | ||||
| @@ -1961,6 +1965,15 @@ struct ieee80211_txq { | ||||
|   *	order and does not need to manage its own reorder buffer or BA session | ||||
|   *	timeout. | ||||
|   * | ||||
| + * @IEEE80211_HW_TX_AMSDU: Hardware (or driver) supports software aggregated | ||||
| + *	A-MSDU frames. Requires software tx queueing and fast-xmit support. | ||||
| + *	When not using minstrel/minstrel_ht rate control, the driver should | ||||
| + *	limit the maximum A-MSDU size based on the current tx rate by setting | ||||
| + *	max_rc_amsdu_len in struct ieee80211_sta. | ||||
| + * | ||||
| + * @IEEE80211_HW_TX_FRAG_LIST: Hardware (or driver) supports sending frag_list | ||||
| + *	skbs, needed for zero-copy software A-MSDU. | ||||
| + * | ||||
|   * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays | ||||
|   */ | ||||
|  enum ieee80211_hw_flags { | ||||
| @@ -1998,6 +2011,8 @@ enum ieee80211_hw_flags { | ||||
|  	IEEE80211_HW_BEACON_TX_STATUS, | ||||
|  	IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR, | ||||
|  	IEEE80211_HW_SUPPORTS_REORDERING_BUFFER, | ||||
| +	IEEE80211_HW_TX_AMSDU, | ||||
| +	IEEE80211_HW_TX_FRAG_LIST, | ||||
|   | ||||
|  	/* keep last, obviously */ | ||||
|  	NUM_IEEE80211_HW_FLAGS | ||||
| @@ -2070,6 +2085,9 @@ enum ieee80211_hw_flags { | ||||
|   *	size is smaller (an example is LinkSys WRT120N with FW v1.0.07 | ||||
|   *	build 002 Jun 18 2012). | ||||
|   * | ||||
| + * @max_tx_fragments: maximum number of tx buffers per (A)-MSDU, sum | ||||
| + *	of 1 + skb_shinfo(skb)->nr_frags for each skb in the frag_list. | ||||
| + * | ||||
|   * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX | ||||
|   *	(if %IEEE80211_HW_QUEUE_CONTROL is set) | ||||
|   * | ||||
| @@ -2124,6 +2142,7 @@ struct ieee80211_hw { | ||||
|  	u8 max_rate_tries; | ||||
|  	u8 max_rx_aggregation_subframes; | ||||
|  	u8 max_tx_aggregation_subframes; | ||||
| +	u8 max_tx_fragments; | ||||
|  	u8 offchannel_tx_hw_queue; | ||||
|  	u8 radiotap_mcs_details; | ||||
|  	u16 radiotap_vht_details; | ||||
| --- a/net/mac80211/agg-tx.c | ||||
| +++ b/net/mac80211/agg-tx.c | ||||
| @@ -935,6 +935,7 @@ void ieee80211_process_addba_resp(struct | ||||
|  				  size_t len) | ||||
|  { | ||||
|  	struct tid_ampdu_tx *tid_tx; | ||||
| +	struct ieee80211_txq *txq; | ||||
|  	u16 capab, tid; | ||||
|  	u8 buf_size; | ||||
|  	bool amsdu; | ||||
| @@ -945,6 +946,10 @@ void ieee80211_process_addba_resp(struct | ||||
|  	buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; | ||||
|  	buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes); | ||||
|   | ||||
| +	txq = sta->sta.txq[tid]; | ||||
| +	if (!amsdu && txq) | ||||
| +		set_bit(IEEE80211_TXQ_NO_AMSDU, &to_txq_info(txq)->flags); | ||||
| + | ||||
|  	mutex_lock(&sta->ampdu_mlme.mtx); | ||||
|   | ||||
|  	tid_tx = rcu_dereference_protected_tid_tx(sta, tid); | ||||
| --- a/net/mac80211/debugfs.c | ||||
| +++ b/net/mac80211/debugfs.c | ||||
| @@ -127,6 +127,8 @@ static const char *hw_flag_names[NUM_IEE | ||||
|  	FLAG(BEACON_TX_STATUS), | ||||
|  	FLAG(NEEDS_UNIQUE_STA_ADDR), | ||||
|  	FLAG(SUPPORTS_REORDERING_BUFFER), | ||||
| +	FLAG(TX_AMSDU), | ||||
| +	FLAG(TX_FRAG_LIST), | ||||
|   | ||||
|  	/* keep last for the build bug below */ | ||||
|  	(void *)0x1 | ||||
| --- a/net/mac80211/ieee80211_i.h | ||||
| +++ b/net/mac80211/ieee80211_i.h | ||||
| @@ -799,6 +799,7 @@ struct mac80211_qos_map { | ||||
|  enum txq_info_flags { | ||||
|  	IEEE80211_TXQ_STOP, | ||||
|  	IEEE80211_TXQ_AMPDU, | ||||
| +	IEEE80211_TXQ_NO_AMSDU, | ||||
|  }; | ||||
|   | ||||
|  struct txq_info { | ||||
| --- a/net/mac80211/tx.c | ||||
| +++ b/net/mac80211/tx.c | ||||
| @@ -1318,6 +1318,10 @@ struct sk_buff *ieee80211_tx_dequeue(str | ||||
|  out: | ||||
|  	spin_unlock_bh(&txqi->queue.lock); | ||||
|   | ||||
| +	if (skb && skb_has_frag_list(skb) && | ||||
| +	    !ieee80211_hw_check(&local->hw, TX_FRAG_LIST)) | ||||
| +		skb_linearize(skb); | ||||
| + | ||||
|  	return skb; | ||||
|  } | ||||
|  EXPORT_SYMBOL(ieee80211_tx_dequeue); | ||||
| @@ -2757,6 +2761,163 @@ void ieee80211_clear_fast_xmit(struct st | ||||
|  		kfree_rcu(fast_tx, rcu_head); | ||||
|  } | ||||
|   | ||||
| +static bool ieee80211_amsdu_realloc_pad(struct ieee80211_local *local, | ||||
| +					struct sk_buff *skb, int headroom, | ||||
| +					int *subframe_len) | ||||
| +{ | ||||
| +	int amsdu_len = *subframe_len + sizeof(struct ethhdr); | ||||
| +	int padding = (4 - amsdu_len) & 3; | ||||
| + | ||||
| +	if (skb_headroom(skb) < headroom || skb_tailroom(skb) < padding) { | ||||
| +		I802_DEBUG_INC(local->tx_expand_skb_head); | ||||
| + | ||||
| +		if (pskb_expand_head(skb, headroom, padding, GFP_ATOMIC)) { | ||||
| +			wiphy_debug(local->hw.wiphy, | ||||
| +				    "failed to reallocate TX buffer\n"); | ||||
| +			return false; | ||||
| +		} | ||||
| +	} | ||||
| + | ||||
| +	if (padding) { | ||||
| +		*subframe_len += padding; | ||||
| +		memset(skb_put(skb, padding), 0, padding); | ||||
| +	} | ||||
| + | ||||
| +	return true; | ||||
| +} | ||||
| + | ||||
| +static bool ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data *sdata, | ||||
| +					 struct ieee80211_fast_tx *fast_tx, | ||||
| +					 struct sk_buff *skb) | ||||
| +{ | ||||
| +	struct ieee80211_local *local = sdata->local; | ||||
| +	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||||
| +	struct ieee80211_hdr *hdr; | ||||
| +	struct ethhdr amsdu_hdr; | ||||
| +	int hdr_len = fast_tx->hdr_len - sizeof(rfc1042_header); | ||||
| +	int subframe_len = skb->len - hdr_len; | ||||
| +	void *data; | ||||
| +	u8 *qc; | ||||
| + | ||||
| +	if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) | ||||
| +		return false; | ||||
| + | ||||
| +	if (info->control.flags & IEEE80211_TX_CTRL_AMSDU) | ||||
| +		return true; | ||||
| + | ||||
| +	if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(amsdu_hdr), | ||||
| +					 &subframe_len)) | ||||
| +		return false; | ||||
| + | ||||
| +	amsdu_hdr.h_proto = cpu_to_be16(subframe_len); | ||||
| +	memcpy(amsdu_hdr.h_source, skb->data + fast_tx->sa_offs, ETH_ALEN); | ||||
| +	memcpy(amsdu_hdr.h_dest, skb->data + fast_tx->da_offs, ETH_ALEN); | ||||
| + | ||||
| +	data = skb_push(skb, sizeof(amsdu_hdr)); | ||||
| +	memmove(data, data + sizeof(amsdu_hdr), hdr_len); | ||||
| +	memcpy(data + hdr_len, &amsdu_hdr, sizeof(amsdu_hdr)); | ||||
| + | ||||
| +	hdr = data; | ||||
| +	qc = ieee80211_get_qos_ctl(hdr); | ||||
| +	*qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT; | ||||
| + | ||||
| +	info->control.flags |= IEEE80211_TX_CTRL_AMSDU; | ||||
| + | ||||
| +	return true; | ||||
| +} | ||||
| + | ||||
| +static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata, | ||||
| +				      struct sta_info *sta, | ||||
| +				      struct ieee80211_fast_tx *fast_tx, | ||||
| +				      struct sk_buff *skb) | ||||
| +{ | ||||
| +	struct ieee80211_local *local = sdata->local; | ||||
| +	u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; | ||||
| +	struct ieee80211_txq *txq = sta->sta.txq[tid]; | ||||
| +	struct txq_info *txqi; | ||||
| +	struct sk_buff **frag_tail, *head; | ||||
| +	int subframe_len = skb->len - ETH_ALEN; | ||||
| +	u8 max_subframes = sta->sta.max_amsdu_subframes; | ||||
| +	int max_frags = local->hw.max_tx_fragments; | ||||
| +	int max_amsdu_len = sta->sta.max_amsdu_len; | ||||
| +	__be16 len; | ||||
| +	void *data; | ||||
| +	bool ret = false; | ||||
| +	int n = 1, nfrags; | ||||
| + | ||||
| +	if (!ieee80211_hw_check(&local->hw, TX_AMSDU)) | ||||
| +		return false; | ||||
| + | ||||
| +	if (!txq) | ||||
| +		return false; | ||||
| + | ||||
| +	txqi = to_txq_info(txq); | ||||
| +	if (test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags)) | ||||
| +		return false; | ||||
| + | ||||
| +	if (sta->sta.max_rc_amsdu_len) | ||||
| +		max_amsdu_len = min_t(int, max_amsdu_len, | ||||
| +				      sta->sta.max_rc_amsdu_len); | ||||
| + | ||||
| +	spin_lock_bh(&txqi->queue.lock); | ||||
| + | ||||
| +	head = skb_peek_tail(&txqi->queue); | ||||
| +	if (!head) | ||||
| +		goto out; | ||||
| + | ||||
| +	if (skb->len + head->len > max_amsdu_len) | ||||
| +		goto out; | ||||
| + | ||||
| +	/* | ||||
| +	 * HT A-MPDU limits maximum MPDU size to 4095 bytes. Since aggregation | ||||
| +	 * sessions are started/stopped without txq flush, use the limit here | ||||
| +	 * to avoid having to de-aggregate later. | ||||
| +	 */ | ||||
| +	if (skb->len + head->len > 4095 && | ||||
| +	    !sta->sta.vht_cap.vht_supported) | ||||
| +		goto out; | ||||
| + | ||||
| +	if (!ieee80211_amsdu_prepare_head(sdata, fast_tx, head)) | ||||
| +		goto out; | ||||
| + | ||||
| +	nfrags = 1 + skb_shinfo(skb)->nr_frags; | ||||
| +	nfrags += 1 + skb_shinfo(head)->nr_frags; | ||||
| +	frag_tail = &skb_shinfo(head)->frag_list; | ||||
| +	while (*frag_tail) { | ||||
| +		nfrags += 1 + skb_shinfo(*frag_tail)->nr_frags; | ||||
| +		frag_tail = &(*frag_tail)->next; | ||||
| +		n++; | ||||
| +	} | ||||
| + | ||||
| +	if (max_subframes && n > max_subframes) | ||||
| +		goto out; | ||||
| + | ||||
| +	if (max_frags && nfrags > max_frags) | ||||
| +		goto out; | ||||
| + | ||||
| +	if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + 2, | ||||
| +					 &subframe_len)) | ||||
| +		return false; | ||||
| + | ||||
| +	ret = true; | ||||
| +	data = skb_push(skb, ETH_ALEN + 2); | ||||
| +	memmove(data, data + ETH_ALEN + 2, 2 * ETH_ALEN); | ||||
| + | ||||
| +	data += 2 * ETH_ALEN; | ||||
| +	len = cpu_to_be16(subframe_len); | ||||
| +	memcpy(data, &len, 2); | ||||
| +	memcpy(data + 2, rfc1042_header, sizeof(rfc1042_header)); | ||||
| + | ||||
| +	head->len += skb->len; | ||||
| +	head->data_len += skb->len; | ||||
| +	*frag_tail = skb; | ||||
| + | ||||
| +out: | ||||
| +	spin_unlock_bh(&txqi->queue.lock); | ||||
| + | ||||
| +	return ret; | ||||
| +} | ||||
| + | ||||
|  static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, | ||||
|  				struct net_device *dev, struct sta_info *sta, | ||||
|  				struct ieee80211_fast_tx *fast_tx, | ||||
| @@ -2811,6 +2972,10 @@ static bool ieee80211_xmit_fast(struct i | ||||
|   | ||||
|  	ieee80211_tx_stats(dev, skb->len + extra_head); | ||||
|   | ||||
| +	if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) && | ||||
| +	    ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb)) | ||||
| +		return true; | ||||
| + | ||||
|  	/* will not be crypto-handled beyond what we do here, so use false | ||||
|  	 * as the may-encrypt argument for the resize to not account for | ||||
|  	 * more room than we already have in 'extra_head' | ||||
| @@ -1,64 +0,0 @@ | ||||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> | ||||
| Date: Wed, 20 Jan 2016 16:46:04 +0100 | ||||
| Subject: [PATCH] brcmfmac: fix setting primary channel for 80 MHz width | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
|  | ||||
| First of all it changes the way we calculate primary channel offset. If | ||||
| we use e.g. 80 MHz channel with primary frequency 5180 MHz (which means | ||||
| center frequency is 5210 MHz) it makes sense to calculate primary offset | ||||
| as -30 MHz. | ||||
| Then it fixes values we compare primary_offset with. We were comparing | ||||
| offset in MHz against -2 or 2 which was resulting in picking a wrong | ||||
| primary channel. | ||||
|  | ||||
| Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | ||||
| @@ -247,7 +247,7 @@ static u16 chandef_to_chanspec(struct br | ||||
|  	brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n", | ||||
|  		  ch->chan->center_freq, ch->center_freq1, ch->width); | ||||
|  	ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1); | ||||
| -	primary_offset = ch->center_freq1 - ch->chan->center_freq; | ||||
| +	primary_offset = ch->chan->center_freq - ch->center_freq1; | ||||
|  	switch (ch->width) { | ||||
|  	case NL80211_CHAN_WIDTH_20: | ||||
|  	case NL80211_CHAN_WIDTH_20_NOHT: | ||||
| @@ -256,24 +256,21 @@ static u16 chandef_to_chanspec(struct br | ||||
|  		break; | ||||
|  	case NL80211_CHAN_WIDTH_40: | ||||
|  		ch_inf.bw = BRCMU_CHAN_BW_40; | ||||
| -		if (primary_offset < 0) | ||||
| +		if (primary_offset > 0) | ||||
|  			ch_inf.sb = BRCMU_CHAN_SB_U; | ||||
|  		else | ||||
|  			ch_inf.sb = BRCMU_CHAN_SB_L; | ||||
|  		break; | ||||
|  	case NL80211_CHAN_WIDTH_80: | ||||
|  		ch_inf.bw = BRCMU_CHAN_BW_80; | ||||
| -		if (primary_offset < 0) { | ||||
| -			if (primary_offset < -CH_10MHZ_APART) | ||||
| -				ch_inf.sb = BRCMU_CHAN_SB_UU; | ||||
| -			else | ||||
| -				ch_inf.sb = BRCMU_CHAN_SB_UL; | ||||
| -		} else { | ||||
| -			if (primary_offset > CH_10MHZ_APART) | ||||
| -				ch_inf.sb = BRCMU_CHAN_SB_LL; | ||||
| -			else | ||||
| -				ch_inf.sb = BRCMU_CHAN_SB_LU; | ||||
| -		} | ||||
| +		if (primary_offset == -30) | ||||
| +			ch_inf.sb = BRCMU_CHAN_SB_LL; | ||||
| +		else if (primary_offset == -10) | ||||
| +			ch_inf.sb = BRCMU_CHAN_SB_LU; | ||||
| +		else if (primary_offset == 10) | ||||
| +			ch_inf.sb = BRCMU_CHAN_SB_UL; | ||||
| +		else | ||||
| +			ch_inf.sb = BRCMU_CHAN_SB_UU; | ||||
|  		break; | ||||
|  	case NL80211_CHAN_WIDTH_80P80: | ||||
|  	case NL80211_CHAN_WIDTH_160: | ||||
| @@ -1,51 +0,0 @@ | ||||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> | ||||
| Date: Tue, 26 Jan 2016 17:57:01 +0100 | ||||
| Subject: [PATCH] brcmfmac: analyze descriptors of current component only | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
|  | ||||
| So far we were looking for address descriptors without a check for | ||||
| crossing current component border. In case of dealing with unsupported | ||||
| descriptor or descriptor missing at all the code would incorrectly get | ||||
| data from another component. | ||||
|  | ||||
| Consider this binary-described component from BCM4366 EROM: | ||||
| 4bf83b01	TAG==CI		CID==0x83b | ||||
| 20080201	TAG==CI		PORTS==0+1	WRAPPERS==0+1 | ||||
| 18400035	TAG==ADDR	SZ_SZD		TYPE_SLAVE | ||||
| 00050000 | ||||
| 18107085	TAG==ADDR	SZ_4K		TYPE_SWRAP | ||||
|  | ||||
| Driver was assigning invalid base address to this core: | ||||
| brcmfmac:  [6 ] core 0x83b:32 base 0x18109000 wrap 0x18107000 | ||||
| which came from totally different component defined in EROM: | ||||
| 43b36701	TAG==CI		CID==0x367 | ||||
| 00000201	TAG==CI		PORTS==0+1	WRAPPERS==0+0 | ||||
| 18109005	TAG==ADDR	SZ_4K		TYPE_SLAVE | ||||
|  | ||||
| This change will also allow us to support components without wrapper | ||||
| address in the future. | ||||
|  | ||||
| Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | ||||
| @@ -803,7 +803,14 @@ static int brcmf_chip_dmp_get_regaddr(st | ||||
|  				*eromaddr -= 4; | ||||
|  				return -EFAULT; | ||||
|  			} | ||||
| -		} while (desc != DMP_DESC_ADDRESS); | ||||
| +		} while (desc != DMP_DESC_ADDRESS && | ||||
| +			 desc != DMP_DESC_COMPONENT); | ||||
| + | ||||
| +		/* stop if we crossed current component border */ | ||||
| +		if (desc == DMP_DESC_COMPONENT) { | ||||
| +			*eromaddr -= 4; | ||||
| +			return 0; | ||||
| +		} | ||||
|   | ||||
|  		/* skip upper 32-bit address descriptor */ | ||||
|  		if (val & DMP_DESC_ADDRSIZE_GT32) | ||||
| @@ -1,28 +0,0 @@ | ||||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> | ||||
| Date: Tue, 26 Jan 2016 17:57:02 +0100 | ||||
| Subject: [PATCH] brcmfmac: allow storing PMU core without wrapper address | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
|  | ||||
| Separated PMU core can be found in new devices and should be used for | ||||
| accessing PMU registers (which were routed through ChipCommon so far). | ||||
| This core is one of exceptions that doesn't have or need wrapper address | ||||
| to be still safely accessible. | ||||
|  | ||||
| Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | ||||
| @@ -883,7 +883,8 @@ int brcmf_chip_dmp_erom_scan(struct brcm | ||||
|  		rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S; | ||||
|   | ||||
|  		/* need core with ports */ | ||||
| -		if (nmw + nsw == 0) | ||||
| +		if (nmw + nsw == 0 && | ||||
| +		    id != BCMA_CORE_PMU) | ||||
|  			continue; | ||||
|   | ||||
|  		/* try to obtain register address info */ | ||||
| @@ -1,43 +0,0 @@ | ||||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> | ||||
| Date: Tue, 26 Jan 2016 17:57:03 +0100 | ||||
| Subject: [PATCH] brcmfmac: read extended capabilities of ChipCommon core | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
|  | ||||
| This is an extra bitfield with info about some present hardware. | ||||
|  | ||||
| Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | ||||
| @@ -1025,6 +1025,9 @@ static int brcmf_chip_setup(struct brcmf | ||||
|  	/* get chipcommon capabilites */ | ||||
|  	pub->cc_caps = chip->ops->read32(chip->ctx, | ||||
|  					 CORE_CC_REG(base, capabilities)); | ||||
| +	pub->cc_caps_ext = chip->ops->read32(chip->ctx, | ||||
| +					     CORE_CC_REG(base, | ||||
| +							 capabilities_ext)); | ||||
|   | ||||
|  	/* get pmu caps & rev */ | ||||
|  	if (pub->cc_caps & CC_CAP_PMU) { | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h | ||||
| @@ -27,6 +27,7 @@ | ||||
|   * @chip: chip identifier. | ||||
|   * @chiprev: chip revision. | ||||
|   * @cc_caps: chipcommon core capabilities. | ||||
| + * @cc_caps_ext: chipcommon core extended capabilities. | ||||
|   * @pmucaps: PMU capabilities. | ||||
|   * @pmurev: PMU revision. | ||||
|   * @rambase: RAM base address (only applicable for ARM CR4 chips). | ||||
| @@ -38,6 +39,7 @@ struct brcmf_chip { | ||||
|  	u32 chip; | ||||
|  	u32 chiprev; | ||||
|  	u32 cc_caps; | ||||
| +	u32 cc_caps_ext; | ||||
|  	u32 pmucaps; | ||||
|  	u32 pmurev; | ||||
|  	u32 rambase; | ||||
| @@ -1,148 +0,0 @@ | ||||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> | ||||
| Date: Tue, 26 Jan 2016 17:57:04 +0100 | ||||
| Subject: [PATCH] brcmfmac: access PMU registers using standalone PMU core if | ||||
|  available | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
|  | ||||
| On recent Broadcom chipsets PMU is present as separated core and it | ||||
| can't be accessed using ChipCommon anymore as it fails with e.g.: | ||||
| [   18.198412] Unhandled fault: imprecise external abort (0x1406) at 0xb6da200f | ||||
|  | ||||
| Add a new helper function that will return a proper core that should be | ||||
| used for accessing PMU registers. | ||||
|  | ||||
| Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | ||||
| @@ -1014,6 +1014,7 @@ static int brcmf_chip_setup(struct brcmf | ||||
|  { | ||||
|  	struct brcmf_chip *pub; | ||||
|  	struct brcmf_core_priv *cc; | ||||
| +	struct brcmf_core *pmu; | ||||
|  	u32 base; | ||||
|  	u32 val; | ||||
|  	int ret = 0; | ||||
| @@ -1030,9 +1031,10 @@ static int brcmf_chip_setup(struct brcmf | ||||
|  							 capabilities_ext)); | ||||
|   | ||||
|  	/* get pmu caps & rev */ | ||||
| +	pmu = brcmf_chip_get_pmu(pub); /* after reading cc_caps_ext */ | ||||
|  	if (pub->cc_caps & CC_CAP_PMU) { | ||||
|  		val = chip->ops->read32(chip->ctx, | ||||
| -					CORE_CC_REG(base, pmucapabilities)); | ||||
| +					CORE_CC_REG(pmu->base, pmucapabilities)); | ||||
|  		pub->pmurev = val & PCAP_REV_MASK; | ||||
|  		pub->pmucaps = val; | ||||
|  	} | ||||
| @@ -1131,6 +1133,23 @@ struct brcmf_core *brcmf_chip_get_chipco | ||||
|  	return &cc->pub; | ||||
|  } | ||||
|   | ||||
| +struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub) | ||||
| +{ | ||||
| +	struct brcmf_core *cc = brcmf_chip_get_chipcommon(pub); | ||||
| +	struct brcmf_core *pmu; | ||||
| + | ||||
| +	/* See if there is separated PMU core available */ | ||||
| +	if (cc->rev >= 35 && | ||||
| +	    pub->cc_caps_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) { | ||||
| +		pmu = brcmf_chip_get_core(pub, BCMA_CORE_PMU); | ||||
| +		if (pmu) | ||||
| +			return pmu; | ||||
| +	} | ||||
| + | ||||
| +	/* Fallback to ChipCommon core for older hardware */ | ||||
| +	return cc; | ||||
| +} | ||||
| + | ||||
|  bool brcmf_chip_iscoreup(struct brcmf_core *pub) | ||||
|  { | ||||
|  	struct brcmf_core_priv *core; | ||||
| @@ -1301,6 +1320,7 @@ bool brcmf_chip_sr_capable(struct brcmf_ | ||||
|  { | ||||
|  	u32 base, addr, reg, pmu_cc3_mask = ~0; | ||||
|  	struct brcmf_chip_priv *chip; | ||||
| +	struct brcmf_core *pmu = brcmf_chip_get_pmu(pub); | ||||
|   | ||||
|  	brcmf_dbg(TRACE, "Enter\n"); | ||||
|   | ||||
| @@ -1320,9 +1340,9 @@ bool brcmf_chip_sr_capable(struct brcmf_ | ||||
|  	case BRCM_CC_4335_CHIP_ID: | ||||
|  	case BRCM_CC_4339_CHIP_ID: | ||||
|  		/* read PMU chipcontrol register 3 */ | ||||
| -		addr = CORE_CC_REG(base, chipcontrol_addr); | ||||
| +		addr = CORE_CC_REG(pmu->base, chipcontrol_addr); | ||||
|  		chip->ops->write32(chip->ctx, addr, 3); | ||||
| -		addr = CORE_CC_REG(base, chipcontrol_data); | ||||
| +		addr = CORE_CC_REG(pmu->base, chipcontrol_data); | ||||
|  		reg = chip->ops->read32(chip->ctx, addr); | ||||
|  		return (reg & pmu_cc3_mask) != 0; | ||||
|  	case BRCM_CC_43430_CHIP_ID: | ||||
| @@ -1330,12 +1350,12 @@ bool brcmf_chip_sr_capable(struct brcmf_ | ||||
|  		reg = chip->ops->read32(chip->ctx, addr); | ||||
|  		return reg != 0; | ||||
|  	default: | ||||
| -		addr = CORE_CC_REG(base, pmucapabilities_ext); | ||||
| +		addr = CORE_CC_REG(pmu->base, pmucapabilities_ext); | ||||
|  		reg = chip->ops->read32(chip->ctx, addr); | ||||
|  		if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0) | ||||
|  			return false; | ||||
|   | ||||
| -		addr = CORE_CC_REG(base, retention_ctl); | ||||
| +		addr = CORE_CC_REG(pmu->base, retention_ctl); | ||||
|  		reg = chip->ops->read32(chip->ctx, addr); | ||||
|  		return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK | | ||||
|  			       PMU_RCTL_LOGIC_DISABLE_MASK)) == 0; | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h | ||||
| @@ -85,6 +85,7 @@ struct brcmf_chip *brcmf_chip_attach(voi | ||||
|  void brcmf_chip_detach(struct brcmf_chip *chip); | ||||
|  struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid); | ||||
|  struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip); | ||||
| +struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub); | ||||
|  bool brcmf_chip_iscoreup(struct brcmf_core *core); | ||||
|  void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset); | ||||
|  void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset, | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | ||||
| @@ -3615,7 +3615,6 @@ brcmf_sdio_drivestrengthinit(struct brcm | ||||
|  	const struct sdiod_drive_str *str_tab = NULL; | ||||
|  	u32 str_mask; | ||||
|  	u32 str_shift; | ||||
| -	u32 base; | ||||
|  	u32 i; | ||||
|  	u32 drivestrength_sel = 0; | ||||
|  	u32 cc_data_temp; | ||||
| @@ -3658,14 +3657,15 @@ brcmf_sdio_drivestrengthinit(struct brcm | ||||
|  	} | ||||
|   | ||||
|  	if (str_tab != NULL) { | ||||
| +		struct brcmf_core *pmu = brcmf_chip_get_pmu(ci); | ||||
| + | ||||
|  		for (i = 0; str_tab[i].strength != 0; i++) { | ||||
|  			if (drivestrength >= str_tab[i].strength) { | ||||
|  				drivestrength_sel = str_tab[i].sel; | ||||
|  				break; | ||||
|  			} | ||||
|  		} | ||||
| -		base = brcmf_chip_get_chipcommon(ci)->base; | ||||
| -		addr = CORE_CC_REG(base, chipcontrol_addr); | ||||
| +		addr = CORE_CC_REG(pmu->base, chipcontrol_addr); | ||||
|  		brcmf_sdiod_regwl(sdiodev, addr, 1, NULL); | ||||
|  		cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL); | ||||
|  		cc_data_temp &= ~str_mask; | ||||
| @@ -3835,8 +3835,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdi | ||||
|  		goto fail; | ||||
|   | ||||
|  	/* set PMUControl so a backplane reset does PMU state reload */ | ||||
| -	reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base, | ||||
| -			       pmucontrol); | ||||
| +	reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol); | ||||
|  	reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err); | ||||
|  	if (err) | ||||
|  		goto fail; | ||||
| @@ -1,38 +0,0 @@ | ||||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> | ||||
| Date: Tue, 26 Jan 2016 17:57:05 +0100 | ||||
| Subject: [PATCH] brcmfmac: add support for 14e4:4365 PCI ID with BCM4366 | ||||
|  chipset | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
|  | ||||
| On Broadcom ARM routers BCM4366 cards are available with 14e4:4365 ID. | ||||
| Unfortunately this ID was already used by Broadcom for cards with | ||||
| BCM43142, a totally different chipset requiring SoftMAC driver. To avoid | ||||
| a conflict between brcmfmac and bcma use more specific ID entry with | ||||
| subvendor and subdevice specified. | ||||
|  | ||||
| Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | ||||
| @@ -1951,6 +1951,9 @@ static const struct dev_pm_ops brcmf_pci | ||||
|   | ||||
|  #define BRCMF_PCIE_DEVICE(dev_id)	{ BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\ | ||||
|  	PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } | ||||
| +#define BRCMF_PCIE_DEVICE_SUB(dev_id, subvend, subdev)	{ \ | ||||
| +	BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\ | ||||
| +	subvend, subdev, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } | ||||
|   | ||||
|  static struct pci_device_id brcmf_pcie_devid_table[] = { | ||||
|  	BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID), | ||||
| @@ -1966,6 +1969,7 @@ static struct pci_device_id brcmf_pcie_d | ||||
|  	BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID), | ||||
|  	BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID), | ||||
|  	BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID), | ||||
| +	BRCMF_PCIE_DEVICE_SUB(0x4365, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4365), | ||||
|  	BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID), | ||||
|  	BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID), | ||||
|  	BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID), | ||||
| @@ -1,32 +0,0 @@ | ||||
| From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> | ||||
| Date: Sun, 31 Jan 2016 12:14:34 +0100 | ||||
| Subject: [PATCH] brcmfmac: treat NULL character in NVRAM as separator | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
|  | ||||
| Platform NVRAM (stored on a flash partition) has entries separated by a | ||||
| NULL (\0) char. Our parsing code switches from VALUE state to IDLE | ||||
| whenever it meets a NULL (\0). When that happens our IDLE handler should | ||||
| simply consume it and analyze whatever is placed ahead. | ||||
|  | ||||
| This fixes harmless warnings spamming debugging output: | ||||
| [  155.165624] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=20: ignoring invalid character | ||||
| [  155.180806] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=44: ignoring invalid character | ||||
| [  155.195971] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=63: ignoring invalid character | ||||
|  | ||||
| Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||
| @@ -93,7 +93,7 @@ static enum nvram_parser_state brcmf_nvr | ||||
|  	c = nvp->data[nvp->pos]; | ||||
|  	if (c == '\n') | ||||
|  		return COMMENT; | ||||
| -	if (is_whitespace(c)) | ||||
| +	if (is_whitespace(c) || c == '\0') | ||||
|  		goto proceed; | ||||
|  	if (c == '#') | ||||
|  		return COMMENT; | ||||
| @@ -1,41 +0,0 @@ | ||||
| From: Sjoerd Simons <sjoerd.simons@collabora.co.uk> | ||||
| Date: Mon, 25 Jan 2016 11:47:29 +0100 | ||||
| Subject: [PATCH] brcmfmac: sdio: Increase the default timeouts a bit | ||||
|  | ||||
| On a Radxa Rock2 board with a Ampak AP6335 (Broadcom 4339 core) it seems | ||||
| the card responds very quickly most of the time, unfortunately during | ||||
| initialisation it sometimes seems to take just a bit over 2 seconds to | ||||
| respond. | ||||
|  | ||||
| This results intialization failing with message like: | ||||
|   brcmf_c_preinit_dcmds: Retreiving cur_etheraddr failed, -52 | ||||
|   brcmf_bus_start: failed: -52 | ||||
|   brcmf_sdio_firmware_callback: dongle is not responding | ||||
|  | ||||
| Increasing the timeout to allow for a bit more headroom allows the | ||||
| card to initialize reliably. | ||||
|  | ||||
| A quick search online after diagnosing/fixing this showed that Google | ||||
| has a similar patch in their ChromeOS tree, so this doesn't seem | ||||
| specific to the board I'm using. | ||||
|  | ||||
| Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk> | ||||
| Reviewed-by: Julian Calaby <julian.calaby@gmail.com> | ||||
| Acked-by: Arend van Spriel <arend@broadcom.com> | ||||
| Reviewed-by: Douglas Anderson <dianders@chromium.org> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | ||||
| @@ -45,8 +45,8 @@ | ||||
|  #include "chip.h" | ||||
|  #include "firmware.h" | ||||
|   | ||||
| -#define DCMD_RESP_TIMEOUT	msecs_to_jiffies(2000) | ||||
| -#define CTL_DONE_TIMEOUT	msecs_to_jiffies(2000) | ||||
| +#define DCMD_RESP_TIMEOUT	msecs_to_jiffies(2500) | ||||
| +#define CTL_DONE_TIMEOUT	msecs_to_jiffies(2500) | ||||
|   | ||||
|  #ifdef DEBUG | ||||
|   | ||||
| @@ -1,87 +0,0 @@ | ||||
| From: Miaoqing Pan <miaoqing@codeaurora.org> | ||||
| Date: Fri, 5 Feb 2016 09:45:50 +0800 | ||||
| Subject: [PATCH] ath9k: make NF load complete quickly and reliably | ||||
|  | ||||
| Make NF load complete quickly and reliably. NF load execution | ||||
| is delayed by HW to end of frame if frame Rx or Tx is ongoing. | ||||
| Increasing timeout to max frame duration. If NF cal is ongoing | ||||
| before NF load, stop it before load, and restart it afterwards. | ||||
|  | ||||
| Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/ath/ath9k/calib.c | ||||
| +++ b/drivers/net/wireless/ath/ath9k/calib.c | ||||
| @@ -241,6 +241,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s | ||||
|  	u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; | ||||
|  	struct ath_common *common = ath9k_hw_common(ah); | ||||
|  	s16 default_nf = ath9k_hw_get_default_nf(ah, chan); | ||||
| +	u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL); | ||||
|   | ||||
|  	if (ah->caldata) | ||||
|  		h = ah->caldata->nfCalHist; | ||||
| @@ -264,6 +265,16 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s | ||||
|  	} | ||||
|   | ||||
|  	/* | ||||
| +	 * stop NF cal if ongoing to ensure NF load completes immediately | ||||
| +	 * (or after end rx/tx frame if ongoing) | ||||
| +	 */ | ||||
| +	if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) { | ||||
| +		REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); | ||||
| +		REG_RMW_BUFFER_FLUSH(ah); | ||||
| +		ENABLE_REG_RMW_BUFFER(ah); | ||||
| +	} | ||||
| + | ||||
| +	/* | ||||
|  	 * Load software filtered NF value into baseband internal minCCApwr | ||||
|  	 * variable. | ||||
|  	 */ | ||||
| @@ -276,18 +287,33 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s | ||||
|   | ||||
|  	/* | ||||
|  	 * Wait for load to complete, should be fast, a few 10s of us. | ||||
| -	 * The max delay was changed from an original 250us to 10000us | ||||
| -	 * since 250us often results in NF load timeout and causes deaf | ||||
| -	 * condition during stress testing 12/12/2009 | ||||
| +	 * The max delay was changed from an original 250us to 22.2 msec. | ||||
| +	 * This would increase timeout to the longest possible frame | ||||
| +	 * (11n max length 22.1 msec) | ||||
|  	 */ | ||||
| -	for (j = 0; j < 10000; j++) { | ||||
| +	for (j = 0; j < 22200; j++) { | ||||
|  		if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & | ||||
| -		     AR_PHY_AGC_CONTROL_NF) == 0) | ||||
| +			      AR_PHY_AGC_CONTROL_NF) == 0) | ||||
|  			break; | ||||
|  		udelay(10); | ||||
|  	} | ||||
|   | ||||
|  	/* | ||||
| +	 * Restart NF so it can continue. | ||||
| +	 */ | ||||
| +	if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) { | ||||
| +		ENABLE_REG_RMW_BUFFER(ah); | ||||
| +		if (bb_agc_ctl & AR_PHY_AGC_CONTROL_ENABLE_NF) | ||||
| +			REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, | ||||
| +				    AR_PHY_AGC_CONTROL_ENABLE_NF); | ||||
| +		if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NO_UPDATE_NF) | ||||
| +			REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, | ||||
| +				    AR_PHY_AGC_CONTROL_NO_UPDATE_NF); | ||||
| +		REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); | ||||
| +		REG_RMW_BUFFER_FLUSH(ah); | ||||
| +	} | ||||
| + | ||||
| +	/* | ||||
|  	 * We timed out waiting for the noisefloor to load, probably due to an | ||||
|  	 * in-progress rx. Simply return here and allow the load plenty of time | ||||
|  	 * to complete before the next calibration interval.  We need to avoid | ||||
| @@ -296,7 +322,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s | ||||
|  	 * here, the baseband nf cal will just be capped by our present | ||||
|  	 * noisefloor until the next calibration timer. | ||||
|  	 */ | ||||
| -	if (j == 10000) { | ||||
| +	if (j == 22200) { | ||||
|  		ath_dbg(common, ANY, | ||||
|  			"Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n", | ||||
|  			REG_READ(ah, AR_PHY_AGC_CONTROL)); | ||||
| @@ -1,54 +0,0 @@ | ||||
| From: Henning Rogge <hrogge@gmail.com> | ||||
| Date: Wed, 3 Feb 2016 13:58:36 +0100 | ||||
| Subject: [PATCH] mac80211: Remove MPP table entries with MPath | ||||
|  | ||||
| Make the mesh_path_del() function remove all mpp table entries | ||||
| that are proxied by the removed mesh path. | ||||
|  | ||||
| Acked-by: Bob Copeland <me@bobcopeland.com> | ||||
| Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de> | ||||
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/mesh_pathtbl.c | ||||
| +++ b/net/mac80211/mesh_pathtbl.c | ||||
| @@ -835,6 +835,29 @@ void mesh_path_flush_by_nexthop(struct s | ||||
|  	rcu_read_unlock(); | ||||
|  } | ||||
|   | ||||
| +static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata, | ||||
| +			       const u8 *proxy) | ||||
| +{ | ||||
| +	struct mesh_table *tbl; | ||||
| +	struct mesh_path *mpp; | ||||
| +	struct mpath_node *node; | ||||
| +	int i; | ||||
| + | ||||
| +	rcu_read_lock(); | ||||
| +	read_lock_bh(&pathtbl_resize_lock); | ||||
| +	tbl = resize_dereference_mpp_paths(); | ||||
| +	for_each_mesh_entry(tbl, node, i) { | ||||
| +		mpp = node->mpath; | ||||
| +		if (ether_addr_equal(mpp->mpp, proxy)) { | ||||
| +			spin_lock(&tbl->hashwlock[i]); | ||||
| +			__mesh_path_del(tbl, node); | ||||
| +			spin_unlock(&tbl->hashwlock[i]); | ||||
| +		} | ||||
| +	} | ||||
| +	read_unlock_bh(&pathtbl_resize_lock); | ||||
| +	rcu_read_unlock(); | ||||
| +} | ||||
| + | ||||
|  static void table_flush_by_iface(struct mesh_table *tbl, | ||||
|  				 struct ieee80211_sub_if_data *sdata) | ||||
|  { | ||||
| @@ -892,6 +915,9 @@ int mesh_path_del(struct ieee80211_sub_i | ||||
|  	int hash_idx; | ||||
|  	int err = 0; | ||||
|   | ||||
| +	/* flush relevant mpp entries first */ | ||||
| +	mpp_flush_by_proxy(sdata, addr); | ||||
| + | ||||
|  	read_lock_bh(&pathtbl_resize_lock); | ||||
|  	tbl = resize_dereference_mesh_paths(); | ||||
|  	hash_idx = mesh_table_hash(addr, sdata, tbl); | ||||
| @@ -1,104 +0,0 @@ | ||||
| From: Henning Rogge <hrogge@gmail.com> | ||||
| Date: Wed, 3 Feb 2016 13:58:37 +0100 | ||||
| Subject: [PATCH] mac80211: let unused MPP table entries timeout | ||||
|  | ||||
| Remember the last time when a mpp table entry is used for | ||||
| rx or tx and remove them after MESH_PATH_EXPIRE time. | ||||
|  | ||||
| Acked-by: Bob Copeland <me@bobcopeland.com> | ||||
| Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de> | ||||
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/mesh_pathtbl.c | ||||
| +++ b/net/mac80211/mesh_pathtbl.c | ||||
| @@ -942,6 +942,46 @@ enddel: | ||||
|  } | ||||
|   | ||||
|  /** | ||||
| + * mpp_path_del - delete a mesh proxy path from the table | ||||
| + * | ||||
| + * @addr: addr address (ETH_ALEN length) | ||||
| + * @sdata: local subif | ||||
| + * | ||||
| + * Returns: 0 if successful | ||||
| + */ | ||||
| +static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) | ||||
| +{ | ||||
| +	struct mesh_table *tbl; | ||||
| +	struct mesh_path *mpath; | ||||
| +	struct mpath_node *node; | ||||
| +	struct hlist_head *bucket; | ||||
| +	int hash_idx; | ||||
| +	int err = 0; | ||||
| + | ||||
| +	read_lock_bh(&pathtbl_resize_lock); | ||||
| +	tbl = resize_dereference_mpp_paths(); | ||||
| +	hash_idx = mesh_table_hash(addr, sdata, tbl); | ||||
| +	bucket = &tbl->hash_buckets[hash_idx]; | ||||
| + | ||||
| +	spin_lock(&tbl->hashwlock[hash_idx]); | ||||
| +	hlist_for_each_entry(node, bucket, list) { | ||||
| +		mpath = node->mpath; | ||||
| +		if (mpath->sdata == sdata && | ||||
| +		    ether_addr_equal(addr, mpath->dst)) { | ||||
| +			__mesh_path_del(tbl, node); | ||||
| +			goto enddel; | ||||
| +		} | ||||
| +	} | ||||
| + | ||||
| +	err = -ENXIO; | ||||
| +enddel: | ||||
| +	mesh_paths_generation++; | ||||
| +	spin_unlock(&tbl->hashwlock[hash_idx]); | ||||
| +	read_unlock_bh(&pathtbl_resize_lock); | ||||
| +	return err; | ||||
| +} | ||||
| + | ||||
| +/** | ||||
|   * mesh_path_tx_pending - sends pending frames in a mesh path queue | ||||
|   * | ||||
|   * @mpath: mesh path to activate | ||||
| @@ -1157,6 +1197,17 @@ void mesh_path_expire(struct ieee80211_s | ||||
|  		     time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) | ||||
|  			mesh_path_del(mpath->sdata, mpath->dst); | ||||
|  	} | ||||
| + | ||||
| +	tbl = rcu_dereference(mpp_paths); | ||||
| +	for_each_mesh_entry(tbl, node, i) { | ||||
| +		if (node->mpath->sdata != sdata) | ||||
| +			continue; | ||||
| +		mpath = node->mpath; | ||||
| +		if ((!(mpath->flags & MESH_PATH_FIXED)) && | ||||
| +		    time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) | ||||
| +			mpp_path_del(mpath->sdata, mpath->dst); | ||||
| +	} | ||||
| + | ||||
|  	rcu_read_unlock(); | ||||
|  } | ||||
|   | ||||
| --- a/net/mac80211/rx.c | ||||
| +++ b/net/mac80211/rx.c | ||||
| @@ -2291,6 +2291,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80 | ||||
|  			spin_lock_bh(&mppath->state_lock); | ||||
|  			if (!ether_addr_equal(mppath->mpp, mpp_addr)) | ||||
|  				memcpy(mppath->mpp, mpp_addr, ETH_ALEN); | ||||
| +			mppath->exp_time = jiffies; | ||||
|  			spin_unlock_bh(&mppath->state_lock); | ||||
|  		} | ||||
|  		rcu_read_unlock(); | ||||
| --- a/net/mac80211/tx.c | ||||
| +++ b/net/mac80211/tx.c | ||||
| @@ -2171,8 +2171,11 @@ static struct sk_buff *ieee80211_build_h | ||||
|  					mpp_lookup = true; | ||||
|  			} | ||||
|   | ||||
| -			if (mpp_lookup) | ||||
| +			if (mpp_lookup) { | ||||
|  				mppath = mpp_path_lookup(sdata, skb->data); | ||||
| +				if (mppath) | ||||
| +					mppath->exp_time = jiffies; | ||||
| +			} | ||||
|   | ||||
|  			if (mppath && mpath) | ||||
|  				mesh_path_del(mpath->sdata, mpath->dst); | ||||
| @@ -1,143 +0,0 @@ | ||||
| From: Henning Rogge <hrogge@gmail.com> | ||||
| Date: Wed, 3 Feb 2016 13:58:38 +0100 | ||||
| Subject: [PATCH] mac80211: Unify mesh and mpp path removal function | ||||
|  | ||||
| mpp_path_del() and mesh_path_del() are mostly the same function. | ||||
| Move common code into a new static function. | ||||
|  | ||||
| Acked-by: Bob Copeland <me@bobcopeland.com> | ||||
| Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de> | ||||
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/mesh_pathtbl.c | ||||
| +++ b/net/mac80211/mesh_pathtbl.c | ||||
| @@ -55,16 +55,21 @@ int mpp_paths_generation; | ||||
|  static DEFINE_RWLOCK(pathtbl_resize_lock); | ||||
|   | ||||
|   | ||||
| +static inline struct mesh_table *resize_dereference_paths( | ||||
| +	struct mesh_table __rcu *table) | ||||
| +{ | ||||
| +	return rcu_dereference_protected(table, | ||||
| +					lockdep_is_held(&pathtbl_resize_lock)); | ||||
| +} | ||||
| + | ||||
|  static inline struct mesh_table *resize_dereference_mesh_paths(void) | ||||
|  { | ||||
| -	return rcu_dereference_protected(mesh_paths, | ||||
| -		lockdep_is_held(&pathtbl_resize_lock)); | ||||
| +	return resize_dereference_paths(mesh_paths); | ||||
|  } | ||||
|   | ||||
|  static inline struct mesh_table *resize_dereference_mpp_paths(void) | ||||
|  { | ||||
| -	return rcu_dereference_protected(mpp_paths, | ||||
| -		lockdep_is_held(&pathtbl_resize_lock)); | ||||
| +	return resize_dereference_paths(mpp_paths); | ||||
|  } | ||||
|   | ||||
|  /* | ||||
| @@ -899,14 +904,17 @@ void mesh_path_flush_by_iface(struct iee | ||||
|  } | ||||
|   | ||||
|  /** | ||||
| - * mesh_path_del - delete a mesh path from the table | ||||
| + * table_path_del - delete a path from the mesh or mpp table | ||||
|   * | ||||
| - * @addr: dst address (ETH_ALEN length) | ||||
| + * @tbl: mesh or mpp path table | ||||
|   * @sdata: local subif | ||||
| + * @addr: dst address (ETH_ALEN length) | ||||
|   * | ||||
|   * Returns: 0 if successful | ||||
|   */ | ||||
| -int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) | ||||
| +static int table_path_del(struct mesh_table __rcu *rcu_tbl, | ||||
| +			  struct ieee80211_sub_if_data *sdata, | ||||
| +			  const u8 *addr) | ||||
|  { | ||||
|  	struct mesh_table *tbl; | ||||
|  	struct mesh_path *mpath; | ||||
| @@ -915,11 +923,7 @@ int mesh_path_del(struct ieee80211_sub_i | ||||
|  	int hash_idx; | ||||
|  	int err = 0; | ||||
|   | ||||
| -	/* flush relevant mpp entries first */ | ||||
| -	mpp_flush_by_proxy(sdata, addr); | ||||
| - | ||||
| -	read_lock_bh(&pathtbl_resize_lock); | ||||
| -	tbl = resize_dereference_mesh_paths(); | ||||
| +	tbl = resize_dereference_paths(rcu_tbl); | ||||
|  	hash_idx = mesh_table_hash(addr, sdata, tbl); | ||||
|  	bucket = &tbl->hash_buckets[hash_idx]; | ||||
|   | ||||
| @@ -935,9 +939,30 @@ int mesh_path_del(struct ieee80211_sub_i | ||||
|   | ||||
|  	err = -ENXIO; | ||||
|  enddel: | ||||
| -	mesh_paths_generation++; | ||||
|  	spin_unlock(&tbl->hashwlock[hash_idx]); | ||||
| +	return err; | ||||
| +} | ||||
| + | ||||
| +/** | ||||
| + * mesh_path_del - delete a mesh path from the table | ||||
| + * | ||||
| + * @addr: dst address (ETH_ALEN length) | ||||
| + * @sdata: local subif | ||||
| + * | ||||
| + * Returns: 0 if successful | ||||
| + */ | ||||
| +int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) | ||||
| +{ | ||||
| +	int err = 0; | ||||
| + | ||||
| +	/* flush relevant mpp entries first */ | ||||
| +	mpp_flush_by_proxy(sdata, addr); | ||||
| + | ||||
| +	read_lock_bh(&pathtbl_resize_lock); | ||||
| +	err = table_path_del(mesh_paths, sdata, addr); | ||||
| +	mesh_paths_generation++; | ||||
|  	read_unlock_bh(&pathtbl_resize_lock); | ||||
| + | ||||
|  	return err; | ||||
|  } | ||||
|   | ||||
| @@ -951,33 +976,13 @@ enddel: | ||||
|   */ | ||||
|  static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) | ||||
|  { | ||||
| -	struct mesh_table *tbl; | ||||
| -	struct mesh_path *mpath; | ||||
| -	struct mpath_node *node; | ||||
| -	struct hlist_head *bucket; | ||||
| -	int hash_idx; | ||||
|  	int err = 0; | ||||
|   | ||||
|  	read_lock_bh(&pathtbl_resize_lock); | ||||
| -	tbl = resize_dereference_mpp_paths(); | ||||
| -	hash_idx = mesh_table_hash(addr, sdata, tbl); | ||||
| -	bucket = &tbl->hash_buckets[hash_idx]; | ||||
| - | ||||
| -	spin_lock(&tbl->hashwlock[hash_idx]); | ||||
| -	hlist_for_each_entry(node, bucket, list) { | ||||
| -		mpath = node->mpath; | ||||
| -		if (mpath->sdata == sdata && | ||||
| -		    ether_addr_equal(addr, mpath->dst)) { | ||||
| -			__mesh_path_del(tbl, node); | ||||
| -			goto enddel; | ||||
| -		} | ||||
| -	} | ||||
| - | ||||
| -	err = -ENXIO; | ||||
| -enddel: | ||||
| -	mesh_paths_generation++; | ||||
| -	spin_unlock(&tbl->hashwlock[hash_idx]); | ||||
| +	err = table_path_del(mpp_paths, sdata, addr); | ||||
| +	mpp_paths_generation++; | ||||
|  	read_unlock_bh(&pathtbl_resize_lock); | ||||
| + | ||||
|  	return err; | ||||
|  } | ||||
|   | ||||
| @@ -1,51 +0,0 @@ | ||||
| From: Sven Eckelmann <sven.eckelmann@open-mesh.com> | ||||
| Date: Tue, 2 Feb 2016 08:12:26 +0100 | ||||
| Subject: [PATCH] mac80211: minstrel: Change expected throughput unit back to | ||||
|  Kbps | ||||
|  | ||||
| The change from cur_tp to the function | ||||
| minstrel_get_tp_avg/minstrel_ht_get_tp_avg changed the unit used for the | ||||
| current throughput. For example in minstrel_ht the correct | ||||
| conversion between them would be: | ||||
|  | ||||
|     mrs->cur_tp / 10 == minstrel_ht_get_tp_avg(..). | ||||
|  | ||||
| This factor 10 must also be included in the calculation of | ||||
| minstrel_get_expected_throughput and minstrel_ht_get_expected_throughput to | ||||
| return values with the unit [Kbps] instead of [10Kbps]. Otherwise routing | ||||
| algorithms like B.A.T.M.A.N. V will make incorrect decision based on these | ||||
| values. Its kernel based implementation expects expected_throughput always | ||||
| to have the unit [Kbps] and not sometimes [10Kbps] and sometimes [Kbps]. | ||||
|  | ||||
| The same requirement has iw or olsrdv2's nl80211 based statistics module | ||||
| which retrieve the same data via NL80211_STA_INFO_TX_BITRATE. | ||||
|  | ||||
| Cc: stable@vger.kernel.org | ||||
| Fixes: 6a27b2c40b48 ("mac80211: restructure per-rate throughput calculation into function") | ||||
| Signed-off-by: Sven Eckelmann <sven@open-mesh.com> | ||||
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/rc80211_minstrel.c | ||||
| +++ b/net/mac80211/rc80211_minstrel.c | ||||
| @@ -711,7 +711,7 @@ static u32 minstrel_get_expected_through | ||||
|  	 * computing cur_tp | ||||
|  	 */ | ||||
|  	tmp_mrs = &mi->r[idx].stats; | ||||
| -	tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma); | ||||
| +	tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma) * 10; | ||||
|  	tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024; | ||||
|   | ||||
|  	return tmp_cur_tp; | ||||
| --- a/net/mac80211/rc80211_minstrel_ht.c | ||||
| +++ b/net/mac80211/rc80211_minstrel_ht.c | ||||
| @@ -1335,7 +1335,8 @@ static u32 minstrel_ht_get_expected_thro | ||||
|  	prob = mi->groups[i].rates[j].prob_ewma; | ||||
|   | ||||
|  	/* convert tp_avg from pkt per second in kbps */ | ||||
| -	tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * AVG_PKT_SIZE * 8 / 1024; | ||||
| +	tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * 10; | ||||
| +	tp_avg = tp_avg * AVG_PKT_SIZE * 8 / 1024; | ||||
|   | ||||
|  	return tp_avg; | ||||
|  } | ||||
| @@ -1,307 +0,0 @@ | ||||
| From: Hante Meuleman <meuleman@broadcom.com> | ||||
| Date: Sun, 7 Feb 2016 18:08:24 +0100 | ||||
| Subject: [PATCH] brcmfmac: Increase nr of supported flowrings. | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
|  | ||||
| New generation devices have firmware which has more than 256 flowrings. | ||||
| E.g. following debugging message comes from 14e4:4365 BCM4366: | ||||
| [  194.606245] brcmfmac: brcmf_pcie_init_ringbuffers Nr of flowrings is 264 | ||||
|  | ||||
| At various code places (related to flowrings) we were using u8 which | ||||
| could lead to storing wrong number or infinite loops when indexing with | ||||
| this type. This issue was quite easy to spot in brcmf_flowring_detach | ||||
| where it led to infinite loop e.g. on failed initialization. | ||||
|  | ||||
| This patch switches code to proper types and increases the maximum | ||||
| number of supported flowrings to 512. | ||||
|  | ||||
| Originally this change was sent in September 2015, but back it was | ||||
| causing a regression on BCM43602 resulting in: | ||||
| Unable to handle kernel NULL pointer dereference at virtual address ... | ||||
|  | ||||
| The reason for this regression was missing update (s/u8/u16) of struct | ||||
| brcmf_flowring_ring. This problem was handled in 9f64df9 ("brcmfmac: Fix | ||||
| bug in flowring management."). Starting with that it's safe to apply | ||||
| this original patch as it doesn't cause a regression anymore. | ||||
|  | ||||
| This patch fixes an infinite loop on BCM4366 which is supported since | ||||
| 4.4 so it makes sense to apply it to stable 4.4+. | ||||
|  | ||||
| Cc: <stable@vger.kernel.org> # 4.4+ | ||||
| Reviewed-by: Arend Van Spriel <arend@broadcom.com> | ||||
| Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> | ||||
| Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> | ||||
| Signed-off-by: Hante Meuleman <meuleman@broadcom.com> | ||||
| Signed-off-by: Arend van Spriel <arend@broadcom.com> | ||||
| Signed-off-by: Rafał Miłecki <zajec5@gmail.com> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c | ||||
| @@ -32,7 +32,7 @@ | ||||
|  #define BRCMF_FLOWRING_LOW		(BRCMF_FLOWRING_HIGH - 256) | ||||
|  #define BRCMF_FLOWRING_INVALID_IFIDX	0xff | ||||
|   | ||||
| -#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16) | ||||
| +#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] * 2 + fifo + ifidx * 16) | ||||
|  #define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16) | ||||
|   | ||||
|  static const u8 brcmf_flowring_prio2fifo[] = { | ||||
| @@ -68,7 +68,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f | ||||
|  			  u8 prio, u8 ifidx) | ||||
|  { | ||||
|  	struct brcmf_flowring_hash *hash; | ||||
| -	u8 hash_idx; | ||||
| +	u16 hash_idx; | ||||
|  	u32 i; | ||||
|  	bool found; | ||||
|  	bool sta; | ||||
| @@ -88,6 +88,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f | ||||
|  	} | ||||
|  	hash_idx =  sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) : | ||||
|  			  BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx); | ||||
| +	hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); | ||||
|  	found = false; | ||||
|  	hash = flow->hash; | ||||
|  	for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { | ||||
| @@ -98,6 +99,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f | ||||
|  			break; | ||||
|  		} | ||||
|  		hash_idx++; | ||||
| +		hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); | ||||
|  	} | ||||
|  	if (found) | ||||
|  		return hash[hash_idx].flowid; | ||||
| @@ -111,7 +113,7 @@ u32 brcmf_flowring_create(struct brcmf_f | ||||
|  { | ||||
|  	struct brcmf_flowring_ring *ring; | ||||
|  	struct brcmf_flowring_hash *hash; | ||||
| -	u8 hash_idx; | ||||
| +	u16 hash_idx; | ||||
|  	u32 i; | ||||
|  	bool found; | ||||
|  	u8 fifo; | ||||
| @@ -131,6 +133,7 @@ u32 brcmf_flowring_create(struct brcmf_f | ||||
|  	} | ||||
|  	hash_idx =  sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) : | ||||
|  			  BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx); | ||||
| +	hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); | ||||
|  	found = false; | ||||
|  	hash = flow->hash; | ||||
|  	for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { | ||||
| @@ -140,6 +143,7 @@ u32 brcmf_flowring_create(struct brcmf_f | ||||
|  			break; | ||||
|  		} | ||||
|  		hash_idx++; | ||||
| +		hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); | ||||
|  	} | ||||
|  	if (found) { | ||||
|  		for (i = 0; i < flow->nrofrings; i++) { | ||||
| @@ -169,7 +173,7 @@ u32 brcmf_flowring_create(struct brcmf_f | ||||
|  } | ||||
|   | ||||
|   | ||||
| -u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid) | ||||
| +u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid) | ||||
|  { | ||||
|  	struct brcmf_flowring_ring *ring; | ||||
|   | ||||
| @@ -179,7 +183,7 @@ u8 brcmf_flowring_tid(struct brcmf_flowr | ||||
|  } | ||||
|   | ||||
|   | ||||
| -static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid, | ||||
| +static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid, | ||||
|  				 bool blocked) | ||||
|  { | ||||
|  	struct brcmf_flowring_ring *ring; | ||||
| @@ -228,10 +232,10 @@ static void brcmf_flowring_block(struct | ||||
|  } | ||||
|   | ||||
|   | ||||
| -void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid) | ||||
| +void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid) | ||||
|  { | ||||
|  	struct brcmf_flowring_ring *ring; | ||||
| -	u8 hash_idx; | ||||
| +	u16 hash_idx; | ||||
|  	struct sk_buff *skb; | ||||
|   | ||||
|  	ring = flow->rings[flowid]; | ||||
| @@ -253,7 +257,7 @@ void brcmf_flowring_delete(struct brcmf_ | ||||
|  } | ||||
|   | ||||
|   | ||||
| -u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, | ||||
| +u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid, | ||||
|  			   struct sk_buff *skb) | ||||
|  { | ||||
|  	struct brcmf_flowring_ring *ring; | ||||
| @@ -279,7 +283,7 @@ u32 brcmf_flowring_enqueue(struct brcmf_ | ||||
|  } | ||||
|   | ||||
|   | ||||
| -struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid) | ||||
| +struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid) | ||||
|  { | ||||
|  	struct brcmf_flowring_ring *ring; | ||||
|  	struct sk_buff *skb; | ||||
| @@ -300,7 +304,7 @@ struct sk_buff *brcmf_flowring_dequeue(s | ||||
|  } | ||||
|   | ||||
|   | ||||
| -void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid, | ||||
| +void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid, | ||||
|  			     struct sk_buff *skb) | ||||
|  { | ||||
|  	struct brcmf_flowring_ring *ring; | ||||
| @@ -311,7 +315,7 @@ void brcmf_flowring_reinsert(struct brcm | ||||
|  } | ||||
|   | ||||
|   | ||||
| -u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid) | ||||
| +u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid) | ||||
|  { | ||||
|  	struct brcmf_flowring_ring *ring; | ||||
|   | ||||
| @@ -326,7 +330,7 @@ u32 brcmf_flowring_qlen(struct brcmf_flo | ||||
|  } | ||||
|   | ||||
|   | ||||
| -void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid) | ||||
| +void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid) | ||||
|  { | ||||
|  	struct brcmf_flowring_ring *ring; | ||||
|   | ||||
| @@ -340,10 +344,10 @@ void brcmf_flowring_open(struct brcmf_fl | ||||
|  } | ||||
|   | ||||
|   | ||||
| -u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid) | ||||
| +u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid) | ||||
|  { | ||||
|  	struct brcmf_flowring_ring *ring; | ||||
| -	u8 hash_idx; | ||||
| +	u16 hash_idx; | ||||
|   | ||||
|  	ring = flow->rings[flowid]; | ||||
|  	hash_idx = ring->hash_id; | ||||
| @@ -384,7 +388,7 @@ void brcmf_flowring_detach(struct brcmf_ | ||||
|  	struct brcmf_pub *drvr = bus_if->drvr; | ||||
|  	struct brcmf_flowring_tdls_entry *search; | ||||
|  	struct brcmf_flowring_tdls_entry *remove; | ||||
| -	u8 flowid; | ||||
| +	u16 flowid; | ||||
|   | ||||
|  	for (flowid = 0; flowid < flow->nrofrings; flowid++) { | ||||
|  		if (flow->rings[flowid]) | ||||
| @@ -408,7 +412,7 @@ void brcmf_flowring_configure_addr_mode( | ||||
|  	struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev); | ||||
|  	struct brcmf_pub *drvr = bus_if->drvr; | ||||
|  	u32 i; | ||||
| -	u8 flowid; | ||||
| +	u16 flowid; | ||||
|   | ||||
|  	if (flow->addr_mode[ifidx] != addr_mode) { | ||||
|  		for (i = 0; i < ARRAY_SIZE(flow->hash); i++) { | ||||
| @@ -434,7 +438,7 @@ void brcmf_flowring_delete_peer(struct b | ||||
|  	struct brcmf_flowring_tdls_entry *prev; | ||||
|  	struct brcmf_flowring_tdls_entry *search; | ||||
|  	u32 i; | ||||
| -	u8 flowid; | ||||
| +	u16 flowid; | ||||
|  	bool sta; | ||||
|   | ||||
|  	sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT); | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h | ||||
| @@ -16,7 +16,7 @@ | ||||
|  #define BRCMFMAC_FLOWRING_H | ||||
|   | ||||
|   | ||||
| -#define BRCMF_FLOWRING_HASHSIZE		256 | ||||
| +#define BRCMF_FLOWRING_HASHSIZE		512		/* has to be 2^x */ | ||||
|  #define BRCMF_FLOWRING_INVALID_ID	0xFFFFFFFF | ||||
|   | ||||
|   | ||||
| @@ -24,7 +24,7 @@ struct brcmf_flowring_hash { | ||||
|  	u8 mac[ETH_ALEN]; | ||||
|  	u8 fifo; | ||||
|  	u8 ifidx; | ||||
| -	u8 flowid; | ||||
| +	u16 flowid; | ||||
|  }; | ||||
|   | ||||
|  enum ring_status { | ||||
| @@ -61,16 +61,16 @@ u32 brcmf_flowring_lookup(struct brcmf_f | ||||
|  			  u8 prio, u8 ifidx); | ||||
|  u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN], | ||||
|  			  u8 prio, u8 ifidx); | ||||
| -void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid); | ||||
| -void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid); | ||||
| -u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid); | ||||
| -u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, | ||||
| +void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid); | ||||
| +void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid); | ||||
| +u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid); | ||||
| +u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid, | ||||
|  			   struct sk_buff *skb); | ||||
| -struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid); | ||||
| -void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid, | ||||
| +struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid); | ||||
| +void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid, | ||||
|  			     struct sk_buff *skb); | ||||
| -u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid); | ||||
| -u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid); | ||||
| +u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid); | ||||
| +u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid); | ||||
|  struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings); | ||||
|  void brcmf_flowring_detach(struct brcmf_flowring *flow); | ||||
|  void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx, | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c | ||||
| @@ -677,7 +677,7 @@ static u32 brcmf_msgbuf_flowring_create( | ||||
|  } | ||||
|   | ||||
|   | ||||
| -static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid) | ||||
| +static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid) | ||||
|  { | ||||
|  	struct brcmf_flowring *flow = msgbuf->flow; | ||||
|  	struct brcmf_commonring *commonring; | ||||
| @@ -1310,7 +1310,7 @@ int brcmf_proto_msgbuf_rx_trigger(struct | ||||
|  } | ||||
|   | ||||
|   | ||||
| -void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid) | ||||
| +void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid) | ||||
|  { | ||||
|  	struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; | ||||
|  	struct msgbuf_tx_flowring_delete_req *delete; | ||||
| @@ -1415,6 +1415,13 @@ int brcmf_proto_msgbuf_attach(struct brc | ||||
|  	u32 count; | ||||
|   | ||||
|  	if_msgbuf = drvr->bus_if->msgbuf; | ||||
| + | ||||
| +	if (if_msgbuf->nrof_flowrings >= BRCMF_FLOWRING_HASHSIZE) { | ||||
| +		brcmf_err("driver not configured for this many flowrings %d\n", | ||||
| +			  if_msgbuf->nrof_flowrings); | ||||
| +		if_msgbuf->nrof_flowrings = BRCMF_FLOWRING_HASHSIZE - 1; | ||||
| +	} | ||||
| + | ||||
|  	msgbuf = kzalloc(sizeof(*msgbuf), GFP_KERNEL); | ||||
|  	if (!msgbuf) | ||||
|  		goto fail; | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h | ||||
| @@ -33,7 +33,7 @@ | ||||
|   | ||||
|   | ||||
|  int brcmf_proto_msgbuf_rx_trigger(struct device *dev); | ||||
| -void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid); | ||||
| +void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid); | ||||
|  int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr); | ||||
|  void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr); | ||||
|  #else | ||||
| @@ -1,22 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Mon, 8 Feb 2016 14:24:36 +0100 | ||||
| Subject: [PATCH] cfg80211: fix faulty variable initialization in | ||||
|  ieee80211_amsdu_to_8023s | ||||
|  | ||||
| reuse_skb is set to true if the code decides to use the last segment. | ||||
| Fixes a memory leak | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/net/wireless/util.c | ||||
| +++ b/net/wireless/util.c | ||||
| @@ -676,7 +676,7 @@ void ieee80211_amsdu_to_8023s(struct sk_ | ||||
|  	u8 *payload; | ||||
|  	int offset = 0, remaining, err; | ||||
|  	struct ethhdr eth; | ||||
| -	bool reuse_skb = true; | ||||
| +	bool reuse_skb = false; | ||||
|  	bool last = false; | ||||
|   | ||||
|  	if (has_80211_header) { | ||||
| @@ -1,132 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Mon, 8 Feb 2016 14:33:19 +0100 | ||||
| Subject: [PATCH] cfg80211: reuse existing page fragments in A-MSDU rx | ||||
|  | ||||
| This massively reduces data copying and thus improves rx performance | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/net/wireless/util.c | ||||
| +++ b/net/wireless/util.c | ||||
| @@ -644,23 +644,93 @@ int ieee80211_data_from_8023(struct sk_b | ||||
|  } | ||||
|  EXPORT_SYMBOL(ieee80211_data_from_8023); | ||||
|   | ||||
| +static void | ||||
| +__frame_add_frag(struct sk_buff *skb, struct page *page, | ||||
| +		 void *ptr, int len, int size) | ||||
| +{ | ||||
| +	struct skb_shared_info *sh = skb_shinfo(skb); | ||||
| +	int page_offset; | ||||
| + | ||||
| +	atomic_inc(&page->_count); | ||||
| +	page_offset = ptr - page_address(page); | ||||
| +	skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size); | ||||
| +} | ||||
| + | ||||
| +static void | ||||
| +__ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame, | ||||
| +			    int offset, int len) | ||||
| +{ | ||||
| +	struct skb_shared_info *sh = skb_shinfo(skb); | ||||
| +	const skb_frag_t *frag = &sh->frags[-1]; | ||||
| +	struct page *frag_page; | ||||
| +	void *frag_ptr; | ||||
| +	int frag_len, frag_size; | ||||
| +	int head_size = skb->len - skb->data_len; | ||||
| +	int cur_len; | ||||
| + | ||||
| +	frag_page = virt_to_head_page(skb->head); | ||||
| +	frag_ptr = skb->data; | ||||
| +	frag_size = head_size; | ||||
| + | ||||
| +	while (offset >= frag_size) { | ||||
| +		offset -= frag_size; | ||||
| +		frag++; | ||||
| +		frag_page = skb_frag_page(frag); | ||||
| +		frag_ptr = skb_frag_address(frag); | ||||
| +		frag_size = skb_frag_size(frag); | ||||
| +	} | ||||
| + | ||||
| +	frag_ptr += offset; | ||||
| +	frag_len = frag_size - offset; | ||||
| + | ||||
| +	cur_len = min(len, frag_len); | ||||
| + | ||||
| +	__frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size); | ||||
| +	len -= cur_len; | ||||
| + | ||||
| +	while (len > 0) { | ||||
| +		frag++; | ||||
| +		frag_len = skb_frag_size(frag); | ||||
| +		cur_len = min(len, frag_len); | ||||
| +		__frame_add_frag(frame, skb_frag_page(frag), | ||||
| +				 skb_frag_address(frag), cur_len, frag_len); | ||||
| +		len -= cur_len; | ||||
| +	} | ||||
| +} | ||||
| + | ||||
|  static struct sk_buff * | ||||
|  __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, | ||||
| -		       int offset, int len) | ||||
| +		       int offset, int len, bool reuse_frag) | ||||
|  { | ||||
|  	struct sk_buff *frame; | ||||
| +	int cur_len = len; | ||||
|   | ||||
|  	if (skb->len - offset < len) | ||||
|  		return NULL; | ||||
|   | ||||
|  	/* | ||||
| +	 * When reusing framents, copy some data to the head to simplify | ||||
| +	 * ethernet header handling and speed up protocol header processing | ||||
| +	 * in the stack later. | ||||
| +	 */ | ||||
| +	if (reuse_frag) | ||||
| +		cur_len = min_t(int, len, 32); | ||||
| + | ||||
| +	/* | ||||
|  	 * Allocate and reserve two bytes more for payload | ||||
|  	 * alignment since sizeof(struct ethhdr) is 14. | ||||
|  	 */ | ||||
| -	frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + len); | ||||
| +	frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len); | ||||
|   | ||||
|  	skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); | ||||
| -	skb_copy_bits(skb, offset, skb_put(frame, len), len); | ||||
| +	skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len); | ||||
| + | ||||
| +	len -= cur_len; | ||||
| +	if (!len) | ||||
| +		return frame; | ||||
| + | ||||
| +	offset += cur_len; | ||||
| +	__ieee80211_amsdu_copy_frag(skb, frame, offset, len); | ||||
|   | ||||
|  	return frame; | ||||
|  } | ||||
| @@ -676,6 +746,7 @@ void ieee80211_amsdu_to_8023s(struct sk_ | ||||
|  	u8 *payload; | ||||
|  	int offset = 0, remaining, err; | ||||
|  	struct ethhdr eth; | ||||
| +	bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb); | ||||
|  	bool reuse_skb = false; | ||||
|  	bool last = false; | ||||
|   | ||||
| @@ -703,12 +774,13 @@ void ieee80211_amsdu_to_8023s(struct sk_ | ||||
|  		offset += sizeof(struct ethhdr); | ||||
|  		/* reuse skb for the last subframe */ | ||||
|  		last = remaining <= subframe_len + padding; | ||||
| -		if (!skb_is_nonlinear(skb) && last) { | ||||
| +		if (!skb_is_nonlinear(skb) && !reuse_frag && last) { | ||||
|  			skb_pull(skb, offset); | ||||
|  			frame = skb; | ||||
|  			reuse_skb = true; | ||||
|  		} else { | ||||
| -			frame = __ieee80211_amsdu_copy(skb, hlen, offset, len); | ||||
| +			frame = __ieee80211_amsdu_copy(skb, hlen, offset, len, | ||||
| +						       reuse_frag); | ||||
|  			if (!frame) | ||||
|  				goto purge; | ||||
|   | ||||
| @@ -1,36 +0,0 @@ | ||||
| From: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> | ||||
| Date: Wed, 10 Feb 2016 16:08:17 +0100 | ||||
| Subject: [PATCH] mac80211: fix wiphy supported_band access | ||||
|  | ||||
| Fix wiphy supported_band access in tx radiotap parsing. In particular, | ||||
| info->band is always set to 0 (IEEE80211_BAND_2GHZ) since it has not | ||||
| assigned yet. This cause a kernel crash on 5GHz only devices. | ||||
| Move ieee80211_parse_tx_radiotap() after info->band assignment | ||||
|  | ||||
| Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/tx.c | ||||
| +++ b/net/mac80211/tx.c | ||||
| @@ -1890,10 +1890,6 @@ netdev_tx_t ieee80211_monitor_start_xmit | ||||
|  	info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS | | ||||
|  		      IEEE80211_TX_CTL_INJECTED; | ||||
|   | ||||
| -	/* process and remove the injection radiotap header */ | ||||
| -	if (!ieee80211_parse_tx_radiotap(local, skb)) | ||||
| -		goto fail; | ||||
| - | ||||
|  	rcu_read_lock(); | ||||
|   | ||||
|  	/* | ||||
| @@ -1955,6 +1951,10 @@ netdev_tx_t ieee80211_monitor_start_xmit | ||||
|  		goto fail_rcu; | ||||
|   | ||||
|  	info->band = chandef->chan->band; | ||||
| +	/* process and remove the injection radiotap header */ | ||||
| +	if (!ieee80211_parse_tx_radiotap(local, skb)) | ||||
| +		goto fail_rcu; | ||||
| + | ||||
|  	ieee80211_xmit(sdata, NULL, skb); | ||||
|  	rcu_read_unlock(); | ||||
|   | ||||
| @@ -1,61 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Thu, 18 Feb 2016 19:30:05 +0100 | ||||
| Subject: [PATCH] mac80211: minstrel_ht: set A-MSDU tx limits based on selected | ||||
|  max_prob_rate | ||||
|  | ||||
| Prevents excessive A-MSDU aggregation at low data rates or bad | ||||
| conditions. | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/rc80211_minstrel_ht.c | ||||
| +++ b/net/mac80211/rc80211_minstrel_ht.c | ||||
| @@ -883,6 +883,39 @@ minstrel_ht_set_rate(struct minstrel_pri | ||||
|  	ratetbl->rate[offset].flags = flags; | ||||
|  } | ||||
|   | ||||
| +static int | ||||
| +minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi) | ||||
| +{ | ||||
| +	int group = mi->max_prob_rate / MCS_GROUP_RATES; | ||||
| +	const struct mcs_group *g = &minstrel_mcs_groups[group]; | ||||
| +	int rate = mi->max_prob_rate % MCS_GROUP_RATES; | ||||
| + | ||||
| +	/* Disable A-MSDU if max_prob_rate is bad */ | ||||
| +	if (mi->groups[group].rates[rate].prob_ewma < MINSTREL_FRAC(50, 100)) | ||||
| +		return 1; | ||||
| + | ||||
| +	/* If the rate is slower than single-stream MCS1, make A-MSDU limit small */ | ||||
| +	if (g->duration[rate] > MCS_DURATION(1, 0, 52)) | ||||
| +		return 500; | ||||
| + | ||||
| +	/* | ||||
| +	 * If the rate is slower than single-stream MCS4, limit A-MSDU to usual | ||||
| +	 * data packet size | ||||
| +	 */ | ||||
| +	if (g->duration[rate] > MCS_DURATION(1, 0, 104)) | ||||
| +		return 1500; | ||||
| + | ||||
| +	/* | ||||
| +	 * If the rate is slower than single-stream MCS7, limit A-MSDU to twice | ||||
| +	 * the usual data packet size | ||||
| +	 */ | ||||
| +	if (g->duration[rate] > MCS_DURATION(1, 0, 260)) | ||||
| +		return 3000; | ||||
| + | ||||
| +	/* unlimited */ | ||||
| +	return 0; | ||||
| +} | ||||
| + | ||||
|  static void | ||||
|  minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) | ||||
|  { | ||||
| @@ -907,6 +940,7 @@ minstrel_ht_update_rates(struct minstrel | ||||
|  		minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_prob_rate); | ||||
|  	} | ||||
|   | ||||
| +	mi->sta->max_rc_amsdu_len = minstrel_ht_get_max_amsdu_len(mi); | ||||
|  	rates->rate[i].idx = -1; | ||||
|  	rate_control_set_rates(mp->hw, mi->sta, rates); | ||||
|  } | ||||
| @@ -1,31 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Thu, 18 Feb 2016 19:45:33 +0100 | ||||
| Subject: [PATCH] mac80211: minstrel_ht: set default tx aggregation timeout to | ||||
|  0 | ||||
|  | ||||
| The value 5000 was put here with the addition of the timeout field to | ||||
| ieee80211_start_tx_ba_session. It was originally added in mac80211 to | ||||
| save resources for drivers like iwlwifi, which only supports a limited | ||||
| number of concurrent aggregation sessions. | ||||
|  | ||||
| Since iwlwifi does not use minstrel_ht and other drivers don't need | ||||
| this, 0 is a better default - especially since there have been | ||||
| recent reports of aggregation setup related issues reproduced with | ||||
| ath9k. This should improve stability without causing any adverse | ||||
| effects. | ||||
|  | ||||
| Cc: stable@vger.kernel.org | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/rc80211_minstrel_ht.c | ||||
| +++ b/net/mac80211/rc80211_minstrel_ht.c | ||||
| @@ -692,7 +692,7 @@ minstrel_aggr_check(struct ieee80211_sta | ||||
|  	if (likely(sta->ampdu_mlme.tid_tx[tid])) | ||||
|  		return; | ||||
|   | ||||
| -	ieee80211_start_tx_ba_session(pubsta, tid, 5000); | ||||
| +	ieee80211_start_tx_ba_session(pubsta, tid, 0); | ||||
|  } | ||||
|   | ||||
|  static void | ||||
| @@ -1,26 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Wed, 24 Feb 2016 12:03:13 +0100 | ||||
| Subject: [PATCH] mac80211: minstrel_ht: fix a logic error in RTS/CTS handling | ||||
| MIME-Version: 1.0 | ||||
| Content-Type: text/plain; charset=UTF-8 | ||||
| Content-Transfer-Encoding: 8bit | ||||
|  | ||||
| RTS/CTS needs to be enabled if the rate is a fallback rate *or* if it's | ||||
| a dual-stream rate and the sta is in dynamic SMPS mode. | ||||
|  | ||||
| Fixes: a3ebb4e1b763 ("mac80211: minstrel_ht: handle peers in dynamic SMPS") | ||||
| Reported-by: Matías Richart <mrichart@fing.edu.uy> | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/rc80211_minstrel_ht.c | ||||
| +++ b/net/mac80211/rc80211_minstrel_ht.c | ||||
| @@ -872,7 +872,7 @@ minstrel_ht_set_rate(struct minstrel_pri | ||||
|  	 *  - if station is in dynamic SMPS (and streams > 1) | ||||
|  	 *  - for fallback rates, to increase chances of getting through | ||||
|  	 */ | ||||
| -	if (offset > 0 && | ||||
| +	if (offset > 0 || | ||||
|  	    (mi->sta->smps_mode == IEEE80211_SMPS_DYNAMIC && | ||||
|  	     group->streams > 1)) { | ||||
|  		ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts; | ||||
| @@ -1,35 +0,0 @@ | ||||
| From: Jouni Malinen <jouni@qca.qualcomm.com> | ||||
| Date: Tue, 1 Mar 2016 00:29:00 +0200 | ||||
| Subject: [PATCH] mac80211: Fix Public Action frame RX in AP mode | ||||
|  | ||||
| Public Action frames use special rules for how the BSSID field (Address | ||||
| 3) is set. A wildcard BSSID is used in cases where the transmitter and | ||||
| recipient are not members of the same BSS. As such, we need to accept | ||||
| Public Action frames with wildcard BSSID. | ||||
|  | ||||
| Commit db8e17324553 ("mac80211: ignore frames between TDLS peers when | ||||
| operating as AP") added a rule that drops Action frames to TDLS-peers | ||||
| based on an Action frame having different DA (Address 1) and BSSID | ||||
| (Address 3) values. This is not correct since it misses the possibility | ||||
| of BSSID being a wildcard BSSID in which case the Address 1 would not | ||||
| necessarily match. | ||||
|  | ||||
| Fix this by allowing mac80211 to accept wildcard BSSID in an Action | ||||
| frame when in AP mode. | ||||
|  | ||||
| Fixes: db8e17324553 ("mac80211: ignore frames between TDLS peers when operating as AP") | ||||
| Cc: stable@vger.kernel.org | ||||
| Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com> | ||||
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/rx.c | ||||
| +++ b/net/mac80211/rx.c | ||||
| @@ -3374,6 +3374,7 @@ static bool ieee80211_accept_frame(struc | ||||
|  				return false; | ||||
|  			/* ignore action frames to TDLS-peers */ | ||||
|  			if (ieee80211_is_action(hdr->frame_control) && | ||||
| +			    !is_broadcast_ether_addr(bssid) && | ||||
|  			    !ether_addr_equal(bssid, hdr->addr1)) | ||||
|  				return false; | ||||
|  		} | ||||
| @@ -1,21 +0,0 @@ | ||||
| From: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> | ||||
| Date: Fri, 19 Feb 2016 11:43:04 +0100 | ||||
| Subject: [PATCH] cfg80211: add radiotap VHT info to rtap_namespace_sizes | ||||
|  | ||||
| Add IEEE80211_RADIOTAP_VHT entry to rtap_namespace_sizes array in order to | ||||
| define alignment and size of VHT info in tx radiotap | ||||
|  | ||||
| Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> | ||||
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/wireless/radiotap.c | ||||
| +++ b/net/wireless/radiotap.c | ||||
| @@ -43,6 +43,7 @@ static const struct radiotap_align_size | ||||
|  	[IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, }, | ||||
|  	[IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, }, | ||||
|  	[IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, }, | ||||
| +	[IEEE80211_RADIOTAP_VHT] = { .align = 2, .size = 12, }, | ||||
|  	/* | ||||
|  	 * add more here as they are defined in radiotap.h | ||||
|  	 */ | ||||
| @@ -1,36 +0,0 @@ | ||||
| From: Sven Eckelmann <sven@narfation.org> | ||||
| Date: Wed, 24 Feb 2016 16:25:49 +0100 | ||||
| Subject: [PATCH] mac80211: fix parsing of 40Mhz in injected radiotap | ||||
|  header | ||||
|  | ||||
| The MCS bandwidth part of the radiotap header is 2 bits wide. The full 2 | ||||
| bit have to compared against IEEE80211_RADIOTAP_MCS_BW_40 and not only if | ||||
| the first bit is set. Otherwise IEEE80211_RADIOTAP_MCS_BW_40 can be | ||||
| confused with IEEE80211_RADIOTAP_MCS_BW_20U. | ||||
|  | ||||
| Fixes: 5ec3aed9ba4c ("mac80211: Parse legacy and HT rate in injected frames") | ||||
| Signed-off-by: Sven Eckelmann <sven@narfation.org> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/tx.c | ||||
| +++ b/net/mac80211/tx.c | ||||
| @@ -1689,7 +1689,7 @@ static bool ieee80211_parse_tx_radiotap( | ||||
|  	bool rate_found = false; | ||||
|  	u8 rate_retries = 0; | ||||
|  	u16 rate_flags = 0; | ||||
| -	u8 mcs_known, mcs_flags; | ||||
| +	u8 mcs_known, mcs_flags, mcs_bw; | ||||
|  	int i; | ||||
|   | ||||
|  	info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | | ||||
| @@ -1765,8 +1765,9 @@ static bool ieee80211_parse_tx_radiotap( | ||||
|  			    mcs_flags & IEEE80211_RADIOTAP_MCS_SGI) | ||||
|  				rate_flags |= IEEE80211_TX_RC_SHORT_GI; | ||||
|   | ||||
| +			mcs_bw = mcs_flags & IEEE80211_RADIOTAP_MCS_BW_MASK; | ||||
|  			if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW && | ||||
| -			    mcs_flags & IEEE80211_RADIOTAP_MCS_BW_40) | ||||
| +			    mcs_bw == IEEE80211_RADIOTAP_MCS_BW_40) | ||||
|  				rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||||
|  			break; | ||||
|   | ||||
| @@ -1,65 +0,0 @@ | ||||
| From: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> | ||||
| Date: Tue, 23 Feb 2016 15:43:35 +0100 | ||||
| Subject: [PATCH] mac80211: parse VHT info in injected frames | ||||
|  | ||||
| Add VHT radiotap parsing support to ieee80211_parse_tx_radiotap(). | ||||
| That capability has been tested using a d-link dir-860l rev b1 running | ||||
| OpenWrt trunk and mt76 driver | ||||
|  | ||||
| Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/tx.c | ||||
| +++ b/net/mac80211/tx.c | ||||
| @@ -1690,6 +1690,8 @@ static bool ieee80211_parse_tx_radiotap( | ||||
|  	u8 rate_retries = 0; | ||||
|  	u16 rate_flags = 0; | ||||
|  	u8 mcs_known, mcs_flags, mcs_bw; | ||||
| +	u16 vht_known; | ||||
| +	u8 vht_mcs = 0, vht_nss = 0; | ||||
|  	int i; | ||||
|   | ||||
|  	info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | | ||||
| @@ -1771,6 +1773,32 @@ static bool ieee80211_parse_tx_radiotap( | ||||
|  				rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||||
|  			break; | ||||
|   | ||||
| +		case IEEE80211_RADIOTAP_VHT: | ||||
| +			vht_known = get_unaligned_le16(iterator.this_arg); | ||||
| +			rate_found = true; | ||||
| + | ||||
| +			rate_flags = IEEE80211_TX_RC_VHT_MCS; | ||||
| +			if ((vht_known & IEEE80211_RADIOTAP_VHT_KNOWN_GI) && | ||||
| +			    (iterator.this_arg[2] & | ||||
| +			     IEEE80211_RADIOTAP_VHT_FLAG_SGI)) | ||||
| +				rate_flags |= IEEE80211_TX_RC_SHORT_GI; | ||||
| +			if (vht_known & | ||||
| +			    IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH) { | ||||
| +				if (iterator.this_arg[3] == 1) | ||||
| +					rate_flags |= | ||||
| +						IEEE80211_TX_RC_40_MHZ_WIDTH; | ||||
| +				else if (iterator.this_arg[3] == 4) | ||||
| +					rate_flags |= | ||||
| +						IEEE80211_TX_RC_80_MHZ_WIDTH; | ||||
| +				else if (iterator.this_arg[3] == 11) | ||||
| +					rate_flags |= | ||||
| +						IEEE80211_TX_RC_160_MHZ_WIDTH; | ||||
| +			} | ||||
| + | ||||
| +			vht_mcs = iterator.this_arg[4] >> 4; | ||||
| +			vht_nss = iterator.this_arg[4] & 0xF; | ||||
| +			break; | ||||
| + | ||||
|  		/* | ||||
|  		 * Please update the file | ||||
|  		 * Documentation/networking/mac80211-injection.txt | ||||
| @@ -1796,6 +1824,9 @@ static bool ieee80211_parse_tx_radiotap( | ||||
|   | ||||
|  		if (rate_flags & IEEE80211_TX_RC_MCS) { | ||||
|  			info->control.rates[0].idx = rate; | ||||
| +		} else if (rate_flags & IEEE80211_TX_RC_VHT_MCS) { | ||||
| +			ieee80211_rate_set_vht(info->control.rates, vht_mcs, | ||||
| +					       vht_nss); | ||||
|  		} else { | ||||
|  			for (i = 0; i < sband->n_bitrates; i++) { | ||||
|  				if (rate * 5 != sband->bitrates[i].bitrate) | ||||
| @@ -1,23 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Wed, 2 Mar 2016 15:51:40 +0100 | ||||
| Subject: [PATCH] mac80211: do not pass injected frames without a valid rate to | ||||
|  the driver | ||||
|  | ||||
| Fall back to rate control if the requested bitrate was not found. | ||||
|  | ||||
| Fixes: dfdfc2beb0dd ("mac80211: Parse legacy and HT rate in injected frames") | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/tx.c | ||||
| +++ b/net/mac80211/tx.c | ||||
| @@ -1837,6 +1837,9 @@ static bool ieee80211_parse_tx_radiotap( | ||||
|  			} | ||||
|  		} | ||||
|   | ||||
| +		if (info->control.rates[0].idx < 0) | ||||
| +			info->control.flags &= ~IEEE80211_TX_CTRL_RATE_INJECT; | ||||
| + | ||||
|  		info->control.rates[0].flags = rate_flags; | ||||
|  		info->control.rates[0].count = min_t(u8, rate_retries + 1, | ||||
|  						     local->hw.max_rate_tries); | ||||
| @@ -1,77 +0,0 @@ | ||||
| From: Felix Fietkau <nbd@openwrt.org> | ||||
| Date: Thu, 3 Mar 2016 23:20:06 +0100 | ||||
| Subject: [PATCH] mac80211: minstrel_ht: improve sample rate skip logic | ||||
|  | ||||
| There were a few issues that were slowing down the process of finding | ||||
| the optimal rate, especially on devices with multi-rate retry | ||||
| limitations: | ||||
|  | ||||
| When max_tp_rate[0] was slower than max_tp_rate[1], the code did not | ||||
| sample max_tp_rate[1], which would often allow it to switch places with | ||||
| max_tp_rate[0] (e.g. if only the first sampling attempts were bad, but the | ||||
| rate is otherwise good). | ||||
|  | ||||
| Also, sample attempts of rates between max_tp_rate[0] and [1] were being | ||||
| ignored in this case, because the code only checked if the rate was | ||||
| slower than [1]. | ||||
|  | ||||
| Fix this by checking against the fastest / second fastest max_tp_rate | ||||
| instead of assuming a specific order between the two. | ||||
|  | ||||
| In my tests this patch significantly reduces the time until minstrel_ht | ||||
| finds the optimal rate right after assoc | ||||
|  | ||||
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> | ||||
| --- | ||||
|  | ||||
| --- a/net/mac80211/rc80211_minstrel_ht.c | ||||
| +++ b/net/mac80211/rc80211_minstrel_ht.c | ||||
| @@ -958,6 +958,7 @@ minstrel_get_sample_rate(struct minstrel | ||||
|  	struct minstrel_rate_stats *mrs; | ||||
|  	struct minstrel_mcs_group_data *mg; | ||||
|  	unsigned int sample_dur, sample_group, cur_max_tp_streams; | ||||
| +	int tp_rate1, tp_rate2; | ||||
|  	int sample_idx = 0; | ||||
|   | ||||
|  	if (mi->sample_wait > 0) { | ||||
| @@ -979,14 +980,22 @@ minstrel_get_sample_rate(struct minstrel | ||||
|  	mrs = &mg->rates[sample_idx]; | ||||
|  	sample_idx += sample_group * MCS_GROUP_RATES; | ||||
|   | ||||
| +	/* Set tp_rate1, tp_rate2 to the highest / second highest max_tp_rate */ | ||||
| +	if (minstrel_get_duration(mi->max_tp_rate[0]) > | ||||
| +	    minstrel_get_duration(mi->max_tp_rate[1])) { | ||||
| +		tp_rate1 = mi->max_tp_rate[1]; | ||||
| +		tp_rate2 = mi->max_tp_rate[0]; | ||||
| +	} else { | ||||
| +		tp_rate1 = mi->max_tp_rate[0]; | ||||
| +		tp_rate2 = mi->max_tp_rate[1]; | ||||
| +	} | ||||
| + | ||||
|  	/* | ||||
|  	 * Sampling might add some overhead (RTS, no aggregation) | ||||
| -	 * to the frame. Hence, don't use sampling for the currently | ||||
| -	 * used rates. | ||||
| +	 * to the frame. Hence, don't use sampling for the highest currently | ||||
| +	 * used highest throughput or probability rate. | ||||
|  	 */ | ||||
| -	if (sample_idx == mi->max_tp_rate[0] || | ||||
| -	    sample_idx == mi->max_tp_rate[1] || | ||||
| -	    sample_idx == mi->max_prob_rate) | ||||
| +	if (sample_idx == mi->max_tp_rate[0] || sample_idx == mi->max_prob_rate) | ||||
|  		return -1; | ||||
|   | ||||
|  	/* | ||||
| @@ -1001,10 +1010,10 @@ minstrel_get_sample_rate(struct minstrel | ||||
|  	 * if the link is working perfectly. | ||||
|  	 */ | ||||
|   | ||||
| -	cur_max_tp_streams = minstrel_mcs_groups[mi->max_tp_rate[0] / | ||||
| +	cur_max_tp_streams = minstrel_mcs_groups[tp_rate1 / | ||||
|  		MCS_GROUP_RATES].streams; | ||||
|  	sample_dur = minstrel_get_duration(sample_idx); | ||||
| -	if (sample_dur >= minstrel_get_duration(mi->max_tp_rate[1]) && | ||||
| +	if (sample_dur >= minstrel_get_duration(tp_rate2) && | ||||
|  	    (cur_max_tp_streams - 1 < | ||||
|  	     minstrel_mcs_groups[sample_group].streams || | ||||
|  	     sample_dur >= minstrel_get_duration(mi->max_prob_rate))) { | ||||
| @@ -1,73 +0,0 @@ | ||||
| From: Hante Meuleman <meuleman@broadcom.com> | ||||
| Date: Wed, 17 Feb 2016 11:26:57 +0100 | ||||
| Subject: [PATCH] brcmfmac: use device memsize config from fw if defined | ||||
|  | ||||
| Newer type pcie devices have memory which get shared between fw and | ||||
| hw. The division of this memory is done firmware compile time. As a | ||||
| result the ramsize as used by driver needs to be adjusted for this. | ||||
| This is done by reading the memory size from the firmware. | ||||
|  | ||||
| Reviewed-by: Arend Van Spriel <arend@broadcom.com> | ||||
| Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> | ||||
| Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> | ||||
| Signed-off-by: Hante Meuleman <meuleman@broadcom.com> | ||||
| Signed-off-by: Arend van Spriel <arend@broadcom.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | ||||
| @@ -207,6 +207,10 @@ static struct brcmf_firmware_mapping brc | ||||
|  #define BRCMF_PCIE_CFGREG_REG_BAR3_CONFIG	0x4F4 | ||||
|  #define BRCMF_PCIE_LINK_STATUS_CTRL_ASPM_ENAB	3 | ||||
|   | ||||
| +/* Magic number at a magic location to find RAM size */ | ||||
| +#define BRCMF_RAMSIZE_MAGIC			0x534d4152	/* SMAR */ | ||||
| +#define BRCMF_RAMSIZE_OFFSET			0x6c | ||||
| + | ||||
|   | ||||
|  struct brcmf_pcie_console { | ||||
|  	u32 base_addr; | ||||
| @@ -1412,6 +1416,28 @@ static const struct brcmf_bus_ops brcmf_ | ||||
|  }; | ||||
|   | ||||
|   | ||||
| +static void | ||||
| +brcmf_pcie_adjust_ramsize(struct brcmf_pciedev_info *devinfo, u8 *data, | ||||
| +			  u32 data_len) | ||||
| +{ | ||||
| +	__le32 *field; | ||||
| +	u32 newsize; | ||||
| + | ||||
| +	if (data_len < BRCMF_RAMSIZE_OFFSET + 8) | ||||
| +		return; | ||||
| + | ||||
| +	field = (__le32 *)&data[BRCMF_RAMSIZE_OFFSET]; | ||||
| +	if (le32_to_cpup(field) != BRCMF_RAMSIZE_MAGIC) | ||||
| +		return; | ||||
| +	field++; | ||||
| +	newsize = le32_to_cpup(field); | ||||
| + | ||||
| +	brcmf_dbg(PCIE, "Found ramsize info in FW, adjusting to 0x%x\n", | ||||
| +		  newsize); | ||||
| +	devinfo->ci->ramsize = newsize; | ||||
| +} | ||||
| + | ||||
| + | ||||
|  static int | ||||
|  brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo, | ||||
|  			       u32 sharedram_addr) | ||||
| @@ -1694,6 +1720,13 @@ static void brcmf_pcie_setup(struct devi | ||||
|   | ||||
|  	brcmf_pcie_attach(devinfo); | ||||
|   | ||||
| +	/* Some of the firmwares have the size of the memory of the device | ||||
| +	 * defined inside the firmware. This is because part of the memory in | ||||
| +	 * the device is shared and the devision is determined by FW. Parse | ||||
| +	 * the firmware and adjust the chip memory size now. | ||||
| +	 */ | ||||
| +	brcmf_pcie_adjust_ramsize(devinfo, (u8 *)fw->data, fw->size); | ||||
| + | ||||
|  	ret = brcmf_pcie_download_fw_nvram(devinfo, fw, nvram, nvram_len); | ||||
|  	if (ret) | ||||
|  		goto fail; | ||||
| @@ -1,58 +0,0 @@ | ||||
| From: Hante Meuleman <meuleman@broadcom.com> | ||||
| Date: Wed, 17 Feb 2016 11:26:58 +0100 | ||||
| Subject: [PATCH] brcmfmac: use bar1 window size as provided by pci subsystem | ||||
|  | ||||
| The PCIE bar1 window size is specified by chip. Currently the | ||||
| ioremap of bar1 was using a define which always matched the size | ||||
| of bar1, but newer chips can have a different bar1 sizes. With | ||||
| this patch the ioremap will be called with the by chip provided | ||||
| window size. | ||||
|  | ||||
| Reviewed-by: Arend Van Spriel <arend@broadcom.com> | ||||
| Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> | ||||
| Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> | ||||
| Signed-off-by: Hante Meuleman <meuleman@broadcom.com> | ||||
| Signed-off-by: Arend van Spriel <arend@broadcom.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | ||||
| @@ -72,7 +72,6 @@ static struct brcmf_firmware_mapping brc | ||||
|   | ||||
|  #define BRCMF_PCIE_FW_UP_TIMEOUT		2000 /* msec */ | ||||
|   | ||||
| -#define BRCMF_PCIE_TCM_MAP_SIZE			(4096 * 1024) | ||||
|  #define BRCMF_PCIE_REG_MAP_SIZE			(32 * 1024) | ||||
|   | ||||
|  /* backplane addres space accessed by BAR0 */ | ||||
| @@ -252,7 +251,6 @@ struct brcmf_pciedev_info { | ||||
|  	char nvram_name[BRCMF_FW_NAME_LEN]; | ||||
|  	void __iomem *regs; | ||||
|  	void __iomem *tcm; | ||||
| -	u32 tcm_size; | ||||
|  	u32 ram_base; | ||||
|  	u32 ram_size; | ||||
|  	struct brcmf_chip *ci; | ||||
| @@ -1592,8 +1590,7 @@ static int brcmf_pcie_get_resource(struc | ||||
|  	} | ||||
|   | ||||
|  	devinfo->regs = ioremap_nocache(bar0_addr, BRCMF_PCIE_REG_MAP_SIZE); | ||||
| -	devinfo->tcm = ioremap_nocache(bar1_addr, BRCMF_PCIE_TCM_MAP_SIZE); | ||||
| -	devinfo->tcm_size = BRCMF_PCIE_TCM_MAP_SIZE; | ||||
| +	devinfo->tcm = ioremap_nocache(bar1_addr, bar1_size); | ||||
|   | ||||
|  	if (!devinfo->regs || !devinfo->tcm) { | ||||
|  		brcmf_err("ioremap() failed (%p,%p)\n", devinfo->regs, | ||||
| @@ -1602,8 +1599,9 @@ static int brcmf_pcie_get_resource(struc | ||||
|  	} | ||||
|  	brcmf_dbg(PCIE, "Phys addr : reg space = %p base addr %#016llx\n", | ||||
|  		  devinfo->regs, (unsigned long long)bar0_addr); | ||||
| -	brcmf_dbg(PCIE, "Phys addr : mem space = %p base addr %#016llx\n", | ||||
| -		  devinfo->tcm, (unsigned long long)bar1_addr); | ||||
| +	brcmf_dbg(PCIE, "Phys addr : mem space = %p base addr %#016llx size 0x%x\n", | ||||
| +		  devinfo->tcm, (unsigned long long)bar1_addr, | ||||
| +		  (unsigned int)bar1_size); | ||||
|   | ||||
|  	return 0; | ||||
|  } | ||||
| @@ -1,34 +0,0 @@ | ||||
| From: Hante Meuleman <meuleman@broadcom.com> | ||||
| Date: Wed, 17 Feb 2016 11:26:59 +0100 | ||||
| Subject: [PATCH] brcmfmac: add support for the PCIE 4366c0 chip | ||||
|  | ||||
| A newer version of the 4366 PCIE chip has been released. Add | ||||
| support for this version of the chip. | ||||
|  | ||||
| Reviewed-by: Arend Van Spriel <arend@broadcom.com> | ||||
| Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> | ||||
| Signed-off-by: Hante Meuleman <meuleman@broadcom.com> | ||||
| Signed-off-by: Arend van Spriel <arend@broadcom.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | ||||
| @@ -53,6 +53,7 @@ BRCMF_FW_NVRAM_DEF(4358, "brcmfmac4358-p | ||||
|  BRCMF_FW_NVRAM_DEF(4359, "brcmfmac4359-pcie.bin", "brcmfmac4359-pcie.txt"); | ||||
|  BRCMF_FW_NVRAM_DEF(4365B, "brcmfmac4365b-pcie.bin", "brcmfmac4365b-pcie.txt"); | ||||
|  BRCMF_FW_NVRAM_DEF(4366B, "brcmfmac4366b-pcie.bin", "brcmfmac4366b-pcie.txt"); | ||||
| +BRCMF_FW_NVRAM_DEF(4366C, "brcmfmac4366c-pcie.bin", "brcmfmac4366c-pcie.txt"); | ||||
|  BRCMF_FW_NVRAM_DEF(4371, "brcmfmac4371-pcie.bin", "brcmfmac4371-pcie.txt"); | ||||
|   | ||||
|  static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { | ||||
| @@ -66,7 +67,8 @@ static struct brcmf_firmware_mapping brc | ||||
|  	BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358), | ||||
|  	BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), | ||||
|  	BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFFF, 4365B), | ||||
| -	BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFFF, 4366B), | ||||
| +	BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B), | ||||
| +	BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C), | ||||
|  	BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), | ||||
|  }; | ||||
|   | ||||
| @@ -1,30 +0,0 @@ | ||||
| From: Hante Meuleman <meuleman@broadcom.com> | ||||
| Date: Wed, 17 Feb 2016 11:27:01 +0100 | ||||
| Subject: [PATCH] brcmfmac: increase timeout for tx eapol | ||||
|  | ||||
| When keys get set and updated this has to happen after eapol got | ||||
| transmitted (without key or old key) before the key can be updated. | ||||
| To make sure the order of sending eapol and configuring key is done | ||||
| correctly a timeout for tx of eapol is applied. This timeout is set | ||||
| to 50 msec, which is not always enough. Especially in AP mode and | ||||
| key updates the timeout may need to be much longer because client(s) | ||||
| can be in powersave. Increase the timeout from 50 to 950 msec. | ||||
|  | ||||
| Reviewed-by: Arend Van Spriel <arend@broadcom.com> | ||||
| Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> | ||||
| Signed-off-by: Hante Meuleman <meuleman@broadcom.com> | ||||
| Signed-off-by: Arend van Spriel <arend@broadcom.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | ||||
| @@ -40,7 +40,7 @@ MODULE_AUTHOR("Broadcom Corporation"); | ||||
|  MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); | ||||
|  MODULE_LICENSE("Dual BSD/GPL"); | ||||
|   | ||||
| -#define MAX_WAIT_FOR_8021X_TX			msecs_to_jiffies(50) | ||||
| +#define MAX_WAIT_FOR_8021X_TX			msecs_to_jiffies(950) | ||||
|   | ||||
|  /* AMPDU rx reordering definitions */ | ||||
|  #define BRCMF_RXREORDER_FLOWID_OFFSET		0 | ||||
| @@ -1,114 +0,0 @@ | ||||
| From: Hante Meuleman <hante.meuleman@broadcom.com> | ||||
| Date: Mon, 11 Apr 2016 11:35:23 +0200 | ||||
| Subject: [PATCH] brcmfmac: insert default boardrev in nvram data if | ||||
|  missing | ||||
|  | ||||
| Some nvram files/stores come without the boardrev information, | ||||
| but firmware requires this to be set. When not found in nvram then | ||||
| add a default boardrev string to the nvram data. | ||||
|  | ||||
| Reported-by: Rafal Milecki <zajec5@gmail.com> | ||||
| Reviewed-by: Arend Van Spriel <arend@broadcom.com> | ||||
| Reviewed-by: Franky (Zhenhui) Lin <franky.lin@broadcom.com> | ||||
| Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com> | ||||
| Signed-off-by: Hante Meuleman <hante.meuleman@broadcom.com> | ||||
| Signed-off-by: Arend van Spriel <arend@broadcom.com> | ||||
| Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | ||||
| --- | ||||
|  | ||||
| --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||
| +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c | ||||
| @@ -29,6 +29,7 @@ | ||||
|  #define BRCMF_FW_MAX_NVRAM_SIZE			64000 | ||||
|  #define BRCMF_FW_NVRAM_DEVPATH_LEN		19	/* devpath0=pcie/1/4/ */ | ||||
|  #define BRCMF_FW_NVRAM_PCIEDEV_LEN		10	/* pcie/1/4/ + \0 */ | ||||
| +#define BRCMF_FW_DEFAULT_BOARDREV		"boardrev=0xff" | ||||
|   | ||||
|  enum nvram_parser_state { | ||||
|  	IDLE, | ||||
| @@ -51,6 +52,7 @@ enum nvram_parser_state { | ||||
|   * @entry: start position of key,value entry. | ||||
|   * @multi_dev_v1: detect pcie multi device v1 (compressed). | ||||
|   * @multi_dev_v2: detect pcie multi device v2. | ||||
| + * @boardrev_found: nvram contains boardrev information. | ||||
|   */ | ||||
|  struct nvram_parser { | ||||
|  	enum nvram_parser_state state; | ||||
| @@ -63,6 +65,7 @@ struct nvram_parser { | ||||
|  	u32 entry; | ||||
|  	bool multi_dev_v1; | ||||
|  	bool multi_dev_v2; | ||||
| +	bool boardrev_found; | ||||
|  }; | ||||
|   | ||||
|  /** | ||||
| @@ -125,6 +128,8 @@ static enum nvram_parser_state brcmf_nvr | ||||
|  			nvp->multi_dev_v1 = true; | ||||
|  		if (strncmp(&nvp->data[nvp->entry], "pcie/", 5) == 0) | ||||
|  			nvp->multi_dev_v2 = true; | ||||
| +		if (strncmp(&nvp->data[nvp->entry], "boardrev", 8) == 0) | ||||
| +			nvp->boardrev_found = true; | ||||
|  	} else if (!is_nvram_char(c) || c == ' ') { | ||||
|  		brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n", | ||||
|  			  nvp->line, nvp->column); | ||||
| @@ -284,6 +289,8 @@ static void brcmf_fw_strip_multi_v1(stru | ||||
|  	while (i < nvp->nvram_len) { | ||||
|  		if ((nvp->nvram[i] - '0' == id) && (nvp->nvram[i + 1] == ':')) { | ||||
|  			i += 2; | ||||
| +			if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0) | ||||
| +				nvp->boardrev_found = true; | ||||
|  			while (nvp->nvram[i] != 0) { | ||||
|  				nvram[j] = nvp->nvram[i]; | ||||
|  				i++; | ||||
| @@ -335,6 +342,8 @@ static void brcmf_fw_strip_multi_v2(stru | ||||
|  	while (i < nvp->nvram_len - len) { | ||||
|  		if (strncmp(&nvp->nvram[i], prefix, len) == 0) { | ||||
|  			i += len; | ||||
| +			if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0) | ||||
| +				nvp->boardrev_found = true; | ||||
|  			while (nvp->nvram[i] != 0) { | ||||
|  				nvram[j] = nvp->nvram[i]; | ||||
|  				i++; | ||||
| @@ -356,6 +365,18 @@ fail: | ||||
|  	nvp->nvram_len = 0; | ||||
|  } | ||||
|   | ||||
| +static void brcmf_fw_add_defaults(struct nvram_parser *nvp) | ||||
| +{ | ||||
| +	if (nvp->boardrev_found) | ||||
| +		return; | ||||
| + | ||||
| +	memcpy(&nvp->nvram[nvp->nvram_len], &BRCMF_FW_DEFAULT_BOARDREV, | ||||
| +	       strlen(BRCMF_FW_DEFAULT_BOARDREV)); | ||||
| +	nvp->nvram_len += strlen(BRCMF_FW_DEFAULT_BOARDREV); | ||||
| +	nvp->nvram[nvp->nvram_len] = '\0'; | ||||
| +	nvp->nvram_len++; | ||||
| +} | ||||
| + | ||||
|  /* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil | ||||
|   * and ending in a NUL. Removes carriage returns, empty lines, comment lines, | ||||
|   * and converts newlines to NULs. Shortens buffer as needed and pads with NULs. | ||||
| @@ -377,16 +398,21 @@ static void *brcmf_fw_nvram_strip(const | ||||
|  		if (nvp.state == END) | ||||
|  			break; | ||||
|  	} | ||||
| -	if (nvp.multi_dev_v1) | ||||
| +	if (nvp.multi_dev_v1) { | ||||
| +		nvp.boardrev_found = false; | ||||
|  		brcmf_fw_strip_multi_v1(&nvp, domain_nr, bus_nr); | ||||
| -	else if (nvp.multi_dev_v2) | ||||
| +	} else if (nvp.multi_dev_v2) { | ||||
| +		nvp.boardrev_found = false; | ||||
|  		brcmf_fw_strip_multi_v2(&nvp, domain_nr, bus_nr); | ||||
| +	} | ||||
|   | ||||
|  	if (nvp.nvram_len == 0) { | ||||
|  		kfree(nvp.nvram); | ||||
|  		return NULL; | ||||
|  	} | ||||
|   | ||||
| +	brcmf_fw_add_defaults(&nvp); | ||||
| + | ||||
|  	pad = nvp.nvram_len; | ||||
|  	*new_length = roundup(nvp.nvram_len + 1, 4); | ||||
|  	while (pad != *new_length) { | ||||
| @@ -1,30 +0,0 @@ | ||||
| --- a/drivers/net/wireless/ath/Makefile | ||||
| +++ b/drivers/net/wireless/ath/Makefile | ||||
| @@ -13,10 +13,10 @@ ath-objs :=	main.o \ | ||||
|  		regd.o \ | ||||
|  		hw.o \ | ||||
|  		key.o \ | ||||
| +		debug.o \ | ||||
|  		dfs_pattern_detector.o \ | ||||
|  		dfs_pri_detector.o | ||||
|   | ||||
| -ath-$(CPTCFG_ATH_DEBUG) += debug.o | ||||
|  ath-$(CPTCFG_ATH_TRACEPOINTS) += trace.o | ||||
|   | ||||
|  ccflags-y += -D__CHECK_ENDIAN__ | ||||
| --- a/drivers/net/wireless/ath/ath.h | ||||
| +++ b/drivers/net/wireless/ath/ath.h | ||||
| @@ -318,13 +318,6 @@ void _ath_dbg(struct ath_common *common, | ||||
|  #endif /* CPTCFG_ATH_DEBUG */ | ||||
|   | ||||
|  /** Returns string describing opmode, or NULL if unknown mode. */ | ||||
| -#ifdef CPTCFG_ATH_DEBUG | ||||
|  const char *ath_opmode_to_string(enum nl80211_iftype opmode); | ||||
| -#else | ||||
| -static inline const char *ath_opmode_to_string(enum nl80211_iftype opmode) | ||||
| -{ | ||||
| -	return "UNKNOWN"; | ||||
| -} | ||||
| -#endif | ||||
|   | ||||
|  #endif /* ATH_H */ | ||||
| @@ -1,11 +0,0 @@ | ||||
| --- a/drivers/net/wireless/ath/ath9k/init.c | ||||
| +++ b/drivers/net/wireless/ath/ath9k/init.c | ||||
| @@ -45,7 +45,7 @@ int ath9k_modparam_nohwcrypt; | ||||
|  module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444); | ||||
|  MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption"); | ||||
|   | ||||
| -int ath9k_led_blink; | ||||
| +int ath9k_led_blink = 1; | ||||
|  module_param_named(blink, ath9k_led_blink, int, 0444); | ||||
|  MODULE_PARM_DESC(blink, "Enable LED blink on activity"); | ||||
|   | ||||
| @@ -1,69 +0,0 @@ | ||||
| --- a/drivers/net/wireless/ath/regd.c | ||||
| +++ b/drivers/net/wireless/ath/regd.c | ||||
| @@ -341,6 +341,10 @@ ath_reg_apply_beaconing_flags(struct wip | ||||
|  	struct ieee80211_channel *ch; | ||||
|  	unsigned int i; | ||||
|   | ||||
| +#ifdef CPTCFG_ATH_USER_REGD | ||||
| +	return; | ||||
| +#endif | ||||
| + | ||||
|  	for (band = 0; band < IEEE80211_NUM_BANDS; band++) { | ||||
|  		if (!wiphy->bands[band]) | ||||
|  			continue; | ||||
| @@ -374,6 +378,10 @@ ath_reg_apply_ir_flags(struct wiphy *wip | ||||
|  { | ||||
|  	struct ieee80211_supported_band *sband; | ||||
|   | ||||
| +#ifdef CPTCFG_ATH_USER_REGD | ||||
| +	return; | ||||
| +#endif | ||||
| + | ||||
|  	sband = wiphy->bands[IEEE80211_BAND_2GHZ]; | ||||
|  	if (!sband) | ||||
|  		return; | ||||
| @@ -402,6 +410,10 @@ static void ath_reg_apply_radar_flags(st | ||||
|  	struct ieee80211_channel *ch; | ||||
|  	unsigned int i; | ||||
|   | ||||
| +#ifdef CPTCFG_ATH_USER_REGD | ||||
| +	return; | ||||
| +#endif | ||||
| + | ||||
|  	if (!wiphy->bands[IEEE80211_BAND_5GHZ]) | ||||
|  		return; | ||||
|   | ||||
| @@ -633,6 +645,11 @@ ath_regd_init_wiphy(struct ath_regulator | ||||
|  	const struct ieee80211_regdomain *regd; | ||||
|   | ||||
|  	wiphy->reg_notifier = reg_notifier; | ||||
| + | ||||
| +#ifdef CPTCFG_ATH_USER_REGD | ||||
| +	return 0; | ||||
| +#endif | ||||
| + | ||||
|  	wiphy->regulatory_flags |= REGULATORY_STRICT_REG | | ||||
|  				   REGULATORY_CUSTOM_REG; | ||||
|   | ||||
| --- a/drivers/net/wireless/ath/Kconfig | ||||
| +++ b/drivers/net/wireless/ath/Kconfig | ||||
| @@ -23,6 +23,9 @@ config WLAN_VENDOR_ATH | ||||
|   | ||||
|  if WLAN_VENDOR_ATH | ||||
|   | ||||
| +config ATH_USER_REGD | ||||
| +	bool "Do not enforce EEPROM regulatory restrictions" | ||||
| + | ||||
|  config ATH_DEBUG | ||||
|  	bool "Atheros wireless debugging" | ||||
|  	---help--- | ||||
| --- a/.local-symbols | ||||
| +++ b/.local-symbols | ||||
| @@ -125,6 +125,7 @@ ADM8211= | ||||
|  ATH_COMMON= | ||||
|  WLAN_VENDOR_ATH= | ||||
|  ATH_DEBUG= | ||||
| +ATH_USER_REGD= | ||||
|  ATH_TRACEPOINTS= | ||||
|  ATH_REG_DYNAMIC_USER_REG_HINTS= | ||||
|  ATH_REG_DYNAMIC_USER_CERT_TESTING= | ||||
| @@ -1,84 +0,0 @@ | ||||
| --- a/drivers/net/wireless/ath/regd.c | ||||
| +++ b/drivers/net/wireless/ath/regd.c | ||||
| @@ -43,7 +43,8 @@ static int __ath_regd_init(struct ath_re | ||||
|  					 NL80211_RRF_NO_OFDM) | ||||
|   | ||||
|  /* We allow IBSS on these on a case by case basis by regulatory domain */ | ||||
| -#define ATH9K_5GHZ_5150_5350	REG_RULE(5150-10, 5350+10, 80, 0, 30,\ | ||||
| +#define ATH9K_5GHZ_5150_5350	REG_RULE(5150-10, 5240+10, 80, 0, 30, 0),\ | ||||
| +				REG_RULE(5260-10, 5350+10, 80, 0, 30,\ | ||||
|  					 NL80211_RRF_NO_IR) | ||||
|  #define ATH9K_5GHZ_5470_5850	REG_RULE(5470-10, 5850+10, 80, 0, 30,\ | ||||
|  					 NL80211_RRF_NO_IR) | ||||
| @@ -61,57 +62,56 @@ static int __ath_regd_init(struct ath_re | ||||
|  #define ATH9K_5GHZ_NO_MIDBAND	ATH9K_5GHZ_5150_5350, \ | ||||
|  				ATH9K_5GHZ_5725_5850 | ||||
|   | ||||
| +#define REGD_RULES(...) \ | ||||
| +	.reg_rules = { __VA_ARGS__ }, \ | ||||
| +	.n_reg_rules = ARRAY_SIZE(((struct ieee80211_reg_rule[]) { __VA_ARGS__ })) | ||||
| + | ||||
|  /* Can be used for: | ||||
|   * 0x60, 0x61, 0x62 */ | ||||
|  static const struct ieee80211_regdomain ath_world_regdom_60_61_62 = { | ||||
| -	.n_reg_rules = 5, | ||||
|  	.alpha2 =  "99", | ||||
| -	.reg_rules = { | ||||
| +	REGD_RULES( | ||||
|  		ATH9K_2GHZ_ALL, | ||||
|  		ATH9K_5GHZ_ALL, | ||||
| -	} | ||||
| +	) | ||||
|  }; | ||||
|   | ||||
|  /* Can be used by 0x63 and 0x65 */ | ||||
|  static const struct ieee80211_regdomain ath_world_regdom_63_65 = { | ||||
| -	.n_reg_rules = 4, | ||||
|  	.alpha2 =  "99", | ||||
| -	.reg_rules = { | ||||
| +	REGD_RULES( | ||||
|  		ATH9K_2GHZ_CH01_11, | ||||
|  		ATH9K_2GHZ_CH12_13, | ||||
|  		ATH9K_5GHZ_NO_MIDBAND, | ||||
| -	} | ||||
| +	) | ||||
|  }; | ||||
|   | ||||
|  /* Can be used by 0x64 only */ | ||||
|  static const struct ieee80211_regdomain ath_world_regdom_64 = { | ||||
| -	.n_reg_rules = 3, | ||||
|  	.alpha2 =  "99", | ||||
| -	.reg_rules = { | ||||
| +	REGD_RULES( | ||||
|  		ATH9K_2GHZ_CH01_11, | ||||
|  		ATH9K_5GHZ_NO_MIDBAND, | ||||
| -	} | ||||
| +	) | ||||
|  }; | ||||
|   | ||||
|  /* Can be used by 0x66 and 0x69 */ | ||||
|  static const struct ieee80211_regdomain ath_world_regdom_66_69 = { | ||||
| -	.n_reg_rules = 3, | ||||
|  	.alpha2 =  "99", | ||||
| -	.reg_rules = { | ||||
| +	REGD_RULES( | ||||
|  		ATH9K_2GHZ_CH01_11, | ||||
|  		ATH9K_5GHZ_ALL, | ||||
| -	} | ||||
| +	) | ||||
|  }; | ||||
|   | ||||
|  /* Can be used by 0x67, 0x68, 0x6A and 0x6C */ | ||||
|  static const struct ieee80211_regdomain ath_world_regdom_67_68_6A_6C = { | ||||
| -	.n_reg_rules = 4, | ||||
|  	.alpha2 =  "99", | ||||
| -	.reg_rules = { | ||||
| +	REGD_RULES( | ||||
|  		ATH9K_2GHZ_CH01_11, | ||||
|  		ATH9K_2GHZ_CH12_13, | ||||
|  		ATH9K_5GHZ_ALL, | ||||
| -	} | ||||
| +	) | ||||
|  }; | ||||
|   | ||||
|  static bool dynamic_country_user_possible(struct ath_regulatory *reg) | ||||
| @@ -1,19 +0,0 @@ | ||||
| --- a/net/wireless/reg.c | ||||
| +++ b/net/wireless/reg.c | ||||
| @@ -2411,6 +2411,8 @@ void regulatory_hint_country_ie(struct w | ||||
|  	enum environment_cap env = ENVIRON_ANY; | ||||
|  	struct regulatory_request *request = NULL, *lr; | ||||
|   | ||||
| +	return; | ||||
| + | ||||
|  	/* IE len must be evenly divisible by 2 */ | ||||
|  	if (country_ie_len & 0x01) | ||||
|  		return; | ||||
| @@ -2617,6 +2619,7 @@ static void restore_regulatory_settings( | ||||
|   | ||||
|  void regulatory_hint_disconnect(void) | ||||
|  { | ||||
| +	return; | ||||
|  	pr_debug("All devices are disconnected, going to restore regulatory settings\n"); | ||||
|  	restore_regulatory_settings(false); | ||||
|  } | ||||
| @@ -1,26 +0,0 @@ | ||||
| --- a/drivers/net/wireless/ath/regd_common.h | ||||
| +++ b/drivers/net/wireless/ath/regd_common.h | ||||
| @@ -32,6 +32,7 @@ enum EnumRd { | ||||
|  	FCC2_WORLD = 0x21, | ||||
|  	FCC2_ETSIC = 0x22, | ||||
|  	FCC6_WORLD = 0x23, | ||||
| +	FCC3_FCCA_2 = 0x2A, | ||||
|  	FRANCE_RES = 0x31, | ||||
|  	FCC3_FCCA = 0x3A, | ||||
|  	FCC3_WORLD = 0x3B, | ||||
| @@ -167,6 +168,7 @@ static struct reg_dmn_pair_mapping regDo | ||||
|  	{FCC2_WORLD, CTL_FCC, CTL_ETSI}, | ||||
|  	{FCC2_ETSIC, CTL_FCC, CTL_ETSI}, | ||||
|  	{FCC3_FCCA, CTL_FCC, CTL_FCC}, | ||||
| +	{FCC3_FCCA_2, CTL_FCC, CTL_FCC}, | ||||
|  	{FCC3_WORLD, CTL_FCC, CTL_ETSI}, | ||||
|  	{FCC4_FCCA, CTL_FCC, CTL_FCC}, | ||||
|  	{FCC5_FCCA, CTL_FCC, CTL_FCC}, | ||||
| @@ -463,6 +465,7 @@ static struct country_code_to_enum_rd al | ||||
|  	{CTRY_UAE, NULL1_WORLD, "AE"}, | ||||
|  	{CTRY_UNITED_KINGDOM, ETSI1_WORLD, "GB"}, | ||||
|  	{CTRY_UNITED_STATES, FCC3_FCCA, "US"}, | ||||
| +	{CTRY_UNITED_STATES, FCC3_FCCA_2, "US"}, | ||||
|  	/* This "PS" is for US public safety actually... to support this we | ||||
|  	 * would need to assign new special alpha2 to CRDA db as with the world | ||||
|  	 * regdomain and use another alpha2 */ | ||||
| @@ -1,47 +0,0 @@ | ||||
| --- a/drivers/net/wireless/ath/regd.c | ||||
| +++ b/drivers/net/wireless/ath/regd.c | ||||
| @@ -114,10 +114,22 @@ static const struct ieee80211_regdomain | ||||
|  	) | ||||
|  }; | ||||
|   | ||||
| +static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) | ||||
| +{ | ||||
| +	return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; | ||||
| +} | ||||
| + | ||||
| +static bool is_default_regd(struct ath_regulatory *reg) | ||||
| +{ | ||||
| +	return ath_regd_get_eepromRD(reg) == CTRY_DEFAULT; | ||||
| +} | ||||
| + | ||||
|  static bool dynamic_country_user_possible(struct ath_regulatory *reg) | ||||
|  { | ||||
|  	if (config_enabled(CPTCFG_ATH_REG_DYNAMIC_USER_CERT_TESTING)) | ||||
|  		return true; | ||||
| +	if (is_default_regd(reg)) | ||||
| +		return true; | ||||
|   | ||||
|  	switch (reg->country_code) { | ||||
|  	case CTRY_UNITED_STATES: | ||||
| @@ -202,11 +214,6 @@ static inline bool is_wwr_sku(u16 regd) | ||||
|  		(regd == WORLD)); | ||||
|  } | ||||
|   | ||||
| -static u16 ath_regd_get_eepromRD(struct ath_regulatory *reg) | ||||
| -{ | ||||
| -	return reg->current_rd & ~WORLDWIDE_ROAMING_FLAG; | ||||
| -} | ||||
| - | ||||
|  bool ath_is_world_regd(struct ath_regulatory *reg) | ||||
|  { | ||||
|  	return is_wwr_sku(ath_regd_get_eepromRD(reg)); | ||||
| @@ -650,6 +657,9 @@ ath_regd_init_wiphy(struct ath_regulator | ||||
|  	return 0; | ||||
|  #endif | ||||
|   | ||||
| +	if (is_default_regd(reg)) | ||||
| +		return 0; | ||||
| + | ||||
|  	wiphy->regulatory_flags |= REGULATORY_STRICT_REG | | ||||
|  				   REGULATORY_CUSTOM_REG; | ||||
|   | ||||
| @@ -1,10 +0,0 @@ | ||||
| --- a/drivers/net/wireless/ath/ath9k/init.c | ||||
| +++ b/drivers/net/wireless/ath/ath9k/init.c | ||||
| @@ -722,6 +722,7 @@ static const struct ieee80211_iface_limi | ||||
|  				 BIT(NL80211_IFTYPE_AP) }, | ||||
|  	{ .max = 1,	.types = BIT(NL80211_IFTYPE_P2P_CLIENT) | | ||||
|  				 BIT(NL80211_IFTYPE_P2P_GO) }, | ||||
| +	{ .max = 1,	.types = BIT(NL80211_IFTYPE_ADHOC) }, | ||||
|  }; | ||||
|   | ||||
|  static const struct ieee80211_iface_limit wds_limits[] = { | ||||
| @@ -1,46 +0,0 @@ | ||||
| --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c | ||||
| +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c | ||||
| @@ -86,13 +86,8 @@ ath5k_add_interface(struct ieee80211_hw | ||||
|  		goto end; | ||||
|  	} | ||||
|   | ||||
| -	/* Don't allow other interfaces if one ad-hoc is configured. | ||||
| -	 * TODO: Fix the problems with ad-hoc and multiple other interfaces. | ||||
| -	 * We would need to operate the HW in ad-hoc mode to allow TSF updates | ||||
| -	 * for the IBSS, but this breaks with additional AP or STA interfaces | ||||
| -	 * at the moment. */ | ||||
| -	if (ah->num_adhoc_vifs || | ||||
| -	    (ah->nvifs && vif->type == NL80211_IFTYPE_ADHOC)) { | ||||
| +	/* Don't allow more than one ad-hoc interface */ | ||||
| +	if (ah->num_adhoc_vifs && vif->type == NL80211_IFTYPE_ADHOC) { | ||||
|  		ATH5K_ERR(ah, "Only one single ad-hoc interface is allowed.\n"); | ||||
|  		ret = -ELNRNG; | ||||
|  		goto end; | ||||
| --- a/drivers/net/wireless/ath/ath5k/base.c | ||||
| +++ b/drivers/net/wireless/ath/ath5k/base.c | ||||
| @@ -1965,7 +1965,7 @@ ath5k_beacon_send(struct ath5k_hw *ah) | ||||
|  	} | ||||
|   | ||||
|  	if ((ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs + | ||||
| -			ah->num_mesh_vifs > 1) || | ||||
| +			ah->num_adhoc_vifs + ah->num_mesh_vifs > 1) || | ||||
|  			ah->opmode == NL80211_IFTYPE_MESH_POINT) { | ||||
|  		u64 tsf = ath5k_hw_get_tsf64(ah); | ||||
|  		u32 tsftu = TSF_TO_TU(tsf); | ||||
| @@ -2051,7 +2051,7 @@ ath5k_beacon_update_timers(struct ath5k_ | ||||
|   | ||||
|  	intval = ah->bintval & AR5K_BEACON_PERIOD; | ||||
|  	if (ah->opmode == NL80211_IFTYPE_AP && ah->num_ap_vifs | ||||
| -		+ ah->num_mesh_vifs > 1) { | ||||
| +		+ ah->num_adhoc_vifs + ah->num_mesh_vifs > 1) { | ||||
|  		intval /= ATH_BCBUF;	/* staggered multi-bss beacons */ | ||||
|  		if (intval < 15) | ||||
|  			ATH5K_WARN(ah, "intval %u is too low, min 15\n", | ||||
| @@ -2518,6 +2518,7 @@ static const struct ieee80211_iface_limi | ||||
|  				 BIT(NL80211_IFTYPE_MESH_POINT) | | ||||
|  #endif | ||||
|  				 BIT(NL80211_IFTYPE_AP) }, | ||||
| +	{ .max = 1,	.types = BIT(NL80211_IFTYPE_ADHOC) }, | ||||
|  }; | ||||
|   | ||||
|  static const struct ieee80211_iface_combination if_comb = { | ||||
| @@ -1,18 +0,0 @@ | ||||
| --- a/drivers/net/wireless/ath/ath5k/reset.c | ||||
| +++ b/drivers/net/wireless/ath/ath5k/reset.c | ||||
| @@ -1154,6 +1154,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum | ||||
|  	tsf_lo = 0; | ||||
|  	mode = 0; | ||||
|   | ||||
| +#if 0 | ||||
|  	/* | ||||
|  	 * Sanity check for fast flag | ||||
|  	 * Fast channel change only available | ||||
| @@ -1161,6 +1162,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum | ||||
|  	 */ | ||||
|  	if (fast && (ah->ah_radio != AR5K_RF2413) && | ||||
|  	(ah->ah_radio != AR5K_RF5413)) | ||||
| +#endif | ||||
|  		fast = false; | ||||
|   | ||||
|  	/* Disable sleep clock operation | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 John Crispin
					John Crispin