blob: b99b8457723747c4b4acf04b443e562819bfd0f4 [file] [log] [blame]
Saurabh Misra09dddeb2014-09-30 16:38:07 -07001/*
2 **************************************************************************
Sundarajan Srinivasan30a53d42015-01-30 10:52:08 -08003 * Copyright (c) 2014,2015, 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 /*
18 * nss_capwap.h
19 * NSS CAPWAP driver interface APIs
20 */
21#include "nss_core.h"
22#include <nss_hal.h>
23#include <linux/module.h>
24#include "nss_cmn.h"
25#include "nss_capwap.h"
26
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/*
50 * Global definitions.
51 */
52extern struct nss_top_instance nss_top_main;
53
54/*
55 * nss_capwap_verify_if_num()
56 * Verify if_num passed to us.
57 */
58static bool nss_capwap_verify_if_num(uint32_t if_num)
59{
60 if (nss_is_dynamic_interface(if_num) == false) {
61 return false;
62 }
63
64 if (nss_dynamic_interface_get_type(if_num) != NSS_DYNAMIC_INTERFACE_TYPE_CAPWAP) {
65 return false;
66 }
67
68 return true;
69}
70
71/*
72 * nss_capwap_refcnt_inc()
73 * Increments refcnt on the tunnel.
74 */
75static void nss_capwap_refcnt_inc(int32_t if_num)
76{
77 if_num = if_num - NSS_DYNAMIC_IF_START;
78 atomic_inc(&nss_capwap_hdl[if_num]->refcnt);
79 nss_assert(atomic_read(&nss_capwap_hdl[if_num]->refcnt) > 0);
80}
81
82/*
83 * nss_capwap_refcnt_dec()
84 * Decrements refcnt on the tunnel.
85 */
86static void nss_capwap_refcnt_dec(int32_t if_num)
87{
88 if_num = if_num - NSS_DYNAMIC_IF_START;
89 nss_assert(atomic_read(&nss_capwap_hdl[if_num]->refcnt) > 0);
90 atomic_dec(&nss_capwap_hdl[if_num]->refcnt);
91}
92
93/*
Saurabh Misraf4a05632015-02-27 17:49:41 -080094 * nss_capwap_refcnt()
Saurabh Misra09dddeb2014-09-30 16:38:07 -070095 * Get refcnt on the tunnel.
96 */
Saurabh Misraf4a05632015-02-27 17:49:41 -080097static uint32_t nss_capwap_refcnt(int32_t if_num)
Saurabh Misra09dddeb2014-09-30 16:38:07 -070098{
99 if_num = if_num - NSS_DYNAMIC_IF_START;
100 return atomic_read(&nss_capwap_hdl[if_num]->refcnt);
101}
102
103/*
104 * nss_capwap_set_msg_callback()
105 * This sets the message callback handler and its associated context
106 */
107static void nss_capwap_set_msg_callback(int32_t if_num, nss_capwap_msg_callback_t cb, void *app_data)
108{
109 struct nss_capwap_handle *h;
110
111 h = nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START];
112 if (!h) {
113 return;
114 }
115
116 h->app_data = app_data;
117 h->msg_callback = cb;
118}
119
120/*
Saurabh Misra3e9f8b02015-03-16 13:30:57 -0700121 * nss_capwap_get_msg_callback()
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700122 * This gets the message callback handler and its associated context
123 */
Saurabh Misra3e9f8b02015-03-16 13:30:57 -0700124static nss_capwap_msg_callback_t nss_capwap_get_msg_callback(int32_t if_num, void **app_data)
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700125{
126 struct nss_capwap_handle *h;
127
128 h = nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START];
129 if (!h) {
130 *app_data = NULL;
131 return NULL;
132 }
133
134 *app_data = h->app_data;
135 return h->msg_callback;
136}
137
138/*
139 * nss_capwapmgr_update_stats()
140 * Update per-tunnel stats for each CAPWAP interface.
141 */
142static void nss_capwapmgr_update_stats(struct nss_capwap_handle *handle, struct nss_capwap_stats_msg *fstats)
143{
144 struct nss_capwap_tunnel_stats *stats;
145
146 stats = &handle->stats;
147
148 stats->rx_segments += fstats->rx_segments;
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700149 stats->dtls_pkts += fstats->dtls_pkts;
Saurabh Misra6db99b52014-12-08 10:33:08 -0800150
151 stats->rx_dup_frag += fstats->rx_dup_frag;
Saurabh Misra3f66e872015-04-03 11:30:42 -0700152 stats->rx_oversize_drops += fstats->rx_oversize_drops;
153 stats->rx_frag_timeout_drops += fstats->rx_frag_timeout_drops;
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700154 stats->rx_queue_full_drops += fstats->rx_queue_full_drops;
155 stats->rx_n2h_queue_full_drops += fstats->rx_n2h_queue_full_drops;
156 stats->rx_mem_failure_drops += fstats->rx_mem_failure_drops;
Saurabh Misra3f66e872015-04-03 11:30:42 -0700157 stats->rx_csum_drops += fstats->rx_csum_drops;
158 stats->rx_malformed += fstats->rx_malformed;
159 stats->rx_frag_gap_drops += fstats->rx_frag_gap_drops;
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700160
Saurabh Misra3f66e872015-04-03 11:30:42 -0700161 stats->tx_segments += fstats->tx_segments;
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700162 stats->tx_queue_full_drops += fstats->tx_queue_full_drops;
163 stats->tx_mem_failure_drops += fstats->tx_mem_failure_drops;
Saurabh Misra3f66e872015-04-03 11:30:42 -0700164 stats->tx_dropped_sg_ref += fstats->tx_dropped_sg_ref;
165 stats->tx_dropped_ver_mis += fstats->tx_dropped_ver_mis;
166 stats->tx_dropped_hroom += fstats->tx_dropped_hroom;
167 stats->tx_dropped_dtls += fstats->tx_dropped_dtls;
168 stats->tx_dropped_nwireless += fstats->tx_dropped_nwireless;
169 stats->tx_dropped_unalign += fstats->tx_dropped_unalign;
Saurabh Misra6db99b52014-12-08 10:33:08 -0800170
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700171 /*
172 * add pnode stats now.
173 */
174 stats->pnode_stats.rx_packets += fstats->pnode_stats.rx_packets;
175 stats->pnode_stats.rx_bytes += fstats->pnode_stats.rx_bytes;
176 stats->pnode_stats.rx_dropped += fstats->pnode_stats.rx_dropped;
177 stats->pnode_stats.tx_packets += fstats->pnode_stats.tx_packets;
178 stats->pnode_stats.tx_bytes += fstats->pnode_stats.tx_bytes;
179}
180
181/*
182 * nss_capwap_handler()
183 * Handle NSS -> HLOS messages for CAPWAP
184 */
Saurabh Misra3e9f8b02015-03-16 13:30:57 -0700185static 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 -0700186{
187 struct nss_capwap_msg *ntm = (struct nss_capwap_msg *)ncm;
188 nss_capwap_msg_callback_t cb;
189
190 /*
191 * Is this a valid request/response packet?
192 */
193 if (ncm->type > NSS_CAPWAP_MSG_TYPE_MAX) {
194 nss_warning("%p: received invalid message %d for CAPWAP interface", nss_ctx, ncm->type);
195 return;
196 }
197
198 if (ncm->len > sizeof(struct nss_capwap_msg)) {
199 nss_warning("%p: Length of message is greater than required: %d", nss_ctx, ncm->interface);
200 return;
201 }
202
203 nss_core_log_msg_failures(nss_ctx, ncm);
204
205 switch (ntm->cm.type) {
206 case NSS_CAPWAP_MSG_TYPE_SYNC_STATS: {
207 uint32_t if_num;
208
209 if_num = ncm->interface - NSS_DYNAMIC_IF_START;
210 if (nss_capwap_hdl[if_num] != NULL) {
211 nss_capwapmgr_update_stats(nss_capwap_hdl[if_num], &ntm->msg.stats);
212 }
213 }
214 }
215
216 /*
217 * Update the callback and app_data for NOTIFY messages.
218 */
219 if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
Saurabh Misra3e9f8b02015-03-16 13:30:57 -0700220 ncm->cb = (uint32_t)nss_capwap_get_msg_callback(ncm->interface, (void **)&ncm->app_data);
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700221 }
222
223 /*
224 * Do we have a callback
225 */
226 if (!ncm->cb) {
227 nss_trace("%p: cb is null for interface %d", nss_ctx, ncm->interface);
228 return;
229 }
230
231 cb = (nss_capwap_msg_callback_t)ncm->cb;
Saurabh Misra3e9f8b02015-03-16 13:30:57 -0700232 cb((void *)ncm->app_data, ntm);
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700233}
234
235/*
236 * nss_capwap_instance_alloc()
237 * Allocate CAPWAP tunnel instance
238 */
239static bool nss_capwap_instance_alloc(struct nss_ctx_instance *nss_ctx, uint32_t if_num)
240{
241 struct nss_capwap_handle *h;
242
243 /*
244 * Allocate a handle
245 */
246 h = kmalloc(sizeof(struct nss_capwap_handle), GFP_ATOMIC);
247 if (h == NULL) {
248 nss_warning("%p: no memory for allocating CAPWAP instance for interface : %d", nss_ctx, if_num);
249 return false;
250 }
Saurabh Misraf4a05632015-02-27 17:49:41 -0800251
252 memset(h, 0, sizeof(struct nss_capwap_handle));
253 h->if_num = if_num;
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700254
255 spin_lock(&nss_capwap_spinlock);
256 if (nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START] != NULL) {
257 spin_unlock(&nss_capwap_spinlock);
258 kfree(h);
259 nss_warning("%p: Another thread is already allocated instance for :%d", nss_ctx, if_num);
260 return false;
261 }
262
263 nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START] = h;
264 spin_unlock(&nss_capwap_spinlock);
265
266 return true;
267}
268
269/*
270 * nss_capwap_tx_msg()
271 * Transmit a CAPWAP message to NSS FW. Don't call this from softirq/interrupts.
272 */
273nss_tx_status_t nss_capwap_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_capwap_msg *msg)
274{
275 struct nss_capwap_msg *nm;
276 struct nss_cmn_msg *ncm = &msg->cm;
277 struct sk_buff *nbuf;
278 int32_t status;
279 int32_t if_num;
280
281 BUG_ON(in_interrupt());
282 BUG_ON(in_softirq());
283 BUG_ON(in_serving_softirq());
284
285 if (nss_capwap_verify_if_num(msg->cm.interface) == false) {
286 return NSS_TX_FAILURE_BAD_PARAM;
287 }
288
289 if (ncm->type >= NSS_CAPWAP_MSG_TYPE_MAX) {
290 return NSS_TX_FAILURE_BAD_PARAM;
291 }
292
293 if_num = msg->cm.interface - NSS_DYNAMIC_IF_START;
294 spin_lock(&nss_capwap_spinlock);
295 if (!nss_capwap_hdl[if_num]) {
296 spin_unlock(&nss_capwap_spinlock);
297 nss_warning("%p: capwap tunnel if_num is not there: %d", nss_ctx, msg->cm.interface);
298 return NSS_TX_FAILURE_BAD_PARAM;
299 }
300 nss_capwap_refcnt_inc(msg->cm.interface);
301 spin_unlock(&nss_capwap_spinlock);
302
303 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
304 nss_warning("%p: capwap msg dropped as core not ready", nss_ctx);
305 status = NSS_TX_FAILURE_NOT_READY;
306 goto out;
307 }
308
309 if (ncm->len > sizeof(struct nss_capwap_msg)) {
310 nss_warning("%p: message length is invalid: %d", nss_ctx, ncm->len);
311 status = NSS_TX_FAILURE_BAD_PARAM;
312 goto out;
313 }
314
315 nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
316 if (unlikely(!nbuf)) {
Sundarajan Srinivasan62fee7e2015-01-22 11:13:10 -0800317 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 -0700318 nss_warning("%p: msg dropped as command allocation failed", nss_ctx);
319 status = NSS_TX_FAILURE;
320 goto out;
321 }
322
323 /*
324 * Copy the message to our skb
325 */
326 nm = (struct nss_capwap_msg *)skb_put(nbuf, sizeof(struct nss_capwap_msg));
327 memcpy(nm, msg, sizeof(struct nss_capwap_msg));
328
329 status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
330 if (status != NSS_CORE_STATUS_SUCCESS) {
331 dev_kfree_skb_any(nbuf);
332 nss_warning("%p: Unable to enqueue 'capwap message' \n", nss_ctx);
333 goto out;
334 }
335
336 nss_hal_send_interrupt(nss_ctx->nmap, nss_ctx->h2n_desc_rings[NSS_IF_CMD_QUEUE].desc_ring.int_bit,
337 NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE);
338
339 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
340
341out:
342 nss_capwap_refcnt_dec(msg->cm.interface);
343 return status;
344}
345EXPORT_SYMBOL(nss_capwap_tx_msg);
346
347/*
348 * nss_capwap_tx_data()
349 * Transmit data buffer (skb) to a NSS interface number
350 */
351nss_tx_status_t nss_capwap_tx_data(struct nss_ctx_instance *nss_ctx, struct sk_buff *os_buf, uint32_t if_num)
352{
353 return nss_if_tx_buf(nss_ctx, os_buf, if_num);
354}
355EXPORT_SYMBOL(nss_capwap_tx_data);
356
357/*
358 ***********************************
359 * Register/Unregister/Miscellaneous APIs
360 ***********************************
361 */
362
363/*
364 * nss_capwap_get_stats()
365 * API for getting stats from a CAPWAP tunnel interface stats
366 */
367bool nss_capwap_get_stats(uint32_t if_num, struct nss_capwap_tunnel_stats *stats)
368{
369 if (nss_capwap_verify_if_num(if_num) == false) {
370 return false;
371 }
372
373 if_num = if_num - NSS_DYNAMIC_IF_START;
374 spin_lock(&nss_capwap_spinlock);
375 if (nss_capwap_hdl[if_num] == NULL) {
376 spin_unlock(&nss_capwap_spinlock);
377 return false;
378 }
379
380 memcpy(stats, &nss_capwap_hdl[if_num]->stats, sizeof(struct nss_capwap_tunnel_stats));
381 spin_unlock(&nss_capwap_spinlock);
382 return true;
383}
384EXPORT_SYMBOL(nss_capwap_get_stats);
385
386/*
387 * nss_capwap_notify_register()
388 * Registers a message notifier with NSS FW. It should not be called from
389 * softirq or interrupts.
390 */
391struct nss_ctx_instance *nss_capwap_notify_register(uint32_t if_num, nss_capwap_msg_callback_t cb, void *app_data)
392{
393 struct nss_ctx_instance *nss_ctx;
394
395 nss_ctx = &nss_top_main.nss[nss_top_main.capwap_handler_id];
396
397 if (nss_capwap_verify_if_num(if_num) == false) {
398 nss_warning("%p: notfiy register received for invalid interface %d", nss_ctx, if_num);
399 return NULL;
400 }
401
402 spin_lock(&nss_capwap_spinlock);
403 if (nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START] != NULL) {
404 spin_unlock(&nss_capwap_spinlock);
405 nss_warning("%p: notfiy register tunnel already exists for interface %d", nss_ctx, if_num);
406 return NULL;
407 }
408 spin_unlock(&nss_capwap_spinlock);
409
410 return nss_ctx;
411}
412EXPORT_SYMBOL(nss_capwap_notify_register);
413
414/*
415 * nss_capwap_notify_unregister()
416 * unregister the CAPWAP notifier for the given interface number (if_num).
417 * It shouldn't be called from softirq or interrupts.
418 */
419nss_tx_status_t nss_capwap_notify_unregister(struct nss_ctx_instance *nss_ctx, uint32_t if_num)
420{
421 struct nss_top_instance *nss_top;
422 int index;
423
424 if (nss_capwap_verify_if_num(if_num) == false) {
425 nss_warning("%p: notify unregister received for invalid interface %d", nss_ctx, if_num);
426 return NSS_TX_FAILURE_BAD_PARAM;
427 }
428
429 nss_top = nss_ctx->nss_top;
430 if (nss_top == NULL) {
431 nss_warning("%p: notify unregister received for invalid nss_top %d", nss_ctx, if_num);
432 return NSS_TX_FAILURE_BAD_PARAM;
433 }
434
435 index = if_num - NSS_DYNAMIC_IF_START;
436 spin_lock(&nss_capwap_spinlock);
437 if (nss_capwap_hdl[index] == NULL) {
438 spin_unlock(&nss_capwap_spinlock);
439 nss_warning("%p: notify unregister received for unallocated if_num: %d", nss_ctx, if_num);
440 return NSS_TX_FAILURE_BAD_PARAM;
441 }
442
443 /*
444 * It's the responsibility of caller to wait and call us again. We return failure saying
445 * that we can't remove msg handler now.
446 */
Saurabh Misraf4a05632015-02-27 17:49:41 -0800447 if (nss_capwap_refcnt(if_num) != 0) {
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700448 spin_unlock(&nss_capwap_spinlock);
449 nss_warning("%p: notify unregister tunnel %d: has reference", nss_ctx, if_num);
450 return NSS_TX_FAILURE_QUEUE;
451 }
452
453 nss_capwap_set_msg_callback(if_num, NULL, NULL);
454 spin_unlock(&nss_capwap_spinlock);
455
456 return NSS_TX_SUCCESS;
457}
458EXPORT_SYMBOL(nss_capwap_notify_unregister);
459
460/*
461 * nss_capwap_data_register()
462 * Registers a data packet notifier with NSS FW.
463 */
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800464struct 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 -0700465{
466 struct nss_ctx_instance *nss_ctx;
467 int core_status;
468
469 nss_ctx = nss_capwap_get_ctx();
470 if (nss_capwap_verify_if_num(if_num) == false) {
471 nss_warning("%p: data register received for invalid interface %d", nss_ctx, if_num);
472 return NULL;
473 }
474
475 spin_lock(&nss_capwap_spinlock);
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800476 if (nss_ctx->nss_top->subsys_dp_register[if_num].ndev != NULL) {
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700477 spin_unlock(&nss_capwap_spinlock);
478 return NULL;
479 }
480 spin_unlock(&nss_capwap_spinlock);
481
482 core_status = nss_core_register_handler(if_num, nss_capwap_msg_handler, NULL);
483 if (core_status != NSS_CORE_STATUS_SUCCESS) {
484 nss_warning("%p: nss core register handler failed for if_num:%d with error :%d", nss_ctx, if_num, core_status);
485 return NULL;
486 }
487
488 if (nss_capwap_instance_alloc(nss_ctx, if_num) == false) {
489 nss_warning("%p: couldn't allocate tunnel instance for if_num:%d", nss_ctx, if_num);
490 return NULL;
491 }
492
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800493 nss_ctx->nss_top->subsys_dp_register[if_num].cb = cb;
494 nss_ctx->nss_top->subsys_dp_register[if_num].app_data = NULL;
495 nss_ctx->nss_top->subsys_dp_register[if_num].ndev = netdev;
496 nss_ctx->nss_top->subsys_dp_register[if_num].features = features;
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700497
498 return nss_ctx;
499}
500EXPORT_SYMBOL(nss_capwap_data_register);
501
502/*
503 * nss_capwap_data_unregister()
504 * Unregister a data packet notifier with NSS FW
505 */
506bool nss_capwap_data_unregister(uint32_t if_num)
507{
508 struct nss_ctx_instance *nss_ctx;
509 struct nss_capwap_handle *h;
510
511 nss_ctx = nss_capwap_get_ctx();
512 if (nss_capwap_verify_if_num(if_num) == false) {
513 nss_warning("%p: data unregister received for invalid interface %d", nss_ctx, if_num);
514 return false;
515 }
516
517 spin_lock(&nss_capwap_spinlock);
518 /*
519 * It's the responsibility of caller to wait and call us again.
520 */
Saurabh Misraf4a05632015-02-27 17:49:41 -0800521 if (nss_capwap_refcnt(if_num) != 0) {
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700522 spin_unlock(&nss_capwap_spinlock);
523 nss_warning("%p: notify unregister tunnel %d: has reference", nss_ctx, if_num);
524 return false;
525 }
526 h = nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START];
527 nss_capwap_hdl[if_num - NSS_DYNAMIC_IF_START] = NULL;
528 spin_unlock(&nss_capwap_spinlock);
529
530 (void) nss_core_unregister_handler(if_num);
531
Sundarajan Srinivasan70374842014-11-19 15:22:52 -0800532 nss_ctx->nss_top->subsys_dp_register[if_num].cb = NULL;
533 nss_ctx->nss_top->subsys_dp_register[if_num].app_data = NULL;
534 nss_ctx->nss_top->subsys_dp_register[if_num].ndev = NULL;
535 nss_ctx->nss_top->subsys_dp_register[if_num].features = 0;
536
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700537 kfree(h);
538 return true;
539}
540EXPORT_SYMBOL(nss_capwap_data_unregister);
541
542/*
543 * nss_capwap_get_ctx()
544 * Return a CAPWAP NSS context.
545 */
546struct nss_ctx_instance *nss_capwap_get_ctx()
547{
548 struct nss_ctx_instance *nss_ctx;
549
550 nss_ctx = &nss_top_main.nss[nss_top_main.capwap_handler_id];
551 return nss_ctx;
552}
553EXPORT_SYMBOL(nss_capwap_get_ctx);
554
555/*
Sundarajan Srinivasan40bea952014-12-02 13:19:34 -0800556 * nss_capwap_get_max_buf_size()
557 * Return a CAPWAP NSS max_buf_size.
558 */
559uint32_t nss_capwap_get_max_buf_size(struct nss_ctx_instance *nss_ctx)
560{
561 return nss_core_get_max_buf_size(nss_ctx);
562}
563EXPORT_SYMBOL(nss_capwap_get_max_buf_size);
564
565/*
Saurabh Misra09dddeb2014-09-30 16:38:07 -0700566 * nss_capwap_init()
567 * Initializes CAPWAP. Gets called from nss_init.c
568 */
569void nss_capwap_init()
570{
571 memset(&nss_capwap_hdl, 0, sizeof(nss_capwap_hdl));
572}
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700573
574/*
575 * nss_capwap_msg_init()
576 * Initialize capwap message.
577 */
578void 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 -0800579 nss_capwap_msg_callback_t cb, void *app_data)
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700580{
581 nss_cmn_msg_init(&ncm->cm, if_num, type, len, (void*)cb, app_data);
582}
583EXPORT_SYMBOL(nss_capwap_msg_init);