driver_cmd_nl80211.c revision b11634b6f66e5ae56fe2212bd5d648157541c6e6
1b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt/* 2b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * Driver interaction with extended Linux CFG8021 3b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * 4b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * This program is free software; you can redistribute it and/or modify 5b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as 6b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * published by the Free Software Foundation. 7b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * 8b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD 9b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * license. 10b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt * 11b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt */ 12b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 13b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt#include "driver_nl80211.h" 14b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 15b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE " 16b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 17b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt#define WPA_PS_ENABLED 0 18b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt#define WPA_PS_DISABLED 1 19b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 20b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidtint send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg, 21b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt int (*valid_handler)(struct nl_msg *, void *), 22b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt void *valid_data); 23b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 24b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidtstatic int wpa_driver_set_btcoex_state(char state) 25b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt{ 26b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt int ret; 27b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt int fd; 28b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 29b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt fd = open("/sys/devices/platform/bcmdhd/bt_coex_state", O_RDWR, 0); 30b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt if (fd == -1) 31b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt return -1; 32b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 33b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt ret = write(fd, &state, sizeof(state)); 34b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt close(fd); 35b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 36b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "%s: set btcoex state to '%c' result = %d", 37b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt __func__, state, ret); 38b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt return (ret > 0) ? 0 : -1; 39b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt} 40b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 41b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidtstatic int wpa_driver_set_power_save(void *priv, int state) 42b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt{ 43b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt struct i802_bss *bss = priv; 44b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt struct wpa_driver_nl80211_data *drv = bss->drv; 45b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt struct nl_msg *msg; 46b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt int ret = -1; 47b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt enum nl80211_ps_state ps_state; 48b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 49b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt msg = nlmsg_alloc(); 50b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt if (!msg) 51b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt return -1; 52b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 53b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, 54b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt NL80211_CMD_SET_POWER_SAVE, 0); 55b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 56b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt if (state == WPA_PS_ENABLED) 57b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt ps_state = NL80211_PS_ENABLED; 58b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt else 59b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt ps_state = NL80211_PS_DISABLED; 60b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 61b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); 62b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE, ps_state); 63b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 64b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt ret = send_and_recv_msgs(drv, msg, NULL, NULL); 65b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt msg = NULL; 66b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt if (ret < 0) 67b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt wpa_printf(MSG_ERROR, "nl80211: Set power mode fail: %d", ret); 68b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidtnla_put_failure: 69b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt nlmsg_free(msg); 70b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt return ret; 71b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt} 72b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 73b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidtstatic int get_power_mode_handler(struct nl_msg *msg, void *arg) 74b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt{ 75b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt struct nlattr *tb[NL80211_ATTR_MAX + 1]; 76b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg)); 77b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt int *state = (int *)arg; 78b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 79b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), 80b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt genlmsg_attrlen(gnlh, 0), NULL); 81b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 82b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt if (!tb[NL80211_ATTR_PS_STATE]) 83b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt return NL_SKIP; 84b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 85b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt if (state) { 86b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt *state = (int)nla_get_u32(tb[NL80211_ATTR_PS_STATE]); 87b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt wpa_printf(MSG_DEBUG, "nl80211: Get power mode = %d", *state); 88b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt *state = (*state == NL80211_PS_ENABLED) ? 89b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt WPA_PS_ENABLED : WPA_PS_DISABLED; 90b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt } 91b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 92b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt return NL_SKIP; 93b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt} 94b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 95b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidtstatic int wpa_driver_get_power_save(void *priv, int *state) 96b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt{ 97b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt struct i802_bss *bss = priv; 98b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt struct wpa_driver_nl80211_data *drv = bss->drv; 99b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt struct nl_msg *msg; 100b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt int ret = -1; 101b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt enum nl80211_ps_state ps_state; 102b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 103b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt msg = nlmsg_alloc(); 104b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt if (!msg) 105b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt return -1; 106b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 107b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, 108b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt NL80211_CMD_GET_POWER_SAVE, 0); 109b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 110b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); 111b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 112b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt ret = send_and_recv_msgs(drv, msg, get_power_mode_handler, state); 113b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt msg = NULL; 114b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt if (ret < 0) 115b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt wpa_printf(MSG_ERROR, "nl80211: Get power mode fail: %d", ret); 116b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidtnla_put_failure: 117b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt nlmsg_free(msg); 118b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt return ret; 119b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt} 120b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 121b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidtint wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, 122b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt size_t buf_len ) 123b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt{ 124b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt struct i802_bss *bss = priv; 125b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt struct wpa_driver_nl80211_data *drv = bss->drv; 126b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt int ret = 0; 127b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 128b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt wpa_msg(drv->ctx, MSG_INFO, "%s: %s", __func__, cmd); 129b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 130b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt if (os_strcasecmp(cmd, "STOP") == 0) { 131b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0); 132b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); 133b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt } else if (os_strcasecmp(cmd, "START") == 0) { 134b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1); 135b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); 136b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt } else if (os_strcasecmp(cmd, "MACADDR") == 0) { 137b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt u8 macaddr[ETH_ALEN] = {}; 138b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 139b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt ret = linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, macaddr); 140b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt if (!ret) 141b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt ret = os_snprintf(buf, buf_len, 142b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt "Macaddr = " MACSTR "\n", MAC2STR(macaddr)); 143b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt } else if (os_strcasecmp(cmd, "RELOAD") == 0) { 144b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); 145b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt } else if (os_strncasecmp(cmd, "POWERMODE ", 10) == 0) { 146b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt int state; 147b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 148b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt state = atoi(cmd + 10); 149b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt ret = wpa_driver_set_power_save(priv, state); 150b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt } else if (os_strncasecmp(cmd, "GETPOWER", 8) == 0) { 151b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt int state = -1; 152b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 153b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt ret = wpa_driver_get_power_save(priv, &state); 154b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt if (!ret && (state != -1)) 155b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt ret = os_snprintf(buf, buf_len, "POWERMODE = %d\n", state); 156b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt } else if (os_strncasecmp(cmd, "BTCOEXMODE ", 11) == 0) { 157b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt char state = cmd[11]; 158b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 159b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt ret = wpa_driver_set_btcoex_state(state); 160b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt } else { 161b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt wpa_printf(MSG_ERROR, "Unsupported command: %s", cmd); 162b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt ret = -1; 163b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt } 164b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt 165b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt return ret; 166b11634b6f66e5ae56fe2212bd5d648157541c6e6Dmitry Shmidt} 167