/* SPDX-License-Identifier: GPL-2.0-only */ /* * policy.c - provides attribute names and policies for commands. * * Copyright (C) 2022-2024 IOPSYS Software Solutions AB. All rights reserved. * Copyright (C) 2025 Genexis AB. * */ enum { SCAN_SSID, SCAN_BSSID, SCAN_CHANNEL, SCAN_OPCLASS, /* SCAN_TYPE, // active, passsive, background */ __SCAN_MAX, }; static const struct blobmsg_policy wl_scan_policy[__SCAN_MAX] = { [SCAN_SSID] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING }, [SCAN_BSSID] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, [SCAN_CHANNEL] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 }, [SCAN_OPCLASS] = { .name = "opclass", .type = BLOBMSG_TYPE_INT32 }, /* [SCAN_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_INT32 }, */ }; enum { SCAN_EX_SSID, SCAN_EX_BSSID, SCAN_EX_OPCLASS, SCAN_EX_CHANNEL, // SCAN_EX_TYPE, // active, passsive, cached */ SCAN_EX_DURATION, __SCAN_EX_MAX, }; static const struct blobmsg_policy wl_scan_ex_policy[__SCAN_EX_MAX] = { [SCAN_EX_SSID] = { .name = "ssid", .type = BLOBMSG_TYPE_ARRAY }, [SCAN_EX_BSSID] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, [SCAN_EX_OPCLASS] = { .name = "opclass", .type = BLOBMSG_TYPE_ARRAY }, [SCAN_EX_CHANNEL] = { .name = "channel", .type = BLOBMSG_TYPE_ARRAY }, // [SCAN_EX_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_INT32 }, [SCAN_EX_DURATION] = { .name = "duration", .type = BLOBMSG_TYPE_INT16 }, }; enum { SCANRES_BSSID, SCANRES_CACHE, __SCANRES_MAX, }; static const struct blobmsg_policy wl_scanres_policy[__SCANRES_MAX] = { [SCANRES_BSSID] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, [SCANRES_CACHE] = { .name = "cache", .type = BLOBMSG_TYPE_BOOL }, }; enum { ACS_PARAM_EXCLUDE_DFS, ACS_PARAM_EXCLUDE_6GHZ_NON_PSC, ACS_PARAM_EXCLUDE_OPCLASS, ACS_PARAM_EXCLUDE_CHANNELS, ACS_PARAM_EXCLUDE_BANDWIDTH, ACS_PARAM_INCLUDE_CHANNELS, ACS_PARAM_INCLUDE_BANDWIDTH, ACS_PARAM_MODE, NUM_ACS_PARAMS, }; enum { ACS_PARAM_CHANNEL_NUMBER, ACS_PARAM_CHANNEL_BANDWIDTH, ACS_PARAM_CHANNEL_WEIGHT, NUM_ACS_CHANNEL_PARAMS, }; static const struct blobmsg_policy wl_acs_policy[NUM_ACS_PARAMS] = { [ACS_PARAM_EXCLUDE_DFS] = { .name = "exclude_dfs", .type = BLOBMSG_TYPE_BOOL }, [ACS_PARAM_EXCLUDE_6GHZ_NON_PSC] = { .name = "exclude_6ghz_non_psc", .type = BLOBMSG_TYPE_BOOL }, [ACS_PARAM_EXCLUDE_OPCLASS] = { .name = "exclude_opclass", .type = BLOBMSG_TYPE_ARRAY}, [ACS_PARAM_EXCLUDE_CHANNELS] = { .name = "exclude_channels", .type = BLOBMSG_TYPE_ARRAY}, [ACS_PARAM_EXCLUDE_BANDWIDTH] = { .name = "exclude_bandwidth", .type = BLOBMSG_TYPE_ARRAY}, [ACS_PARAM_INCLUDE_CHANNELS] = { .name = "channels", .type = BLOBMSG_TYPE_ARRAY}, [ACS_PARAM_INCLUDE_BANDWIDTH] = { .name = "bandwidth", .type = BLOBMSG_TYPE_ARRAY}, [ACS_PARAM_MODE] = { .name = "mode", .type = BLOBMSG_TYPE_STRING}, }; enum { CAC_CHANNEL, CAC_BANDWIDTH, CAC_METHOD, __CAC_MAX, }; static const struct blobmsg_policy wl_cac_policy[__CAC_MAX] = { [CAC_CHANNEL] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 }, [CAC_BANDWIDTH] = { .name = "bandwidth", .type = BLOBMSG_TYPE_INT32 }, [CAC_METHOD] = { .name = "method", .type = BLOBMSG_TYPE_INT32 }, }; enum { ADD_IFACE_ARGS, ADD_IFACE_CONF, __ADD_IFACE_MAX, }; static const struct blobmsg_policy add_iface_policy[__ADD_IFACE_MAX] = { [ADD_IFACE_ARGS] = { .name = "args", .type = BLOBMSG_TYPE_TABLE }, [ADD_IFACE_CONF] = { .name = "config", .type = BLOBMSG_TYPE_BOOL }, }; enum { DEL_IFACE_IFNAME, DEL_IFACE_CONF, __DEL_IFACE_MAX, }; static const struct blobmsg_policy del_iface_policy[__DEL_IFACE_MAX] = { [DEL_IFACE_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, [DEL_IFACE_CONF] = { .name = "config", .type = BLOBMSG_TYPE_BOOL }, }; enum { DUMP_CHANNELS_FOR_BANDWIDTH, NUM_DUMP_CHANNELS, }; static const struct blobmsg_policy wl_dump_channels_policy[NUM_DUMP_CHANNELS] = { [DUMP_CHANNELS_FOR_BANDWIDTH] = { .name = "bandwidth", .type = BLOBMSG_TYPE_INT32 }, }; enum { RADAR_CHANNEL, RADAR_BANDWIDTH, RADAR_TYPE, RADAR_SUBBAND_MASK, __RADAR_MAX, }; static const struct blobmsg_policy wl_radar_policy[__RADAR_MAX] = { [RADAR_CHANNEL] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 }, [RADAR_BANDWIDTH] = { .name = "bandwidth", .type = BLOBMSG_TYPE_INT32 }, [RADAR_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_INT32 }, [RADAR_SUBBAND_MASK] = { .name = "subband_mask", .type = BLOBMSG_TYPE_INT32 }, }; enum { GET_PNAME, __GET_MAX, }; static const struct blobmsg_policy radio_get_param_policy[__GET_MAX] = { [GET_PNAME] = { .name = "param", .type = BLOBMSG_TYPE_STRING }, }; enum { CHAN_SWITCH_COUNT, CHAN_SWITCH_CHANNEL, /* primary ctrl-channel */ CHAN_SWITCH_FREQ, CHAN_SWITCH_SEC_CHAN_OFFSET, CHAN_SWITCH_CF1, CHAN_SWITCH_CF2, CHAN_SWITCH_BW, CHAN_SWITCH_BLOCK_TX, CHAN_SWITCH_HT, CHAN_SWITCH_VHT, CHAN_SWITCH_HE, CHAN_SWITCH_EHT, CHAN_SWITCH_AUTO_HT, __CHAN_SWITCH_MAX, }; static const struct blobmsg_policy chan_switch_policy[__CHAN_SWITCH_MAX] = { [CHAN_SWITCH_COUNT] = { .name = "count", .type = BLOBMSG_TYPE_INT32 }, [CHAN_SWITCH_CHANNEL] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 }, [CHAN_SWITCH_FREQ] = { .name = "freq", .type = BLOBMSG_TYPE_INT32 }, [CHAN_SWITCH_SEC_CHAN_OFFSET] = { .name = "sec_chan_offset", .type = BLOBMSG_TYPE_INT32 }, [CHAN_SWITCH_CF1] = { .name = "cf1", .type = BLOBMSG_TYPE_INT32 }, [CHAN_SWITCH_CF2] = { .name = "cf2", .type = BLOBMSG_TYPE_INT32 }, [CHAN_SWITCH_BW] = { .name = "bw", .type = BLOBMSG_TYPE_INT32 }, [CHAN_SWITCH_BLOCK_TX] = { .name = "blocktx", .type = BLOBMSG_TYPE_BOOL }, [CHAN_SWITCH_HT] = { .name = "ht", .type = BLOBMSG_TYPE_BOOL }, [CHAN_SWITCH_VHT] = { .name = "vht", .type = BLOBMSG_TYPE_BOOL }, [CHAN_SWITCH_HE] = { .name = "he", .type = BLOBMSG_TYPE_BOOL }, [CHAN_SWITCH_EHT] = { .name = "eht", .type = BLOBMSG_TYPE_BOOL }, [CHAN_SWITCH_AUTO_HT] = { .name = "auto-ht", .type = BLOBMSG_TYPE_BOOL }, }; enum { DEBUG_LEVEL, __DEBUG_LEVEL_MAX, }; static const struct blobmsg_policy wifi_set_debug_policy[__DEBUG_LEVEL_MAX] = { [DEBUG_LEVEL] = { .name = "level", .type = BLOBMSG_TYPE_INT32 }, }; /* detailed stainfo policy */ enum { STAINFO_MACADDR, /* sta macaddress */ __STAINFO_MAX, }; static const struct blobmsg_policy stainfo_policy[__STAINFO_MAX] = { [STAINFO_MACADDR] = { .name = "sta", .type = BLOBMSG_TYPE_STRING }, }; /* list neighbors policy */ enum { NBR_LIST_SSID, /* ssid filter */ NBR_LIST_CLIENT, /* from beacon report by client */ __NBR_LIST_MAX, }; static const struct blobmsg_policy nbr_list_policy[__NBR_LIST_MAX] = { [NBR_LIST_SSID] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING }, [NBR_LIST_CLIENT] = { .name = "client", .type = BLOBMSG_TYPE_STRING }, }; /* sta disconnect policy */ enum { STA_DISCONNECT_STA, /* sta mac ':' separated */ STA_DISCONNECT_REASON, __STA_DISCONNECT_MAX, }; static const struct blobmsg_policy sta_disconnect_policy[__STA_DISCONNECT_MAX] = { [STA_DISCONNECT_STA] = { .name = "sta", .type = BLOBMSG_TYPE_STRING }, [STA_DISCONNECT_REASON] = { .name = "reason", .type = BLOBMSG_TYPE_INT32 } }; /* sta monitor policy */ enum { STA_MONITOR_ADDR, /* sta mac ':' separated */ __STA_MONITOR_MAX, }; static const struct blobmsg_policy sta_monitor_policy[__STA_MONITOR_MAX] = { [STA_MONITOR_ADDR] = { .name = "sta", .type = BLOBMSG_TYPE_STRING }, }; /* add neighbor policy */ enum { NBR_ADD_BSSID, /* bssid ':' separated */ NBR_ADD_CHANNEL, NBR_ADD_BINFO, /* bssid info; default = 0x3 (reachable) */ NBR_ADD_REG, /* regulatory; default = 0 */ NBR_ADD_PHY, /* phytype; default = 9 = PHY_VHT */ __NBR_ADD_MAX, }; static const struct blobmsg_policy nbr_add_policy[__NBR_ADD_MAX] = { [NBR_ADD_BSSID] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, [NBR_ADD_CHANNEL] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 }, [NBR_ADD_BINFO] = { .name = "bssid_info", .type = BLOBMSG_TYPE_STRING }, [NBR_ADD_REG] = { .name = "reg", .type = BLOBMSG_TYPE_INT32 }, [NBR_ADD_PHY] = { .name = "phy", .type = BLOBMSG_TYPE_INT32 }, }; /* delete neighbor policy */ enum { NBR_DEL_BSSID, __NBR_DEL_MAX, }; static const struct blobmsg_policy nbr_del_policy[__NBR_DEL_MAX] = { [NBR_DEL_BSSID] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, }; /* send neighbor request policy */ enum { NBR_REQ_CLIENT, NBR_REQ_OPCLASS, NBR_REQ_CHANNEL, NBR_REQ_DURATION, NBR_REQ_MODE, NBR_REQ_BSSID, NBR_REQ_REP_DETAIL, NBR_REQ_SSID, NBR_REQ_CHAN_REPORT, NBR_REQ_ELEMENT_IDS, __NBR_REQ_MAX, }; static const struct blobmsg_policy nbr_req_policy[__NBR_REQ_MAX] = { [NBR_REQ_CLIENT] = { .name = "client", .type = BLOBMSG_TYPE_STRING }, [NBR_REQ_OPCLASS] = { .name = "opclass", .type = BLOBMSG_TYPE_INT32 }, [NBR_REQ_CHANNEL] = { .name = "channel", .type = BLOBMSG_TYPE_INT32 }, [NBR_REQ_DURATION] = { .name = "duration", .type = BLOBMSG_TYPE_INT32 }, [NBR_REQ_MODE] = { .name = "mode", .type = BLOBMSG_TYPE_STRING }, [NBR_REQ_BSSID] = { .name = "bssid", .type = BLOBMSG_TYPE_STRING }, [NBR_REQ_REP_DETAIL] = { .name = "reporting_detail", .type = BLOBMSG_TYPE_INT32 }, [NBR_REQ_SSID] = { .name = "ssid", .type = BLOBMSG_TYPE_STRING }, [NBR_REQ_CHAN_REPORT] = { .name = "channel_report", .type = BLOBMSG_TYPE_ARRAY }, [NBR_REQ_ELEMENT_IDS] = { .name = "request_element", .type = BLOBMSG_TYPE_ARRAY }, }; /* send btm request policy */ enum { BTM_REQ_STA, BTM_REQ_TARGET, BTM_REQ_MODE, BTM_REQ_DISASSOC_TMO, BTM_REQ_VALIDITY_INT, BTM_REQ_DIALOG_TOKEN, BTM_REQ_BSSTERM_DUR, BTM_REQ_MBO_REASON, /* MBO r19, 4.2.6: Transition Reason Code Attribute (id=0x06) */ BTM_REQ_MBO_CELL_PREF, /* MBO r19, 4.2.5: Cellular Data Connection Preference (id=0x05) */ BTM_REQ_MBO_REASSOC_DELAY, /* MBO r19, 4.2.8: Assoc retry delay (id=0x08), 0-65535 */ __BTM_REQ_MAX, }; static const struct blobmsg_policy btmreq_policy[__BTM_REQ_MAX] = { [BTM_REQ_STA] = { .name = "sta", .type = BLOBMSG_TYPE_STRING }, [BTM_REQ_TARGET] = { .name = "target_ap", .type = BLOBMSG_TYPE_ARRAY }, [BTM_REQ_MODE] = { .name = "mode", .type = BLOBMSG_TYPE_INT32 }, [BTM_REQ_DISASSOC_TMO] = { .name = "disassoc_tmo", .type = BLOBMSG_TYPE_INT32 }, [BTM_REQ_VALIDITY_INT] = { .name = "validity_int", .type = BLOBMSG_TYPE_INT32 }, [BTM_REQ_DIALOG_TOKEN] = { .name = "dialog_token", .type = BLOBMSG_TYPE_INT32 }, [BTM_REQ_BSSTERM_DUR] = { .name = "bssterm_dur", .type = BLOBMSG_TYPE_INT32 }, [BTM_REQ_MBO_REASON] = { .name = "mbo_reason", .type = BLOBMSG_TYPE_INT32 }, [BTM_REQ_MBO_CELL_PREF] = { .name = "mbo_cell_pref", .type = BLOBMSG_TYPE_INT32 }, [BTM_REQ_MBO_REASSOC_DELAY] = { .name = "mbo_reassoc_delay", .type = BLOBMSG_TYPE_INT32 }, }; /* send association controll policy */ enum { ASSOC_CNTRL_CLIENT, ASSOC_CNTRL_ENABLE, __ASSOC_CNTRL_MAX, }; static const struct blobmsg_policy assoc_cntrl_policy[__ASSOC_CNTRL_MAX] = { [ASSOC_CNTRL_CLIENT] = { .name = "client", .type = BLOBMSG_TYPE_ARRAY }, [ASSOC_CNTRL_ENABLE] = { .name = "enable", .type = BLOBMSG_TYPE_INT32 }, }; /* block station policy */ enum { BLOCK_STATION_MACADDR, BLOCK_STATION_BLOCK, __BLOCK_STATION_MAX, }; static const struct blobmsg_policy block_station_policy[__BLOCK_STATION_MAX] = { [BLOCK_STATION_MACADDR] = { .name = "client", .type = BLOBMSG_TYPE_STRING }, [BLOCK_STATION_BLOCK] = { .name = "block", .type = BLOBMSG_TYPE_INT32 }, }; /* apmld block station policy */ enum { APMLD_BLOCK_STATION_MACADDR, APMLD_BLOCK_STATION_BLOCK, APMLD_BLOCK_STATION_BAND, __APMLD_BLOCK_STATION_MAX, }; static const struct blobmsg_policy apmld_block_station_policy[__APMLD_BLOCK_STATION_MAX] = { [APMLD_BLOCK_STATION_MACADDR] = { .name = "client", .type = BLOBMSG_TYPE_STRING }, [APMLD_BLOCK_STATION_BLOCK] = { .name = "block", .type = BLOBMSG_TYPE_INT32 }, [APMLD_BLOCK_STATION_BAND] = { .name = "band", .type = BLOBMSG_TYPE_INT32 }, }; /* apmld get blocked maclist */ enum { APMLD_BLOCKED_MACLIST_BAND, __APMLD_BLOCKED_MACLIST_MAX, }; static const struct blobmsg_policy apmld_blocked_maclist_policy[__APMLD_BLOCKED_MACLIST_MAX] = { [APMLD_BLOCKED_MACLIST_BAND] = { .name = "band", .type = BLOBMSG_TYPE_INT32 }, }; /* dump beacon policy */ enum { DUMP_BEACON_BAND, __DUMP_BEACON_MAX, }; static const struct blobmsg_policy dump_beacon_policy[__DUMP_BEACON_MAX] = { [DUMP_BEACON_BAND] = { .name = "band", .type = BLOBMSG_TYPE_INT32 }, }; /* vendor_ie add/del policy */ enum { VSIE_MGMT_STYPE, /* bitmask of (1 << mgmt frame subtype) */ VSIE_OUI, VSIE_DATA, __VSIE_MAX, }; static const struct blobmsg_policy vsie_policy[__VSIE_MAX] = { [VSIE_MGMT_STYPE] = { .name = "mgmt", .type = BLOBMSG_TYPE_INT32 }, [VSIE_OUI] = { .name = "oui", .type = BLOBMSG_TYPE_STRING}, [VSIE_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING}, }; /* link measure request policy */ enum { LINKMEAS_STA, __LINKMEAS_MAX, }; static const struct blobmsg_policy linkmeas_policy[__LINKMEAS_MAX] = { [LINKMEAS_STA] = { .name = "sta", .type = BLOBMSG_TYPE_STRING }, }; enum { MBO_DISALLOW_ASSOC_REASON, __MBO_DISALLOW_ASSOC_MAX, }; static const struct blobmsg_policy mbo_disallow_assoc_policy[__MBO_DISALLOW_ASSOC_MAX] = { [MBO_DISALLOW_ASSOC_REASON] = { .name = "reason", .type = BLOBMSG_TYPE_INT32 }, }; /* send qos map policy */ enum { AP_SEND_QOS_MAP_CONF_ADDR, /* sta mac ':' separated */ __AP_SEND_QOS_MAP_CONF_MAX, }; static const struct blobmsg_policy ap_send_qos_map_conf_policy[__AP_SEND_QOS_MAP_CONF_MAX] = { [AP_SEND_QOS_MAP_CONF_ADDR] = { .name = "sta", .type = BLOBMSG_TYPE_STRING }, }; /* set qos map policy */ enum { AP_SET_QOS_MAP_SET, /* Array of u32 elements making up a QoS map */ __AP_SET_QOS_MAP_SET_MAX, }; static const struct blobmsg_policy ap_set_qos_map_policy[__AP_SET_QOS_MAP_SET_MAX] = { [AP_SET_QOS_MAP_SET] = { .name = "set", .type = BLOBMSG_TYPE_ARRAY }, }; /* disconnect from ap policy */ enum { AP_DISCONNECT_REASON, /* deauth/disassoc reason code */ __AP_DISCONNECT_MAX, }; static const struct blobmsg_policy ap_disconnect_policy[__AP_DISCONNECT_MAX] = { [AP_DISCONNECT_REASON] = { .name = "reason", .type = BLOBMSG_TYPE_INT32} }; enum { STA_4ADDR_ENABLE, __STA_4ADDR_MAX, }; static const struct blobmsg_policy sta_4addr_policy[__STA_4ADDR_MAX] = { [STA_4ADDR_ENABLE] = { .name = "enable", .type = BLOBMSG_TYPE_INT32} }; enum { ACTION_DST, ACTION_WAIT, ACTION_FREQ, ACTION_FRAME, ACTION_SRC, __ACTION_MAX, }; static const struct blobmsg_policy send_action_policy[__ACTION_MAX] = { [ACTION_DST] = { .name = "dst", .type = BLOBMSG_TYPE_STRING }, [ACTION_WAIT] = { .name = "wait", .type = BLOBMSG_TYPE_INT32 }, [ACTION_FREQ] = { .name = "freq", .type = BLOBMSG_TYPE_INT32 }, [ACTION_FRAME] = { .name = "frame", .type = BLOBMSG_TYPE_STRING }, [ACTION_SRC] = { .name = "src", .type = BLOBMSG_TYPE_STRING }, }; enum { DPP_LISTEN_FREQ, __DPP_LISTEN_MAX, }; static const struct blobmsg_policy dpp_listen_policy[__DPP_LISTEN_MAX] = { [DPP_LISTEN_FREQ] = { .name = "freq", .type = BLOBMSG_TYPE_INT32 } }; enum { SUBSCRIBE_FRAME_TYPE, SUBSCRIBE_FRAME_SUBTYPE, __SUBSCRIBE_FRAME_MAX, }; static const struct blobmsg_policy subscribe_frame_policy[__SUBSCRIBE_FRAME_MAX] = { [SUBSCRIBE_FRAME_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_INT32 }, [SUBSCRIBE_FRAME_SUBTYPE] = { .name = "stype", .type = BLOBMSG_TYPE_INT32 }, }; /* WPS attributes follow */ enum { ATTR_PIN, __ATTR_PIN_MAX, }; static const struct blobmsg_policy pin_policy[__ATTR_PIN_MAX] = { [ATTR_PIN] = { .name = "pin", .type = BLOBMSG_TYPE_STRING }, }; enum { WPS_ATTR_IFNAME, __ATTR_IFNAME_ONLY, }; static const struct blobmsg_policy ifname_policy[__ATTR_IFNAME_ONLY] = { [WPS_ATTR_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, }; enum { PIN_SET_IFNAME, PIN_SET_PIN, __PIN_SET_MAX, }; static const struct blobmsg_policy pin_set_policy[__PIN_SET_MAX] = { [PIN_SET_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, [PIN_SET_PIN] = { .name = "pin", .type = BLOBMSG_TYPE_STRING }, }; enum { WPS_START_ATTR_IFNAME, WPS_START_ATTR_MODE, WPS_START_ATTR_ROLE, WPS_START_ATTR_STA_PIN, __WPS_START_ATTR_MAX, }; static const struct blobmsg_policy wps_start_policy[__WPS_START_ATTR_MAX] = { [WPS_START_ATTR_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING }, [WPS_START_ATTR_MODE] = { .name = "mode", .type = BLOBMSG_TYPE_STRING }, [WPS_START_ATTR_ROLE] = { .name = "role", .type = BLOBMSG_TYPE_STRING }, [WPS_START_ATTR_STA_PIN] = { .name = "pin", .type = BLOBMSG_TYPE_STRING }, };