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