blob: 34c09d9e3aa8ae930cfa4cba1151a2a5252531c9 [file] [log] [blame]
Saurabh Misra09dddeb2014-09-30 16:38:07 -07001/*
2 **************************************************************************
Stephen Wangaed46332016-12-12 17:29:03 -08003 * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
Saurabh Misra09dddeb2014-09-30 16:38:07 -07004 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all copies.
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 **************************************************************************
15 */
16
17 /*
Yu Huang8c107082017-07-24 14:58:26 -070018 * nss_capwap.c
Saurabh Misra09dddeb2014-09-30 16:38:07 -070019 * NSS CAPWAP driver interface APIs
20 */
21#include "nss_core.h"
Saurabh Misra09dddeb2014-09-30 16:38:07 -070022#include "nss_capwap.h"
Stephen Wang1f6ad492016-01-27 23:42:06 -080023#include "nss_cmn.h"
24#include "nss_tx_rx_common.h"
Yu Huang8c107082017-07-24 14:58:26 -070025#include "nss_capwap_stats.h"
Saurabh Misra09dddeb2014-09-30 16:38:07 -070026
27/*
28 * Spinlock for protecting tunnel operations colliding with a tunnel destroy
29 */
30DEFINE_SPINLOCK(nss_capwap_spinlock);
31
32/*
33 * Array of pointer for NSS CAPWAP handles. Each handle has per-tunnel
34 * stats based on the if_num which is an index.
35 *
36 * Per CAPWAP tunnel/interface number instance.
37 */
38struct nss_capwap_handle {
39 atomic_t refcnt; /**< Reference count on the tunnel */
Saurabh Misraf4a05632015-02-27 17:49:41 -080040 uint32_t if_num; /**< Interface number */
Saurabh Misra09dddeb2014-09-30 16:38:07 -070041 uint32_t tunnel_status; /**< 0=disable, 1=enabled */
42 struct nss_ctx_instance *ctx; /**< Pointer to context */
43 nss_capwap_msg_callback_t msg_callback; /**< Msg callback */
44 void *app_data; /**< App data (argument) */
45 struct nss_capwap_tunnel_stats stats; /**< Stats per-interface number */
46};
47static struct nss_capwap_handle *nss_capwap_hdl[NSS_MAX_DYNAMIC_INTERFACES];
48
49/*
Saurabh Misra09dddeb2014-09-30 16:38:07 -070050 * nss_capwap_verify_if_num()
51 * Verify if_num passed to us.
52 */
53static bool nss_capwap_verify_if_num(uint32_t if_num)
54{
55 if (nss_is_dynamic_interface(if_num) == false) {
56 return false;
57 }
58
Stephen Wange8b8d0d2017-02-24 17:05:22 -080059 if (nss_dynamic_interface_get_type(nss_capwap_get_ctx(), if_num) != NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP) {
Saurabh Misra09dddeb2014-09-30 16:38:07 -070060 return false;
61 }
62
63 return true;
64}
65
66/*
67 * nss_capwap_refcnt_inc()
68 * Increments refcnt on the tunnel.
69 */
70static void nss_capwap_refcnt_inc(int32_t if_num)
71{
72 if_num = if_num - NSS_DYNAMIC_IF_START;
73 atomic_inc(&nss_capwap_hdl[if_num]->refcnt);
74 nss_assert(atomic_read(&nss_capwap_hdl[if_num]->refcnt) > 0);
75}
76
77/*
78 * nss_capwap_refcnt_dec()
79 * Decrements refcnt on the tunnel.
80 */
81static void nss_capwap_refcnt_dec(int32_t if_num)
82{
83 if_num = if_num - NSS_DYNAMIC_IF_START;
84 nss_assert(atomic_read(&nss_capwap_hdl[if_num]->refcnt) > 0);
85 atomic_dec(&nss_capwap_hdl[if_num]->refcnt);
86}
87
88/*
Saurabh Misraf4a05632015-02-27 17:49:41 -080089 * nss_capwap_refcnt()
Saurabh Misra09dddeb2014-09-30 16:38:07 -070090 * Get refcnt on the tunnel.
91 */
Saurabh Misraf4a05632015-02-27 17:49:41 -080092static uint32_t nss_capwap_refcnt(int32_t if_num)
Saurabh Misra09dddeb2014-09-30 16:38:07 -070093{
94 if_num = if_num - NSS_DYNAMIC_IF_START;
95 return atomic_read(&nss_capwap_hdl[if_num]->refcnt);
96}
97
98/*
99 * nss_capwap_set_msg_callback()
100 * This sets the message callback handler and its associated context
101 */
102static void nss_capwap_set_msg_callback(int32_t if_num, nss_capwap_msg_callback_t cb, void *app_data)
103{
104 struct nss_capwap_handle *h;
105
106 h = nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START];
107 if (!h) {
108 return;
109 }
110
111 h->app_data = app_data;
112 h->msg_callback = cb;
113}
114
115/*
Saurabh Misra3e9f8b02015-03-16 13:30:57 -0700116 * nss_capwap_get_msg_callback()
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700117 * This gets the message callback handler and its associated context
118 */
Saurabh Misra3e9f8b02015-03-16 13:30:57 -0700119static nss_capwap_msg_callback_t nss_capwap_get_msg_callback(int32_t if_num, void **app_data)
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700120{
121 struct nss_capwap_handle *h;
122
123 h = nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START];
124 if (!h) {
125 *app_data = NULL;
126 return NULL;
127 }
128
129 *app_data = h->app_data;
130 return h->msg_callback;
131}
132
133/*
134 * nss_capwapmgr_update_stats()
135 * Update per-tunnel stats for each CAPWAP interface.
136 */
137static void nss_capwapmgr_update_stats(struct nss_capwap_handle *handle, struct nss_capwap_stats_msg *fstats)
138{
139 struct nss_capwap_tunnel_stats *stats;
140
141 stats = &handle->stats;
142
143 stats->rx_segments += fstats->rx_segments;
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700144 stats->dtls_pkts += fstats->dtls_pkts;
Saurabh Misra6db99b52014-12-08 10:33:08 -0800145
146 stats->rx_dup_frag += fstats->rx_dup_frag;
Saurabh Misra3f66e872015-04-03 11:30:42 -0700147 stats->rx_oversize_drops += fstats->rx_oversize_drops;
148 stats->rx_frag_timeout_drops += fstats->rx_frag_timeout_drops;
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700149 stats->rx_queue_full_drops += fstats->rx_queue_full_drops;
150 stats->rx_n2h_queue_full_drops += fstats->rx_n2h_queue_full_drops;
151 stats->rx_mem_failure_drops += fstats->rx_mem_failure_drops;
Saurabh Misra3f66e872015-04-03 11:30:42 -0700152 stats->rx_csum_drops += fstats->rx_csum_drops;
153 stats->rx_malformed += fstats->rx_malformed;
154 stats->rx_frag_gap_drops += fstats->rx_frag_gap_drops;
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700155
Saurabh Misra3f66e872015-04-03 11:30:42 -0700156 stats->tx_segments += fstats->tx_segments;
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700157 stats->tx_queue_full_drops += fstats->tx_queue_full_drops;
158 stats->tx_mem_failure_drops += fstats->tx_mem_failure_drops;
Saurabh Misra3f66e872015-04-03 11:30:42 -0700159 stats->tx_dropped_sg_ref += fstats->tx_dropped_sg_ref;
160 stats->tx_dropped_ver_mis += fstats->tx_dropped_ver_mis;
161 stats->tx_dropped_hroom += fstats->tx_dropped_hroom;
162 stats->tx_dropped_dtls += fstats->tx_dropped_dtls;
163 stats->tx_dropped_nwireless += fstats->tx_dropped_nwireless;
164 stats->tx_dropped_unalign += fstats->tx_dropped_unalign;
Saurabh Misra6db99b52014-12-08 10:33:08 -0800165
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700166 /*
167 * add pnode stats now.
168 */
169 stats->pnode_stats.rx_packets += fstats->pnode_stats.rx_packets;
170 stats->pnode_stats.rx_bytes += fstats->pnode_stats.rx_bytes;
ratheesh kannoth89948ff2017-10-03 08:59:02 +0530171 stats->pnode_stats.rx_dropped += nss_cmn_rx_dropped_sum(&fstats->pnode_stats);
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700172 stats->pnode_stats.tx_packets += fstats->pnode_stats.tx_packets;
173 stats->pnode_stats.tx_bytes += fstats->pnode_stats.tx_bytes;
174}
175
176/*
177 * nss_capwap_handler()
178 * Handle NSS -> HLOS messages for CAPWAP
179 */
Saurabh Misra3e9f8b02015-03-16 13:30:57 -0700180static void nss_capwap_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700181{
182 struct nss_capwap_msg *ntm = (struct nss_capwap_msg *)ncm;
183 nss_capwap_msg_callback_t cb;
184
185 /*
186 * Is this a valid request/response packet?
187 */
188 if (ncm->type > NSS_CAPWAP_MSG_TYPE_MAX) {
189 nss_warning("%p: received invalid message %d for CAPWAP interface", nss_ctx, ncm->type);
190 return;
191 }
192
Suruchi Agarwalef8a8702016-01-08 12:40:08 -0800193 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_capwap_msg)) {
194 nss_warning("%p: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700195 return;
196 }
197
198 nss_core_log_msg_failures(nss_ctx, ncm);
199
200 switch (ntm->cm.type) {
201 case NSS_CAPWAP_MSG_TYPE_SYNC_STATS: {
202 uint32_t if_num;
203
204 if_num = ncm->interface - NSS_DYNAMIC_IF_START;
205 if (nss_capwap_hdl[if_num] != NULL) {
206 nss_capwapmgr_update_stats(nss_capwap_hdl[if_num], &ntm->msg.stats);
207 }
208 }
209 }
210
211 /*
212 * Update the callback and app_data for NOTIFY messages.
213 */
214 if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
Stephen Wangaed46332016-12-12 17:29:03 -0800215 ncm->cb = (nss_ptr_t)nss_capwap_get_msg_callback(ncm->interface, (void **)&ncm->app_data);
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700216 }
217
218 /*
219 * Do we have a callback
220 */
221 if (!ncm->cb) {
222 nss_trace("%p: cb is null for interface %d", nss_ctx, ncm->interface);
223 return;
224 }
225
226 cb = (nss_capwap_msg_callback_t)ncm->cb;
Saurabh Misra3e9f8b02015-03-16 13:30:57 -0700227 cb((void *)ncm->app_data, ntm);
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700228}
229
230/*
231 * nss_capwap_instance_alloc()
232 * Allocate CAPWAP tunnel instance
233 */
234static bool nss_capwap_instance_alloc(struct nss_ctx_instance *nss_ctx, uint32_t if_num)
235{
236 struct nss_capwap_handle *h;
237
238 /*
239 * Allocate a handle
240 */
241 h = kmalloc(sizeof(struct nss_capwap_handle), GFP_ATOMIC);
242 if (h == NULL) {
243 nss_warning("%p: no memory for allocating CAPWAP instance for interface : %d", nss_ctx, if_num);
244 return false;
245 }
Saurabh Misraf4a05632015-02-27 17:49:41 -0800246
247 memset(h, 0, sizeof(struct nss_capwap_handle));
248 h->if_num = if_num;
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700249
250 spin_lock(&nss_capwap_spinlock);
251 if (nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START] != NULL) {
252 spin_unlock(&nss_capwap_spinlock);
253 kfree(h);
254 nss_warning("%p: Another thread is already allocated instance for :%d", nss_ctx, if_num);
255 return false;
256 }
257
258 nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START] = h;
259 spin_unlock(&nss_capwap_spinlock);
260
261 return true;
262}
263
264/*
265 * nss_capwap_tx_msg()
266 * Transmit a CAPWAP message to NSS FW. Don't call this from softirq/interrupts.
267 */
268nss_tx_status_t nss_capwap_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_capwap_msg *msg)
269{
270 struct nss_capwap_msg *nm;
271 struct nss_cmn_msg *ncm = &msg->cm;
272 struct sk_buff *nbuf;
273 int32_t status;
274 int32_t if_num;
275
276 BUG_ON(in_interrupt());
277 BUG_ON(in_softirq());
278 BUG_ON(in_serving_softirq());
279
280 if (nss_capwap_verify_if_num(msg->cm.interface) == false) {
281 return NSS_TX_FAILURE_BAD_PARAM;
282 }
283
284 if (ncm->type >= NSS_CAPWAP_MSG_TYPE_MAX) {
285 return NSS_TX_FAILURE_BAD_PARAM;
286 }
287
288 if_num = msg->cm.interface - NSS_DYNAMIC_IF_START;
289 spin_lock(&nss_capwap_spinlock);
290 if (!nss_capwap_hdl[if_num]) {
291 spin_unlock(&nss_capwap_spinlock);
292 nss_warning("%p: capwap tunnel if_num is not there: %d", nss_ctx, msg->cm.interface);
293 return NSS_TX_FAILURE_BAD_PARAM;
294 }
295 nss_capwap_refcnt_inc(msg->cm.interface);
296 spin_unlock(&nss_capwap_spinlock);
297
298 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
299 nss_warning("%p: capwap msg dropped as core not ready", nss_ctx);
300 status = NSS_TX_FAILURE_NOT_READY;
301 goto out;
302 }
303
Suruchi Agarwalef8a8702016-01-08 12:40:08 -0800304 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_capwap_msg)) {
305 nss_warning("%p: message length is invalid: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700306 status = NSS_TX_FAILURE_BAD_PARAM;
307 goto out;
308 }
309
310 nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
311 if (unlikely(!nbuf)) {
Sundarajan Srinivasan62fee7e2015-01-22 11:13:10 -0800312 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700313 nss_warning("%p: msg dropped as command allocation failed", nss_ctx);
314 status = NSS_TX_FAILURE;
315 goto out;
316 }
317
318 /*
319 * Copy the message to our skb
320 */
321 nm = (struct nss_capwap_msg *)skb_put(nbuf, sizeof(struct nss_capwap_msg));
322 memcpy(nm, msg, sizeof(struct nss_capwap_msg));
323
324 status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
325 if (status != NSS_CORE_STATUS_SUCCESS) {
326 dev_kfree_skb_any(nbuf);
327 nss_warning("%p: Unable to enqueue 'capwap message' \n", nss_ctx);
328 goto out;
329 }
330
Stephen Wang90c67de2016-04-26 15:15:59 -0700331 nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700332
333 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
334
335out:
336 nss_capwap_refcnt_dec(msg->cm.interface);
337 return status;
338}
339EXPORT_SYMBOL(nss_capwap_tx_msg);
340
341/*
Stephen Wangcf9c21c2016-02-18 17:54:16 -0800342 * nss_capwap_tx_buf()
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700343 * Transmit data buffer (skb) to a NSS interface number
344 */
Stephen Wangcf9c21c2016-02-18 17:54:16 -0800345nss_tx_status_t nss_capwap_tx_buf(struct nss_ctx_instance *nss_ctx, struct sk_buff *os_buf, uint32_t if_num)
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700346{
Stephen Wangcf9c21c2016-02-18 17:54:16 -0800347 int32_t status;
Stephen Wangcf9c21c2016-02-18 17:54:16 -0800348
349 NSS_VERIFY_CTX_MAGIC(nss_ctx);
350
351 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
352 nss_warning("%p: NSS core is not ready", nss_ctx);
353 return NSS_TX_FAILURE_NOT_READY;
354 }
355
356 BUG_ON(!nss_capwap_verify_if_num(if_num));
357
Stephen Wangcf9c21c2016-02-18 17:54:16 -0800358 status = nss_core_send_buffer(nss_ctx, if_num, os_buf, NSS_IF_DATA_QUEUE_0, H2N_BUFFER_PACKET, H2N_BIT_FLAG_VIRTUAL_BUFFER);
359 if (unlikely(status != NSS_CORE_STATUS_SUCCESS)) {
360 nss_warning("%p: Unable to enqueue capwap packet\n", nss_ctx);
361 if (status == NSS_CORE_STATUS_FAILURE_QUEUE) {
362 return NSS_TX_FAILURE_QUEUE;
363 }
364 return NSS_TX_FAILURE;
365 }
366
Stephen Wang90c67de2016-04-26 15:15:59 -0700367 nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
Stephen Wangcf9c21c2016-02-18 17:54:16 -0800368
369 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_PACKET]);
370 return NSS_TX_SUCCESS;
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700371}
Stephen Wangcf9c21c2016-02-18 17:54:16 -0800372EXPORT_SYMBOL(nss_capwap_tx_buf);
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700373
374/*
375 ***********************************
376 * Register/Unregister/Miscellaneous APIs
377 ***********************************
378 */
379
380/*
381 * nss_capwap_get_stats()
382 * API for getting stats from a CAPWAP tunnel interface stats
383 */
384bool nss_capwap_get_stats(uint32_t if_num, struct nss_capwap_tunnel_stats *stats)
385{
386 if (nss_capwap_verify_if_num(if_num) == false) {
387 return false;
388 }
389
390 if_num = if_num - NSS_DYNAMIC_IF_START;
391 spin_lock(&nss_capwap_spinlock);
392 if (nss_capwap_hdl[if_num] == NULL) {
393 spin_unlock(&nss_capwap_spinlock);
394 return false;
395 }
396
397 memcpy(stats, &nss_capwap_hdl[if_num]->stats, sizeof(struct nss_capwap_tunnel_stats));
398 spin_unlock(&nss_capwap_spinlock);
399 return true;
400}
401EXPORT_SYMBOL(nss_capwap_get_stats);
402
403/*
404 * nss_capwap_notify_register()
405 * Registers a message notifier with NSS FW. It should not be called from
406 * softirq or interrupts.
407 */
408struct nss_ctx_instance *nss_capwap_notify_register(uint32_t if_num, nss_capwap_msg_callback_t cb, void *app_data)
409{
410 struct nss_ctx_instance *nss_ctx;
411
412 nss_ctx = &nss_top_main.nss[nss_top_main.capwap_handler_id];
413
414 if (nss_capwap_verify_if_num(if_num) == false) {
415 nss_warning("%p: notfiy register received for invalid interface %d", nss_ctx, if_num);
416 return NULL;
417 }
418
419 spin_lock(&nss_capwap_spinlock);
420 if (nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START] != NULL) {
421 spin_unlock(&nss_capwap_spinlock);
422 nss_warning("%p: notfiy register tunnel already exists for interface %d", nss_ctx, if_num);
423 return NULL;
424 }
425 spin_unlock(&nss_capwap_spinlock);
426
427 return nss_ctx;
428}
429EXPORT_SYMBOL(nss_capwap_notify_register);
430
431/*
432 * nss_capwap_notify_unregister()
433 * unregister the CAPWAP notifier for the given interface number (if_num).
434 * It shouldn't be called from softirq or interrupts.
435 */
436nss_tx_status_t nss_capwap_notify_unregister(struct nss_ctx_instance *nss_ctx, uint32_t if_num)
437{
438 struct nss_top_instance *nss_top;
439 int index;
440
441 if (nss_capwap_verify_if_num(if_num) == false) {
442 nss_warning("%p: notify unregister received for invalid interface %d", nss_ctx, if_num);
443 return NSS_TX_FAILURE_BAD_PARAM;
444 }
445
446 nss_top = nss_ctx->nss_top;
447 if (nss_top == NULL) {
448 nss_warning("%p: notify unregister received for invalid nss_top %d", nss_ctx, if_num);
449 return NSS_TX_FAILURE_BAD_PARAM;
450 }
451
452 index = if_num - NSS_DYNAMIC_IF_START;
453 spin_lock(&nss_capwap_spinlock);
454 if (nss_capwap_hdl[index] == NULL) {
455 spin_unlock(&nss_capwap_spinlock);
456 nss_warning("%p: notify unregister received for unallocated if_num: %d", nss_ctx, if_num);
457 return NSS_TX_FAILURE_BAD_PARAM;
458 }
459
460 /*
461 * It's the responsibility of caller to wait and call us again. We return failure saying
462 * that we can't remove msg handler now.
463 */
Saurabh Misraf4a05632015-02-27 17:49:41 -0800464 if (nss_capwap_refcnt(if_num) != 0) {
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700465 spin_unlock(&nss_capwap_spinlock);
466 nss_warning("%p: notify unregister tunnel %d: has reference", nss_ctx, if_num);
467 return NSS_TX_FAILURE_QUEUE;
468 }
469
470 nss_capwap_set_msg_callback(if_num, NULL, NULL);
471 spin_unlock(&nss_capwap_spinlock);
472
473 return NSS_TX_SUCCESS;
474}
475EXPORT_SYMBOL(nss_capwap_notify_unregister);
476
477/*
478 * nss_capwap_data_register()
479 * Registers a data packet notifier with NSS FW.
480 */
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800481struct nss_ctx_instance *nss_capwap_data_register(uint32_t if_num, nss_capwap_buf_callback_t cb, struct net_device *netdev, uint32_t features)
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700482{
483 struct nss_ctx_instance *nss_ctx;
484 int core_status;
485
486 nss_ctx = nss_capwap_get_ctx();
487 if (nss_capwap_verify_if_num(if_num) == false) {
488 nss_warning("%p: data register received for invalid interface %d", nss_ctx, if_num);
489 return NULL;
490 }
491
492 spin_lock(&nss_capwap_spinlock);
Stephen Wang84e0e992016-09-07 12:31:40 -0700493 if (nss_ctx->subsys_dp_register[if_num].ndev != NULL) {
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700494 spin_unlock(&nss_capwap_spinlock);
495 return NULL;
496 }
497 spin_unlock(&nss_capwap_spinlock);
498
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700499 core_status = nss_core_register_handler(nss_ctx, if_num, nss_capwap_msg_handler, NULL);
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700500 if (core_status != NSS_CORE_STATUS_SUCCESS) {
501 nss_warning("%p: nss core register handler failed for if_num:%d with error :%d", nss_ctx, if_num, core_status);
502 return NULL;
503 }
504
505 if (nss_capwap_instance_alloc(nss_ctx, if_num) == false) {
506 nss_warning("%p: couldn't allocate tunnel instance for if_num:%d", nss_ctx, if_num);
507 return NULL;
508 }
509
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700510 nss_core_register_subsys_dp(nss_ctx, if_num, cb, NULL, NULL, netdev, features);
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700511
512 return nss_ctx;
513}
514EXPORT_SYMBOL(nss_capwap_data_register);
515
516/*
517 * nss_capwap_data_unregister()
518 * Unregister a data packet notifier with NSS FW
519 */
520bool nss_capwap_data_unregister(uint32_t if_num)
521{
522 struct nss_ctx_instance *nss_ctx;
523 struct nss_capwap_handle *h;
524
525 nss_ctx = nss_capwap_get_ctx();
526 if (nss_capwap_verify_if_num(if_num) == false) {
527 nss_warning("%p: data unregister received for invalid interface %d", nss_ctx, if_num);
528 return false;
529 }
530
531 spin_lock(&nss_capwap_spinlock);
532 /*
533 * It's the responsibility of caller to wait and call us again.
534 */
Saurabh Misraf4a05632015-02-27 17:49:41 -0800535 if (nss_capwap_refcnt(if_num) != 0) {
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700536 spin_unlock(&nss_capwap_spinlock);
537 nss_warning("%p: notify unregister tunnel %d: has reference", nss_ctx, if_num);
538 return false;
539 }
540 h = nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START];
541 nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START] = NULL;
542 spin_unlock(&nss_capwap_spinlock);
543
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700544 (void) nss_core_unregister_handler(nss_ctx, if_num);
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700545
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700546 nss_core_unregister_subsys_dp(nss_ctx, if_num);
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800547
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700548 kfree(h);
549 return true;
550}
551EXPORT_SYMBOL(nss_capwap_data_unregister);
552
553/*
554 * nss_capwap_get_ctx()
555 * Return a CAPWAP NSS context.
556 */
557struct nss_ctx_instance *nss_capwap_get_ctx()
558{
559 struct nss_ctx_instance *nss_ctx;
560
561 nss_ctx = &nss_top_main.nss[nss_top_main.capwap_handler_id];
562 return nss_ctx;
563}
564EXPORT_SYMBOL(nss_capwap_get_ctx);
565
566/*
Stephen Wang1f6ad492016-01-27 23:42:06 -0800567 * nss_capwap_ifnum_with_core_id()
568 * Append core id to capwap interface num
569 */
570int nss_capwap_ifnum_with_core_id(int if_num)
571{
572 struct nss_ctx_instance *nss_ctx = nss_capwap_get_ctx();
573
574 NSS_VERIFY_CTX_MAGIC(nss_ctx);
575 if (nss_is_dynamic_interface(if_num) == false) {
576 nss_info("%p: Invalid if_num: %d, must be a dynamic interface\n", nss_ctx, if_num);
577 return 0;
578 }
579 return NSS_INTERFACE_NUM_APPEND_COREID(nss_ctx, if_num);
580}
581EXPORT_SYMBOL(nss_capwap_ifnum_with_core_id);
582
583/*
Sundarajan Srinivasan40bea952014-12-02 13:19:34 -0800584 * nss_capwap_get_max_buf_size()
585 * Return a CAPWAP NSS max_buf_size.
586 */
587uint32_t nss_capwap_get_max_buf_size(struct nss_ctx_instance *nss_ctx)
588{
589 return nss_core_get_max_buf_size(nss_ctx);
590}
591EXPORT_SYMBOL(nss_capwap_get_max_buf_size);
592
593/*
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700594 * nss_capwap_init()
595 * Initializes CAPWAP. Gets called from nss_init.c
596 */
597void nss_capwap_init()
598{
599 memset(&nss_capwap_hdl, 0, sizeof(nss_capwap_hdl));
Yu Huang8c107082017-07-24 14:58:26 -0700600 nss_capwap_stats_dentry_create();
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700601}
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700602
603/*
604 * nss_capwap_msg_init()
605 * Initialize capwap message.
606 */
607void nss_capwap_msg_init(struct nss_capwap_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len,
Sundarajan Srinivasan30a53d42015-01-30 10:52:08 -0800608 nss_capwap_msg_callback_t cb, void *app_data)
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700609{
610 nss_cmn_msg_init(&ncm->cm, if_num, type, len, (void*)cb, app_data);
611}
612EXPORT_SYMBOL(nss_capwap_msg_init);