123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948 |
- /*
- * FST module - Control Interface implementation
- * Copyright (c) 2014, Qualcomm Atheros, Inc.
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
- #include "utils/includes.h"
- #include "utils/common.h"
- #include "common/defs.h"
- #include "list.h"
- #include "fst/fst.h"
- #include "fst/fst_internal.h"
- #include "fst_ctrl_defs.h"
- #include "fst_ctrl_iface.h"
- static struct fst_group * get_fst_group_by_id(const char *id)
- {
- struct fst_group *g;
- foreach_fst_group(g) {
- const char *group_id = fst_group_get_id(g);
- if (os_strncmp(group_id, id, os_strlen(group_id)) == 0)
- return g;
- }
- return NULL;
- }
- /* notifications */
- static Boolean format_session_state_extra(const union fst_event_extra *extra,
- char *buffer, size_t size)
- {
- int len;
- char reject_str[32] = FST_CTRL_PVAL_NONE;
- const char *initiator = FST_CTRL_PVAL_NONE;
- const struct fst_event_extra_session_state *ss;
- ss = &extra->session_state;
- if (ss->new_state != FST_SESSION_STATE_INITIAL)
- return TRUE;
- switch (ss->extra.to_initial.reason) {
- case REASON_REJECT:
- if (ss->extra.to_initial.reject_code != WLAN_STATUS_SUCCESS)
- os_snprintf(reject_str, sizeof(reject_str), "%u",
- ss->extra.to_initial.reject_code);
- /* no break */
- case REASON_TEARDOWN:
- case REASON_SWITCH:
- switch (ss->extra.to_initial.initiator) {
- case FST_INITIATOR_LOCAL:
- initiator = FST_CS_PVAL_INITIATOR_LOCAL;
- break;
- case FST_INITIATOR_REMOTE:
- initiator = FST_CS_PVAL_INITIATOR_REMOTE;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- len = os_snprintf(buffer, size,
- FST_CES_PNAME_REASON "=%s "
- FST_CES_PNAME_REJECT_CODE "=%s "
- FST_CES_PNAME_INITIATOR "=%s",
- fst_reason_name(ss->extra.to_initial.reason),
- reject_str, initiator);
- return !os_snprintf_error(size, len);
- }
- static void fst_ctrl_iface_notify(struct fst_iface *f, u32 session_id,
- enum fst_event_type event_type,
- const union fst_event_extra *extra)
- {
- struct fst_group *g;
- char extra_str[128] = "";
- const struct fst_event_extra_session_state *ss;
- const struct fst_event_extra_iface_state *is;
- const struct fst_event_extra_peer_state *ps;
- /*
- * FST can use any of interface objects as it only sends messages
- * on global Control Interface, so we just pick the 1st one.
- */
- if (!f) {
- foreach_fst_group(g) {
- f = fst_group_first_iface(g);
- if (f)
- break;
- }
- if (!f)
- return;
- }
- WPA_ASSERT(f->iface_obj.ctx);
- switch (event_type) {
- case EVENT_FST_IFACE_STATE_CHANGED:
- if (!extra)
- return;
- is = &extra->iface_state;
- wpa_msg_global_only(f->iface_obj.ctx, MSG_INFO,
- FST_CTRL_EVENT_IFACE " %s "
- FST_CEI_PNAME_IFNAME "=%s "
- FST_CEI_PNAME_GROUP "=%s",
- is->attached ? FST_CEI_PNAME_ATTACHED :
- FST_CEI_PNAME_DETACHED,
- is->ifname, is->group_id);
- break;
- case EVENT_PEER_STATE_CHANGED:
- if (!extra)
- return;
- ps = &extra->peer_state;
- wpa_msg_global_only(fst_iface_get_wpa_obj_ctx(f), MSG_INFO,
- FST_CTRL_EVENT_PEER " %s "
- FST_CEP_PNAME_IFNAME "=%s "
- FST_CEP_PNAME_ADDR "=" MACSTR,
- ps->connected ? FST_CEP_PNAME_CONNECTED :
- FST_CEP_PNAME_DISCONNECTED,
- ps->ifname, MAC2STR(ps->addr));
- break;
- case EVENT_FST_SESSION_STATE_CHANGED:
- if (!extra)
- return;
- if (!format_session_state_extra(extra, extra_str,
- sizeof(extra_str))) {
- fst_printf(MSG_ERROR,
- "CTRL: Cannot format STATE_CHANGE extra");
- extra_str[0] = 0;
- }
- ss = &extra->session_state;
- wpa_msg_global_only(fst_iface_get_wpa_obj_ctx(f), MSG_INFO,
- FST_CTRL_EVENT_SESSION " "
- FST_CES_PNAME_SESSION_ID "=%u "
- FST_CES_PNAME_EVT_TYPE "=%s "
- FST_CES_PNAME_OLD_STATE "=%s "
- FST_CES_PNAME_NEW_STATE "=%s %s",
- session_id,
- fst_session_event_type_name(event_type),
- fst_session_state_name(ss->old_state),
- fst_session_state_name(ss->new_state),
- extra_str);
- break;
- case EVENT_FST_ESTABLISHED:
- case EVENT_FST_SETUP:
- wpa_msg_global_only(fst_iface_get_wpa_obj_ctx(f), MSG_INFO,
- FST_CTRL_EVENT_SESSION " "
- FST_CES_PNAME_SESSION_ID "=%u "
- FST_CES_PNAME_EVT_TYPE "=%s",
- session_id,
- fst_session_event_type_name(event_type));
- break;
- }
- }
- /* command processors */
- /* fst session_get */
- static int session_get(const char *session_id, char *buf, size_t buflen)
- {
- struct fst_session *s;
- struct fst_iface *new_iface, *old_iface;
- const u8 *old_peer_addr, *new_peer_addr;
- u32 id;
- id = strtoul(session_id, NULL, 0);
- s = fst_session_get_by_id(id);
- if (!s) {
- fst_printf(MSG_WARNING, "CTRL: Cannot find session %u", id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- old_peer_addr = fst_session_get_peer_addr(s, TRUE);
- new_peer_addr = fst_session_get_peer_addr(s, FALSE);
- new_iface = fst_session_get_iface(s, FALSE);
- old_iface = fst_session_get_iface(s, TRUE);
- return os_snprintf(buf, buflen,
- FST_CSG_PNAME_OLD_PEER_ADDR "=" MACSTR "\n"
- FST_CSG_PNAME_NEW_PEER_ADDR "=" MACSTR "\n"
- FST_CSG_PNAME_NEW_IFNAME "=%s\n"
- FST_CSG_PNAME_OLD_IFNAME "=%s\n"
- FST_CSG_PNAME_LLT "=%u\n"
- FST_CSG_PNAME_STATE "=%s\n",
- MAC2STR(old_peer_addr),
- MAC2STR(new_peer_addr),
- new_iface ? fst_iface_get_name(new_iface) :
- FST_CTRL_PVAL_NONE,
- old_iface ? fst_iface_get_name(old_iface) :
- FST_CTRL_PVAL_NONE,
- fst_session_get_llt(s),
- fst_session_state_name(fst_session_get_state(s)));
- }
- /* fst session_set */
- static int session_set(const char *session_id, char *buf, size_t buflen)
- {
- struct fst_session *s;
- char *p, *q;
- u32 id;
- int ret;
- id = strtoul(session_id, &p, 0);
- s = fst_session_get_by_id(id);
- if (!s) {
- fst_printf(MSG_WARNING, "CTRL: Cannot find session %u", id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- if (*p != ' ' || !(q = os_strchr(p + 1, '=')))
- return os_snprintf(buf, buflen, "FAIL\n");
- p++;
- if (os_strncasecmp(p, FST_CSS_PNAME_OLD_IFNAME, q - p) == 0) {
- ret = fst_session_set_str_ifname(s, q + 1, TRUE);
- } else if (os_strncasecmp(p, FST_CSS_PNAME_NEW_IFNAME, q - p) == 0) {
- ret = fst_session_set_str_ifname(s, q + 1, FALSE);
- } else if (os_strncasecmp(p, FST_CSS_PNAME_OLD_PEER_ADDR, q - p) == 0) {
- ret = fst_session_set_str_peer_addr(s, q + 1, TRUE);
- } else if (os_strncasecmp(p, FST_CSS_PNAME_NEW_PEER_ADDR, q - p) == 0) {
- ret = fst_session_set_str_peer_addr(s, q + 1, FALSE);
- } else if (os_strncasecmp(p, FST_CSS_PNAME_LLT, q - p) == 0) {
- ret = fst_session_set_str_llt(s, q + 1);
- } else {
- fst_printf(MSG_ERROR, "CTRL: Unknown parameter: %s", p);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- return os_snprintf(buf, buflen, "%s\n", ret ? "FAIL" : "OK");
- }
- /* fst session_add/remove */
- static int session_add(const char *group_id, char *buf, size_t buflen)
- {
- struct fst_group *g;
- struct fst_session *s;
- g = get_fst_group_by_id(group_id);
- if (!g) {
- fst_printf(MSG_WARNING, "CTRL: Cannot find group '%s'",
- group_id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- s = fst_session_create(g);
- if (!s) {
- fst_printf(MSG_ERROR,
- "CTRL: Cannot create session for group '%s'",
- group_id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- return os_snprintf(buf, buflen, "%u\n", fst_session_get_id(s));
- }
- static int session_remove(const char *session_id, char *buf, size_t buflen)
- {
- struct fst_session *s;
- struct fst_group *g;
- u32 id;
- id = strtoul(session_id, NULL, 0);
- s = fst_session_get_by_id(id);
- if (!s) {
- fst_printf(MSG_WARNING, "CTRL: Cannot find session %u", id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- g = fst_session_get_group(s);
- fst_session_reset(s);
- fst_session_delete(s);
- fst_group_delete_if_empty(g);
- return os_snprintf(buf, buflen, "OK\n");
- }
- /* fst session_initiate */
- static int session_initiate(const char *session_id, char *buf, size_t buflen)
- {
- struct fst_session *s;
- u32 id;
- id = strtoul(session_id, NULL, 0);
- s = fst_session_get_by_id(id);
- if (!s) {
- fst_printf(MSG_WARNING, "CTRL: Cannot find session %u", id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- if (fst_session_initiate_setup(s)) {
- fst_printf(MSG_WARNING, "CTRL: Cannot initiate session %u", id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- return os_snprintf(buf, buflen, "OK\n");
- }
- /* fst session_respond */
- static int session_respond(const char *session_id, char *buf, size_t buflen)
- {
- struct fst_session *s;
- char *p;
- u32 id;
- u8 status_code;
- id = strtoul(session_id, &p, 0);
- s = fst_session_get_by_id(id);
- if (!s) {
- fst_printf(MSG_WARNING, "CTRL: Cannot find session %u", id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- if (*p != ' ')
- return os_snprintf(buf, buflen, "FAIL\n");
- p++;
- if (!os_strcasecmp(p, FST_CS_PVAL_RESPONSE_ACCEPT)) {
- status_code = WLAN_STATUS_SUCCESS;
- } else if (!os_strcasecmp(p, FST_CS_PVAL_RESPONSE_REJECT)) {
- status_code = WLAN_STATUS_PENDING_ADMITTING_FST_SESSION;
- } else {
- fst_printf(MSG_WARNING,
- "CTRL: session %u: unknown response status: %s",
- id, p);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- if (fst_session_respond(s, status_code)) {
- fst_printf(MSG_WARNING, "CTRL: Cannot respond to session %u",
- id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- fst_printf(MSG_INFO, "CTRL: session %u responded", id);
- return os_snprintf(buf, buflen, "OK\n");
- }
- /* fst session_transfer */
- static int session_transfer(const char *session_id, char *buf, size_t buflen)
- {
- struct fst_session *s;
- u32 id;
- id = strtoul(session_id, NULL, 0);
- s = fst_session_get_by_id(id);
- if (!s) {
- fst_printf(MSG_WARNING, "CTRL: Cannot find session %u", id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- if (fst_session_initiate_switch(s)) {
- fst_printf(MSG_WARNING,
- "CTRL: Cannot initiate ST for session %u", id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- return os_snprintf(buf, buflen, "OK\n");
- }
- /* fst session_teardown */
- static int session_teardown(const char *session_id, char *buf, size_t buflen)
- {
- struct fst_session *s;
- u32 id;
- id = strtoul(session_id, NULL, 0);
- s = fst_session_get_by_id(id);
- if (!s) {
- fst_printf(MSG_WARNING, "CTRL: Cannot find session %u", id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- if (fst_session_tear_down_setup(s)) {
- fst_printf(MSG_WARNING, "CTRL: Cannot tear down session %u",
- id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- return os_snprintf(buf, buflen, "OK\n");
- }
- #ifdef CONFIG_FST_TEST
- /* fst test_request */
- static int test_request(const char *request, char *buf, size_t buflen)
- {
- const char *p = request;
- int ret;
- if (!os_strncasecmp(p, FST_CTR_SEND_SETUP_REQUEST,
- os_strlen(FST_CTR_SEND_SETUP_REQUEST))) {
- ret = fst_test_req_send_fst_request(
- p + os_strlen(FST_CTR_SEND_SETUP_REQUEST));
- } else if (!os_strncasecmp(p, FST_CTR_SEND_SETUP_RESPONSE,
- os_strlen(FST_CTR_SEND_SETUP_RESPONSE))) {
- ret = fst_test_req_send_fst_response(
- p + os_strlen(FST_CTR_SEND_SETUP_RESPONSE));
- } else if (!os_strncasecmp(p, FST_CTR_SEND_ACK_REQUEST,
- os_strlen(FST_CTR_SEND_ACK_REQUEST))) {
- ret = fst_test_req_send_ack_request(
- p + os_strlen(FST_CTR_SEND_ACK_REQUEST));
- } else if (!os_strncasecmp(p, FST_CTR_SEND_ACK_RESPONSE,
- os_strlen(FST_CTR_SEND_ACK_RESPONSE))) {
- ret = fst_test_req_send_ack_response(
- p + os_strlen(FST_CTR_SEND_ACK_RESPONSE));
- } else if (!os_strncasecmp(p, FST_CTR_SEND_TEAR_DOWN,
- os_strlen(FST_CTR_SEND_TEAR_DOWN))) {
- ret = fst_test_req_send_tear_down(
- p + os_strlen(FST_CTR_SEND_TEAR_DOWN));
- } else if (!os_strncasecmp(p, FST_CTR_GET_FSTS_ID,
- os_strlen(FST_CTR_GET_FSTS_ID))) {
- u32 fsts_id = fst_test_req_get_fsts_id(
- p + os_strlen(FST_CTR_GET_FSTS_ID));
- if (fsts_id != FST_FSTS_ID_NOT_FOUND)
- return os_snprintf(buf, buflen, "%u\n", fsts_id);
- return os_snprintf(buf, buflen, "FAIL\n");
- } else if (!os_strncasecmp(p, FST_CTR_GET_LOCAL_MBIES,
- os_strlen(FST_CTR_GET_LOCAL_MBIES))) {
- return fst_test_req_get_local_mbies(
- p + os_strlen(FST_CTR_GET_LOCAL_MBIES), buf, buflen);
- } else if (!os_strncasecmp(p, FST_CTR_IS_SUPPORTED,
- os_strlen(FST_CTR_IS_SUPPORTED))) {
- ret = 0;
- } else {
- fst_printf(MSG_ERROR, "CTRL: Unknown parameter: %s", p);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- return os_snprintf(buf, buflen, "%s\n", ret ? "FAIL" : "OK");
- }
- #endif /* CONFIG_FST_TEST */
- /* fst list_sessions */
- struct list_sessions_cb_ctx {
- char *buf;
- size_t buflen;
- size_t reply_len;
- };
- static void list_session_enum_cb(struct fst_group *g, struct fst_session *s,
- void *ctx)
- {
- struct list_sessions_cb_ctx *c = ctx;
- int ret;
- ret = os_snprintf(c->buf, c->buflen, " %u", fst_session_get_id(s));
- c->buf += ret;
- c->buflen -= ret;
- c->reply_len += ret;
- }
- static int list_sessions(const char *group_id, char *buf, size_t buflen)
- {
- struct list_sessions_cb_ctx ctx;
- struct fst_group *g;
- g = get_fst_group_by_id(group_id);
- if (!g) {
- fst_printf(MSG_WARNING, "CTRL: Cannot find group '%s'",
- group_id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- ctx.buf = buf;
- ctx.buflen = buflen;
- ctx.reply_len = 0;
- fst_session_enum(g, list_session_enum_cb, &ctx);
- ctx.reply_len += os_snprintf(buf + ctx.reply_len, ctx.buflen, "\n");
- return ctx.reply_len;
- }
- /* fst iface_peers */
- static int iface_peers(const char *group_id, char *buf, size_t buflen)
- {
- const char *ifname;
- struct fst_group *g;
- struct fst_iface *f;
- struct fst_get_peer_ctx *ctx;
- const u8 *addr;
- unsigned found = 0;
- int ret = 0;
- g = get_fst_group_by_id(group_id);
- if (!g) {
- fst_printf(MSG_WARNING, "CTRL: Cannot find group '%s'",
- group_id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- ifname = os_strchr(group_id, ' ');
- if (!ifname)
- return os_snprintf(buf, buflen, "FAIL\n");
- ifname++;
- foreach_fst_group_iface(g, f) {
- const char *in = fst_iface_get_name(f);
- if (os_strncmp(ifname, in, os_strlen(in)) == 0) {
- found = 1;
- break;
- }
- }
- if (!found)
- return os_snprintf(buf, buflen, "FAIL\n");
- addr = fst_iface_get_peer_first(f, &ctx, FALSE);
- for (; addr != NULL; addr = fst_iface_get_peer_next(f, &ctx, FALSE)) {
- int res;
- res = os_snprintf(buf + ret, buflen - ret, MACSTR "\n",
- MAC2STR(addr));
- if (os_snprintf_error(buflen - ret, res))
- break;
- ret += res;
- }
- return ret;
- }
- static int get_peer_mbies(const char *params, char *buf, size_t buflen)
- {
- char *endp;
- char ifname[FST_MAX_INTERFACE_SIZE];
- u8 peer_addr[ETH_ALEN];
- struct fst_group *g;
- struct fst_iface *iface = NULL;
- const struct wpabuf *mbies;
- if (fst_read_next_text_param(params, ifname, sizeof(ifname), &endp) ||
- !*ifname)
- goto problem;
- while (isspace(*endp))
- endp++;
- if (fst_read_peer_addr(endp, peer_addr))
- goto problem;
- foreach_fst_group(g) {
- iface = fst_group_get_iface_by_name(g, ifname);
- if (!iface)
- continue;
- }
- if (!iface)
- goto problem;
- mbies = fst_iface_get_peer_mb_ie(iface, peer_addr);
- if (!mbies)
- goto problem;
- return wpa_snprintf_hex(buf, buflen, wpabuf_head(mbies),
- wpabuf_len(mbies));
- problem:
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- /* fst list_ifaces */
- static int list_ifaces(const char *group_id, char *buf, size_t buflen)
- {
- struct fst_group *g;
- struct fst_iface *f;
- int ret = 0;
- g = get_fst_group_by_id(group_id);
- if (!g) {
- fst_printf(MSG_WARNING, "CTRL: Cannot find group '%s'",
- group_id);
- return os_snprintf(buf, buflen, "FAIL\n");
- }
- foreach_fst_group_iface(g, f) {
- int res;
- const u8 *iface_addr = fst_iface_get_addr(f);
- res = os_snprintf(buf + ret, buflen - ret,
- "%s|" MACSTR "|%u|%u\n",
- fst_iface_get_name(f),
- MAC2STR(iface_addr),
- fst_iface_get_priority(f),
- fst_iface_get_llt(f));
- if (os_snprintf_error(buflen - ret, res))
- break;
- ret += res;
- }
- return ret;
- }
- /* fst list_groups */
- static int list_groups(const char *cmd, char *buf, size_t buflen)
- {
- struct fst_group *g;
- int ret = 0;
- foreach_fst_group(g) {
- int res;
- res = os_snprintf(buf + ret, buflen - ret, "%s\n",
- fst_group_get_id(g));
- if (os_snprintf_error(buflen - ret, res))
- break;
- ret += res;
- }
- return ret;
- }
- static const char * band_freq(enum mb_band_id band)
- {
- static const char *band_names[] = {
- [MB_BAND_ID_WIFI_2_4GHZ] "2.4GHZ",
- [MB_BAND_ID_WIFI_5GHZ] "5GHZ",
- [MB_BAND_ID_WIFI_60GHZ] "60GHZ",
- };
- return fst_get_str_name(band, band_names, ARRAY_SIZE(band_names));
- }
- static int print_band(unsigned num, struct fst_iface *iface, const u8 *addr,
- char *buf, size_t buflen)
- {
- const struct wpabuf *wpabuf;
- enum hostapd_hw_mode hw_mode;
- u8 channel;
- int ret = 0;
- fst_iface_get_channel_info(iface, &hw_mode, &channel);
- ret += os_snprintf(buf + ret, buflen - ret, "band%u_frequency=%s\n",
- num, band_freq(fst_hw_mode_to_band(hw_mode)));
- ret += os_snprintf(buf + ret, buflen - ret, "band%u_iface=%s\n",
- num, fst_iface_get_name(iface));
- wpabuf = fst_iface_get_peer_mb_ie(iface, addr);
- if (wpabuf) {
- ret += os_snprintf(buf + ret, buflen - ret, "band%u_mb_ies=",
- num);
- ret += wpa_snprintf_hex(buf + ret, buflen - ret,
- wpabuf_head(wpabuf),
- wpabuf_len(wpabuf));
- ret += os_snprintf(buf + ret, buflen - ret, "\n");
- }
- ret += os_snprintf(buf + ret, buflen - ret, "band%u_fst_group_id=%s\n",
- num, fst_iface_get_group_id(iface));
- ret += os_snprintf(buf + ret, buflen - ret, "band%u_fst_priority=%u\n",
- num, fst_iface_get_priority(iface));
- ret += os_snprintf(buf + ret, buflen - ret, "band%u_fst_llt=%u\n",
- num, fst_iface_get_llt(iface));
- return ret;
- }
- static void fst_ctrl_iface_on_iface_state_changed(struct fst_iface *i,
- Boolean attached)
- {
- union fst_event_extra extra;
- os_memset(&extra, 0, sizeof(extra));
- extra.iface_state.attached = attached;
- os_strlcpy(extra.iface_state.ifname, fst_iface_get_name(i),
- sizeof(extra.iface_state.ifname));
- os_strlcpy(extra.iface_state.group_id, fst_iface_get_group_id(i),
- sizeof(extra.iface_state.group_id));
- fst_ctrl_iface_notify(i, FST_INVALID_SESSION_ID,
- EVENT_FST_IFACE_STATE_CHANGED, &extra);
- }
- static int fst_ctrl_iface_on_iface_added(struct fst_iface *i)
- {
- fst_ctrl_iface_on_iface_state_changed(i, TRUE);
- return 0;
- }
- static void fst_ctrl_iface_on_iface_removed(struct fst_iface *i)
- {
- fst_ctrl_iface_on_iface_state_changed(i, FALSE);
- }
- static void fst_ctrl_iface_on_event(enum fst_event_type event_type,
- struct fst_iface *i, struct fst_session *s,
- const union fst_event_extra *extra)
- {
- u32 session_id = s ? fst_session_get_id(s) : FST_INVALID_SESSION_ID;
- fst_ctrl_iface_notify(i, session_id, event_type, extra);
- }
- static const struct fst_ctrl ctrl_cli = {
- .on_iface_added = fst_ctrl_iface_on_iface_added,
- .on_iface_removed = fst_ctrl_iface_on_iface_removed,
- .on_event = fst_ctrl_iface_on_event,
- };
- const struct fst_ctrl *fst_ctrl_cli = &ctrl_cli;
- int fst_ctrl_iface_mb_info(const u8 *addr, char *buf, size_t buflen)
- {
- struct fst_group *g;
- struct fst_iface *f;
- unsigned num = 0;
- int ret = 0;
- foreach_fst_group(g) {
- foreach_fst_group_iface(g, f) {
- if (fst_iface_is_connected(f, addr)) {
- ret += print_band(num++, f, addr,
- buf + ret, buflen - ret);
- }
- }
- }
- return ret;
- }
- /* fst ctrl processor */
- int fst_ctrl_iface_receive(const char *cmd, char *reply, size_t reply_size)
- {
- static const struct fst_command {
- const char *name;
- unsigned has_param;
- int (*process)(const char *group_id, char *buf, size_t buflen);
- } commands[] = {
- { FST_CMD_LIST_GROUPS, 0, list_groups},
- { FST_CMD_LIST_IFACES, 1, list_ifaces},
- { FST_CMD_IFACE_PEERS, 1, iface_peers},
- { FST_CMD_GET_PEER_MBIES, 1, get_peer_mbies},
- { FST_CMD_LIST_SESSIONS, 1, list_sessions},
- { FST_CMD_SESSION_ADD, 1, session_add},
- { FST_CMD_SESSION_REMOVE, 1, session_remove},
- { FST_CMD_SESSION_GET, 1, session_get},
- { FST_CMD_SESSION_SET, 1, session_set},
- { FST_CMD_SESSION_INITIATE, 1, session_initiate},
- { FST_CMD_SESSION_RESPOND, 1, session_respond},
- { FST_CMD_SESSION_TRANSFER, 1, session_transfer},
- { FST_CMD_SESSION_TEARDOWN, 1, session_teardown},
- #ifdef CONFIG_FST_TEST
- { FST_CMD_TEST_REQUEST, 1, test_request },
- #endif /* CONFIG_FST_TEST */
- { NULL, 0, NULL }
- };
- const struct fst_command *c;
- const char *p;
- const char *temp;
- Boolean non_spaces_found;
- for (c = commands; c->name; c++) {
- if (os_strncasecmp(cmd, c->name, os_strlen(c->name)) != 0)
- continue;
- p = cmd + os_strlen(c->name);
- if (c->has_param) {
- if (!isspace(p[0]))
- return os_snprintf(reply, reply_size, "FAIL\n");
- p++;
- temp = p;
- non_spaces_found = FALSE;
- while (*temp) {
- if (!isspace(*temp)) {
- non_spaces_found = TRUE;
- break;
- }
- temp++;
- }
- if (!non_spaces_found)
- return os_snprintf(reply, reply_size, "FAIL\n");
- }
- return c->process(p, reply, reply_size);
- }
- return os_snprintf(reply, reply_size, "UNKNOWN FST COMMAND\n");
- }
- int fst_read_next_int_param(const char *params, Boolean *valid, char **endp)
- {
- int ret = -1;
- const char *curp;
- *valid = FALSE;
- *endp = (char *) params;
- curp = params;
- if (*curp) {
- ret = (int) strtol(curp, endp, 0);
- if (!**endp || isspace(**endp))
- *valid = TRUE;
- }
- return ret;
- }
- int fst_read_next_text_param(const char *params, char *buf, size_t buflen,
- char **endp)
- {
- size_t max_chars_to_copy;
- char *cur_dest;
- *endp = (char *) params;
- while (isspace(**endp))
- (*endp)++;
- if (!**endp || buflen <= 1)
- return -EINVAL;
- max_chars_to_copy = buflen - 1;
- /* We need 1 byte for the terminating zero */
- cur_dest = buf;
- while (**endp && !isspace(**endp) && max_chars_to_copy > 0) {
- *cur_dest = **endp;
- (*endp)++;
- cur_dest++;
- max_chars_to_copy--;
- }
- *cur_dest = 0;
- return 0;
- }
- int fst_read_peer_addr(const char *mac, u8 *peer_addr)
- {
- if (hwaddr_aton(mac, peer_addr)) {
- fst_printf(MSG_WARNING, "Bad peer_mac %s: invalid addr string",
- mac);
- return -1;
- }
- if (is_zero_ether_addr(peer_addr) ||
- is_multicast_ether_addr(peer_addr)) {
- fst_printf(MSG_WARNING, "Bad peer_mac %s: not a unicast addr",
- mac);
- return -1;
- }
- return 0;
- }
- int fst_parse_attach_command(const char *cmd, char *ifname, size_t ifname_size,
- struct fst_iface_cfg *cfg)
- {
- char *pos;
- char *endp;
- Boolean is_valid;
- int val;
- if (fst_read_next_text_param(cmd, ifname, ifname_size, &endp) ||
- fst_read_next_text_param(endp, cfg->group_id, sizeof(cfg->group_id),
- &endp))
- return -EINVAL;
- cfg->llt = FST_DEFAULT_LLT_CFG_VALUE;
- cfg->priority = 0;
- pos = os_strstr(endp, FST_ATTACH_CMD_PNAME_LLT);
- if (pos) {
- pos += os_strlen(FST_ATTACH_CMD_PNAME_LLT);
- if (*pos == '=') {
- val = fst_read_next_int_param(pos + 1, &is_valid,
- &endp);
- if (is_valid)
- cfg->llt = val;
- }
- }
- pos = os_strstr(endp, FST_ATTACH_CMD_PNAME_PRIORITY);
- if (pos) {
- pos += os_strlen(FST_ATTACH_CMD_PNAME_PRIORITY);
- if (*pos == '=') {
- val = fst_read_next_int_param(pos + 1, &is_valid,
- &endp);
- if (is_valid)
- cfg->priority = (u8) val;
- }
- }
- return 0;
- }
- int fst_parse_detach_command(const char *cmd, char *ifname, size_t ifname_size)
- {
- char *endp;
- return fst_read_next_text_param(cmd, ifname, ifname_size, &endp);
- }
- int fst_iface_detach(const char *ifname)
- {
- struct fst_group *g;
- foreach_fst_group(g) {
- struct fst_iface *f;
- f = fst_group_get_iface_by_name(g, ifname);
- if (f) {
- fst_detach(f);
- return 0;
- }
- }
- return -EINVAL;
- }
|