[PATCH] driver_nl80211: set_country fix

Johannes Berg johannes at sipsolutions.net
Mon Jun 24 04:04:21 EDT 2013


On Sun, 2013-06-23 at 16:07 +0300, Igal Chernobelsky wrote:
> Regulatory domain setting may take some time.
> Getting reg domain info immediately after reg domain setting returns
> invalid reg domain data. Loop is added to read reg domain info back and
> to compare set country. If read country does not match, fail to 1 sec sleep
> and retry get/compare again.
> 
> Signed-off-by: Igal Chernobelsky <igalc at ti.com>
> ---
>  src/drivers/driver_nl80211.c |   53 +++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 52 insertions(+), 1 deletions(-)
> 
> diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
> index f705a0c..cc5084b 100644
> --- a/src/drivers/driver_nl80211.c
> +++ b/src/drivers/driver_nl80211.c
> @@ -2689,6 +2689,37 @@ static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
>  }
>  
> 
> +static int get_country_handler(struct nl_msg *msg, void *arg)
> +{
> +	char * alpha2 = (char *) arg;
> +	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
> +	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
> +
> +	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
> +		  genlmsg_attrlen(gnlh, 0), NULL);
> +	if (!tb_msg[NL80211_ATTR_REG_ALPHA2]) {
> +		wpa_printf(MSG_DEBUG, "nl80211: No country information "
> +			   "available");
> +		return NL_SKIP;
> +	}
> +	os_memcpy(alpha2, nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]), 3);
> +	return NL_SKIP;
> +}
> +
> +static int nl80211_get_country(struct wpa_driver_nl80211_data *drv,
> +				char *alpha2)
> +{
> +	struct nl_msg *msg;
> +
> +	msg = nlmsg_alloc();
> +	if (!msg)
> +		return -ENOMEM;
> +
> +	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
> +	return send_and_recv_msgs(drv, msg, get_country_handler, alpha2);
> +}
> +
> +
>  /**
>   * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
>   * @priv: driver_nl80211 private data
> @@ -2703,7 +2734,10 @@ static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
>  	struct i802_bss *bss = priv;
>  	struct wpa_driver_nl80211_data *drv = bss->drv;
>  	char alpha2[3];
> +	char alpha2_res[3];
>  	struct nl_msg *msg;
> +	int count;
> +	int ret;
>  
>  	msg = nlmsg_alloc();
>  	if (!msg)
> @@ -2718,7 +2752,24 @@ static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
>  	NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
>  	if (send_and_recv_msgs(drv, msg, NULL, NULL))
>  		return -EINVAL;
> -	return 0;
> +
> +	/* Validate coutry setting and retry up to 3 times if not match */
> +	for (count = 0; count < 3; count++) {
> +		os_memset(alpha2_res, 0, sizeof(alpha2));
> +		ret = nl80211_get_country(drv, alpha2_res);
> +		if (ret)
> +			return ret;
> +		if (os_strncmp(alpha2, alpha2_res, 3)) {
> +			wpa_printf(MSG_DEBUG, "wpa_driver_nl80211_set_country:"
> +					"retry country set after delay");
> +			os_sleep(1, 0);
> +		} else {
> +			/* contry set is completed */
> +			return 0;
> +		}
> +	}
> +	wpa_printf(MSG_ERROR, "wpa_driver_nl80211_set_country: failed");
> +	return -EINVAL;

I don't think this is really a failure -- if you request a country but
the kernel already has one it might create an intersection etc. Might
want to even abort the loop in that case.

johannes



More information about the HostAP mailing list