mirror of
				https://github.com/Telecominfraproject/wlan-ap.git
				synced 2025-10-31 18:38:10 +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/ipq40xx | ||||||
|   - patches/ipq806x |   - patches/ipq806x | ||||||
|   - patches/ipq807x |   - patches/ipq807x | ||||||
|   - patches/rtkmipsel |  | ||||||
|   - patches/rest |   - patches/rest | ||||||
|   - patches/x86 |   - 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