ctrl_iface.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 
00018 #ifndef CONFIG_NATIVE_WINDOWS
00019 
00020 #include <sys/un.h>
00021 #include <sys/stat.h>
00022 #include <stddef.h>
00023 
00024 #include "hostapd.h"
00025 #include "eloop.h"
00026 #include "config.h"
00027 #include "ieee802_1x.h"
00028 #include "wpa.h"
00029 #include "radius/radius_client.h"
00030 #include "ieee802_11.h"
00031 #include "ctrl_iface.h"
00032 #include "sta_info.h"
00033 #include "accounting.h"
00034 #include "wps_hostapd.h"
00035 #include "drivers/driver.h"
00036 #include "ctrl_iface_ap.h"
00037 
00038 
00039 struct wpa_ctrl_dst {
00040         struct wpa_ctrl_dst *next;
00041         struct sockaddr_un addr;
00042         socklen_t addrlen;
00043         int debug_level;
00044         int errors;
00045 };
00046 
00047 
00048 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
00049                                     const char *buf, size_t len);
00050 
00051 
00052 static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
00053                                      struct sockaddr_un *from,
00054                                      socklen_t fromlen)
00055 {
00056         struct wpa_ctrl_dst *dst;
00057 
00058         dst = os_zalloc(sizeof(*dst));
00059         if (dst == NULL)
00060                 return -1;
00061         os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
00062         dst->addrlen = fromlen;
00063         dst->debug_level = MSG_INFO;
00064         dst->next = hapd->ctrl_dst;
00065         hapd->ctrl_dst = dst;
00066         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
00067                     (u8 *) from->sun_path,
00068                     fromlen - offsetof(struct sockaddr_un, sun_path));
00069         return 0;
00070 }
00071 
00072 
00073 static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
00074                                      struct sockaddr_un *from,
00075                                      socklen_t fromlen)
00076 {
00077         struct wpa_ctrl_dst *dst, *prev = NULL;
00078 
00079         dst = hapd->ctrl_dst;
00080         while (dst) {
00081                 if (fromlen == dst->addrlen &&
00082                     os_memcmp(from->sun_path, dst->addr.sun_path,
00083                               fromlen - offsetof(struct sockaddr_un, sun_path))
00084                     == 0) {
00085                         if (prev == NULL)
00086                                 hapd->ctrl_dst = dst->next;
00087                         else
00088                                 prev->next = dst->next;
00089                         os_free(dst);
00090                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
00091                                     (u8 *) from->sun_path,
00092                                     fromlen -
00093                                     offsetof(struct sockaddr_un, sun_path));
00094                         return 0;
00095                 }
00096                 prev = dst;
00097                 dst = dst->next;
00098         }
00099         return -1;
00100 }
00101 
00102 
00103 static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
00104                                     struct sockaddr_un *from,
00105                                     socklen_t fromlen,
00106                                     char *level)
00107 {
00108         struct wpa_ctrl_dst *dst;
00109 
00110         wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
00111 
00112         dst = hapd->ctrl_dst;
00113         while (dst) {
00114                 if (fromlen == dst->addrlen &&
00115                     os_memcmp(from->sun_path, dst->addr.sun_path,
00116                               fromlen - offsetof(struct sockaddr_un, sun_path))
00117                     == 0) {
00118                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
00119                                     "level", (u8 *) from->sun_path, fromlen -
00120                                     offsetof(struct sockaddr_un, sun_path));
00121                         dst->debug_level = atoi(level);
00122                         return 0;
00123                 }
00124                 dst = dst->next;
00125         }
00126 
00127         return -1;
00128 }
00129 
00130 
00131 static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
00132                                       const char *txtaddr)
00133 {
00134         u8 addr[ETH_ALEN];
00135         struct sta_info *sta;
00136 
00137         wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
00138 
00139         if (hwaddr_aton(txtaddr, addr))
00140                 return -1;
00141 
00142         sta = ap_get_sta(hapd, addr);
00143         if (sta)
00144                 return 0;
00145 
00146         wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
00147                    "notification", MAC2STR(addr));
00148         sta = ap_sta_add(hapd, addr);
00149         if (sta == NULL)
00150                 return -1;
00151 
00152         hostapd_new_assoc_sta(hapd, sta, 0);
00153         return 0;
00154 }
00155 
00156 
00157 #ifdef CONFIG_IEEE80211W
00158 #ifdef NEED_AP_MLME
00159 static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
00160                                        const char *txtaddr)
00161 {
00162         u8 addr[ETH_ALEN];
00163         u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
00164 
00165         wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
00166 
00167         if (hwaddr_aton(txtaddr, addr))
00168                 return -1;
00169 
00170         os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
00171         ieee802_11_send_sa_query_req(hapd, addr, trans_id);
00172 
00173         return 0;
00174 }
00175 #endif /* NEED_AP_MLME */
00176 #endif /* CONFIG_IEEE80211W */
00177 
00178 
00179 #ifdef CONFIG_WPS
00180 static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
00181 {
00182         char *pin = os_strchr(txt, ' ');
00183         char *timeout_txt;
00184         int timeout;
00185 
00186         if (pin == NULL)
00187                 return -1;
00188         *pin++ = '\0';
00189 
00190         timeout_txt = os_strchr(pin, ' ');
00191         if (timeout_txt) {
00192                 *timeout_txt++ = '\0';
00193                 timeout = atoi(timeout_txt);
00194         } else
00195                 timeout = 0;
00196 
00197         return hostapd_wps_add_pin(hapd, txt, pin, timeout);
00198 }
00199 
00200 
00201 #ifdef CONFIG_WPS_OOB
00202 static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
00203 {
00204         char *path, *method, *name;
00205 
00206         path = os_strchr(txt, ' ');
00207         if (path == NULL)
00208                 return -1;
00209         *path++ = '\0';
00210 
00211         method = os_strchr(path, ' ');
00212         if (method == NULL)
00213                 return -1;
00214         *method++ = '\0';
00215 
00216         name = os_strchr(method, ' ');
00217         if (name != NULL)
00218                 *name++ = '\0';
00219 
00220         return hostapd_wps_start_oob(hapd, txt, path, method, name);
00221 }
00222 #endif /* CONFIG_WPS_OOB */
00223 #endif /* CONFIG_WPS */
00224 
00225 
00226 static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
00227                                        void *sock_ctx)
00228 {
00229         struct hostapd_data *hapd = eloop_ctx;
00230         char buf[256];
00231         int res;
00232         struct sockaddr_un from;
00233         socklen_t fromlen = sizeof(from);
00234         char *reply;
00235         const int reply_size = 4096;
00236         int reply_len;
00237 
00238         res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
00239                        (struct sockaddr *) &from, &fromlen);
00240         if (res < 0) {
00241                 perror("recvfrom(ctrl_iface)");
00242                 return;
00243         }
00244         buf[res] = '\0';
00245         wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
00246 
00247         reply = os_malloc(reply_size);
00248         if (reply == NULL) {
00249                 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
00250                        fromlen);
00251                 return;
00252         }
00253 
00254         os_memcpy(reply, "OK\n", 3);
00255         reply_len = 3;
00256 
00257         if (os_strcmp(buf, "PING") == 0) {
00258                 os_memcpy(reply, "PONG\n", 5);
00259                 reply_len = 5;
00260         } else if (os_strcmp(buf, "MIB") == 0) {
00261                 reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
00262                 if (reply_len >= 0) {
00263                         res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
00264                                           reply_size - reply_len);
00265                         if (res < 0)
00266                                 reply_len = -1;
00267                         else
00268                                 reply_len += res;
00269                 }
00270                 if (reply_len >= 0) {
00271                         res = ieee802_1x_get_mib(hapd, reply + reply_len,
00272                                                  reply_size - reply_len);
00273                         if (res < 0)
00274                                 reply_len = -1;
00275                         else
00276                                 reply_len += res;
00277                 }
00278                 if (reply_len >= 0) {
00279                         res = radius_client_get_mib(hapd->radius,
00280                                                     reply + reply_len,
00281                                                     reply_size - reply_len);
00282                         if (res < 0)
00283                                 reply_len = -1;
00284                         else
00285                                 reply_len += res;
00286                 }
00287         } else if (os_strcmp(buf, "STA-FIRST") == 0) {
00288                 reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
00289                                                          reply_size);
00290         } else if (os_strncmp(buf, "STA ", 4) == 0) {
00291                 reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
00292                                                    reply_size);
00293         } else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
00294                 reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
00295                                                         reply_size);
00296         } else if (os_strcmp(buf, "ATTACH") == 0) {
00297                 if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
00298                         reply_len = -1;
00299         } else if (os_strcmp(buf, "DETACH") == 0) {
00300                 if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
00301                         reply_len = -1;
00302         } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
00303                 if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
00304                                                     buf + 6))
00305                         reply_len = -1;
00306         } else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
00307                 if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
00308                         reply_len = -1;
00309 #ifdef CONFIG_IEEE80211W
00310 #ifdef NEED_AP_MLME
00311         } else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
00312                 if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
00313                         reply_len = -1;
00314 #endif /* NEED_AP_MLME */
00315 #endif /* CONFIG_IEEE80211W */
00316 #ifdef CONFIG_WPS
00317         } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
00318                 if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
00319                         reply_len = -1;
00320         } else if (os_strcmp(buf, "WPS_PBC") == 0) {
00321                 if (hostapd_wps_button_pushed(hapd))
00322                         reply_len = -1;
00323 #ifdef CONFIG_WPS_OOB
00324         } else if (os_strncmp(buf, "WPS_OOB ", 8) == 0) {
00325                 if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
00326                         reply_len = -1;
00327 #endif /* CONFIG_WPS_OOB */
00328 #endif /* CONFIG_WPS */
00329         } else {
00330                 os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
00331                 reply_len = 16;
00332         }
00333 
00334         if (reply_len < 0) {
00335                 os_memcpy(reply, "FAIL\n", 5);
00336                 reply_len = 5;
00337         }
00338         sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
00339         os_free(reply);
00340 }
00341 
00342 
00343 static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
00344 {
00345         char *buf;
00346         size_t len;
00347 
00348         if (hapd->conf->ctrl_interface == NULL)
00349                 return NULL;
00350 
00351         len = os_strlen(hapd->conf->ctrl_interface) +
00352                 os_strlen(hapd->conf->iface) + 2;
00353         buf = os_malloc(len);
00354         if (buf == NULL)
00355                 return NULL;
00356 
00357         os_snprintf(buf, len, "%s/%s",
00358                     hapd->conf->ctrl_interface, hapd->conf->iface);
00359         buf[len - 1] = '\0';
00360         return buf;
00361 }
00362 
00363 
00364 static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
00365                                       const char *txt, size_t len)
00366 {
00367         struct hostapd_data *hapd = ctx;
00368         if (hapd == NULL)
00369                 return;
00370         hostapd_ctrl_iface_send(hapd, level, txt, len);
00371 }
00372 
00373 
00374 int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
00375 {
00376         struct sockaddr_un addr;
00377         int s = -1;
00378         char *fname = NULL;
00379 
00380         hapd->ctrl_sock = -1;
00381 
00382         if (hapd->conf->ctrl_interface == NULL)
00383                 return 0;
00384 
00385         if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
00386                 if (errno == EEXIST) {
00387                         wpa_printf(MSG_DEBUG, "Using existing control "
00388                                    "interface directory.");
00389                 } else {
00390                         perror("mkdir[ctrl_interface]");
00391                         goto fail;
00392                 }
00393         }
00394 
00395         if (hapd->conf->ctrl_interface_gid_set &&
00396             chown(hapd->conf->ctrl_interface, 0,
00397                   hapd->conf->ctrl_interface_gid) < 0) {
00398                 perror("chown[ctrl_interface]");
00399                 return -1;
00400         }
00401 
00402         if (os_strlen(hapd->conf->ctrl_interface) + 1 +
00403             os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
00404                 goto fail;
00405 
00406         s = socket(PF_UNIX, SOCK_DGRAM, 0);
00407         if (s < 0) {
00408                 perror("socket(PF_UNIX)");
00409                 goto fail;
00410         }
00411 
00412         os_memset(&addr, 0, sizeof(addr));
00413 #ifdef __FreeBSD__
00414         addr.sun_len = sizeof(addr);
00415 #endif /* __FreeBSD__ */
00416         addr.sun_family = AF_UNIX;
00417         fname = hostapd_ctrl_iface_path(hapd);
00418         if (fname == NULL)
00419                 goto fail;
00420         os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
00421         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00422                 wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
00423                            strerror(errno));
00424                 if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00425                         wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
00426                                    " allow connections - assuming it was left"
00427                                    "over from forced program termination");
00428                         if (unlink(fname) < 0) {
00429                                 perror("unlink[ctrl_iface]");
00430                                 wpa_printf(MSG_ERROR, "Could not unlink "
00431                                            "existing ctrl_iface socket '%s'",
00432                                            fname);
00433                                 goto fail;
00434                         }
00435                         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
00436                             0) {
00437                                 perror("bind(PF_UNIX)");
00438                                 goto fail;
00439                         }
00440                         wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
00441                                    "ctrl_iface socket '%s'", fname);
00442                 } else {
00443                         wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
00444                                    "be in use - cannot override it");
00445                         wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
00446                                    "not used anymore", fname);
00447                         os_free(fname);
00448                         fname = NULL;
00449                         goto fail;
00450                 }
00451         }
00452 
00453         if (hapd->conf->ctrl_interface_gid_set &&
00454             chown(fname, 0, hapd->conf->ctrl_interface_gid) < 0) {
00455                 perror("chown[ctrl_interface/ifname]");
00456                 goto fail;
00457         }
00458 
00459         if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
00460                 perror("chmod[ctrl_interface/ifname]");
00461                 goto fail;
00462         }
00463         os_free(fname);
00464 
00465         hapd->ctrl_sock = s;
00466         eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
00467                                  NULL);
00468         hapd->msg_ctx = hapd;
00469         wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
00470 
00471         return 0;
00472 
00473 fail:
00474         if (s >= 0)
00475                 close(s);
00476         if (fname) {
00477                 unlink(fname);
00478                 os_free(fname);
00479         }
00480         return -1;
00481 }
00482 
00483 
00484 void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
00485 {
00486         struct wpa_ctrl_dst *dst, *prev;
00487 
00488         if (hapd->ctrl_sock > -1) {
00489                 char *fname;
00490                 eloop_unregister_read_sock(hapd->ctrl_sock);
00491                 close(hapd->ctrl_sock);
00492                 hapd->ctrl_sock = -1;
00493                 fname = hostapd_ctrl_iface_path(hapd);
00494                 if (fname)
00495                         unlink(fname);
00496                 os_free(fname);
00497 
00498                 if (hapd->conf->ctrl_interface &&
00499                     rmdir(hapd->conf->ctrl_interface) < 0) {
00500                         if (errno == ENOTEMPTY) {
00501                                 wpa_printf(MSG_DEBUG, "Control interface "
00502                                            "directory not empty - leaving it "
00503                                            "behind");
00504                         } else {
00505                                 perror("rmdir[ctrl_interface]");
00506                         }
00507                 }
00508         }
00509 
00510         dst = hapd->ctrl_dst;
00511         while (dst) {
00512                 prev = dst;
00513                 dst = dst->next;
00514                 os_free(prev);
00515         }
00516 }
00517 
00518 
00519 static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
00520                                     const char *buf, size_t len)
00521 {
00522         struct wpa_ctrl_dst *dst, *next;
00523         struct msghdr msg;
00524         int idx;
00525         struct iovec io[2];
00526         char levelstr[10];
00527 
00528         dst = hapd->ctrl_dst;
00529         if (hapd->ctrl_sock < 0 || dst == NULL)
00530                 return;
00531 
00532         os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
00533         io[0].iov_base = levelstr;
00534         io[0].iov_len = os_strlen(levelstr);
00535         io[1].iov_base = (char *) buf;
00536         io[1].iov_len = len;
00537         os_memset(&msg, 0, sizeof(msg));
00538         msg.msg_iov = io;
00539         msg.msg_iovlen = 2;
00540 
00541         idx = 0;
00542         while (dst) {
00543                 next = dst->next;
00544                 if (level >= dst->debug_level) {
00545                         wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
00546                                     (u8 *) dst->addr.sun_path, dst->addrlen -
00547                                     offsetof(struct sockaddr_un, sun_path));
00548                         msg.msg_name = &dst->addr;
00549                         msg.msg_namelen = dst->addrlen;
00550                         if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
00551                                 int _errno = errno;
00552                                 wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
00553                                            "%d - %s",
00554                                            idx, errno, strerror(errno));
00555                                 dst->errors++;
00556                                 if (dst->errors > 10 || _errno == ENOENT) {
00557                                         hostapd_ctrl_iface_detach(
00558                                                 hapd, &dst->addr,
00559                                                 dst->addrlen);
00560                                 }
00561                         } else
00562                                 dst->errors = 0;
00563                 }
00564                 idx++;
00565                 dst = next;
00566         }
00567 }
00568 
00569 #endif /* CONFIG_NATIVE_WINDOWS */
00570 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:47 2009 for hostapd by  doxygen 1.6.1