| /* |
| ************************************************************************** |
| * Copyright (c) 2021, The Linux Foundation. All rights reserved. |
| * |
| * Permission to use, copy, modify, and/or distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| ************************************************************************** |
| */ |
| |
| /* |
| * nss_wifi_meshmgr.c |
| * NSS to HLOS WiFi-Mesh manager |
| */ |
| |
| #include <linux/module.h> |
| #include <linux/netdevice.h> |
| #include <linux/of.h> |
| #include <nss_api_if.h> |
| #include <nss_wifi_meshmgr.h> |
| #include "nss_wifi_mesh_priv.h" |
| |
| /* |
| * WiFi-Mesh context |
| */ |
| static struct nss_wifi_meshmgr_ctx wmgr_ctx; |
| |
| /* |
| * nss_wifi_meshmgr_verify_if_num() |
| * Verify interface number. |
| */ |
| static bool nss_wifi_meshmgr_verify_if_num(int32_t if_num, enum nss_dynamic_interface_type di_type) |
| { |
| return (nss_is_dynamic_interface(if_num) && |
| (nss_dynamic_interface_get_type(wmgr_ctx.nss_ctx, if_num) == di_type)); |
| } |
| |
| /* |
| * nss_wifi_meshmgr_tx_msg() |
| * WiFi-Mesh message send API |
| */ |
| static nss_wifi_meshmgr_status_t nss_wifi_meshmgr_tx_msg(struct nss_wifi_mesh_msg *msg) |
| { |
| return nss_wifi_mesh_tx_msg(wmgr_ctx.nss_ctx, msg); |
| } |
| |
| /* |
| * nss_wifi_meshmgr_ctx_insert() |
| * Insert the mesh context into global table |
| */ |
| static int32_t nss_wifi_meshmgr_ctx_insert(struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx) |
| { |
| int32_t i, idx = -1; |
| struct net_device *dev; |
| |
| assert_spin_locked(&wmgr_ctx.ref_lock); |
| |
| /* |
| * Check if the context already exist for the same netdev. |
| */ |
| for (i = 0; i < NSS_WIFI_MESH_MAX; i++) { |
| if (!wmgr_ctx.mesh_ctx[i]) { |
| idx = i; |
| continue; |
| } |
| |
| dev = (wmgr_ctx.mesh_ctx[i])->dev; |
| if (dev == wmesh_ctx->dev) { |
| nss_wifi_meshmgr_warn("%px: The mesh context already exist for dev:%s", |
| &wmgr_ctx, wmesh_ctx->dev->name); |
| return -1; |
| } |
| } |
| |
| if (idx == -1) { |
| return idx; |
| } |
| |
| wmgr_ctx.mesh_ctx[idx] = wmesh_ctx; |
| return idx; |
| } |
| |
| /* |
| * nss_wifi_meshmgr_ctx_remove() |
| * Remove the mesh context from global table |
| */ |
| static void nss_wifi_meshmgr_ctx_remove(struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx) |
| { |
| int32_t i; |
| |
| assert_spin_locked(&wmgr_ctx.ref_lock); |
| |
| for (i = 0; i < NSS_WIFI_MESH_MAX; i++) { |
| if (wmgr_ctx.mesh_ctx[i] != wmesh_ctx) { |
| continue; |
| } |
| |
| wmgr_ctx.mesh_ctx[i] = NULL; |
| return; |
| } |
| } |
| |
| /* |
| * nss_wifi_meshmgr_cleanup() |
| * Clean up the mesh context. |
| */ |
| static void nss_wifi_meshmgr_cleanup(struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx) |
| { |
| int32_t encap_ifnum, decap_ifnum; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| nss_wifi_meshmgr_trace("%px: Mesh handle cleanup called for: %s\n", &wmgr_ctx, wmesh_ctx->dev->name); |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| decap_ifnum = wmesh_ctx->decap_ifnum; |
| |
| /* |
| * Unregister and dealloc decap DI. |
| */ |
| nss_unregister_wifi_mesh_if(decap_ifnum); |
| nss_status = nss_dynamic_interface_dealloc_node(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Failed to dealloc decap: %d\n", &wmgr_ctx, nss_status); |
| } |
| |
| /* |
| * Unregister and dealloc encap DI. |
| */ |
| nss_unregister_wifi_mesh_if(encap_ifnum); |
| nss_status = nss_dynamic_interface_dealloc_node(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Failed to dealloc encap: %d\n", &wmgr_ctx, nss_status); |
| } |
| |
| dev_put(wmesh_ctx->dev); |
| kfree(wmesh_ctx); |
| } |
| |
| /* |
| * nss_wifi_meshmgr_ref_dec() |
| * Find and decrement the reference counter. |
| */ |
| static void nss_wifi_meshmgr_ref_dec(struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx) |
| { |
| if (atomic_dec_and_test(&wmesh_ctx->ref)) { |
| nss_wifi_meshmgr_cleanup(wmesh_ctx); |
| } |
| } |
| |
| /* |
| * nss_wifi_meshmgr_find_and_ref_inc() |
| * Find and inreae the reference counter. |
| */ |
| static struct nss_wifi_meshmgr_mesh_ctx *nss_wifi_meshmgr_find_and_ref_inc(nss_wifi_mesh_handle_t mesh_handle) |
| { |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| |
| if ((mesh_handle < 0) || (mesh_handle >= NSS_WIFI_MESH_MAX)) { |
| nss_wifi_meshmgr_warn("%px: Invalid mesh handle: %d\n", &wmgr_ctx, mesh_handle); |
| return NULL; |
| } |
| |
| spin_lock_bh(&wmgr_ctx.ref_lock); |
| wmesh_ctx = wmgr_ctx.mesh_ctx[mesh_handle]; |
| if (wmesh_ctx && atomic_inc_and_test(&wmesh_ctx->ref)) { |
| BUG_ON(1); |
| } |
| spin_unlock_bh(&wmgr_ctx.ref_lock); |
| return wmesh_ctx; |
| } |
| |
| /* |
| * nss_wifi_meshmgr_remap_error() |
| * Remap the error code. |
| */ |
| static nss_wifi_meshmgr_status_t nss_wifi_meshmgr_remap_error(enum nss_wifi_mesh_error_types error) |
| { |
| switch (error) { |
| case NSS_WIFI_MESH_ERROR_UNKNOWN_MSG: |
| return NSS_WIFI_MESHMGR_FAILURE_UNKNOWN_MSG; |
| case NSS_WIFI_MESH_ERROR_TTL_CONFIG: |
| return NSS_WIFI_MESHMGR_FAILURE_TTL_CONFIG; |
| case NSS_WIFI_MESH_ERROR_REFRESH_TIME_CONFIG: |
| return NSS_WIFI_MESHMGR_FAILURE_REFRESH_TIME_CONFIG; |
| case NSS_WIFI_MESH_ERROR_MPP_LEARNING_MODE_CONFIG: |
| return NSS_WIFI_MESHMGR_FAILURE_MPP_LEARNING_MODE_CONFIG; |
| case NSS_WIFI_MESH_ERROR_PATH_ADD_MAX_RADIO_CNT: |
| return NSS_WIFI_MESHMGR_FAILURE_PATH_ADD_MAX_RADIO_CNT; |
| case NSS_WIFI_MESH_ERROR_PATH_ADD_INVALID_INTERFACE_NUM: |
| return NSS_WIFI_MESHMGR_FAILURE_PATH_ADD_INVALID_INTERFACE_NUM; |
| case NSS_WIFI_MESH_ERROR_PATH_ADD_INTERFACE_NUM_NOT_FOUND: |
| return NSS_WIFI_MESHMGR_FAILURE_PATH_ADD_INTERFACE_NUM_NOT_FOUND; |
| case NSS_WIFI_MESH_ERROR_PATH_TABLE_FULL: |
| return NSS_WIFI_MESHMGR_FAILURE_PATH_TABLE_FULL; |
| case NSS_WIFI_MESH_ERROR_PATH_ALLOC_FAIL: |
| return NSS_WIFI_MESHMGR_FAILURE_PATH_ALLOC_FAIL; |
| case NSS_WIFI_MESH_ERROR_PATH_INSERT_FAIL: |
| return NSS_WIFI_MESHMGR_FAILURE_PATH_INSERT_FAIL; |
| case NSS_WIFI_MESH_ERROR_PATH_NOT_FOUND: |
| return NSS_WIFI_MESHMGR_FAILURE_PATH_NOT_FOUND; |
| case NSS_WIFI_MESH_ERROR_PATH_UNHASHED: |
| return NSS_WIFI_MESHMGR_FAILURE_PATH_UNHASHED; |
| case NSS_WIFI_MESH_ERROR_PATH_DELETE_FAIL: |
| return NSS_WIFI_MESHMGR_FAILURE_PATH_DELETE_FAIL; |
| case NSS_WIFI_MESH_ERROR_PROXY_PATH_NOT_FOUND: |
| return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_NOT_FOUND; |
| case NSS_WIFI_MESH_ERROR_PROXY_PATH_UNHASHED: |
| return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_UNHASHED; |
| case NSS_WIFI_MESH_ERROR_PROXY_PATH_DELETE_FAIL: |
| return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_DELETE_FAIL; |
| case NSS_WIFI_MESH_ERROR_PROXY_PATH_EXISTS: |
| return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_EXISTS; |
| case NSS_WIFI_MESH_ERROR_PROXY_PATH_ALLOC_FAIL: |
| return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_ALLOC_FAIL; |
| case NSS_WIFI_MESH_ERROR_PROXY_PATH_INSERT_FAIL: |
| return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_INSERT_FAIL; |
| case NSS_WIFI_MESH_ERROR_PROXY_PATH_TABLE_FULL: |
| return NSS_WIFI_MESHMGR_FAILURE_PROXY_PATH_TABLE_FULL; |
| case NSS_WIFI_MESH_ERROR_PB_ALLOC_FAIL: |
| return NSS_WIFI_MESHMGR_FAILURE_PB_ALLOC_FAIL; |
| case NSS_WIFI_MESH_ERROR_ENQUEUE_TO_HOST_FAIL: |
| return NSS_WIFI_MESHMGR_FAILURE_ENQUEUE_TO_HOST_FAIL; |
| case NSS_WIFI_MESH_ERROR_ENABLE_INTERFACE_FAIL: |
| return NSS_WIFI_MESHMGR_FAILURE_ENABLE_INTERFACE_FAIL; |
| case NSS_WIFI_MESH_ERROR_DISABLE_INTERFACE_FAIL: |
| return NSS_WIFI_MESHMGR_FAILURE_DISABLE_INTERFACE_FAIL; |
| case NSS_WIFI_MESH_ERROR_INVALID_EXCEPTION_NUM: |
| return NSS_WIFI_MESHMGR_FAILURE_INVALID_EXCEPTION_NUM; |
| case NSS_WIFI_MESH_ERROR_ONESHOT_ALREADY_ATTACHED: |
| return NSS_WIFI_MESHMGR_FAILURE_ONESHOT_ALREADY_ATTACHED; |
| default: |
| return NSS_WIFI_MESHMGR_FAILURE; |
| }; |
| } |
| |
| /* |
| * nss_wifi_meshmgr_tx_msg_cb() |
| * Callback to handle the completion of NSS->HLOS messages. |
| */ |
| static void nss_wifi_meshmgr_tx_msg_cb(void *app_data, struct nss_cmn_msg *ncm) |
| { |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx = (struct nss_wifi_meshmgr_mesh_ctx *)app_data; |
| uint32_t error_code = ncm->error; |
| |
| /* |
| * FIXME: The wmesh_ctx can be invalid if the memory goes away with the caller being timedout. |
| */ |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_SUCCESS; |
| if (ncm->response != NSS_CMN_RESPONSE_ACK) { |
| nss_wifi_meshmgr_warn("%px: WiFi-Mesh error response %d error_code: %u\n", &wmgr_ctx, ncm->response, error_code); |
| wmesh_ctx->response = nss_wifi_meshmgr_remap_error(error_code); |
| } |
| |
| complete(&wmesh_ctx->complete); |
| } |
| |
| /* |
| * nss_wifi_meshmgr_tx_msg_sync() |
| * Transmit a WiFi mesh message to NSS firmware synchronously. |
| */ |
| static nss_wifi_meshmgr_status_t nss_wifi_meshmgr_tx_msg_sync(struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx, struct nss_wifi_mesh_msg *wmesh_msg) |
| { |
| nss_wifi_meshmgr_status_t status; |
| int ret; |
| |
| down(&wmesh_ctx->sem); |
| status = nss_wifi_meshmgr_tx_msg(wmesh_msg); |
| if (status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh tx sync msg failed: %d\n", &wmgr_ctx, status); |
| up(&wmesh_ctx->sem); |
| return status; |
| } |
| |
| /* |
| * Wait for the acknowledgement. |
| */ |
| ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); |
| if (!ret) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; |
| } |
| |
| status = wmesh_ctx->response; |
| up(&wmesh_ctx->sem); |
| return status; |
| } |
| |
| /* |
| * nss_wifi_meshmgr_tx_buf() |
| * Send packets to mesh I/F |
| */ |
| nss_wifi_meshmgr_status_t nss_wifi_meshmgr_tx_buf(nss_wifi_mesh_handle_t mesh_handle, struct sk_buff *os_buf) |
| { |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| int32_t encap_ifnum; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| |
| /* |
| * Verify the encap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| nss_status = nss_wifi_mesh_tx_buf(wmgr_ctx.nss_ctx, os_buf, encap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_tx_buf); |
| |
| /* |
| * nss_wifi_meshmgr_if_down() |
| * Make the NSS interface down synchronously. |
| */ |
| nss_wifi_meshmgr_status_t nss_wifi_meshmgr_if_down(nss_wifi_mesh_handle_t mesh_handle) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| nss_wifi_meshmgr_status_t nss_status; |
| int32_t encap_ifnum, decap_ifnum; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| decap_ifnum = wmesh_ctx->decap_ifnum; |
| |
| /* |
| * Verify the I/F encap and decap number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER) || |
| nss_wifi_meshmgr_verify_if_num(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER))) { |
| nss_wifi_meshmgr_warn("%px: Interface verification failed\n", &wmgr_ctx); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Initialize the encap I/F down message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_IF_CLOSE, |
| sizeof(struct nss_if_close), nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| |
| /* |
| * Send the I/F down message to the encap I/F. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg_sync(wmesh_ctx, &wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh link encap I/F down failed: %d.\n", &wmgr_ctx, nss_status); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Initialize the decap I/F down message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, decap_ifnum, NSS_IF_CLOSE, |
| sizeof(struct nss_if_close), nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| |
| /* |
| * Send the I/F down message to the decap I/F. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg_sync(wmesh_ctx, &wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh link decap I/F down failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_if_down); |
| |
| /* |
| * nss_wifi_meshmgr_if_up() |
| * Make the NSS interface up synchronously. |
| */ |
| nss_wifi_meshmgr_status_t nss_wifi_meshmgr_if_up(nss_wifi_mesh_handle_t mesh_handle) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| nss_wifi_meshmgr_status_t nss_status; |
| int32_t encap_ifnum, decap_ifnum; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| decap_ifnum = wmesh_ctx->decap_ifnum; |
| |
| /* |
| * Verify the I/F encap and decap number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER) || |
| nss_wifi_meshmgr_verify_if_num(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER))) { |
| nss_wifi_meshmgr_warn("%px: Interface verification failed\n", &wmgr_ctx); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Initialize the encap I/F up message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_IF_OPEN, |
| sizeof(struct nss_if_open), nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| |
| /* |
| * Send the I/F up message to the encap I/F. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg_sync(wmesh_ctx, &wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh link encap I/F up failed: %d.\n", &wmgr_ctx, nss_status); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Initialize the I/F decap up message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, decap_ifnum, NSS_IF_OPEN, |
| sizeof(struct nss_if_open), nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| |
| /* |
| * Send the I/F up message to the decap interface. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg_sync(wmesh_ctx, &wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh link decap I/F up failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_if_up); |
| |
| /* |
| * nss_wifi_meshmgr_dump_mesh_path() |
| * Dump mesh path table request asynchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_dump_mesh_path(nss_wifi_mesh_handle_t mesh_handle, nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| nss_wifi_meshmgr_status_t nss_status; |
| int32_t encap_ifnum; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| |
| /* |
| * Verify the encap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Initialize the path dump request message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_PATH_TABLE_DUMP, |
| sizeof(struct nss_wifi_mesh_path_table_dump), msg_cb, app_data); |
| |
| /* |
| * Send the path dump request mesage to the NSS asynchronously. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh dump mesh path failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_dump_mesh_path); |
| |
| /* |
| * nss_wifi_meshmgr_dump_mesh_path_sync() |
| * Dump mesh path table request synchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_dump_mesh_path_sync(nss_wifi_mesh_handle_t mesh_handle) |
| { |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| nss_wifi_meshmgr_status_t nss_status; |
| int32_t ret; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| /* |
| * Send the path dump request mesage to the NSS synchronously. |
| */ |
| down(&wmesh_ctx->sem); |
| nss_status = nss_wifi_meshmgr_dump_mesh_path(mesh_handle, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh path dump msg failed: %d.\n", &wmgr_ctx, nss_status); |
| up(&wmesh_ctx->sem); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Wait for the acknowledgement |
| */ |
| ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); |
| if (!ret) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; |
| } |
| |
| nss_status = wmesh_ctx->response; |
| up(&wmesh_ctx->sem); |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_dump_mesh_path_sync); |
| |
| /* |
| * nss_wifi_meshmgr_dump_mesh_proxy_path() |
| * Dump mesh proxy path table request asynchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_dump_mesh_proxy_path(nss_wifi_mesh_handle_t mesh_handle, nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| nss_wifi_meshmgr_status_t nss_status; |
| int32_t encap_ifnum; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| |
| /* |
| * Verify the encap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Initialize the proxy path table message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_PROXY_PATH_TABLE_DUMP, |
| sizeof(struct nss_wifi_mesh_proxy_path_table_dump), msg_cb, app_data); |
| |
| /* |
| * Send the proxy path dump message to NSS asynchronously. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh link vap proxy path dump failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_dump_mesh_proxy_path); |
| |
| /* |
| * nss_wifi_meshmgr_dump_mesh_path_sync() |
| * Dump mesh proxy path table request synchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_dump_mesh_proxy_path_sync(nss_wifi_mesh_handle_t mesh_handle) |
| { |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| nss_wifi_meshmgr_status_t nss_status; |
| int32_t ret; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| /* |
| * Send the path dump request to the NSS synchronously. |
| */ |
| down(&wmesh_ctx->sem); |
| nss_status = nss_wifi_meshmgr_dump_mesh_proxy_path(mesh_handle, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh proxy path dump msg failed: %d.\n", &wmgr_ctx, nss_status); |
| up(&wmesh_ctx->sem); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Wait for the acknowledgement |
| */ |
| ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); |
| if (!ret) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; |
| } |
| |
| nss_status = wmesh_ctx->response; |
| up(&wmesh_ctx->sem); |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_dump_mesh_proxy_path_sync); |
| |
| /* |
| * nss_wifi_meshmgr_assoc_link_vap() |
| * Associate the link interface to the mesh I/F asynchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_assoc_link_vap(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_assoc_link_vap *wmalv, |
| nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) |
| { |
| struct nss_wifi_vdev_msg *wifivdevmsg; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| struct nss_wifi_vdev_set_next_hop_msg *next_hop_msg = NULL; |
| int32_t decap_ifnum, link_ifnum; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| wifivdevmsg = kzalloc(sizeof(*wifivdevmsg), GFP_ATOMIC); |
| if (!wifivdevmsg) { |
| nss_wifi_meshmgr_warn("%px: Failed to allocate message memmory", &wmgr_ctx); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| decap_ifnum = wmesh_ctx->decap_ifnum; |
| |
| /* |
| * Verify the decap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, decap_ifnum); |
| kfree(wifivdevmsg); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| |
| link_ifnum = wmalv->link_vap_id; |
| |
| /* |
| * Verify the link VAP I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(link_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_VAP))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, link_ifnum); |
| kfree(wifivdevmsg); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| |
| next_hop_msg = &wifivdevmsg->msg.next_hop; |
| next_hop_msg->ifnumber = decap_ifnum; |
| nss_cmn_msg_init(&wifivdevmsg->cm, link_ifnum, NSS_WIFI_VDEV_SET_NEXT_HOP, sizeof(*next_hop_msg), |
| msg_cb, app_data); |
| |
| /* |
| * Send the link vap mesage to the NSS synchronously. |
| */ |
| nss_status = nss_wifi_vdev_tx_msg(wmgr_ctx.nss_ctx, wifivdevmsg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh link vap association failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| kfree(wifivdevmsg); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_assoc_link_vap); |
| |
| /* |
| * nss_wifi_meshmgr_assoc_link_vap_sync() |
| * Associate the link VAP to the mesh I/F synchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_assoc_link_vap_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_assoc_link_vap *wmalv) |
| { |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| nss_wifi_meshmgr_status_t nss_status; |
| int32_t ret; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| /* |
| * Send the link vap mesage to the NSS synchronously. |
| */ |
| down(&wmesh_ctx->sem); |
| nss_status = nss_wifi_meshmgr_assoc_link_vap(mesh_handle, wmalv, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh link vap association failed: %d.\n", &wmgr_ctx, nss_status); |
| up(&wmesh_ctx->sem); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Wait for the acknowledgement |
| */ |
| ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); |
| if (!ret) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; |
| } |
| |
| nss_status = wmesh_ctx->response; |
| up(&wmesh_ctx->sem); |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_assoc_link_vap_sync); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_config_update() |
| * Update mesh configuration message asynchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_config_update(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_config_msg *wmcum, |
| nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| struct nss_wifi_mesh_config_msg *nwmcum; |
| int32_t encap_ifnum, decap_ifnum; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| decap_ifnum = wmesh_ctx->decap_ifnum; |
| |
| /* |
| * Verify the encap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Verify the decap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER))) { |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, decap_ifnum); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Initialize the mesh configuration messsage. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nwmcum = &wmesh_msg.msg.mesh_config; |
| memcpy(nwmcum, wmcum, sizeof(*nwmcum)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_INTERFACE_CONFIGURE, |
| sizeof(*nwmcum), msg_cb, app_data); |
| |
| /* |
| * Send the configuration message to encap I/F. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh configuration message failed: %d.\n", &wmgr_ctx, nss_status); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Initialize the mesh configuration messsage. |
| */ |
| nss_wifi_mesh_msg_init(&wmesh_msg, decap_ifnum, NSS_WIFI_MESH_MSG_INTERFACE_CONFIGURE, |
| sizeof(*nwmcum), msg_cb, app_data); |
| |
| /* |
| * Send the configuration message decap I/F. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh configuration message failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_config_update); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_config_update_sync() |
| * Update mesh configuration message synchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_config_update_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_config_msg *wmcum) |
| { |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| nss_wifi_meshmgr_status_t nss_status; |
| int32_t ret; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| /* |
| * Send the message to NSS synchronously. |
| */ |
| down(&wmesh_ctx->sem); |
| nss_status = nss_wifi_meshmgr_mesh_config_update(mesh_handle, wmcum, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh proxy path update failed: %d.\n", &wmgr_ctx, nss_status); |
| up(&wmesh_ctx->sem); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Wait for the acknowledgement |
| */ |
| ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); |
| if (!ret) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; |
| } |
| |
| nss_status = wmesh_ctx->response; |
| up(&wmesh_ctx->sem); |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_config_update_sync); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_proxy_path_delete() |
| * Delete the mesh proxy path asynchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_proxy_path_delete(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_proxy_path_del_msg *wmppdm, |
| nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| struct nss_wifi_mesh_proxy_path_del_msg *nwmppdm; |
| int32_t encap_ifnum; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| |
| /* |
| * Verify the encap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Initialize the message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nwmppdm = &wmesh_msg.msg.proxy_del_msg; |
| memcpy(nwmppdm, wmppdm, sizeof(*nwmppdm)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_PROXY_PATH_DELETE, |
| sizeof(*nwmppdm), msg_cb, app_data); |
| |
| /* |
| * Send the message to NSS asynchronously. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh proxy path delete failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_proxy_path_delete); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_proxy_path_delete_sync() |
| * Delete the mesh proxy path synchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_proxy_path_delete_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_proxy_path_del_msg *wmppdm) |
| { |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| nss_wifi_meshmgr_status_t nss_status; |
| int32_t ret; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| /* |
| * Send the message to NSS synchronously. |
| */ |
| down(&wmesh_ctx->sem); |
| nss_status = nss_wifi_meshmgr_mesh_proxy_path_delete(mesh_handle, wmppdm, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh proxy path delete failed: %d.\n", &wmgr_ctx, nss_status); |
| up(&wmesh_ctx->sem); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Wait for the acknowledgement |
| */ |
| ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); |
| if (!ret) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; |
| } |
| |
| nss_status = wmesh_ctx->response; |
| up(&wmesh_ctx->sem); |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_proxy_path_delete_sync); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_proxy_path_update() |
| * Mesh prpxy path update message asynchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_proxy_path_update(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_proxy_path_update_msg *wmppum, |
| nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| struct nss_wifi_mesh_proxy_path_update_msg *nwmppum; |
| int32_t encap_ifnum; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| |
| /* |
| * Verify the encap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Initialize the message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nwmppum = &wmesh_msg.msg.proxy_update_msg; |
| memcpy(nwmppum, wmppum, sizeof(*nwmppum)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_PROXY_PATH_UPDATE, |
| sizeof(*nwmppum), msg_cb, app_data); |
| |
| /* |
| * Send the message to NSS asynchronously |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh proxy path update failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_proxy_path_update); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_proxy_path_update_sync() |
| * Send proxy update message synchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_proxy_path_update_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_proxy_path_update_msg *wmppum) |
| { |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| nss_wifi_meshmgr_status_t nss_status; |
| int32_t ret; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| /* |
| * Send the message to NSS synchronously. |
| */ |
| down(&wmesh_ctx->sem); |
| nss_status = nss_wifi_meshmgr_mesh_proxy_path_update(mesh_handle, wmppum, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh proxy path update failed: %d.\n", &wmgr_ctx, nss_status); |
| up(&wmesh_ctx->sem); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Wait for the acknowledgement |
| */ |
| ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); |
| if (!ret) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; |
| } |
| |
| nss_status = wmesh_ctx->response; |
| up(&wmesh_ctx->sem); |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_proxy_path_update_sync); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_proxy_path_add() |
| * Send mesh proxy add message asynchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_proxy_path_add(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_proxy_path_add_msg *wmppam, |
| nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| struct nss_wifi_mesh_proxy_path_add_msg *nwmppam; |
| int32_t encap_ifnum; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| |
| /* |
| * Verify the encap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Initialize the message |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nwmppam = &wmesh_msg.msg.proxy_add_msg; |
| memcpy(nwmppam, wmppam, sizeof(*nwmppam)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_PROXY_PATH_ADD, |
| sizeof(*nwmppam), msg_cb, app_data); |
| |
| /* |
| * Send the message to NSS asynchronously. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh proxy path add failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_proxy_path_add); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_proxy_path_add_sync() |
| * Send mesh proxy add message synchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_proxy_path_add_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_proxy_path_add_msg *wmppam) |
| { |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| int32_t ret; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| /* |
| * Send the message to NSS synchronously. |
| */ |
| down(&wmesh_ctx->sem); |
| nss_status = nss_wifi_meshmgr_mesh_proxy_path_add(mesh_handle, wmppam, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh proxy path add failed: %d.\n", &wmgr_ctx, nss_status); |
| up(&wmesh_ctx->sem); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Wait for the acknowledgement |
| */ |
| ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); |
| if (!ret) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; |
| } |
| |
| nss_status = wmesh_ctx->response; |
| up(&wmesh_ctx->sem); |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_proxy_path_add_sync); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_path_delete() |
| * Send the mesh path delete message asynchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_path_delete(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_mpath_del_msg *wmpdm, |
| nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| struct nss_wifi_mesh_mpath_del_msg *nwmpdm; |
| int32_t encap_ifnum; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| |
| /* |
| * Verify the encap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Initialize the message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nwmpdm = &wmesh_msg.msg.mpath_del; |
| memcpy(nwmpdm, wmpdm, sizeof(*nwmpdm)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_MPATH_DELETE, |
| sizeof(*nwmpdm), msg_cb, app_data); |
| |
| /* |
| * Send the message to NSS asynchronously. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh path delete failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_delete); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_path_delete_sync() |
| * Send the mesh path delete message synchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_path_delete_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_mpath_del_msg *wmpdm) |
| { |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| int32_t ret; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| /* |
| * Send the message to NSS synchronously. |
| */ |
| down(&wmesh_ctx->sem); |
| nss_status = nss_wifi_meshmgr_mesh_path_delete(mesh_handle, wmpdm, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh path delete failed: %d.\n", &wmgr_ctx, nss_status); |
| up(&wmesh_ctx->sem); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Wait for the acknowledgement |
| */ |
| ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); |
| if (!ret) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; |
| } |
| |
| nss_status = wmesh_ctx->response; |
| up(&wmesh_ctx->sem); |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_delete_sync); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_path_add() |
| * Mesh path add message asynchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_path_add(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_mpath_add_msg *wmpam, |
| nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_mesh_mpath_add_msg *nwmpam; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| int32_t encap_ifnum; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| |
| /* |
| * Verify the encap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Initialize the message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nwmpam = &wmesh_msg.msg.mpath_add; |
| memcpy(nwmpam, wmpam, sizeof(*nwmpam)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_MPATH_ADD, |
| sizeof(*nwmpam), msg_cb, app_data); |
| |
| /* |
| * Send the message to NSS asynchronously. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh path addition failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_add); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_path_add_sync() |
| * Mesh path add message synchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_path_add_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_mpath_add_msg *wmpam) |
| { |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| int32_t ret; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| /* |
| * Send the message to NSS synchronously. |
| */ |
| down(&wmesh_ctx->sem); |
| nss_status = nss_wifi_meshmgr_mesh_path_add(mesh_handle, wmpam, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh path addition failed: %d.\n", &wmgr_ctx, nss_status); |
| up(&wmesh_ctx->sem); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Wait for the acknowledgement |
| */ |
| ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); |
| if (!ret) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; |
| } |
| |
| nss_status = wmesh_ctx->response; |
| up(&wmesh_ctx->sem); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_add_sync); |
| |
| /* |
| * nss_wifi_meshmgr_mpath_update() |
| * Send mesh path update message asynchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_path_update(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_mpath_update_msg *wmpum, |
| nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_mesh_mpath_update_msg *nwmpum; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| int32_t encap_ifnum; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| |
| /* |
| * Verify the encap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Initialize the mesh path update message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nwmpum = &wmesh_msg.msg.mpath_update; |
| memcpy(nwmpum, wmpum, sizeof(*nwmpum)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_MPATH_UPDATE, |
| sizeof(*nwmpum), msg_cb, app_data); |
| |
| /* |
| * Send the message to NSS asynchronously. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh MPath update failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_update); |
| |
| /* |
| * nss_wifi_meshmgr_mpath_update_sync() |
| * Send mesh path update message sychronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_path_update_sync(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_mpath_update_msg *wmpum) |
| { |
| nss_wifi_meshmgr_status_t nss_status; |
| int32_t ret; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| /* |
| * Send the message to NSS synchronously. |
| */ |
| down(&wmesh_ctx->sem); |
| nss_status = nss_wifi_meshmgr_mesh_path_update(mesh_handle, wmpum, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh MPath update failed: %d.\n", &wmgr_ctx, nss_status); |
| up(&wmesh_ctx->sem); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Wait for the acknowledgement |
| */ |
| ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); |
| if (!ret) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; |
| } |
| |
| nss_status = wmesh_ctx->response; |
| up(&wmesh_ctx->sem); |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_update_sync); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_path_exception() |
| * Mesh path exception msg asynchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_path_exception(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_exception_flag_msg *wmefm, |
| nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_mesh_exception_flag_msg *nwmefm; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| int32_t encap_ifnum; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| |
| /* |
| * Verify the encap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Initialize the message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nwmefm = &wmesh_msg.msg.exception_msg; |
| memcpy(nwmefm, wmefm, sizeof(*nwmefm)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_EXCEPTION_FLAG, |
| sizeof(*nwmefm), msg_cb, app_data); |
| |
| /* |
| * Send the message to NSS asynchronously. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh path exception message failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_exception); |
| |
| /* |
| * nss_wifi_meshmgr_mesh_path_exception_sync() |
| * Send mesh path exception message sychronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_mesh_path_exception_sync(nss_wifi_mesh_handle_t mesh_handle,struct nss_wifi_mesh_exception_flag_msg *wmefm) |
| { |
| nss_wifi_meshmgr_status_t nss_status; |
| int32_t ret; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| /* |
| * Send the message to NSS synchronously. |
| */ |
| down(&wmesh_ctx->sem); |
| nss_status = nss_wifi_meshmgr_mesh_path_exception(mesh_handle, wmefm, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh path exception message failed: %d.\n", &wmgr_ctx, nss_status); |
| up(&wmesh_ctx->sem); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Wait for the acknowledgement |
| */ |
| ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); |
| if (!ret) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; |
| } |
| |
| nss_status = wmesh_ctx->response; |
| up(&wmesh_ctx->sem); |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_mesh_path_exception_sync); |
| |
| /* |
| * nss_wifi_meshmgr_config_mesh_exception() |
| * Configure mesh exception asynchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_config_mesh_exception(nss_wifi_mesh_handle_t mesh_handle, struct nss_wifi_mesh_rate_limit_config *wmrlc, |
| nss_wifi_mesh_msg_callback_t msg_cb, void *app_data) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_mesh_rate_limit_config *nwmrlc; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| int32_t encap_ifnum, decap_ifnum, ifnum; |
| nss_wifi_meshmgr_status_t nss_status; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| |
| /* |
| * Verify the encap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| decap_ifnum = wmesh_ctx->decap_ifnum; |
| |
| /* |
| * Verify the decap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, decap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| switch(wmrlc->exception_num) { |
| case NSS_WIFI_MESH_DS_MESH_PATH_NOT_FOUND: |
| ifnum = encap_ifnum; |
| break; |
| |
| case NSS_WIFI_MESH_US_MESH_PROXY_NOT_FOUND: |
| ifnum = decap_ifnum; |
| break; |
| |
| case NSS_WIFI_MESH_US_MESH_PATH_NOT_FOUND: |
| ifnum = decap_ifnum; |
| break; |
| } |
| |
| /* |
| * Initialize the message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nwmrlc = &wmesh_msg.msg.exc_cfg; |
| memcpy(nwmrlc, wmrlc, sizeof(*nwmrlc)); |
| nss_wifi_mesh_msg_init(&wmesh_msg, ifnum, NSS_WIFI_MESH_CONFIG_EXCEPTION, |
| sizeof(*nwmrlc), msg_cb, app_data); |
| |
| /* |
| * Send the message to NSS asynchronously. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg(&wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh config exception message failed: %d.\n", &wmgr_ctx, nss_status); |
| } |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_config_mesh_exception); |
| |
| /* |
| * nss_wifi_meshmgr_config_mesh_exception_sync() |
| * Configure mesh exception synchronously. |
| */ |
| nss_wifi_meshmgr_status_t |
| nss_wifi_meshmgr_config_mesh_exception_sync(nss_wifi_mesh_handle_t mesh_handle,struct nss_wifi_mesh_rate_limit_config *wmrlc) |
| { |
| nss_wifi_meshmgr_status_t nss_status; |
| int32_t ret; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_NULL_MESH_CTX; |
| } |
| |
| /* |
| * Send the message to NSS synchronously. |
| */ |
| down(&wmesh_ctx->sem); |
| nss_status = nss_wifi_meshmgr_config_mesh_exception(mesh_handle, wmrlc, nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Mesh config exception message failed: %d.\n", &wmgr_ctx, nss_status); |
| up(&wmesh_ctx->sem); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| |
| /* |
| * Wait for the acknowledgement |
| */ |
| ret = wait_for_completion_timeout(&wmesh_ctx->complete, msecs_to_jiffies(NSS_WIFI_MESH_TX_TIMEOUT)); |
| if (!ret) { |
| nss_wifi_meshmgr_warn("%px: WiFi mesh msg tx failed due to timeout\n", &wmgr_ctx); |
| wmesh_ctx->response = NSS_WIFI_MESHMGR_FAILURE_SYNC_TIMEOUT; |
| } |
| |
| nss_status = wmesh_ctx->response; |
| up(&wmesh_ctx->sem); |
| |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_config_mesh_exception_sync); |
| |
| /* |
| * nss_wifi_meshmgr_if_destroy_sync() |
| * Function to unregister and destroy dynamic interfaces synchronously. |
| */ |
| nss_wifi_meshmgr_status_t nss_wifi_meshmgr_if_destroy_sync(nss_wifi_mesh_handle_t mesh_handle) |
| { |
| int32_t encap_ifnum, decap_ifnum; |
| nss_wifi_meshmgr_status_t nss_status; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| |
| wmesh_ctx = nss_wifi_meshmgr_find_and_ref_inc(mesh_handle); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Mesh context is null\n", &wmgr_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE_BAD_PARAM; |
| } |
| |
| encap_ifnum = wmesh_ctx->encap_ifnum; |
| decap_ifnum = wmesh_ctx->decap_ifnum; |
| |
| /* |
| * Verify the encap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, encap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Verify the decap I/F number against it types. |
| */ |
| if (!(nss_wifi_meshmgr_verify_if_num(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER))) { |
| nss_wifi_meshmgr_warn("%px: I/F num: 0x%x verification failed\n", &wmgr_ctx, decap_ifnum); |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return NSS_WIFI_MESHMGR_FAILURE; |
| } |
| |
| /* |
| * Send the I/F down message to NSS. |
| */ |
| nss_status = nss_wifi_meshmgr_if_down(mesh_handle); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Sending mesh I/F down to NSS failed: %d\n", &wmgr_ctx, nss_status); |
| } |
| |
| /* |
| * Remove mesh context from the table. |
| */ |
| spin_lock_bh(&wmgr_ctx.ref_lock); |
| nss_wifi_meshmgr_ctx_remove(wmesh_ctx); |
| wmgr_ctx.mesh_count--; |
| spin_unlock_bh(&wmgr_ctx.ref_lock); |
| |
| /* |
| * Release the reference taken during alloc. |
| */ |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| |
| /* |
| * Release the reference for the find taken at the beginning of the function. |
| */ |
| nss_wifi_meshmgr_ref_dec(wmesh_ctx); |
| return nss_status; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_if_destroy_sync); |
| |
| /* |
| * nss_wifi_meshmgr_if_create_sync() |
| * Create and register dynamic interface synchronously. |
| * |
| * Note: Synchronous create message, callbacks are used for driver registration not message handling. |
| */ |
| nss_wifi_mesh_handle_t nss_wifi_meshmgr_if_create_sync(struct net_device *dev, struct nss_wifi_mesh_config_msg *wmcm, |
| nss_wifi_mesh_data_callback_t data_cb, |
| nss_wifi_mesh_ext_data_callback_t ext_data_cb, |
| nss_wifi_mesh_msg_callback_t event_cb) |
| { |
| struct nss_wifi_mesh_msg wmesh_msg; |
| struct nss_wifi_mesh_config_msg *nwmcm; |
| int32_t encap_ifnum, decap_ifnum; |
| uint32_t features = 0; |
| nss_wifi_mesh_handle_t mesh_handle; |
| nss_wifi_meshmgr_status_t nss_status; |
| struct nss_wifi_meshmgr_mesh_ctx *wmesh_ctx; |
| |
| spin_lock_bh(&wmgr_ctx.ref_lock); |
| if (wmgr_ctx.mesh_count == NSS_WIFI_MESH_MAX) { |
| nss_wifi_meshmgr_warn("%px: Reached maxed number of mesh interface\n", dev); |
| spin_unlock_bh(&wmgr_ctx.ref_lock); |
| return -1; |
| } |
| |
| wmgr_ctx.mesh_count++; |
| spin_unlock_bh(&wmgr_ctx.ref_lock); |
| |
| dev_hold(dev); |
| wmesh_ctx = kzalloc(sizeof(*wmesh_ctx), GFP_ATOMIC); |
| if (!wmesh_ctx) { |
| nss_wifi_meshmgr_warn("%px: Failed to allocate memory for mesh context\n", dev); |
| goto ctx_alloc_fail; |
| } |
| |
| wmesh_ctx->dev = dev; |
| sema_init(&wmesh_ctx->sem, 1); |
| init_completion(&wmesh_ctx->complete); |
| |
| /* |
| * Alloc the encap dynamic interface node. |
| */ |
| encap_ifnum = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER); |
| if (encap_ifnum < 0) { |
| nss_wifi_meshmgr_warn("%px: Encap allocation failed.\n", dev); |
| goto encap_alloc_fail; |
| } |
| |
| if (nss_register_wifi_mesh_if(encap_ifnum, data_cb, ext_data_cb, event_cb, |
| NSS_WIFI_MESH_DP_INNER, dev, features) != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Encap registration failed.\n", dev); |
| goto encap_reg_fail; |
| } |
| |
| /* |
| * Allocate and register decap interface. |
| */ |
| decap_ifnum = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER); |
| if (decap_ifnum < 0) { |
| nss_wifi_meshmgr_warn("%px: Decap allocation failed.\n", dev); |
| goto decap_alloc_fail; |
| } |
| |
| |
| if (nss_register_wifi_mesh_if(decap_ifnum, data_cb, ext_data_cb, event_cb, |
| NSS_WIFI_MESH_DP_OUTER, dev, features) != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Decap registration failed.\n", dev); |
| goto decap_reg_fail; |
| } |
| |
| wmesh_ctx->encap_ifnum = encap_ifnum; |
| wmesh_ctx->decap_ifnum = decap_ifnum; |
| |
| nss_wifi_meshmgr_trace("%px: Successfully registered encap and decap iface for Mesh\n", dev); |
| |
| /* |
| * Initialize the encap configuration message. |
| */ |
| memset(&wmesh_msg, 0, sizeof(struct nss_wifi_mesh_msg)); |
| nwmcm = &wmesh_msg.msg.mesh_config; |
| nwmcm->ttl = wmcm->ttl; |
| nwmcm->mesh_path_refresh_time = wmcm->mesh_path_refresh_time; |
| nwmcm->mpp_learning_mode = wmcm->mpp_learning_mode; |
| nwmcm->config_flags = wmcm->config_flags | NSS_WIFI_MESH_CONFIG_FLAG_SIBLING_IF_NUM_VALID; |
| nwmcm->sibling_ifnum = decap_ifnum; |
| |
| ether_addr_copy(nwmcm->local_mac_addr, wmcm->local_mac_addr); |
| nss_wifi_mesh_msg_init(&wmesh_msg, encap_ifnum, NSS_WIFI_MESH_MSG_INTERFACE_CONFIGURE, |
| sizeof(*nwmcm), nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| |
| /* |
| * Send the encap configuration message. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg_sync(wmesh_ctx, &wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Encap configuration message failed: %d.\n", dev, nss_status); |
| goto config_failed; |
| } |
| |
| /* |
| * Initialize the decap configuration message. |
| */ |
| nwmcm->sibling_ifnum = encap_ifnum; |
| nwmcm->block_mesh_forwarding = wmcm->block_mesh_forwarding; |
| nss_wifi_mesh_msg_init(&wmesh_msg, decap_ifnum, NSS_WIFI_MESH_MSG_INTERFACE_CONFIGURE, |
| sizeof(*nwmcm), nss_wifi_meshmgr_tx_msg_cb, wmesh_ctx); |
| |
| /* |
| * Send the decap configuration message. |
| */ |
| nss_status = nss_wifi_meshmgr_tx_msg_sync(wmesh_ctx, &wmesh_msg); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Decap configuration message failed: %d.\n", dev, nss_status); |
| goto config_failed; |
| } |
| |
| /* |
| * Take the self reference on the mesh context. |
| */ |
| atomic_set(&wmesh_ctx->ref, 1); |
| |
| /* |
| * Add the Mesh context to the mesh manager's list. |
| */ |
| spin_lock_bh(&wmgr_ctx.ref_lock); |
| mesh_handle = nss_wifi_meshmgr_ctx_insert(wmesh_ctx); |
| if (mesh_handle < 0) { |
| spin_unlock_bh(&wmgr_ctx.ref_lock); |
| nss_wifi_meshmgr_warn("%px: Insertion for mesh context failed", &wmgr_ctx); |
| goto config_failed; |
| } |
| |
| spin_unlock_bh(&wmgr_ctx.ref_lock); |
| |
| nss_wifi_meshmgr_trace("%px: WiFi Mesh interface count:%d.\n", dev, wmgr_ctx.mesh_count); |
| return mesh_handle; |
| |
| config_failed: |
| nss_unregister_wifi_mesh_if(decap_ifnum); |
| decap_reg_fail: |
| nss_dynamic_interface_dealloc_node(decap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_OUTER); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Decap interface dealloc failed: %d\n", dev, nss_status); |
| } |
| decap_alloc_fail: |
| nss_unregister_wifi_mesh_if(encap_ifnum); |
| encap_reg_fail: |
| nss_dynamic_interface_dealloc_node(encap_ifnum, NSS_DYNAMIC_INTERFACE_TYPE_WIFI_MESH_INNER); |
| if (nss_status != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px: Encap interface dealloc failed: %d\n", dev, nss_status); |
| } |
| encap_alloc_fail: |
| kfree(wmesh_ctx); |
| ctx_alloc_fail: |
| spin_lock_bh(&wmgr_ctx.ref_lock); |
| wmgr_ctx.mesh_count--; |
| spin_unlock_bh(&wmgr_ctx.ref_lock); |
| dev_put(dev); |
| return -1; |
| } |
| EXPORT_SYMBOL(nss_wifi_meshmgr_if_create_sync); |
| |
| /* |
| * nss_wifi_meshmgr_exit_module() |
| * WiFi-Mesh module exit function |
| */ |
| static void __exit nss_wifi_meshmgr_exit_module(void) |
| { |
| int32_t i; |
| |
| /* |
| * Check if there are any mesh I/F. Delete all the mesh I/F from NSS FW and free. |
| */ |
| for (i = 0; i < NSS_WIFI_MESH_MAX; i++) { |
| if (nss_wifi_meshmgr_if_destroy_sync(i) != NSS_WIFI_MESHMGR_SUCCESS) { |
| nss_wifi_meshmgr_warn("%px Destroy failed or context does not exist", &wmgr_ctx); |
| } |
| } |
| nss_wifi_meshmgr_info("Module %s unloaded\n", NSS_CLIENT_BUILD_ID); |
| } |
| |
| /* |
| * nss_wifi_meshmgr_init_module() |
| * Wi-Fi mesh manager module init function |
| */ |
| static int __init nss_wifi_meshmgr_init_module(void) |
| { |
| struct nss_ctx_instance *nss_ctx; |
| int32_t idx; |
| |
| #ifdef CONFIG_OF |
| /* |
| * If the node is not compatible, don't do anything. |
| */ |
| if (!of_find_node_by_name(NULL, "nss-common")) { |
| nss_wifi_meshmgr_warn("NSS common not found.\n"); |
| return -1; |
| } |
| #endif |
| |
| nss_ctx = nss_wifi_mesh_get_context(); |
| if (!nss_ctx) { |
| nss_wifi_meshmgr_warn("NSS SoC context is NULL.\n"); |
| return -1; |
| } |
| |
| wmgr_ctx.nss_ctx = nss_ctx; |
| for (idx = 0; idx < NSS_WIFI_MESH_MAX; idx++) { |
| wmgr_ctx.mesh_ctx[idx] = NULL; |
| } |
| |
| wmgr_ctx.mesh_count = 0; |
| spin_lock_init(&wmgr_ctx.ref_lock); |
| |
| nss_wifi_meshmgr_info("Module %s loaded\n", NSS_CLIENT_BUILD_ID); |
| return 0; |
| } |
| |
| module_init(nss_wifi_meshmgr_init_module); |
| module_exit(nss_wifi_meshmgr_exit_module); |
| |
| MODULE_LICENSE("Dual BSD/GPL"); |
| MODULE_DESCRIPTION("NSS WiFi-Mesh manager"); |