2 * Driver interaction with extended Linux CFG8021
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.
8 * Alternatively, this software may be distributed under the terms of BSD
14 #include <sys/types.h>
19 #include "linux_ioctl.h"
20 #include "driver_nl80211.h"
21 #include "wpa_supplicant_i.h"
24 #include "android_drv.h"
27 typedef struct android_wifi_priv_cmd
{
31 } android_wifi_priv_cmd
;
33 static int drv_errors
= 0;
35 static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data
*drv
)
38 if (drv_errors
> DRV_NUMBER_SEQUENTIAL_ERRORS
) {
40 wpa_msg(drv
->ctx
, MSG_INFO
, WPA_EVENT_DRIVER_STATE
"HANGED");
44 static void wpa_driver_notify_country_change(void *ctx
, char *cmd
)
46 if ((os_strncasecmp(cmd
, "COUNTRY", 7) == 0) ||
47 (os_strncasecmp(cmd
, "SETBAND", 7) == 0)) {
48 union wpa_event_data event
;
50 os_memset(&event
, 0, sizeof(event
));
51 event
.channel_list_changed
.initiator
= REGDOM_SET_BY_USER
;
52 if (os_strncasecmp(cmd
, "COUNTRY", 7) == 0) {
53 event
.channel_list_changed
.type
= REGDOM_TYPE_COUNTRY
;
54 if (os_strlen(cmd
) > 9) {
55 event
.channel_list_changed
.alpha2
[0] = cmd
[8];
56 event
.channel_list_changed
.alpha2
[1] = cmd
[9];
59 event
.channel_list_changed
.type
= REGDOM_TYPE_UNKNOWN
;
61 wpa_supplicant_event(ctx
, EVENT_CHANNEL_LIST_CHANGED
, &event
);
65 int wpa_driver_nl80211_driver_cmd(void *priv
, char *cmd
, char *buf
,
68 struct i802_bss
*bss
= priv
;
69 struct wpa_driver_nl80211_data
*drv
= bss
->drv
;
71 android_wifi_priv_cmd priv_cmd
;
74 if (os_strcasecmp(cmd
, "STOP") == 0) {
75 linux_set_iface_flags(drv
->global
->ioctl_sock
, bss
->ifname
, 0);
76 wpa_msg(drv
->ctx
, MSG_INFO
, WPA_EVENT_DRIVER_STATE
"STOPPED");
77 } else if (os_strcasecmp(cmd
, "START") == 0) {
78 linux_set_iface_flags(drv
->global
->ioctl_sock
, bss
->ifname
, 1);
79 wpa_msg(drv
->ctx
, MSG_INFO
, WPA_EVENT_DRIVER_STATE
"STARTED");
80 } else if (os_strcasecmp(cmd
, "MACADDR") == 0) {
81 u8 macaddr
[ETH_ALEN
] = {};
83 ret
= linux_get_ifhwaddr(drv
->global
->ioctl_sock
, bss
->ifname
, macaddr
);
85 ret
= os_snprintf(buf
, buf_len
,
86 "Macaddr = " MACSTR
"\n", MAC2STR(macaddr
));
87 } else { /* Use private command */
88 os_memcpy(buf
, cmd
, strlen(cmd
) + 1);
89 memset(&ifr
, 0, sizeof(ifr
));
90 memset(&priv_cmd
, 0, sizeof(priv_cmd
));
91 os_strlcpy(ifr
.ifr_name
, bss
->ifname
, IFNAMSIZ
);
94 priv_cmd
.used_len
= buf_len
;
95 priv_cmd
.total_len
= buf_len
;
96 ifr
.ifr_data
= &priv_cmd
;
98 if ((ret
= ioctl(drv
->global
->ioctl_sock
, SIOCDEVPRIVATE
+ 2, &ifr
)) < 0) {
99 wpa_printf(MSG_ERROR
, "%s: failed to issue private command: %s", __func__
, cmd
);
100 wpa_driver_send_hang_msg(drv
);
104 if ((os_strcasecmp(cmd
, "LINKSPEED") == 0) ||
105 (os_strcasecmp(cmd
, "RSSI") == 0) ||
106 (os_strcasecmp(cmd
, "GETBAND") == 0) ||
107 (os_strncasecmp(cmd
, "WLS_BATCHING", 12) == 0))
109 wpa_driver_notify_country_change(drv
->ctx
, cmd
);
110 wpa_printf(MSG_DEBUG
, "%s %s len = %d, %zu", __func__
, buf
, ret
, strlen(buf
));
116 int wpa_driver_set_p2p_noa(void *priv
, u8 count
, int start
, int duration
)
118 char buf
[MAX_DRV_CMD_SIZE
];
120 memset(buf
, 0, sizeof(buf
));
121 wpa_printf(MSG_DEBUG
, "%s: Entry", __func__
);
122 snprintf(buf
, sizeof(buf
), "P2P_SET_NOA %d %d %d", count
, start
, duration
);
123 return wpa_driver_nl80211_driver_cmd(priv
, buf
, buf
, strlen(buf
)+1);
126 int wpa_driver_get_p2p_noa(void *priv __unused
, u8
*buf __unused
, size_t len __unused
)
128 /* Return 0 till we handle p2p_presence request completely in the driver */
132 int wpa_driver_set_p2p_ps(void *priv
, int legacy_ps
, int opp_ps
, int ctwindow
)
134 char buf
[MAX_DRV_CMD_SIZE
];
136 memset(buf
, 0, sizeof(buf
));
137 wpa_printf(MSG_DEBUG
, "%s: Entry", __func__
);
138 snprintf(buf
, sizeof(buf
), "P2P_SET_PS %d %d %d", legacy_ps
, opp_ps
, ctwindow
);
139 return wpa_driver_nl80211_driver_cmd(priv
, buf
, buf
, strlen(buf
) + 1);
142 int wpa_driver_set_ap_wps_p2p_ie(void *priv
, const struct wpabuf
*beacon
,
143 const struct wpabuf
*proberesp
,
144 const struct wpabuf
*assocresp
)
147 const struct wpabuf
*ap_wps_p2p_ie
= NULL
;
149 char *_cmd
= "SET_AP_P2P_WPS_IE";
158 enum if_type iftype
= NONE
;
161 const struct wpabuf
*src
;
169 wpa_printf(MSG_DEBUG
, "%s: Entry", __func__
);
171 if (((proberesp
!= NULL
) && (beacon
== NULL
)) ||
172 ((proberesp
== NULL
) && (beacon
== NULL
) && (assocresp
== NULL
)))
173 /* P2P Device mode Probe Response IEs */
174 iftype
= IF_TYPE_P2P_DEVICE
;
175 else if ((proberesp
!= NULL
) && (beacon
!= NULL
) && (assocresp
!= NULL
))
176 iftype
= IF_TYPE_P2P_GROUP
;
178 for (i
= 0; cmd_arr
[i
].cmd
!= -1; i
++) {
179 ap_wps_p2p_ie
= cmd_arr
[i
].src
;
181 buf_len
= strlen(_cmd
) + 3 + wpabuf_len(ap_wps_p2p_ie
);
182 buf
= os_zalloc(buf_len
);
184 wpa_printf(MSG_ERROR
, "%s: Out of memory",
193 pbuf
+= snprintf(pbuf
, buf_len
- wpabuf_len(ap_wps_p2p_ie
),
194 "%s %d %d",_cmd
, cmd_arr
[i
].cmd
, iftype
);
196 os_memcpy(pbuf
, wpabuf_head(ap_wps_p2p_ie
), wpabuf_len(ap_wps_p2p_ie
));
197 ret
= wpa_driver_nl80211_driver_cmd(priv
, buf
, buf
, buf_len
);