static int parse_mntr_flags(int *_argc, char ***_argv, struct nl_msg *msg) { struct nl_msg *flags; int err = -ENOBUFS; enum nl80211_mntr_flags flag; int argc = *_argc; char **argv = *_argv; flags = nlmsg_alloc(); if (!flags) return -ENOMEM; while (argc) { int ok = 0; for (flag = __NL80211_MNTR_FLAG_INVALID; flag <= NL80211_MNTR_FLAG_MAX; flag++) { if (strcmp(*argv, mntr_flags[flag]) == 0) { ok = 1; /* * This shouldn't be adding "flag" if that is * zero, but due to a problem in the kernel's * nl80211 code (using NLA_NESTED policy) it * will reject an empty nested attribute but * not one that contains an invalid attribute */ NLA_PUT_FLAG(flags, flag); break; } } if (!ok) { err = -EINVAL; goto out; } argc--; argv++; } nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); err = 0; nla_put_failure: out: nlmsg_free(flags); *_argc = argc; *_argv = argv; return err; }
// Has to be a separate function because of gotos, ew void nl80211_parseflags(int nflags, int *in_flags, struct nl_msg *msg) { #ifdef HAVE_LINUX_NETLINK struct nl_msg *flags; unsigned int x; enum nl80211_mntr_flags flag = NL80211_MNTR_FLAG_MAX; if ((flags = nlmsg_alloc()) == NULL) { return; } for (x = 0; x < nflags; x++) { switch (in_flags[x]) { case nl80211_mntr_flag_none: continue; break; case nl80211_mntr_flag_fcsfail: flag = NL80211_MNTR_FLAG_FCSFAIL; break; case nl80211_mntr_flag_plcpfail: flag = NL80211_MNTR_FLAG_PLCPFAIL; break; case nl80211_mntr_flag_control: flag = NL80211_MNTR_FLAG_CONTROL; break; case nl80211_mntr_flag_otherbss: flag = NL80211_MNTR_FLAG_OTHER_BSS; break; case nl80211_mntr_flag_cookframe: flag = NL80211_MNTR_FLAG_COOK_FRAMES; break; } NLA_PUT_FLAG(flags, flag); } nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags); nla_put_failure: nlmsg_free(flags); #endif }
static int handle_wowlan_enable(struct nl80211_state *state, struct nl_cb *cb, struct nl_msg *msg, int argc, char **argv, enum id_input id) { struct nlattr *wowlan, *pattern; struct nl_msg *patterns = NULL; enum { PS_REG, PS_PAT, } parse_state = PS_REG; int err = -ENOBUFS; unsigned char *pat, *mask; size_t patlen; int patnum = 0; wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); if (!wowlan) return -ENOBUFS; while (argc) { switch (parse_state) { case PS_REG: if (strcmp(argv[0], "any") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY); else if (strcmp(argv[0], "disconnect") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); else if (strcmp(argv[0], "magic-packet") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); else if (strcmp(argv[0], "gtk-rekey-failure") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE); else if (strcmp(argv[0], "eap-identity-request") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST); else if (strcmp(argv[0], "4way-handshake") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE); else if (strcmp(argv[0], "rfkill-release") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE); else if (strcmp(argv[0], "patterns") == 0) { parse_state = PS_PAT; patterns = nlmsg_alloc(); if (!patterns) { err = -ENOMEM; goto nla_put_failure; } } else { err = 1; goto nla_put_failure; } break; case PS_PAT: if (parse_hex_mask(argv[0], &pat, &patlen, &mask)) { err = 1; goto nla_put_failure; } pattern = nla_nest_start(patterns, ++patnum); NLA_PUT(patterns, NL80211_WOWLAN_PKTPAT_MASK, DIV_ROUND_UP(patlen, 8), mask); NLA_PUT(patterns, NL80211_WOWLAN_PKTPAT_PATTERN, patlen, pat); nla_nest_end(patterns, pattern); free(mask); free(pat); break; } argv++; argc--; } if (patterns) nla_put_nested(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, patterns); nla_nest_end(msg, wowlan); err = 0; nla_put_failure: nlmsg_free(patterns); return err; }
static int handle_wowlan_enable(struct nl80211_state *state, struct nl_msg *msg, int argc, char **argv, enum id_input id) { struct nlattr *wowlan, *pattern; struct nl_msg *patterns = NULL; enum { PS_REG, PS_PAT, } parse_state = PS_REG; int err = -ENOBUFS; unsigned char *pat, *mask; size_t patlen; int patnum = 0, pkt_offset; char *eptr, *value1, *value2, *sptr = NULL; wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); if (!wowlan) return -ENOBUFS; while (argc) { switch (parse_state) { case PS_REG: if (strcmp(argv[0], "any") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY); else if (strcmp(argv[0], "disconnect") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT); else if (strcmp(argv[0], "magic-packet") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT); else if (strcmp(argv[0], "gtk-rekey-failure") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE); else if (strcmp(argv[0], "eap-identity-request") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST); else if (strcmp(argv[0], "4way-handshake") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE); else if (strcmp(argv[0], "rfkill-release") == 0) NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE); else if (strcmp(argv[0], "tcp") == 0) { argv++; argc--; if (!argc) { err = 1; goto nla_put_failure; } err = wowlan_parse_tcp_file(msg, argv[0]); if (err) goto nla_put_failure; } else if (strcmp(argv[0], "patterns") == 0) { parse_state = PS_PAT; patterns = nlmsg_alloc(); if (!patterns) { err = -ENOMEM; goto nla_put_failure; } } else if (strcmp(argv[0], "net-detect") == 0) { argv++; argc--; if (!argc) { err = 1; goto nla_put_failure; } err = wowlan_parse_net_detect(msg, &argc, &argv); if (err) goto nla_put_failure; continue; } else { err = 1; goto nla_put_failure; } break; case PS_PAT: value1 = strtok_r(argv[0], "+", &sptr); value2 = strtok_r(NULL, "+", &sptr); if (!value2) { pkt_offset = 0; value2 = value1; } else { pkt_offset = strtoul(value1, &eptr, 10); if (eptr != value1 + strlen(value1)) { err = 1; goto nla_put_failure; } } if (parse_hex_mask(value2, &pat, &patlen, &mask)) { err = 1; goto nla_put_failure; } pattern = nla_nest_start(patterns, ++patnum); NLA_PUT(patterns, NL80211_PKTPAT_MASK, DIV_ROUND_UP(patlen, 8), mask); NLA_PUT(patterns, NL80211_PKTPAT_PATTERN, patlen, pat); NLA_PUT_U32(patterns, NL80211_PKTPAT_OFFSET, pkt_offset); nla_nest_end(patterns, pattern); free(mask); free(pat); break; } argv++; argc--; } if (patterns) nla_put_nested(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, patterns); nla_nest_end(msg, wowlan); err = 0; nla_put_failure: nlmsg_free(patterns); return err; }
static int nl80211_set_wowlan_triggers(struct i802_bss *bss, int enable) { struct nl_msg *msg, *pats = NULL; struct wpa_driver_nl80211_data *drv = bss->drv; struct nlattr *wowtrig, *pat; int i, ret = -1; int filters; bss->drv->wowlan_enabled = !!enable; msg = nlmsg_alloc(); if (!msg) return -ENOMEM; genlmsg_put(msg, 0, 0, drv->global->nl80211_id, 0, 0, NL80211_CMD_SET_WOWLAN, 0); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->drv->first_bss.ifindex); wowtrig = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS); if (!wowtrig) { ret = -ENOBUFS; goto nla_put_failure; } if (!enable) { NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY); } else { pats = nlmsg_alloc(); if (!pats) { ret = -ENOMEM; goto nla_put_failure; } /* In ginger filter 0 and 1 are always set but in ICS we * only enable unicast. Make sure to always set it, otherwise * unicast packets will be dropped. * bcast packets are dropped and handled by the firmware */ filters = bss->drv->wowlan_triggers |= 1; for (i = 0; i < NR_RX_FILTERS; i++) { if (filters & (1 << i)) { struct rx_filter *rx_filter = &rx_filters[i]; int patnr = 1; u8 *pattern = nl80211_rx_filter_get_pattern(rx_filter,bss); if (!pattern) continue; pat = nla_nest_start(pats, patnr++); NLA_PUT(pats, NL80211_WOWLAN_PKTPAT_MASK, rx_filter->mask_len, rx_filter->mask); NLA_PUT(pats, NL80211_WOWLAN_PKTPAT_PATTERN, rx_filter->pattern_len, pattern); nla_nest_end(pats, pat); } } } if (pats) nla_put_nested(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN, pats); nla_nest_end(msg, wowtrig); ret = send_and_recv_msgs(bss->drv, msg, NULL, NULL); if (ret < 0) wpa_printf(MSG_ERROR, "Failed to set WoWLAN trigger:%d\n", ret); if (pats) nlmsg_free(pats); return 0; nla_put_failure: nlmsg_free(msg); return ret; }
int parse_keys(struct nl_msg *msg, char **argv[], int *argc) { struct nlattr *keys; int i = 0; bool have_default = false; char *arg = **argv; char keybuf[13]; int pos = 0; if (!*argc) return 1; if (!memcmp(&arg[pos], "psk", 3)) { char psk_keybuf[32]; int cipher_suite, akm_suite; if (*argc < 4) goto explain; pos+=3; if (arg[pos] != ':') goto explain; pos++; NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, NL80211_WPA_VERSION_2); if (strlen(&arg[pos]) != (sizeof(psk_keybuf) * 2) || !hex2bin(&arg[pos], psk_keybuf)) { printf("Bad PSK\n"); return -EINVAL; } NLA_PUT(msg, NL80211_ATTR_PMK, 32, psk_keybuf); NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, NL80211_AUTHTYPE_OPEN_SYSTEM); *argv += 1; *argc -= 1; arg = **argv; akm_suite = parse_akm_suite(arg); if (akm_suite < 0) goto explain; NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, akm_suite); *argv += 1; *argc -= 1; arg = **argv; cipher_suite = parse_cipher_suite(arg); if (cipher_suite < 0) goto explain; NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher_suite); *argv += 1; *argc -= 1; arg = **argv; cipher_suite = parse_cipher_suite(arg); if (cipher_suite < 0) goto explain; NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher_suite); *argv += 1; *argc -= 1; return 0; } NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY); keys = nla_nest_start(msg, NL80211_ATTR_KEYS); if (!keys) return -ENOBUFS; do { int keylen; struct nlattr *key = nla_nest_start(msg, ++i); char *keydata; arg = **argv; pos = 0; if (!key) return -ENOBUFS; if (arg[pos] == 'd') { NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); pos++; if (arg[pos] == ':') pos++; have_default = true; } if (!isdigit(arg[pos])) goto explain; NLA_PUT_U8(msg, NL80211_KEY_IDX, arg[pos++] - '0'); if (arg[pos++] != ':') goto explain; keydata = arg + pos; switch (strlen(keydata)) { case 10: keydata = hex2bin(keydata, keybuf); /* fall through */ case 5: NLA_PUT_U32(msg, NL80211_KEY_CIPHER, 0x000FAC01); keylen = 5; break; case 26: keydata = hex2bin(keydata, keybuf); /* fall through */ case 13: NLA_PUT_U32(msg, NL80211_KEY_CIPHER, 0x000FAC05); keylen = 13; break; default: goto explain; } if (!keydata) goto explain; NLA_PUT(msg, NL80211_KEY_DATA, keylen, keydata); *argv += 1; *argc -= 1; /* one key should be TX key */ if (!have_default && !*argc) NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT); nla_nest_end(msg, key); } while (*argc); nla_nest_end(msg, keys); return 0; nla_put_failure: return -ENOBUFS; explain: fprintf(stderr, "key must be [d:]index:data where\n" " 'd:' means default (transmit) key\n" " 'index:' is a single digit (0-3)\n" " 'data' must be 5 or 13 ascii chars\n" " or 10 or 26 hex digits\n" "for example: d:2:6162636465 is the same as d:2:abcde\n" "or psk:data <AKM Suite> <pairwise CIPHER> <groupwise CIPHER> where\n" " 'data' is the PSK (output of wpa_passphrase and the CIPHER can be CCMP or GCMP\n" "for example: psk:0123456789abcdef PSK CCMP CCMP\n" "The allowed AKM suites are PSK, FT/PSK, PSK/SHA-256\n" "The allowed Cipher suites are TKIP, CCMP, GCMP, GCMP-256, CCMP-256\n"); return 2; }