libiwinfo: fix two segfaults in nl80211 backend
[project/luci.git] / contrib / package / iwinfo / src / iwinfo_nl80211.c
index 3e0e7dd..7f27e25 100644 (file)
 
 #define min(x, y) ((x) < (y)) ? (x) : (y)
 
 
 #define min(x, y) ((x) < (y)) ? (x) : (y)
 
+extern struct iwinfo_iso3166_label ISO3166_Names[];
 static struct nl80211_state *nls = NULL;
 
 static int nl80211_init(void)
 {
 static struct nl80211_state *nls = NULL;
 
 static int nl80211_init(void)
 {
-       int err;
+       int err, fd;
 
        if( !nls )
        {
 
        if( !nls )
        {
@@ -52,6 +53,13 @@ static int nl80211_init(void)
                        goto err;
                }
 
                        goto err;
                }
 
+               fd = nl_socket_get_fd(nls->nl_sock);
+               if( fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0 )
+               {
+                       err = -EINVAL;
+                       goto err;
+               }
+
                if( genl_ctrl_alloc_cache(nls->nl_sock, &nls->nl_cache)) {
                        err = -ENOMEM;
                        goto err;
                if( genl_ctrl_alloc_cache(nls->nl_sock, &nls->nl_cache)) {
                        err = -ENOMEM;
                        goto err;
@@ -128,6 +136,12 @@ static void nl80211_free(struct nl80211_msg_conveyor *cv)
 
        if( cv && cv->msg )
                nlmsg_free(cv->msg);
 
        if( cv && cv->msg )
                nlmsg_free(cv->msg);
+
+       if( cv )
+       {
+               cv->cb  = NULL;
+               cv->msg = NULL;
+       }
 }
 
 static struct nl80211_msg_conveyor * nl80211_msg(const char *ifname, int cmd, int flags)
 }
 
 static struct nl80211_msg_conveyor * nl80211_msg(const char *ifname, int cmd, int flags)
@@ -331,6 +345,9 @@ static char * nl80211_wpasupp_info(const char *ifname, const char *cmd)
        remote_length = sizeof(remote.sun_family) + sprintf(remote.sun_path,
                "/var/run/wpa_supplicant-%s/%s", ifname, ifname);
 
        remote_length = sizeof(remote.sun_family) + sprintf(remote.sun_path,
                "/var/run/wpa_supplicant-%s/%s", ifname, ifname);
 
+       if( fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC) < 0 )
+               goto out;
+
        if( connect(sock, (struct sockaddr *) &remote, remote_length) )
                goto out;
 
        if( connect(sock, (struct sockaddr *) &remote, remote_length) )
                goto out;
 
@@ -567,6 +584,7 @@ int nl80211_get_signal(const char *ifname, int *buf)
 
 int nl80211_get_noise(const char *ifname, int *buf)
 {
 
 int nl80211_get_noise(const char *ifname, int *buf)
 {
+       int rv = -1;
        struct nl80211_msg_conveyor *req, *res;
        struct nlattr *si[NL80211_SURVEY_INFO_MAX + 1];
 
        struct nl80211_msg_conveyor *req, *res;
        struct nlattr *si[NL80211_SURVEY_INFO_MAX + 1];
 
@@ -584,10 +602,11 @@ int nl80211_get_noise(const char *ifname, int *buf)
                        if( res->attr[NL80211_ATTR_SURVEY_INFO] )
                        {
                                if( !nla_parse_nested(si, NL80211_SURVEY_INFO_MAX,
                        if( res->attr[NL80211_ATTR_SURVEY_INFO] )
                        {
                                if( !nla_parse_nested(si, NL80211_SURVEY_INFO_MAX,
-                                               res->attr[NL80211_ATTR_SURVEY_INFO], sp) )
+                                               res->attr[NL80211_ATTR_SURVEY_INFO], sp) &&
+                                       si[NL80211_SURVEY_INFO_NOISE] )
                                {
                                        *buf = (int8_t)nla_get_u8(si[NL80211_SURVEY_INFO_NOISE]);
                                {
                                        *buf = (int8_t)nla_get_u8(si[NL80211_SURVEY_INFO_NOISE]);
-                                       return 0;
+                                       rv = 0;
                                }
                        }
                        nl80211_free(res);
                                }
                        }
                        nl80211_free(res);
@@ -595,7 +614,7 @@ int nl80211_get_noise(const char *ifname, int *buf)
                nl80211_free(req);
        }
 
                nl80211_free(req);
        }
 
-       return -1;
+       return rv;
 }
 
 int nl80211_get_quality(const char *ifname, int *buf)
 }
 
 int nl80211_get_quality(const char *ifname, int *buf)
@@ -937,7 +956,7 @@ int nl80211_get_txpwrlist(const char *ifname, char *buf, int *len)
                                                break;
                                        }
                                }
                                                break;
                                        }
                                }
-                       }                       
+                       }
 
                        nl80211_free(res);
                }
 
                        nl80211_free(res);
                }
@@ -1155,10 +1174,50 @@ int nl80211_get_freqlist(const char *ifname, char *buf, int *len)
        return wext_get_freqlist(ifname, buf, len);
 }
 
        return wext_get_freqlist(ifname, buf, len);
 }
 
+int nl80211_get_country(const char *ifname, char *buf)
+{
+       int rv = -1;
+       struct nl80211_msg_conveyor *req, *res;
+
+       req = nl80211_msg(ifname, NL80211_CMD_GET_REG, 0);
+       if( req )
+       {
+               res = nl80211_send(req);
+               if( res )
+               {
+                       if( res->attr[NL80211_ATTR_REG_ALPHA2] )
+                       {
+                               memcpy(buf, nla_data(res->attr[NL80211_ATTR_REG_ALPHA2]), 2);
+                               rv = 0;
+                       }
+                       nl80211_free(res);
+               }
+               nl80211_free(req);
+       }
+
+       return rv;
+}
+
+int nl80211_get_countrylist(const char *ifname, char *buf, int *len)
+{
+       int i, count;
+       struct iwinfo_iso3166_label *l;
+       struct iwinfo_country_entry *e = (struct iwinfo_country_entry *)buf;
+
+       for( l = ISO3166_Names, count = 0; l->iso3166; l++, e++, count++ )
+       {
+               e->iso3166 = l->iso3166;
+               e->ccode[0] = (l->iso3166 / 256);
+               e->ccode[1] = (l->iso3166 % 256);
+       }
+
+       *len = (count * sizeof(struct iwinfo_country_entry));
+       return 0;
+}
+
 int nl80211_get_mbssid_support(const char *ifname, int *buf)
 {
        /* We assume that multi bssid is always possible */
        *buf = 1;
        return 0;
 }
 int nl80211_get_mbssid_support(const char *ifname, int *buf)
 {
        /* We assume that multi bssid is always possible */
        *buf = 1;
        return 0;
 }
-