static int wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[]) { struct wpa_cli_cmd *cmd, *match = NULL; int count; int ret = 0; count = 0; cmd = wpa_cli_commands; while (cmd->cmd) { if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0) { match = cmd; if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { /* we have an exact match */ count = 1; break; } count++; } cmd++; } if (count > 1) { printf("Ambiguous command '%s'; possible commands:", argv[0]); cmd = wpa_cli_commands; while (cmd->cmd) { if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0) { printf(" %s", cmd->cmd); } cmd++; } printf("\n"); ret = 1; } else if (count == 0) { printf("Unknown command '%s'\n", argv[0]); ret = 1; } else { #ifdef ANDROID if( os_strncasecmp( "level", argv[0], os_strlen(argv[0]) ) == 0 ) { ctrl = monitor_conn; } #endif ret = match->handler(ctrl, argc - 1, &argv[1]); } return ret; }
int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len ) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct ifreq ifr; android_wifi_priv_cmd priv_cmd; int ret = 0; if (os_strcasecmp(cmd, "STOP") == 0) { linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0); wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); } else if (os_strcasecmp(cmd, "START") == 0) { linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1); wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); } else if (os_strcasecmp(cmd, "MACADDR") == 0) { u8 macaddr[ETH_ALEN] = {}; ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr); if (!ret) ret = os_snprintf(buf, buf_len, "Macaddr = " MACSTR "\n", MAC2STR(macaddr)); } else { /* Use private command */ memset(&ifr, 0, sizeof(ifr)); memset(&priv_cmd, 0, sizeof(priv_cmd)); os_memcpy(buf, cmd, strlen(cmd) + 1); os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); priv_cmd.buf = buf; priv_cmd.used_len = buf_len; priv_cmd.total_len = buf_len; ifr.ifr_data = &priv_cmd; if ((ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr)) < 0) { wpa_printf(MSG_ERROR, "%s: failed to issue private commands\n", __func__); } else { drv_errors = 0; ret = 0; if ((os_strcasecmp(cmd, "LINKSPEED") == 0) || (os_strcasecmp(cmd, "RSSI") == 0) || (os_strcasecmp(cmd, "GETBAND") == 0) ) ret = strlen(buf); else if (os_strcasecmp(cmd, "COUNTRY") == 0) wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, NULL); else if (os_strncasecmp(cmd, "SETBAND", 7) == 0) wpa_printf(MSG_DEBUG, "%s: %s ", __func__, cmd); else if (os_strcasecmp(cmd, "P2P_DEV_ADDR") == 0) wpa_printf(MSG_DEBUG, "%s: P2P: Device address ("MACSTR")", __func__, MAC2STR(buf)); else if (os_strcasecmp(cmd, "P2P_SET_PS") == 0) wpa_printf(MSG_DEBUG, "%s: P2P: %s ", __func__, buf); else if (os_strcasecmp(cmd, "P2P_SET_NOA") == 0) wpa_printf(MSG_DEBUG, "%s: P2P: %s ", __func__, buf); else wpa_printf(MSG_DEBUG, "%s %s len = %d, %d", __func__, buf, ret, strlen(buf)); } } return ret; }
c_bool u_userGetSPBFromEnvUri() { char *uri = NULL; c_bool spb = FALSE; cf_element platformConfig = NULL; cf_element dc = NULL; cf_element elemName = NULL; cf_element singleProcess = NULL; cf_data elementData = NULL; cf_data dataName; c_value value; cfgprs_status r; uri = os_getenv ("OSPL_URI"); r = cfg_parse_ospl (uri, &platformConfig); if (r == CFGPRS_OK) { dc = cf_element (cf_elementChild (platformConfig, CFG_DOMAIN)); if (dc) { singleProcess = cf_element(cf_elementChild(dc, CFG_SINGLEPROCESS)); if (singleProcess != NULL) { elementData = cf_data(cf_elementChild(singleProcess, "#text")); if (elementData != NULL) { value = cf_dataValue(elementData); if (os_strncasecmp(value.is.String, "TRUE", 4) == 0) { /* A SingleProcess value of True implies that Heap is to be used */ spb = TRUE; } } } } } return spb; }
static const char * wps_er_find_wfadevice(const char *data) { const char *tag, *tagname, *end; char *val; int found = 0; while (!found) { /* Find next <device> */ for (;;) { if (xml_next_tag(data, &tag, &tagname, &end)) return NULL; data = end; if (!os_strncasecmp(tagname, "device", 6) && *tag != '/' && (tagname[6] == '>' || !isgraph(tagname[6]))) { break; } } /* Check whether deviceType is WFADevice */ val = xml_get_first_item(data, "deviceType"); if (val == NULL) return NULL; wpa_printf(MSG_DEBUG, "WPS ER: Found deviceType '%s'", val); found = os_strcasecmp(val, "urn:schemas-wifialliance-org:" "device:WFADevice:1") == 0; os_free(val); } return data; }
/* A POST body looks something like (per upnp spec): * <?xml version="1.0"?> * <s:Envelope * xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" * s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> * <s:Body> * <u:actionName xmlns:u="urn:schemas-upnp-org:service:serviceType:v"> * <argumentName>in arg value</argumentName> * other in args and their values go here, if any * </u:actionName> * </s:Body> * </s:Envelope> * * where : * s: might be some other namespace name followed by colon * u: might be some other namespace name followed by colon * actionName will be replaced according to action requested * schema following actionName will be WFA scheme instead * argumentName will be actual argument name * (in arg value) will be actual argument value */ char * xml_get_first_item(const char *doc, const char *item) { const char *match = item; int match_len = os_strlen(item); const char *tag, *tagname, *end; char *value; /* * This is crude: ignore any possible tag name conflicts and go right * to the first tag of this name. This should be ok for the limited * domain of UPnP messages. */ for (;;) { if (xml_next_tag(doc, &tag, &tagname, &end)) return NULL; doc = end; if (!os_strncasecmp(tagname, match, match_len) && *tag != '/' && (tagname[match_len] == '>' || !isgraph(tagname[match_len]))) { break; } } end = doc; while (*end && *end != '<') end++; value = os_zalloc(1 + (end - doc)); if (value == NULL) return NULL; os_memcpy(value, doc, end - doc); return value; }
/* * update channel list in wpa_supplicant * if coutry code chanaged */ static void wpa_driver_notify_country_change(void *ctx, char *cmd) { if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) { union wpa_event_data event; os_memset(&event, 0, sizeof(event)); event.channel_list_changed.initiator = REGDOM_SET_BY_USER; if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) { event.channel_list_changed.type = REGDOM_TYPE_COUNTRY; if (os_strlen(cmd) > 9) { event.channel_list_changed.alpha2[0] = cmd[8]; event.channel_list_changed.alpha2[1] = cmd[9]; } } else event.channel_list_changed.type = REGDOM_TYPE_UNKNOWN; wpa_supplicant_event(ctx, EVENT_CHANNEL_LIST_CHANGED, &event); } }
/* Given that we have received a header w/ POST, act upon it * * Format of POST (case-insensitive): * * First line must be: * POST /<file> HTTP/1.1 * Since we don't do anything fancy we just ignore other lines. * * Our response (if no error) which includes only required lines is: * HTTP/1.1 200 OK * Connection: close * Content-Type: text/xml * Date: <rfc1123-date> * * Header lines must end with \r\n * Per RFC 2616, content-length: is not required but connection:close * would appear to be required (given that we will be closing it!). */ static void web_connection_parse_post(struct upnp_wps_device_sm *sm, struct sockaddr_in *cli, struct http_request *req, const char *filename) { enum http_reply_code ret; char *data = http_request_get_data(req); /* body of http msg */ const char *action = NULL; size_t action_len = 0; const char *replyname = NULL; /* argument name for the reply */ struct wpabuf *reply = NULL; /* data for the reply */ if (os_strcasecmp(filename, UPNP_WPS_DEVICE_CONTROL_FILE)) { wpa_printf(MSG_INFO, "WPS UPnP: Invalid POST filename %s", filename); ret = HTTP_NOT_FOUND; goto bad; } ret = UPNP_INVALID_ACTION; action = web_get_action(req, &action_len); if (action == NULL) goto bad; if (!os_strncasecmp("GetDeviceInfo", action, action_len)) ret = web_process_get_device_info(sm, &reply, &replyname); else if (!os_strncasecmp("PutMessage", action, action_len)) ret = web_process_put_message(sm, data, &reply, &replyname); else if (!os_strncasecmp("PutWLANResponse", action, action_len)) ret = web_process_put_wlan_response(sm, data, &reply, &replyname); else if (!os_strncasecmp("SetSelectedRegistrar", action, action_len)) ret = web_process_set_selected_registrar(sm, cli, data, &reply, &replyname); else wpa_printf(MSG_INFO, "WPS UPnP: Unknown POST type"); bad: if (ret != HTTP_OK) wpa_printf(MSG_INFO, "WPS UPnP: POST failure ret=%d", ret); web_connection_send_reply(req, ret, action, action_len, reply, replyname); wpabuf_free(reply); }
static int ctrl_command(int s, int argc, char *argv[]) { const struct wlantest_cli_cmd *cmd, *match = NULL; int count = 0; int ret = 0; for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) { if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0) { match = cmd; if (os_strcasecmp(cmd->cmd, argv[0]) == 0) { /* exact match */ count = 1; break; } count++; } } if (count > 1) { printf("Ambiguous command '%s'; possible commands:", argv[0]); for (cmd = wlantest_cli_commands; cmd->cmd; cmd++) { if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0) { printf(" %s", cmd->cmd); } } printf("\n"); ret = 1; } else if (count == 0) { printf("Unknown command '%s'\n", argv[0]); ret = 1; } else { ret = match->handler(s, argc - 1, &argv[1]); } return ret; }
/* scanf does not support this */ static c_bool u_cfValueScanBoolean( c_char *dataPtr, c_bool *resultPtr) { c_bool result = FALSE; size_t l; l = strspn(dataPtr, CF_SPACES); if (l <= strlen(dataPtr)) { if (os_strncasecmp(&dataPtr[l], "TRUE", 4) == 0) { *resultPtr = TRUE; result = TRUE; } else { if (os_strncasecmp(&dataPtr[l], "FALSE", 5) == 0) { *resultPtr = FALSE; result = TRUE; } } } return result; }
static char * wpa_cli_cmd_gen(const char *text, int state) { static int i, len; const char *cmd; if (state == 0) { i = 0; len = os_strlen(text); } while ((cmd = wpa_cli_commands[i].cmd)) { i++; if (os_strncasecmp(cmd, text, len) == 0) return os_strdup(cmd); } return NULL; }
static int cmd_has_sensitive_data(const char *cmd) { const char *c, *delim; int n; size_t len; delim = os_strchr(cmd, ' '); if (delim) len = delim - cmd; else len = os_strlen(cmd); for (n = 0; (c = wpa_cli_commands[n].cmd); n++) { if (os_strncasecmp(cmd, c, len) == 0 && len == os_strlen(c)) return (wpa_cli_commands[n].flags & cli_cmd_flag_sensitive); } return 0; }
/* httpread_hdr_line_get -- When file is ready, returns pointer * to line within header content matching the given tag * (after the tag itself and any spaces/tabs). * * The tag should end with a colon for reliable matching. * * If not found, returns NULL; */ char * httpread_hdr_line_get(struct httpread *h, const char *tag) { int tag_len = os_strlen(tag); char *hdr = h->hdr; hdr = os_strchr(hdr, '\n'); if (hdr == NULL) return NULL; hdr++; for (;;) { if (!os_strncasecmp(hdr, tag, tag_len)) { hdr += tag_len; while (*hdr == ' ' || *hdr == '\t') hdr++; return hdr; } hdr = os_strchr(hdr, '\n'); if (hdr == NULL) return NULL; hdr++; } }
static const char * web_get_action(struct http_request *req, size_t *action_len) { const char *match; int match_len; char *b; char *action; *action_len = 0; /* The SOAPAction line of the header tells us what we want to do */ b = http_request_get_hdr_line(req, "SOAPAction:"); if (b == NULL) return NULL; if (*b == '"') b++; else return NULL; match = urn_wfawlanconfig; match_len = os_strlen(urn_wfawlanconfig) - 1; if (os_strncasecmp(b, match, match_len)) return NULL; b += match_len; /* skip over version */ while (isgraph(*b) && *b != '#') b++; if (*b != '#') return NULL; b++; /* Following the sharp(#) should be the action and a double quote */ action = b; while (isgraph(*b) && *b != '"') b++; if (*b != '"') return NULL; *action_len = b - action; return action; }
u_char * os_strcasestrn(u_char *s1, char *s2, size_t n) { os_uint_t c1, c2; c2 = (os_uint_t) *s2++; c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; do { do { c1 = (os_uint_t) *s1++; if (c1 == 0) { return NULL; } c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; } while (c1 != c2); } while (os_strncasecmp(s1, (u_char *) s2, n) != 0); return --s1; }
static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *pos, size_t slen) { char fname[256]; int png; FILE *f; u16 data_len; wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Icon Binary File", MAC2STR(sa)); if (slen < 4) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " "value from " MACSTR, MAC2STR(sa)); return -1; } wpa_printf(MSG_DEBUG, "HS 2.0: Download Status Code %u", *pos); if (*pos != 0) return -1; pos++; slen--; if ((size_t) 1 + pos[0] > slen) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " "value from " MACSTR, MAC2STR(sa)); return -1; } wpa_hexdump_ascii(MSG_DEBUG, "Icon Type", pos + 1, pos[0]); png = os_strncasecmp((char *) pos + 1, "image/png", 9) == 0; slen -= 1 + pos[0]; pos += 1 + pos[0]; if (slen < 2) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " "value from " MACSTR, MAC2STR(sa)); return -1; } data_len = WPA_GET_LE16(pos); pos += 2; slen -= 2; if (data_len > slen) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " "value from " MACSTR, MAC2STR(sa)); return -1; } wpa_printf(MSG_DEBUG, "Icon Binary Data: %u bytes", data_len); if (wpa_s->conf->osu_dir == NULL) return -1; wpa_s->osu_icon_id++; if (wpa_s->osu_icon_id == 0) wpa_s->osu_icon_id++; snprintf(fname, sizeof(fname), "%s/osu-icon-%u.%s", wpa_s->conf->osu_dir, wpa_s->osu_icon_id, png ? "png" : "icon"); f = fopen(fname, "wb"); if (f == NULL) return -1; if (fwrite(pos, slen, 1, f) != 1) { fclose(f); unlink(fname); return -1; } fclose(f); wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP-ICON %s", fname); return 0; }
int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len ) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct ifreq ifr; android_wifi_priv_cmd priv_cmd; int ret = 0; if (os_strcasecmp(cmd, "STOP") == 0) { linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0); wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); } else if (os_strcasecmp(cmd, "START") == 0) { linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1); wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); } else if (os_strcasecmp(cmd, "MACADDR") == 0) { u8 macaddr[ETH_ALEN] = {}; ret = linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, macaddr); if (!ret) ret = os_snprintf(buf, buf_len, "Macaddr = " MACSTR "\n", MAC2STR(macaddr)); } else if (os_strcasecmp(cmd, "RELOAD") == 0) { wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); } else if (os_strncasecmp(cmd, "POWERMODE ", 10) == 0) { int state; state = atoi(cmd + 10); ret = wpa_driver_set_power_save(priv, state); if (ret < 0) wpa_driver_send_hang_msg(drv); else drv_errors = 0; } else if (os_strncasecmp(cmd, "GETPOWER", 8) == 0) { int state = -1; ret = wpa_driver_get_power_save(priv, &state); if (!ret && (state != -1)) { ret = os_snprintf(buf, buf_len, "POWERMODE = %d\n", state); drv_errors = 0; } else { wpa_driver_send_hang_msg(drv); } } else { /* Use private command */ if (os_strcasecmp(cmd, "BGSCAN-START") == 0) { ret = wpa_driver_set_backgroundscan_params(priv); if (ret < 0) { return ret; } os_memcpy(buf, "PNOFORCE 1", 11); } else if (os_strcasecmp(cmd, "BGSCAN-STOP") == 0) { os_memcpy(buf, "PNOFORCE 0", 11); } else { os_memcpy(buf, cmd, strlen(cmd) + 1); } memset(&ifr, 0, sizeof(ifr)); memset(&priv_cmd, 0, sizeof(priv_cmd)); os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); priv_cmd.buf = buf; priv_cmd.used_len = buf_len; priv_cmd.total_len = buf_len; ifr.ifr_data = &priv_cmd; //alber test if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr)) < 0) { //alber test wpa_printf(MSG_ERROR, "%s: failed to issue private commands\n", __func__); //alber test wpa_driver_send_hang_msg(drv); //alber } else { drv_errors = 0; ret = 0; if ((os_strcasecmp(cmd, "LINKSPEED") == 0) || (os_strcasecmp(cmd, "RSSI") == 0) || (os_strcasecmp(cmd, "GETBAND") == 0) || (os_strcasecmp(cmd, "P2P_GET_NOA") == 0)) ret = strlen(buf); wpa_printf(MSG_DEBUG, "%s %s len = %d, %d", __func__, buf, ret, strlen(buf)); //alber test } } return ret; }
/*----------------------------------------------------------------------------- Routine Name: wpa_driver_tista_driver_cmd Routine Description: executes driver-specific commands Arguments: priv - pointer to private data structure cmd - command buf - return buffer buf_len - buffer length Return Value: actual buffer length - success, -1 - failure -----------------------------------------------------------------------------*/ static int wpa_driver_tista_driver_cmd( void *priv, char *cmd, char *buf, size_t buf_len ) { struct wpa_driver_ti_data *drv = (struct wpa_driver_ti_data *)priv; int ret = -1, prev_events, flags; wpa_printf(MSG_DEBUG, "%s %s", __func__, cmd); if( os_strcasecmp(cmd, "start") == 0 ) { wpa_printf(MSG_DEBUG,"Start command"); scan_exit(drv); /* Clear scan cache */ ret = wpa_driver_tista_driver_start(priv); if( ret == 0 ) { drv->driver_is_loaded = TRUE; wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); } return( TI2WPA_STATUS(ret) ); } TI_CHECK_DRIVER( drv->driver_is_loaded, -1 ); if( os_strcasecmp(cmd, "stop") == 0 ) { wpa_printf(MSG_DEBUG,"Stop command"); if ((wpa_driver_wext_get_ifflags(drv->wext, &flags) == 0) && (flags & IFF_UP)) { wpa_printf(MSG_ERROR, "TI: %s when iface is UP", cmd); wpa_driver_wext_set_ifflags(drv->wext, flags & ~IFF_UP); } ret = wpa_driver_tista_driver_stop(priv); if( ret == 0 ) { scan_exit(drv); /* Clear scan cache */ drv->driver_is_loaded = FALSE; wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); } } if( os_strcasecmp(cmd, "reload") == 0 ) { wpa_printf(MSG_DEBUG,"Reload command"); ret = 0; wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); } else if( os_strcasecmp(cmd, "macaddr") == 0 ) { wpa_driver_tista_get_mac_addr(priv); wpa_printf(MSG_DEBUG, "Macaddr command"); ret = sprintf(buf, "Macaddr = " MACSTR "\n", MAC2STR(drv->own_addr)); wpa_printf(MSG_DEBUG, "buf %s", buf); } else if( os_strcasecmp(cmd, "scan-passive") == 0 ) { wpa_printf(MSG_DEBUG,"Scan Passive command"); drv->scan_type = SCAN_TYPE_NORMAL_PASSIVE; ret = 0; } else if( os_strcasecmp(cmd, "scan-active") == 0 ) { wpa_printf(MSG_DEBUG,"Scan Active command"); drv->scan_type = SCAN_TYPE_NORMAL_ACTIVE; ret = 0; } else if( os_strcasecmp(cmd, "scan-mode") == 0 ) { wpa_printf(MSG_DEBUG,"Scan Mode command"); ret = snprintf(buf, buf_len, "ScanMode = %u\n", drv->scan_type); if (ret < (int)buf_len) { return( ret ); } } else if( os_strcasecmp(cmd, "linkspeed") == 0 ) { struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx); wpa_printf(MSG_DEBUG,"Link Speed command"); drv->link_speed = wpa_s->link_speed / 1000000; ret = sprintf(buf,"LinkSpeed %u\n", drv->link_speed); wpa_printf(MSG_DEBUG, "buf %s", buf); } else if( os_strncasecmp(cmd, "scan-channels", 13) == 0 ) { int noOfChan; noOfChan = atoi(cmd + 13); wpa_printf(MSG_DEBUG,"Scan Channels command = %d", noOfChan); if( (noOfChan > 0) && (noOfChan <= MAX_NUMBER_OF_CHANNELS_PER_SCAN) ) drv->scan_channels = noOfChan; ret = sprintf(buf,"Scan-Channels = %d\n", drv->scan_channels); wpa_printf(MSG_DEBUG, "buf %s", buf); } else if( os_strcasecmp(cmd, "rssi-approx") == 0 ) { scan_result_t *cur_res; struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx); scan_ssid_t *p_ssid; int rssi, len; wpa_printf(MSG_DEBUG,"rssi-approx command"); if( !wpa_s ) return( ret ); cur_res = scan_get_by_bssid(drv, wpa_s->bssid); if( cur_res ) { p_ssid = scan_get_ssid(cur_res); if( p_ssid ) { len = (int)(p_ssid->ssid_len); rssi = cur_res->level; if( (len > 0) && (len <= MAX_SSID_LEN) && (len < (int)buf_len)) { os_memcpy((void *)buf, (void *)(p_ssid->ssid), len); ret = len; ret += snprintf(&buf[ret], buf_len-len, " rssi %d\n", rssi); } } } } else if( os_strcasecmp(cmd, "rssi") == 0 ) { u8 ssid[MAX_SSID_LEN]; scan_result_t *cur_res; struct wpa_supplicant *wpa_s = (struct wpa_supplicant *)(drv->ctx); int rssi_data, rssi_beacon, len; wpa_printf(MSG_DEBUG,"rssi command"); ret = wpa_driver_tista_get_rssi(priv, &rssi_data, &rssi_beacon); if( ret == 0 ) { len = wpa_driver_tista_get_ssid(priv, (u8 *)ssid); wpa_printf(MSG_DEBUG,"rssi_data %d rssi_beacon %d", rssi_data, rssi_beacon); if( (len > 0) && (len <= MAX_SSID_LEN) ) { os_memcpy((void *)buf, (void *)ssid, len); ret = len; ret += sprintf(&buf[ret], " rssi %d\n", rssi_beacon); wpa_printf(MSG_DEBUG, "buf %s", buf); /* Update cached value */ if( !wpa_s ) return( ret ); cur_res = scan_get_by_bssid(drv, wpa_s->bssid); if( cur_res ) cur_res->level = rssi_beacon; } else { wpa_printf(MSG_DEBUG, "Fail to get ssid when reporting rssi"); ret = -1; } } } else if( os_strncasecmp(cmd, "powermode", 9) == 0 ) { u32 mode; TPowerMgr_PowerMode tMode; mode = (u32)atoi(cmd + 9); wpa_printf(MSG_DEBUG,"Power Mode command = %u", mode); if( mode < POWER_MODE_MAX ) { tMode.PowerMode = (PowerMgr_PowerMode_e)mode; tMode.PowerMngPriority = POWER_MANAGER_USER_PRIORITY; ret = wpa_driver_tista_config_power_management( priv, &tMode, 1 ); } } else if (os_strncasecmp(cmd, "getpower", 8) == 0 ) { u32 mode; TPowerMgr_PowerMode tMode; os_memset(&tMode, 0, sizeof(TPowerMgr_PowerMode)); ret = wpa_driver_tista_config_power_management( priv, &tMode, 0 ); if( ret == 0 ) { ret = sprintf(buf, "powermode = %u\n", tMode.PowerMode); wpa_printf(MSG_DEBUG, "buf %s", buf); } } else if( os_strncasecmp(cmd, "btcoexmode", 10) == 0 ) { u32 mode; mode = (u32)atoi(cmd + 10); wpa_printf(MSG_DEBUG,"BtCoex Mode command = %u", mode); ret = wpa_driver_tista_enable_bt_coe( priv, mode ); if( ret == 0 ) { drv->btcoex_mode = mode; } } else if( os_strcasecmp(cmd, "btcoexstat") == 0 ) { u32 status = drv->btcoex_mode; wpa_printf(MSG_DEBUG,"BtCoex Status"); ret = wpa_driver_tista_get_bt_coe_status( priv, &status ); if( ret == 0 ) { ret = sprintf(buf, "btcoexstatus = 0x%x\n", status); wpa_printf(MSG_DEBUG, "buf %s", buf); } } else if( os_strcasecmp(cmd, "rxfilter-start") == 0 ) { wpa_printf(MSG_DEBUG,"Rx Data Filter Start command"); ret = wpa_driver_tista_driver_enable_rx_data_filter( priv ); } else if( os_strcasecmp(cmd, "rxfilter-stop") == 0 ) { wpa_printf(MSG_DEBUG,"Rx Data Filter Stop command"); ret = wpa_driver_tista_driver_disable_rx_data_filter( priv ); } else if( os_strcasecmp(cmd, "rxfilter-statistics") == 0 ) { TCuCommon_RxDataFilteringStatistics stats; int len, i; os_memset(&stats, 0, sizeof(TCuCommon_RxDataFilteringStatistics)); wpa_printf(MSG_DEBUG,"Rx Data Filter Statistics command"); ret = wpa_driver_tista_driver_rx_data_filter_statistics( priv, &stats ); if( ret == 0 ) { ret = snprintf(buf, buf_len, "RxFilterStat: %u", (u32)stats.unmatchedPacketsCount); for(i=0; ( i < MAX_DATA_FILTERS ); i++) { ret += snprintf(&buf[ret], buf_len-ret, " %u", (u32)stats.matchedPacketsCount[i]); } ret += snprintf(&buf[ret], buf_len-ret, "\n"); if (ret >= (int)buf_len) { ret = -1; } } } else if( os_strncasecmp(cmd, "rxfilter-add", 12) == 0 ) { TRxDataFilterRequest dfreq; char *cp = cmd + 12; char *endp; int type; if (*cp != '\0') { type = (int)strtol(cp, &endp, 0); if (endp != cp) { wpa_printf(MSG_DEBUG,"Rx Data Filter Add [%d] command", type); ret = prepare_filter_struct( priv, type, &dfreq ); if( ret == 0 ) { ret = wpa_driver_tista_driver_rx_data_filter( priv, &dfreq, 1 ); } } } } else if( os_strncasecmp(cmd, "rxfilter-remove",15) == 0 ) { TRxDataFilterRequest dfreq; char *cp = cmd + 15; char *endp; int type; if (*cp != '\0') { type = (int)strtol(cp, &endp, 0); if (endp != cp) { wpa_printf(MSG_DEBUG,"Rx Data Filter remove [%d] command", type); ret = prepare_filter_struct( priv, type, &dfreq ); if( ret == 0 ) { ret = wpa_driver_tista_driver_rx_data_filter( priv, &dfreq, 0 ); } } } } else { wpa_printf(MSG_DEBUG,"Unsupported command"); } return ret; }
static int wpa_driver_priv_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len) { struct wpa_driver_awext_data *drv = priv; int ret = -1; int flags; wpa_printf(MSG_DEBUG, "AWEXT: %s %s", __func__, cmd); if (os_strcasecmp(cmd, "start") == 0) { wpa_printf(MSG_DEBUG,"Start command"); return (ret); } if (os_strcasecmp(cmd, "stop") == 0) { wpa_printf(MSG_DEBUG,"Stop command"); if ((wpa_driver_awext_get_ifflags(drv, &flags) == 0) && (flags & IFF_UP)) { wpa_printf(MSG_ERROR, "WEXT: %s when iface is UP", cmd); wpa_driver_awext_set_ifflags(drv, flags & ~IFF_UP); } } else if (os_strcasecmp(cmd, "reload") == 0) { wpa_printf(MSG_DEBUG,"Reload command"); wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); return ret; } else if (os_strcasecmp(cmd, "macaddr") == 0) { struct ifreq ifr; os_memset(&ifr, 0, sizeof(ifr)); os_strncpy(ifr.ifr_name, drv->ifname, IFNAMSIZ); if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) < 0) { perror("ioctl[SIOCGIFHWADDR]"); ret = -1; } else { u8 *macaddr = (u8 *) ifr.ifr_hwaddr.sa_data; ret = snprintf(buf, buf_len, "Macaddr = " MACSTR "\n", MAC2STR(macaddr)); } } else if (os_strcasecmp(cmd, "scan-passive") == 0) { wpa_printf(MSG_DEBUG,"Scan Passive command"); } else if (os_strcasecmp(cmd, "scan-active") == 0) { wpa_printf(MSG_DEBUG,"Scan Active command"); } else if (os_strcasecmp(cmd, "linkspeed") == 0) { struct iwreq wrq; unsigned int linkspeed; os_strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ); wpa_printf(MSG_DEBUG,"Link Speed command"); if (ioctl(drv->ioctl_sock, SIOCGIWRATE, &wrq) < 0) { perror("ioctl[SIOCGIWRATE]"); ret = -1; } else { linkspeed = wrq.u.bitrate.value / 1000000; ret = snprintf(buf, buf_len, "LinkSpeed %d\n", linkspeed); } } else if (os_strncasecmp(cmd, "scan-channels", 13) == 0) { } else if ((os_strcasecmp(cmd, "rssi") == 0) || (os_strcasecmp(cmd, "rssi-approx") == 0)) { struct iwreq wrq; struct iw_statistics stats; signed int rssi; wpa_printf(MSG_DEBUG, ">>>. DRIVER AWEXT RSSI "); wrq.u.data.pointer = (caddr_t) &stats; wrq.u.data.length = sizeof(stats); wrq.u.data.flags = 1; /* Clear updated flag */ strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ); if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &wrq) < 0) { perror("ioctl[SIOCGIWSTATS]"); ret = -1; } else { if (stats.qual.updated & IW_QUAL_DBM) { /* Values in dBm, stored in u8 with range 63 : -192 */ rssi = ( stats.qual.level > 63 ) ? stats.qual.level - 0x100 : stats.qual.level; } else { rssi = stats.qual.level; } if (drv->ssid_len != 0 && drv->ssid_len < buf_len) { os_memcpy((void *) buf, (void *) (drv->ssid), drv->ssid_len ); ret = drv->ssid_len; ret += snprintf(&buf[ret], buf_len-ret, " rssi %d\n", rssi); if (ret < (int)buf_len) { return( ret ); } ret = -1; } } } else if (os_strncasecmp(cmd, "powermode", 9) == 0) { } else if (os_strncasecmp(cmd, "getpower", 8) == 0) { } else if (os_strncasecmp(cmd, "get-rts-threshold", 17) == 0) { struct iwreq wrq; unsigned int rtsThreshold; strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ); if (ioctl(drv->ioctl_sock, SIOCGIWRTS, &wrq) < 0) { perror("ioctl[SIOCGIWRTS]"); ret = -1; } else { rtsThreshold = wrq.u.rts.value; wpa_printf(MSG_DEBUG,"Get RTS Threshold command = %d", rtsThreshold); ret = snprintf(buf, buf_len, "rts-threshold = %u\n", rtsThreshold); if (ret < (int)buf_len) { return( ret ); } } } else if (os_strncasecmp(cmd, "set-rts-threshold", 17) == 0) { struct iwreq wrq; unsigned int rtsThreshold; char *cp = cmd + 17; char *endp; strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ); if (*cp != '\0') { rtsThreshold = (unsigned int)strtol(cp, &endp, 0); if (endp != cp) { wrq.u.rts.value = rtsThreshold; wrq.u.rts.fixed = 1; wrq.u.rts.disabled = 0; if (ioctl(drv->ioctl_sock, SIOCSIWRTS, &wrq) < 0) { perror("ioctl[SIOCGIWRTS]"); ret = -1; } else { rtsThreshold = wrq.u.rts.value; wpa_printf(MSG_DEBUG,"Set RTS Threshold command = %d", rtsThreshold); ret = 0; } } } } else if (os_strcasecmp(cmd, "btcoexscan-start") == 0) { } else if (os_strcasecmp(cmd, "btcoexscan-stop") == 0) { } else if (os_strcasecmp(cmd, "rxfilter-start") == 0) { wpa_printf(MSG_DEBUG,"Rx Data Filter Start command"); } else if (os_strcasecmp(cmd, "rxfilter-stop") == 0) { wpa_printf(MSG_DEBUG,"Rx Data Filter Stop command"); } else if (os_strcasecmp(cmd, "rxfilter-statistics") == 0) { } else if (os_strncasecmp(cmd, "rxfilter-add", 12) == 0 ) { } else if (os_strncasecmp(cmd, "rxfilter-remove",15) == 0) { } else if (os_strcasecmp(cmd, "snr") == 0) { struct iwreq wrq; struct iw_statistics stats; int snr, rssi, noise; wrq.u.data.pointer = (caddr_t) &stats; wrq.u.data.length = sizeof(stats); wrq.u.data.flags = 1; /* Clear updated flag */ strncpy(wrq.ifr_name, drv->ifname, IFNAMSIZ); if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &wrq) < 0) { perror("ioctl[SIOCGIWSTATS]"); ret = -1; } else { if (stats.qual.updated & IW_QUAL_DBM) { /* Values in dBm, stored in u8 with range 63 : -192 */ rssi = ( stats.qual.level > 63 ) ? stats.qual.level - 0x100 : stats.qual.level; noise = ( stats.qual.noise > 63 ) ? stats.qual.noise - 0x100 : stats.qual.noise; } else { rssi = stats.qual.level; noise = stats.qual.noise; } snr = rssi - noise; ret = snprintf(buf, buf_len, "snr = %u\n", (unsigned int)snr); if (ret < (int)buf_len) { return( ret ); } } } else if (os_strncasecmp(cmd, "btcoexmode", 10) == 0) { } else if( os_strcasecmp(cmd, "btcoexstat") == 0 ) { } else { wpa_printf(MSG_DEBUG,"Unsupported command"); } return (ret); }
static void wps_er_ssdp_rx(int sd, void *eloop_ctx, void *sock_ctx) { struct wps_er *er = eloop_ctx; struct sockaddr_in addr; /* client address */ socklen_t addr_len; int nread; char buf[MULTICAST_MAX_READ], *pos, *pos2, *start; int wfa = 0, byebye = 0; int max_age = -1; char *location = NULL; u8 uuid[WPS_UUID_LEN]; addr_len = sizeof(addr); nread = recvfrom(sd, buf, sizeof(buf) - 1, 0, (struct sockaddr *) &addr, &addr_len); if (nread <= 0) return; buf[nread] = '\0'; if (er->filter_addr.s_addr && er->filter_addr.s_addr != addr.sin_addr.s_addr) return; wpa_printf(MSG_DEBUG, "WPS ER: Received SSDP from %s", inet_ntoa(addr.sin_addr)); wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Received SSDP contents", (u8 *) buf, nread); if (sd == er->multicast_sd) { /* Reply to M-SEARCH */ if (os_strncmp(buf, "HTTP/1.1 200 OK", 15) != 0) return; /* unexpected response header */ } else { /* Unsolicited message (likely NOTIFY or M-SEARCH) */ if (os_strncmp(buf, "NOTIFY ", 7) != 0) return; /* only process notifications */ } os_memset(uuid, 0, sizeof(uuid)); for (start = buf; start && *start; start = pos) { pos = os_strchr(start, '\n'); if (pos) { if (pos[-1] == '\r') pos[-1] = '\0'; *pos++ = '\0'; } if (os_strstr(start, "schemas-wifialliance-org:device:" "WFADevice:1")) wfa = 1; if (os_strstr(start, "schemas-wifialliance-org:service:" "WFAWLANConfig:1")) wfa = 1; if (os_strncasecmp(start, "LOCATION:", 9) == 0) { start += 9; while (*start == ' ') start++; location = start; } else if (os_strncasecmp(start, "NTS:", 4) == 0) { if (os_strstr(start, "ssdp:byebye")) byebye = 1; } else if (os_strncasecmp(start, "CACHE-CONTROL:", 14) == 0) { start += 9; while (*start == ' ') start++; pos2 = os_strstr(start, "max-age="); if (pos2 == NULL) continue; pos2 += 8; max_age = atoi(pos2); } else if (os_strncasecmp(start, "USN:", 4) == 0) { start += 4; pos2 = os_strstr(start, "uuid:"); if (pos2) { pos2 += 5; while (*pos2 == ' ') pos2++; if (uuid_str2bin(pos2, uuid) < 0) { wpa_printf(MSG_DEBUG, "WPS ER: " "Invalid UUID in USN: %s", pos2); return; } } } } if (!wfa) return; /* Not WPS advertisement/reply */ if (byebye) { wps_er_ap_remove(er, &addr.sin_addr); return; } if (!location) return; /* Unknown location */ if (max_age < 1) return; /* No max-age reported */ wpa_printf(MSG_DEBUG, "WPS ER: AP discovered: %s " "(packet source: %s max-age: %d)", location, inet_ntoa(addr.sin_addr), max_age); wps_er_ap_add(er, uuid, &addr.sin_addr, location, max_age); }
static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *pos, size_t slen, u8 dialog_token) { char fname[256]; int png; FILE *f; u16 data_len; struct icon_entry *icon; dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) { if (icon->dialog_token == dialog_token && !icon->image && os_memcmp(icon->bssid, sa, ETH_ALEN) == 0) { icon->image = os_malloc(slen); if (!icon->image) return -1; os_memcpy(icon->image, pos, slen); icon->image_len = slen; hs20_remove_duplicate_icons(wpa_s, icon); wpa_msg(wpa_s, MSG_INFO, RX_HS20_ICON MACSTR " %s %u", MAC2STR(sa), icon->file_name, (unsigned int) icon->image_len); return 0; } } wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Icon Binary File", MAC2STR(sa)); if (slen < 4) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " "value from " MACSTR, MAC2STR(sa)); return -1; } wpa_printf(MSG_DEBUG, "HS 2.0: Download Status Code %u", *pos); if (*pos != 0) return -1; pos++; slen--; if ((size_t) 1 + pos[0] > slen) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " "value from " MACSTR, MAC2STR(sa)); return -1; } wpa_hexdump_ascii(MSG_DEBUG, "Icon Type", pos + 1, pos[0]); png = os_strncasecmp((char *) pos + 1, "image/png", 9) == 0; slen -= 1 + pos[0]; pos += 1 + pos[0]; if (slen < 2) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " "value from " MACSTR, MAC2STR(sa)); return -1; } data_len = WPA_GET_LE16(pos); pos += 2; slen -= 2; if (data_len > slen) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " "value from " MACSTR, MAC2STR(sa)); return -1; } wpa_printf(MSG_DEBUG, "Icon Binary Data: %u bytes", data_len); if (wpa_s->conf->osu_dir == NULL) return -1; wpa_s->osu_icon_id++; if (wpa_s->osu_icon_id == 0) wpa_s->osu_icon_id++; snprintf(fname, sizeof(fname), "%s/osu-icon-%u.%s", wpa_s->conf->osu_dir, wpa_s->osu_icon_id, png ? "png" : "icon"); f = fopen(fname, "wb"); if (f == NULL) return -1; hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname); if (fwrite(pos, slen, 1, f) != 1) { fclose(f); unlink(fname); return -1; } fclose(f); wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP_ICON "%s", fname); return 0; }
int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len ) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct ifreq ifr; int ret = 0; if (os_strcasecmp(cmd, "STOP") == 0) { linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0); wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); } else if (os_strcasecmp(cmd, "START") == 0) { linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1); wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); } else if (os_strcasecmp(cmd, "RELOAD") == 0) { wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); } else if (os_strncasecmp(cmd, "POWERMODE ", 10) == 0) { int mode; mode = atoi(cmd + 10); ret = wpa_driver_set_power_save(priv, mode); if (ret < 0) { wpa_driver_send_hang_msg(drv); } else { g_power_mode = mode; g_drv_errors = 0; } } else if (os_strncasecmp(cmd, "GETPOWER", 8) == 0) { ret = os_snprintf(buf, buf_len, "POWERMODE = %d\n", g_power_mode); } else if (os_strncasecmp(cmd, "BTCOEXMODE ", 11) == 0) { int mode = atoi(cmd + 11); if (mode == BLUETOOTH_COEXISTENCE_MODE_DISABLED) { /* disable BT-coex */ ret = wpa_driver_toggle_btcoex_state('0'); } else if (mode == BLUETOOTH_COEXISTENCE_MODE_SENSE) { /* enable BT-coex */ ret = wpa_driver_toggle_btcoex_state('1'); } else { wpa_printf(MSG_DEBUG, "invalid btcoex mode: %d", mode); ret = -1; } } else if (os_strcasecmp(cmd, "MACADDR") == 0) { u8 macaddr[ETH_ALEN] = {}; ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr); if (!ret) ret = os_snprintf(buf, buf_len, "Macaddr = " MACSTR "\n", MAC2STR(macaddr)); } else if( os_strncasecmp(cmd, "RXFILTER-ADD ", 13) == 0 ) { int i = nl80211_parse_wowlan_trigger_nr(cmd + 13); if(i < 0) return i; return nl80211_toggle_wowlan_trigger(bss, i, 1); } else if( os_strncasecmp(cmd, "RXFILTER-REMOVE ", 16) == 0 ) { int i = nl80211_parse_wowlan_trigger_nr(cmd + 16); if(i < 0) return i; return nl80211_toggle_wowlan_trigger(bss, i, 0); } else if( os_strcasecmp(cmd, "RXFILTER-START") == 0 ) { return nl80211_set_wowlan_triggers(bss, 1); } else if( os_strcasecmp(cmd, "RXFILTER-STOP") == 0 ) { return nl80211_set_wowlan_triggers(bss, 0); } else if( os_strncasecmp(cmd, "DROPBCAST", 9) == 0 ) { char *value = cmd + 10; if (!os_strcasecmp(value, "ENABLE") || !os_strcasecmp(value, "1")) { ret = nl80211_toggle_dropbcast(1); } else if (!os_strcasecmp(value, "DISABLE") || !os_strcasecmp(value, "0")) { ret = nl80211_toggle_dropbcast(0); } else if (!os_strcasecmp(value, "GET") || !os_strlen(value)) { ret = nl80211_dropbcast_get(buf, buf_len); } else { wpa_printf(MSG_ERROR, "Invalid parameter for DROPBCAST: %s", value); ret = -1; } } else if( os_strncasecmp(cmd, "SETBAND ", 8) == 0 ) { int val = atoi(cmd + 8); ret = 0; if ( val < 0 || val > 2 ) ret = -1; } else { wpa_printf(MSG_INFO, "%s: Unsupported command %s", __func__, cmd); } return ret; }
static void wpa_cli_interactive(void) { #define max_args 10 char cmdbuf[256], *cmd, *argv[max_args], *pos; int argc; #ifdef CONFIG_READLINE char *home, *hfile = NULL; #endif /* CONFIG_READLINE */ printf("\nInteractive mode\n\n"); #ifdef CONFIG_READLINE rl_attempted_completion_function = wpa_cli_completion; home = getenv("HOME"); if (home) { const char *fname = ".wpa_cli_history"; int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1; hfile = os_malloc(hfile_len); if (hfile) { os_snprintf(hfile, hfile_len, "%s/%s", home, fname); hfile[hfile_len - 1] = '\0'; read_history(hfile); stifle_history(100); } } #endif /* CONFIG_READLINE */ do { wpa_cli_recv_pending(monitor_conn, 0, 0); #ifndef CONFIG_NATIVE_WINDOWS alarm(1); #endif /* CONFIG_NATIVE_WINDOWS */ #ifdef CONFIG_READLINE cmd = readline("> "); if (cmd && *cmd) { HIST_ENTRY *h; while (next_history()) ; h = previous_history(); if (h == NULL || os_strcmp(cmd, h->line) != 0) add_history(cmd); next_history(); } #else /* CONFIG_READLINE */ printf("> "); cmd = fgets(cmdbuf, sizeof(cmdbuf), stdin); #endif /* CONFIG_READLINE */ #ifndef CONFIG_NATIVE_WINDOWS alarm(0); #endif /* CONFIG_NATIVE_WINDOWS */ if (cmd == NULL) break; wpa_cli_recv_pending(monitor_conn, 0, 0); pos = cmd; while (*pos != '\0') { if (*pos == '\n') { *pos = '\0'; break; } pos++; } argc = 0; pos = cmd; for (;;) { while (*pos == ' ') pos++; if (*pos == '\0') break; argv[argc] = pos; argc++; if (argc == max_args) break; if (*pos == '"') { char *pos2 = os_strrchr(pos, '"'); if (pos2) pos = pos2 + 1; } while (*pos != '\0' && *pos != ' ') pos++; if (*pos == ' ') *pos++ = '\0'; } if (argc) wpa_request(ctrl_conn, argc, argv); if (cmd != cmdbuf) os_free(cmd); } while (!wpa_cli_quit); #ifdef CONFIG_READLINE if (hfile) { /* Save command history, excluding lines that may contain * passwords. */ HIST_ENTRY *h; history_set_pos(0); h = next_history(); while (h) { char *p = h->line; while (*p == ' ' || *p == '\t') p++; if (os_strncasecmp(p, "pa", 2) == 0 || os_strncasecmp(p, "o", 1) == 0 || os_strncasecmp(p, "n", 1)) { h = remove_history(where_history()); if (h) { os_free(h->line); os_free(h->data); os_free(h); } h = current_history(); } else { h = next_history(); } } write_history(hfile); os_free(hfile); } #endif /* CONFIG_READLINE */ }
static void wpa_cli_reconnect(void) { wpa_cli_close_connection(); ctrl_conn = wpa_cli_open_connection(ctrl_ifname); if (ctrl_conn) { printf("Connection to wpa_supplicant re-established\n"); #ifdef ANDROID if (wpa_ctrl_attach(monitor_conn) == 0) { #else if (wpa_ctrl_attach(ctrl_conn) == 0) { #endif wpa_cli_attached = 1; } else { printf("Warning: Failed to attach to " "wpa_supplicant.\n"); } } } static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read, int action_monitor) { int first = 1; #ifdef ANDROID if (ctrl == NULL) { #else if (ctrl_conn == NULL) { #endif wpa_cli_reconnect(); return; } while (wpa_ctrl_pending(ctrl) > 0) { char buf[256]; size_t len = sizeof(buf) - 1; if (wpa_ctrl_recv(ctrl, buf, &len) == 0) { buf[len] = '\0'; if (action_monitor) wpa_cli_action_process(buf); else { if (in_read && first) printf("\n"); first = 0; printf("%s\n", buf); } } else { printf("Could not read pending message.\n"); break; } } if (wpa_ctrl_pending(ctrl) < 0) { printf("Connection to wpa_supplicant lost - trying to " "reconnect\n"); wpa_cli_reconnect(); } } #ifdef CONFIG_READLINE static char * wpa_cli_cmd_gen(const char *text, int state) { static int i, len; const char *cmd; if (state == 0) { i = 0; len = os_strlen(text); } while ((cmd = wpa_cli_commands[i].cmd)) { i++; if (os_strncasecmp(cmd, text, len) == 0) return os_strdup(cmd); } return NULL; } static char * wpa_cli_dummy_gen(const char *text, int state) { return NULL; } static char ** wpa_cli_completion(const char *text, int start, int end) { return rl_completion_matches(text, start == 0 ? wpa_cli_cmd_gen : wpa_cli_dummy_gen); } #endif /* CONFIG_READLINE */ static void wpa_cli_interactive(void) { #define max_args 10 char cmdbuf[256], *cmd, *argv[max_args], *pos; int argc; #ifdef CONFIG_READLINE char *home, *hfile = NULL; #endif /* CONFIG_READLINE */ printf("\nInteractive mode\n\n"); #ifdef CONFIG_READLINE rl_attempted_completion_function = wpa_cli_completion; home = getenv("HOME"); if (home) { const char *fname = ".wpa_cli_history"; int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1; hfile = os_malloc(hfile_len); if (hfile) { int res; res = os_snprintf(hfile, hfile_len, "%s/%s", home, fname); if (res >= 0 && res < hfile_len) { hfile[hfile_len - 1] = '\0'; read_history(hfile); stifle_history(100); } } } #endif /* CONFIG_READLINE */ do { #ifdef ANDROID wpa_cli_recv_pending(monitor_conn, 0, 0); #else wpa_cli_recv_pending(ctrl_conn, 0, 0); #endif #ifndef CONFIG_NATIVE_WINDOWS alarm(ping_interval); #endif /* CONFIG_NATIVE_WINDOWS */ #ifdef CONFIG_READLINE cmd = readline("> "); if (cmd && *cmd) { HIST_ENTRY *h; while (next_history()) ; h = previous_history(); if (h == NULL || os_strcmp(cmd, h->line) != 0) add_history(cmd); next_history(); } #else /* CONFIG_READLINE */ printf("> "); cmd = fgets(cmdbuf, sizeof(cmdbuf), stdin); #endif /* CONFIG_READLINE */ #ifndef CONFIG_NATIVE_WINDOWS alarm(0); #endif /* CONFIG_NATIVE_WINDOWS */ if (cmd == NULL) break; #ifdef ANDROID wpa_cli_recv_pending(monitor_conn, 0, 0); #else wpa_cli_recv_pending(ctrl_conn, 0, 0); #endif pos = cmd; while (*pos != '\0') { if (*pos == '\n') { *pos = '\0'; break; } pos++; } argc = 0; pos = cmd; for (;;) { while (*pos == ' ') pos++; if (*pos == '\0') break; argv[argc] = pos; argc++; if (argc == max_args) break; if (*pos == '"') { char *pos2 = os_strrchr(pos, '"'); if (pos2) pos = pos2 + 1; } while (*pos != '\0' && *pos != ' ') pos++; if (*pos == ' ') *pos++ = '\0'; } if (argc) wpa_request(ctrl_conn, argc, argv); if (cmd != cmdbuf) os_free(cmd); } while (!wpa_cli_quit); #ifdef CONFIG_READLINE if (hfile) { /* Save command history, excluding lines that may contain * passwords. */ HIST_ENTRY *h; history_set_pos(0); while ((h = current_history())) { char *p = h->line; while (*p == ' ' || *p == '\t') p++; if (cmd_has_sensitive_data(p)) { h = remove_history(where_history()); if (h) { os_free(h->line); os_free(h->data); os_free(h); } else next_history(); } else next_history(); } write_history(hfile); os_free(hfile); } #endif /* CONFIG_READLINE */ }
int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len ) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct ifreq ifr; android_wifi_priv_cmd priv_cmd; int ret = 0; if (os_strcasecmp(cmd, "STOP") == 0) { linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0); wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STOPPED"); } else if (os_strcasecmp(cmd, "START") == 0) { linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1); wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "STARTED"); } else if (os_strcasecmp(cmd, "MACADDR") == 0) { u8 macaddr[ETH_ALEN] = {}; ret = linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, macaddr); if (!ret) ret = os_snprintf(buf, buf_len, "Macaddr = " MACSTR "\n", MAC2STR(macaddr)); } else if (os_strcasecmp(cmd, "RELOAD") == 0) { wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED"); } else if (os_strncasecmp(cmd, "POWERMODE ", 10) == 0) { int state; state = atoi(cmd + 10); ret = wpa_driver_set_power_save(priv, state); if (ret < 0) wpa_driver_send_hang_msg(drv); else drv_errors = 0; } else if (os_strncasecmp(cmd, "GETPOWER", 8) == 0) { int state = -1; ret = wpa_driver_get_power_save(priv, &state); if (!ret && (state != -1)) { ret = os_snprintf(buf, buf_len, "POWERMODE = %d\n", state); drv_errors = 0; } else { wpa_driver_send_hang_msg(drv); } } else if(os_strcmp(cmd, "SCAN-ACTIVE") == 0) { return 0; /* unsupported function */ } else if(os_strcmp(cmd, "SCAN-PASSIVE") == 0) { return 0; /* unsupported function */ } else if(os_strncmp(cmd, "RXFILTER-ADD ", 13) == 0) { return 0; /* Ignore it */ } else if(os_strncmp(cmd, "RXFILTER-REMOVE ", 16) == 0) { return 0; /* Ignore it */ } else if(os_strncmp(cmd, "BTCOEXMODE ", 11) == 0) { int mode; if (sscanf(cmd, "%*s %d", &mode)==1) { /* * Android disable BT-COEX when obtaining dhcp packet except there is headset is connected * It enable the BT-COEX after dhcp process is finished * We ignore since we have our way to do bt-coex during dhcp obtaining. */ switch (mode) { case 1: /* Disable*/ break; case 0: /* Enable */ /* fall through */ case 2: /* Sense*/ /* fall through */ default: break; } return 0; /* ignore it */ } } else if(os_strcmp(cmd, "RXFILTER-START") == 0) { // STUB return 0; } else if(os_strcmp(cmd, "RXFILTER-STOP") == 0) { // STUB return 0; } else { /* Use private command */ if (os_strcasecmp(cmd, "BGSCAN-START") == 0) { ret = wpa_driver_set_backgroundscan_params(priv); if (ret < 0) { return ret; } os_memcpy(buf, "PNOFORCE 1", 11); } else if (os_strcasecmp(cmd, "BGSCAN-STOP") == 0) { os_memcpy(buf, "PNOFORCE 0", 11); } else { os_memcpy(buf, cmd, strlen(cmd) + 1); } memset(&ifr, 0, sizeof(ifr)); memset(&priv_cmd, 0, sizeof(priv_cmd)); os_strncpy(ifr.ifr_name, bss->ifname, IFNAMSIZ); priv_cmd.buf = buf; priv_cmd.used_len = buf_len; priv_cmd.total_len = buf_len; ifr.ifr_data = &priv_cmd; if ((ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr)) < 0) { wpa_printf(MSG_ERROR, "%s: failed to issue private commands\n", __func__); wpa_driver_send_hang_msg(drv); } else { drv_errors = 0; ret = 0; if ((os_strcasecmp(cmd, "LINKSPEED") == 0) || (os_strcasecmp(cmd, "RSSI") == 0) || (os_strcasecmp(cmd, "GETBAND") == 0) ) ret = strlen(buf); wpa_printf(MSG_DEBUG, "%s %s len = %d, %d", __func__, buf, ret, strlen(buf)); } } return ret; }
/* subscr_addr_add_url -- add address(es) for one url to subscription */ static void subscr_addr_add_url(struct subscription *s, const char *url, size_t url_len) { int alloc_len; char *scratch_mem = NULL; char *mem; char *domain_and_port; char *delim; char *path; char *domain; int port = 80; /* port to send to (default is port 80) */ struct addrinfo hints; struct addrinfo *result = NULL; struct addrinfo *rp; int rerr; /* url MUST begin with http: */ if (url_len < 7 || os_strncasecmp(url, "http://", 7)) goto fail; url += 7; url_len -= 7; /* allocate memory for the extra stuff we need */ alloc_len = 2 * (url_len + 1); scratch_mem = os_zalloc(alloc_len); if (scratch_mem == NULL) goto fail; mem = scratch_mem; os_strncpy(mem, url, url_len); wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", mem); domain_and_port = mem; mem += 1 + os_strlen(mem); delim = os_strchr(domain_and_port, '/'); if (delim) { *delim++ = 0; /* null terminate domain and port */ path = delim; } else { path = domain_and_port + os_strlen(domain_and_port); } domain = mem; strcpy(domain, domain_and_port); delim = os_strchr(domain, ':'); if (delim) { *delim++ = 0; /* null terminate domain */ if (isdigit(*delim)) port = atol(delim); } /* * getaddrinfo does the right thing with dotted decimal notations, or * will resolve domain names. Resolving domain names will unfortunately * hang the entire program until it is resolved or it times out * internal to getaddrinfo; fortunately we think that the use of actual * domain names (vs. dotted decimal notations) should be uncommon. */ os_memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; /* IPv4 */ hints.ai_socktype = SOCK_STREAM; #if NO_DOMAIN_NAME_RESOLUTION /* Suppress domain name resolutions that would halt * the program for periods of time */ hints.ai_flags = AI_NUMERICHOST; #else /* Allow domain name resolution. */ hints.ai_flags = 0; #endif hints.ai_protocol = 0; /* Any protocol? */ rerr = getaddrinfo(domain, NULL /* fill in port ourselves */, &hints, &result); if (rerr) { wpa_printf(MSG_INFO, "WPS UPnP: Resolve error %d (%s) on: %s", rerr, gai_strerror(rerr), domain); goto fail; } for (rp = result; rp; rp = rp->ai_next) { struct subscr_addr *a; /* Limit no. of address to avoid denial of service attack */ if (dl_list_len(&s->addr_list) >= MAX_ADDR_PER_SUBSCRIPTION) { wpa_printf(MSG_INFO, "WPS UPnP: subscr_addr_add_url: " "Ignoring excessive addresses"); break; } a = os_zalloc(sizeof(*a) + alloc_len); if (a == NULL) continue; mem = (void *) (a + 1); a->domain_and_port = mem; strcpy(mem, domain_and_port); mem += 1 + strlen(mem); a->path = mem; if (path[0] != '/') *mem++ = '/'; strcpy(mem, path); mem += 1 + os_strlen(mem); os_memcpy(&a->saddr, rp->ai_addr, sizeof(a->saddr)); a->saddr.sin_port = htons(port); dl_list_add(&s->addr_list, &a->list); } fail: if (result) freeaddrinfo(result); os_free(scratch_mem); }
int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf, size_t buf_len ) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; struct ifreq ifr; struct wpa_supplicant *wpa_s; struct hostapd_data *hapd; int handled = 0; int cmd_len = 0; union wpa_event_data event; static int user_force_band = 0; int ret = -1; if (drv == NULL) { wpa_printf(MSG_ERROR, "%s: drv is NULL. Exiting", __func__); return -1; } if (drv->ctx == NULL) { wpa_printf(MSG_ERROR, "%s: drv->ctx is NULL. Exiting", __func__); return -1; } if (os_strcmp(bss->ifname, "ap0") == 0) { hapd = (struct hostapd_data *)(drv->ctx); } else { wpa_s = (struct wpa_supplicant *)(drv->ctx); if (wpa_s->conf == NULL) { wpa_printf(MSG_ERROR, "%s: wpa_s->conf is NULL. Exiting", __func__); return -1; } } wpa_printf(MSG_DEBUG, "iface %s recv cmd %s", bss->ifname, cmd); handled = 1; if (os_strncasecmp(cmd, "POWERMODE ", 10) == 0) { int state; state = atoi(cmd + 10); wpa_printf(MSG_DEBUG, "POWERMODE=%d", state); } else if (os_strncmp(cmd, "MACADDR", os_strlen("MACADDR")) == 0) { u8 macaddr[ETH_ALEN] = {}; os_memcpy(&macaddr, wpa_s->own_addr, ETH_ALEN); ret = snprintf(buf, buf_len, "Macaddr = " MACSTR "\n", MAC2STR(macaddr)); wpa_printf(MSG_DEBUG, "%s", buf); } else if(os_strncasecmp(cmd, "COUNTRY", os_strlen("COUNTRY"))==0) { if (os_strlen(cmd) != os_strlen("COUNTRY") + 3) { wpa_printf(MSG_DEBUG, "Ignore COUNTRY cmd %s", cmd); ret = 0; } else { wpa_printf(MSG_INFO, "set country: %s", cmd+8); // ret = wpa_drv_set_country(wpa_s, cmd+8); ret = wpa_driver_mediatek_set_country(priv, cmd+8); if (ret == 0) { wpa_printf(MSG_DEBUG, "Update channel list after country code changed"); wpa_driver_notify_country_change(wpa_s, cmd); } } } else if (os_strcasecmp(cmd, "start") == 0) { if (ret = linux_set_iface_flags(drv->global->ioctl_sock, drv->first_bss->ifname, 1)) { wpa_printf(MSG_INFO, "nl80211: Could not set interface UP, ret=%d \n", ret); } else { wpa_msg(drv->ctx, MSG_INFO, "CTRL-EVENT-DRIVER-STATE STARTED"); } } else if (os_strcasecmp(cmd, "stop") == 0) { if (drv->associated) { ret = wpa_drv_deauthenticate(wpa_s, drv->bssid, WLAN_REASON_DEAUTH_LEAVING); if (ret != 0) wpa_printf(MSG_DEBUG, "DRIVER-STOP error, ret=%d", ret); } else { wpa_printf(MSG_INFO, "nl80211: not associated, no need to deauthenticate \n"); } if (ret = linux_set_iface_flags(drv->global->ioctl_sock, drv->first_bss->ifname, 0)) { wpa_printf(MSG_INFO, "nl80211: Could not set interface Down, ret=%d \n", ret); } else { wpa_msg(drv->ctx, MSG_INFO, "CTRL-EVENT-DRIVER-STATE STOPPED"); } } else if (os_strncasecmp(cmd, "getpower", 8) == 0) { u32 mode; // ret = wpa_driver_wext_driver_get_power(drv, &mode); if (ret == 0) { ret = snprintf(buf, buf_len, "powermode = %u\n", mode); wpa_printf(MSG_DEBUG, "%s", buf); if (ret < (int)buf_len) return ret; } } else if (os_strncasecmp(cmd, "get-rts-threshold", 17) == 0) { u32 thd; // ret = wpa_driver_wext_driver_get_rts(drv, &thd); if (ret == 0) { ret = snprintf(buf, buf_len, "rts-threshold = %u\n", thd); wpa_printf(MSG_DEBUG, "%s", buf); if (ret < (int)buf_len) return ret; } } else if (os_strncasecmp(cmd, "set-rts-threshold", 17) == 0) { u32 thd = 0; char *cp = cmd + 17; char *endp; if (*cp != '\0') { thd = (u32)strtol(cp, &endp, 0); // if (endp != cp) // ret = wpa_driver_wext_driver_set_rts(drv, thd); } } else if (os_strcasecmp(cmd, "btcoexscan-start") == 0) { ret = 0; /* mt5921 linux driver not implement yet */ } else if (os_strcasecmp(cmd, "btcoexscan-stop") == 0) { ret = 0; /* mt5921 linux driver not implement yet */ } else if (os_strncasecmp(cmd, "btcoexmode", 10) == 0) { ret = 0; /* mt5921 linux driver not implement yet */ } else { handled = 0; wpa_printf(MSG_INFO, "Unsupported command"); } return ret; }
/* httpread_read_handler -- called when socket ready to read * * Note: any extra data we read past end of transmitted file is ignored; * if we were to support keeping connections open for multiple files then * this would have to be addressed. */ static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx) { struct httpread *h = sock_ctx; int nread; char *rbp; /* pointer into read buffer */ char *hbp; /* pointer into header buffer */ char *bbp; /* pointer into body buffer */ char readbuf[HTTPREAD_READBUF_SIZE]; /* temp use to read into */ if (httpread_debug >= 20) wpa_printf(MSG_DEBUG, "ENTER httpread_read_handler(%p)", h); /* read some at a time, then search for the interal * boundaries between header and data and etc. */ nread = read(h->sd, readbuf, sizeof(readbuf)); if (nread < 0) goto bad; if (nread == 0) { /* end of transmission... this may be normal * or may be an error... in some cases we can't * tell which so we must assume it is normal then. */ if (!h->got_hdr) { /* Must at least have completed header */ wpa_printf(MSG_DEBUG, "httpread premature eof(%p)", h); goto bad; } if (h->chunked || h->got_content_length) { /* Premature EOF; e.g. dropped connection */ wpa_printf(MSG_DEBUG, "httpread premature eof(%p) %d/%d", h, h->body_nbytes, h->content_length); goto bad; } /* No explicit length, hopefully we have all the data * although dropped connections can cause false * end */ if (httpread_debug >= 10) wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h); h->got_body = 1; goto got_file; } rbp = readbuf; /* Header consists of text lines (terminated by both CR and LF) * and an empty line (CR LF only). */ if (!h->got_hdr) { hbp = h->hdr + h->hdr_nbytes; /* add to headers until: * -- we run out of data in read buffer * -- or, we run out of header buffer room * -- or, we get double CRLF in headers */ for (;;) { if (nread == 0) goto get_more; if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) { goto bad; } *hbp++ = *rbp++; nread--; h->hdr_nbytes++; if (h->hdr_nbytes >= 4 && hbp[-1] == '\n' && hbp[-2] == '\r' && hbp[-3] == '\n' && hbp[-4] == '\r' ) { h->got_hdr = 1; *hbp = 0; /* null terminate */ break; } } /* here we've just finished reading the header */ if (httpread_hdr_analyze(h)) { wpa_printf(MSG_DEBUG, "httpread bad hdr(%p)", h); goto bad; } if (h->max_bytes == 0) { if (httpread_debug >= 10) wpa_printf(MSG_DEBUG, "httpread no body hdr end(%p)", h); goto got_file; } if (h->got_content_length && h->content_length == 0) { if (httpread_debug >= 10) wpa_printf(MSG_DEBUG, "httpread zero content length(%p)", h); goto got_file; } } /* Certain types of requests never have data and so * must be specially recognized. */ if (!os_strncasecmp(h->hdr, "SUBSCRIBE", 9) || !os_strncasecmp(h->hdr, "UNSUBSCRIBE", 11) || !os_strncasecmp(h->hdr, "HEAD", 4) || !os_strncasecmp(h->hdr, "GET", 3)) { if (!h->got_body) { if (httpread_debug >= 10) wpa_printf(MSG_DEBUG, "httpread NO BODY for sp. type"); } h->got_body = 1; goto got_file; } /* Data can be just plain binary data, or if "chunked" * consists of chunks each with a header, ending with * an ending header. */ if (!h->got_body) { /* Here to get (more of) body */ /* ensure we have enough room for worst case for body * plus a null termination character */ if (h->body_alloc_nbytes < (h->body_nbytes + nread + 1)) { char *new_body; int new_alloc_nbytes; if (h->body_nbytes >= h->max_bytes) goto bad; new_alloc_nbytes = h->body_alloc_nbytes + HTTPREAD_BODYBUF_DELTA; /* For content-length case, the first time * through we allocate the whole amount * we need. */ if (h->got_content_length && new_alloc_nbytes < (h->content_length + 1)) new_alloc_nbytes = h->content_length + 1; if ((new_body = os_realloc(h->body, new_alloc_nbytes)) == NULL) goto bad; h->body = new_body; h->body_alloc_nbytes = new_alloc_nbytes; } /* add bytes */ bbp = h->body + h->body_nbytes; for (;;) { int ncopy; /* See if we need to stop */ if (h->chunked && h->in_chunk_data == 0) { /* in chunk header */ char *cbp = h->body + h->chunk_start; if (bbp-cbp >= 2 && bbp[-2] == '\r' && bbp[-1] == '\n') { /* end of chunk hdr line */ /* hdr line consists solely * of a hex numeral and CFLF */ if (!isxdigit(*cbp)) goto bad; h->chunk_size = strtoul(cbp, NULL, 16); /* throw away chunk header * so we have only real data */ h->body_nbytes = h->chunk_start; bbp = cbp; if (h->chunk_size == 0) { /* end of chunking */ /* trailer follows */ h->in_trailer = 1; if (httpread_debug >= 20) wpa_printf( MSG_DEBUG, "httpread end chunks(%p)", h); break; } h->in_chunk_data = 1; /* leave chunk_start alone */ } } else if (h->chunked) { /* in chunk data */ if ((h->body_nbytes - h->chunk_start) == (h->chunk_size + 2)) { /* end of chunk reached, * new chunk starts */ /* check chunk ended w/ CRLF * which we'll throw away */ if (bbp[-1] == '\n' && bbp[-2] == '\r') { } else goto bad; h->body_nbytes -= 2; bbp -= 2; h->chunk_start = h->body_nbytes; h->in_chunk_data = 0; h->chunk_size = 0; /* just in case */ } } else if (h->got_content_length && h->body_nbytes >= h->content_length) { h->got_body = 1; if (httpread_debug >= 10) wpa_printf( MSG_DEBUG, "httpread got content(%p)", h); goto got_file; } if (nread <= 0) break; /* Now transfer. Optimize using memcpy where we can. */ if (h->chunked && h->in_chunk_data) { /* copy up to remainder of chunk data * plus the required CR+LF at end */ ncopy = (h->chunk_start + h->chunk_size + 2) - h->body_nbytes; } else if (h->chunked) { /*in chunk header -- don't optimize */ *bbp++ = *rbp++; nread--; h->body_nbytes++; continue; } else if (h->got_content_length) { ncopy = h->content_length - h->body_nbytes; } else { ncopy = nread; } /* Note: should never be 0 */ if (ncopy > nread) ncopy = nread; os_memcpy(bbp, rbp, ncopy); bbp += ncopy; h->body_nbytes += ncopy; rbp += ncopy; nread -= ncopy; } /* body copy loop */ } /* !got_body */ if (h->chunked && h->in_trailer) { /* If "chunked" then there is always a trailer, * consisting of zero or more non-empty lines * ending with CR LF and then an empty line w/ CR LF. * We do NOT support trailers except to skip them -- * this is supported (generally) by the http spec. */ bbp = h->body + h->body_nbytes; for (;;) { int c; if (nread <= 0) break; c = *rbp++; nread--; switch (h->trailer_state) { case trailer_line_begin: if (c == '\r') h->trailer_state = trailer_empty_cr; else h->trailer_state = trailer_nonempty; break; case trailer_empty_cr: /* end empty line */ if (c == '\n') { h->trailer_state = trailer_line_begin; h->in_trailer = 0; if (httpread_debug >= 10) wpa_printf( MSG_DEBUG, "httpread got content(%p)", h); h->got_body = 1; goto got_file; } h->trailer_state = trailer_nonempty; break; case trailer_nonempty: if (c == '\r') h->trailer_state = trailer_nonempty_cr; break; case trailer_nonempty_cr: if (c == '\n') h->trailer_state = trailer_line_begin; else h->trailer_state = trailer_nonempty; break; } } } goto get_more; bad: /* Error */ wpa_printf(MSG_DEBUG, "httpread read/parse failure (%p)", h); (*h->cb)(h, h->cookie, HTTPREAD_EVENT_ERROR); return; get_more: return; got_file: if (httpread_debug >= 10) wpa_printf(MSG_DEBUG, "httpread got file %d bytes type %d", h->body_nbytes, h->hdr_type); /* Null terminate for convenience of some applications */ if (h->body) h->body[h->body_nbytes] = 0; /* null terminate */ h->got_file = 1; /* Assume that we do NOT support keeping connection alive, * and just in case somehow we don't get destroyed right away, * unregister now. */ if (h->sd_registered) eloop_unregister_sock(h->sd, EVENT_TYPE_READ); h->sd_registered = 0; /* The application can destroy us whenever they feel like... * cancel timeout. */ if (h->to_registered) eloop_cancel_timeout(httpread_timeout_handler, NULL, h); h->to_registered = 0; (*h->cb)(h, h->cookie, HTTPREAD_EVENT_FILE_READY); }
/* Given that we have received a header w/ SUBSCRIBE, act upon it * * Format of SUBSCRIBE (case-insensitive): * * First line must be: * SUBSCRIBE /wps_event HTTP/1.1 * * Our response (if no error) which includes only required lines is: * HTTP/1.1 200 OK * Server: xx, UPnP/1.0, xx * SID: uuid:xxxxxxxxx * Timeout: Second-<n> * Content-Length: 0 * Date: xxxx * * Header lines must end with \r\n * Per RFC 2616, content-length: is not required but connection:close * would appear to be required (given that we will be closing it!). */ static void web_connection_parse_subscribe(struct upnp_wps_device_sm *sm, struct http_request *req, const char *filename) { struct wpabuf *buf; char *b; char *hdr = http_request_get_hdr(req); char *h; char *match; int match_len; char *end; int len; int got_nt = 0; u8 uuid[UUID_LEN]; int got_uuid = 0; char *callback_urls = NULL; struct subscription *s = NULL; enum http_reply_code ret = HTTP_INTERNAL_SERVER_ERROR; buf = wpabuf_alloc(1000); if (buf == NULL) { http_request_deinit(req); return; } wpa_hexdump_ascii(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE", (u8 *) hdr, os_strlen(hdr)); /* Parse/validate headers */ h = hdr; /* First line: SUBSCRIBE /wps_event HTTP/1.1 * has already been parsed. */ if (os_strcasecmp(filename, UPNP_WPS_DEVICE_EVENT_FILE) != 0) { ret = HTTP_PRECONDITION_FAILED; goto error; } wpa_printf(MSG_DEBUG, "WPS UPnP: HTTP SUBSCRIBE for event"); end = os_strchr(h, '\n'); while (end) { /* Option line by option line */ h = end + 1; end = os_strchr(h, '\n'); if (end == NULL) break; /* no unterminated lines allowed */ /* NT assures that it is our type of subscription; * not used for a renewal. **/ match = "NT:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; match = "upnp:event"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) != 0) { ret = HTTP_BAD_REQUEST; goto error; } got_nt = 1; continue; } /* HOST should refer to us */ #if 0 match = "HOST:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; ..... } #endif /* CALLBACK gives one or more URLs for NOTIFYs * to be sent as a result of the subscription. * Each URL is enclosed in angle brackets. */ match = "CALLBACK:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; len = end - h; os_free(callback_urls); callback_urls = dup_binstr(h, len); if (callback_urls == NULL) { ret = HTTP_INTERNAL_SERVER_ERROR; goto error; } if (len > 0 && callback_urls[len - 1] == '\r') callback_urls[len - 1] = '\0'; continue; } /* SID is only for renewal */ match = "SID:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) == 0) { h += match_len; while (*h == ' ' || *h == '\t') h++; match = "uuid:"; match_len = os_strlen(match); if (os_strncasecmp(h, match, match_len) != 0) { ret = HTTP_BAD_REQUEST; goto error; } h += match_len; while (*h == ' ' || *h == '\t') h++; if (uuid_str2bin(h, uuid)) { ret = HTTP_BAD_REQUEST; goto error; } got_uuid = 1; continue; } /* TIMEOUT is requested timeout, but apparently we can * just ignore this. */ }
/* subscr_addr_add_url -- add address(es) for one url to subscription */ static void subscr_addr_add_url(struct subscription *s, const char *url, size_t url_len) { int alloc_len; char *scratch_mem = NULL; char *mem; char *host; char *delim; char *path; int port = 80; /* port to send to (default is port 80) */ struct addrinfo hints; struct addrinfo *result = NULL; struct addrinfo *rp; int rerr; size_t host_len, path_len; /* url MUST begin with http: */ if (url_len < 7 || os_strncasecmp(url, "http://", 7)) goto fail; url += 7; url_len -= 7; /* Make a copy of the string to allow modification during parsing */ scratch_mem = dup_binstr(url, url_len); if (scratch_mem == NULL) goto fail; wpa_printf(MSG_DEBUG, "WPS UPnP: Adding URL '%s'", scratch_mem); host = scratch_mem; path = os_strchr(host, '/'); if (path) *path++ = '\0'; /* null terminate host */ /* Process and remove optional port component */ delim = os_strchr(host, ':'); if (delim) { *delim = '\0'; /* null terminate host name for now */ if (isdigit(delim[1])) port = atol(delim + 1); } /* * getaddrinfo does the right thing with dotted decimal notations, or * will resolve domain names. Resolving domain names will unfortunately * hang the entire program until it is resolved or it times out * internal to getaddrinfo; fortunately we think that the use of actual * domain names (vs. dotted decimal notations) should be uncommon. */ os_memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; /* IPv4 */ hints.ai_socktype = SOCK_STREAM; #if NO_DOMAIN_NAME_RESOLUTION /* Suppress domain name resolutions that would halt * the program for periods of time */ hints.ai_flags = AI_NUMERICHOST; #else /* Allow domain name resolution. */ hints.ai_flags = 0; #endif hints.ai_protocol = 0; /* Any protocol? */ rerr = getaddrinfo(host, NULL /* fill in port ourselves */, &hints, &result); if (rerr) { wpa_printf(MSG_INFO, "WPS UPnP: Resolve error %d (%s) on: %s", rerr, gai_strerror(rerr), host); goto fail; } if (delim) *delim = ':'; /* Restore port */ host_len = os_strlen(host); path_len = path ? os_strlen(path) : 0; alloc_len = host_len + 1 + 1 + path_len + 1; for (rp = result; rp; rp = rp->ai_next) { struct subscr_addr *a; /* Limit no. of address to avoid denial of service attack */ if (dl_list_len(&s->addr_list) >= MAX_ADDR_PER_SUBSCRIPTION) { wpa_printf(MSG_INFO, "WPS UPnP: subscr_addr_add_url: " "Ignoring excessive addresses"); break; } a = os_zalloc(sizeof(*a) + alloc_len); if (a == NULL) break; mem = (char *) (a + 1); a->domain_and_port = mem; os_memcpy(mem, host, host_len); mem += host_len + 1; a->path = mem; if (path == NULL || path[0] != '/') *mem++ = '/'; if (path) os_memcpy(mem, path, path_len); os_memcpy(&a->saddr, rp->ai_addr, sizeof(a->saddr)); a->saddr.sin_port = htons(port); dl_list_add(&s->addr_list, &a->list); } fail: if (result) freeaddrinfo(result); os_free(scratch_mem); }