blob: e09ca71fa1ac30dd106c1018530002105379e92c [file] [log] [blame]
Tushar Mathurff8741b2015-12-02 20:28:59 +05301/*
2 **************************************************************************
3 * Copyright (c) 2016, The Linux Foundation. All rights reserved.
4 * 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#include "nss_tx_rx_common.h"
18#include "nss_dtls_stats.h"
19
20#define NSS_DTLS_TX_TIMEOUT 3000 /* 3 Seconds */
21
22/*
23 * Data structures to store DTLS nss debug stats
24 */
25static DEFINE_SPINLOCK(nss_dtls_session_debug_stats_lock);
26static struct nss_stats_dtls_session_debug nss_dtls_session_debug_stats[NSS_MAX_DTLS_SESSIONS];
27
28/*
29 * Private data structure
30 */
31static struct nss_dtls_pvt {
32 struct semaphore sem;
33 struct completion complete;
34 int response;
35 void *cb;
36 void *app_data;
37} dtls_pvt;
38
39
40/*
41 * nss_dtls_verify_if_num()
42 * Verify if_num passed to us.
43 */
44static bool nss_dtls_verify_if_num(uint32_t if_num)
45{
46 if (nss_is_dynamic_interface(if_num) == false)
47 return false;
48
49 if (nss_dynamic_interface_get_type(if_num)
50 != NSS_DYNAMIC_INTERFACE_TYPE_DTLS)
51 return false;
52
53 return true;
54}
55
56/*
57 * nss_dtls_session_stats_sync
58 * Per DTLS session debug stats
59 */
60static void nss_dtls_session_stats_sync(struct nss_ctx_instance *nss_ctx,
61 struct nss_dtls_session_stats *stats_msg,
62 uint16_t if_num)
63{
64 int i;
65 struct nss_stats_dtls_session_debug *s = NULL;
66
67 NSS_VERIFY_CTX_MAGIC(nss_ctx);
68
69 spin_lock_bh(&nss_dtls_session_debug_stats_lock);
70 for (i = 0; i < NSS_MAX_DTLS_SESSIONS; i++) {
71 if (nss_dtls_session_debug_stats[i].if_num != if_num) {
72 continue;
73 }
74
75 s = &nss_dtls_session_debug_stats[i];
76 break;
77 }
78
79 if (!s) {
80 spin_unlock_bh(&nss_dtls_session_debug_stats_lock);
81 return;
82 }
83
84 s->stats[NSS_STATS_DTLS_SESSION_RX_PKTS] += stats_msg->node_stats.rx_packets;
85 s->stats[NSS_STATS_DTLS_SESSION_TX_PKTS] += stats_msg->node_stats.tx_packets;
86 s->stats[NSS_STATS_DTLS_SESSION_RX_DROPPED] += stats_msg->node_stats.rx_dropped;
87 s->stats[NSS_STATS_DTLS_SESSION_RX_AUTH_DONE] += stats_msg->rx_auth_done;
88 s->stats[NSS_STATS_DTLS_SESSION_TX_AUTH_DONE] += stats_msg->tx_auth_done;
89 s->stats[NSS_STATS_DTLS_SESSION_RX_CIPHER_DONE] += stats_msg->rx_cipher_done;
90 s->stats[NSS_STATS_DTLS_SESSION_TX_CIPHER_DONE] += stats_msg->tx_cipher_done;
91 s->stats[NSS_STATS_DTLS_SESSION_RX_CBUF_ALLOC_FAIL] += stats_msg->rx_cbuf_alloc_fail;
92 s->stats[NSS_STATS_DTLS_SESSION_TX_CBUF_ALLOC_FAIL] += stats_msg->tx_cbuf_alloc_fail;
93 s->stats[NSS_STATS_DTLS_SESSION_TX_CENQUEUE_FAIL] += stats_msg->tx_cenqueue_fail;
94 s->stats[NSS_STATS_DTLS_SESSION_RX_CENQUEUE_FAIL] += stats_msg->rx_cenqueue_fail;
95 s->stats[NSS_STATS_DTLS_SESSION_TX_DROPPED_HROOM] += stats_msg->tx_dropped_hroom;
96 s->stats[NSS_STATS_DTLS_SESSION_TX_DROPPED_TROOM] += stats_msg->tx_dropped_troom;
97 s->stats[NSS_STATS_DTLS_SESSION_TX_FORWARD_ENQUEUE_FAIL] += stats_msg->tx_forward_enqueue_fail;
98 s->stats[NSS_STATS_DTLS_SESSION_RX_FORWARD_ENQUEUE_FAIL] += stats_msg->rx_forward_enqueue_fail;
99 s->stats[NSS_STATS_DTLS_SESSION_RX_INVALID_VERSION] += stats_msg->rx_invalid_version;
100 s->stats[NSS_STATS_DTLS_SESSION_RX_INVALID_EPOCH] += stats_msg->rx_invalid_epoch;
101 s->stats[NSS_STATS_DTLS_SESSION_RX_MALFORMED] += stats_msg->rx_malformed;
102 s->stats[NSS_STATS_DTLS_SESSION_RX_CIPHER_FAIL] += stats_msg->rx_cipher_fail;
103 s->stats[NSS_STATS_DTLS_SESSION_RX_AUTH_FAIL] += stats_msg->rx_auth_fail;
104 s->stats[NSS_STATS_DTLS_SESSION_RX_CAPWAP_CLASSIFY_FAIL] += stats_msg->rx_capwap_classify_fail;
105 s->stats[NSS_STATS_DTLS_SESSION_RX_SINGLE_REC_DGRAM] += stats_msg->rx_single_rec_dgram;
106 s->stats[NSS_STATS_DTLS_SESSION_RX_MULTI_REC_DGRAM] += stats_msg->rx_multi_rec_dgram;
107 s->stats[NSS_STATS_DTLS_SESSION_RX_REPLAY_FAIL] += stats_msg->rx_replay_fail;
108 s->stats[NSS_STATS_DTLS_SESSION_RX_REPLAY_DUPLICATE] += stats_msg->rx_replay_duplicate;
109 s->stats[NSS_STATS_DTLS_SESSION_RX_REPLAY_OUT_OF_WINDOW] += stats_msg->rx_replay_out_of_window;
110 s->stats[NSS_STATS_DTLS_SESSION_OUTFLOW_QUEUE_FULL] += stats_msg->outflow_queue_full;
111 s->stats[NSS_STATS_DTLS_SESSION_DECAP_QUEUE_FULL] += stats_msg->decap_queue_full;
112 s->stats[NSS_STATS_DTLS_SESSION_PBUF_ALLOC_FAIL] += stats_msg->pbuf_alloc_fail;
113 s->stats[NSS_STATS_DTLS_SESSION_PBUF_COPY_FAIL] += stats_msg->pbuf_copy_fail;
114 s->stats[NSS_STATS_DTLS_SESSION_EPOCH] = stats_msg->epoch;
115 s->stats[NSS_STATS_DTLS_SESSION_TX_SEQ_HIGH] = stats_msg->tx_seq_high;
116 s->stats[NSS_STATS_DTLS_SESSION_TX_SEQ_LOW] = stats_msg->tx_seq_low;
117 spin_unlock_bh(&nss_dtls_session_debug_stats_lock);
118}
119
120/*
121 * nss_dtls_session_debug_stats_get()
122 * Get session DTLS statitics.
123 */
124void nss_dtls_session_debug_stats_get(struct nss_stats_dtls_session_debug *stats)
125{
126 int i;
127
128 if (!stats) {
129 nss_warning("No memory to copy dtls session stats");
130 return;
131 }
132
133 spin_lock_bh(&nss_dtls_session_debug_stats_lock);
134 for (i = 0; i < NSS_MAX_DTLS_SESSIONS; i++) {
135 if (nss_dtls_session_debug_stats[i].valid) {
136 memcpy(stats, &nss_dtls_session_debug_stats[i],
137 sizeof(struct nss_stats_dtls_session_debug));
138 stats++;
139 }
140 }
141 spin_unlock_bh(&nss_dtls_session_debug_stats_lock);
142}
143
144/*
145 * nss_dtls_handler()
146 * Handle NSS -> HLOS messages for dtls tunnel
147 */
148static void nss_dtls_handler(struct nss_ctx_instance *nss_ctx,
149 struct nss_cmn_msg *ncm,
150 __attribute__((unused))void *app_data)
151{
152 struct nss_dtls_msg *ntm = (struct nss_dtls_msg *)ncm;
153 void *ctx;
154
155 nss_dtls_msg_callback_t cb;
156
157 NSS_VERIFY_CTX_MAGIC(nss_ctx);
158 BUG_ON(!nss_dtls_verify_if_num(ncm->interface));
159
160 /*
161 * Is this a valid request/response packet?
162 */
163 if (ncm->type >= NSS_DTLS_MSG_MAX) {
164 nss_warning("%p: received invalid message %d "
165 "for DTLS interface %d",
166 nss_ctx, ncm->type, ncm->interface);
167 return;
168 }
169
Suruchi Agarwalef8a8702016-01-08 12:40:08 -0800170 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_dtls_msg)) {
Tushar Mathurff8741b2015-12-02 20:28:59 +0530171 nss_warning("%p: dtls message length is invalid: %d",
172 nss_ctx, ncm->len);
173 return;
174 }
175
176 switch (ntm->cm.type) {
177 case NSS_DTLS_MSG_SESSION_STATS:
178 nss_dtls_session_stats_sync(nss_ctx,
179 &ntm->msg.stats,
180 ncm->interface);
181 break;
182 }
183
184 /*
185 * Update the callback and app_data for NOTIFY messages
186 */
187 if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
188 ncm->cb = (uint32_t)nss_ctx->nss_top->dtls_msg_callback;
189 ncm->app_data = (uint32_t)nss_ctx->nss_top->subsys_dp_register[ncm->interface].app_data;
190 }
191
192 /*
193 * Log failures
194 */
195 nss_core_log_msg_failures(nss_ctx, ncm);
196
197 /*
198 * callback
199 */
200 cb = (nss_dtls_msg_callback_t)ncm->cb;
201 ctx = (void *)ncm->app_data;
202
203 /*
204 * call dtls session callback
205 */
206 if (!cb) {
207 nss_warning("%p: No callback for dtls session interface %d",
208 nss_ctx, ncm->interface);
209 return;
210 }
211
212 cb(ctx, ntm);
213}
214
215/*
216 * nss_dtls_callback()
217 * Callback to handle the completion of NSS->HLOS messages.
218 */
219static void nss_dtls_callback(void *app_data, struct nss_dtls_msg *nim)
220{
221 nss_dtls_msg_callback_t callback = (nss_dtls_msg_callback_t)dtls_pvt.cb;
222 void *data = dtls_pvt.app_data;
223
224 dtls_pvt.cb = NULL;
225 dtls_pvt.app_data = NULL;
226
227 if (nim->cm.response != NSS_CMN_RESPONSE_ACK) {
228 nss_warning("dtls Error response %d\n", nim->cm.response);
229
230 dtls_pvt.response = NSS_TX_FAILURE;
231 if (callback) {
232 callback(data, nim);
233 }
234
235 complete(&dtls_pvt.complete);
236 return;
237 }
238
239 dtls_pvt.response = NSS_TX_SUCCESS;
240 if (callback) {
241 callback(data, nim);
242 }
243
244 complete(&dtls_pvt.complete);
245}
246
247/*
248 * nss_dtls_tx_buf()
249 * Transmit buffer over DTLS interface
250 */
251nss_tx_status_t nss_dtls_tx_buf(struct sk_buff *skb, uint32_t if_num,
252 struct nss_ctx_instance *nss_ctx)
253{
254 int32_t status;
255 uint16_t int_bit = 0;
256
257 NSS_VERIFY_CTX_MAGIC(nss_ctx);
258
259 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
260 nss_warning("%p: 'DTLS If Tx' core not ready", nss_ctx);
261 return NSS_TX_FAILURE_NOT_READY;
262 }
263
264 BUG_ON(!nss_dtls_verify_if_num(if_num));
265
266 int_bit = nss_ctx->h2n_desc_rings[NSS_IF_DATA_QUEUE_0].desc_ring.int_bit;
267
268 status = nss_core_send_buffer(nss_ctx, if_num, skb,
269 NSS_IF_DATA_QUEUE_0,
270 H2N_BUFFER_PACKET,
271 H2N_BIT_FLAG_VIRTUAL_BUFFER);
272 if (unlikely(status != NSS_CORE_STATUS_SUCCESS)) {
273 nss_warning("%p: Unable to enqueue 'DTLS If Tx' packet\n", nss_ctx);
274 if (status == NSS_CORE_STATUS_FAILURE_QUEUE) {
275 return NSS_TX_FAILURE_QUEUE;
276 }
277
278 return NSS_TX_FAILURE;
279 }
280
281 nss_hal_send_interrupt(nss_ctx->nmap, int_bit,
282 NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE);
283
284 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_PACKET]);
285 return NSS_TX_SUCCESS;
286}
287EXPORT_SYMBOL(nss_dtls_tx_buf);
288
289/*
290 * nss_dtls_tx_msg()
291 * Transmit a DTLS message to NSS firmware
292 */
293nss_tx_status_t nss_dtls_tx_msg(struct nss_ctx_instance *nss_ctx,
294 struct nss_dtls_msg *msg)
295{
296 struct nss_dtls_msg *nm;
297 struct nss_cmn_msg *ncm = &msg->cm;
298 struct sk_buff *nbuf;
299 uint16_t int_bit = 0;
300 int32_t status;
301
302 NSS_VERIFY_CTX_MAGIC(nss_ctx);
303 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
304 nss_warning("%p: dtls msg dropped as core not ready", nss_ctx);
305 return NSS_TX_FAILURE_NOT_READY;
306 }
307
308 /*
309 * Sanity check the message
310 */
311 BUG_ON(!nss_dtls_verify_if_num(ncm->interface));
312
313 int_bit = nss_ctx->h2n_desc_rings[NSS_IF_CMD_QUEUE].desc_ring.int_bit;
314
315 if (ncm->type > NSS_DTLS_MSG_MAX) {
316 nss_warning("%p: dtls message type out of range: %d",
317 nss_ctx, ncm->type);
318 return NSS_TX_FAILURE;
319 }
320
Suruchi Agarwalef8a8702016-01-08 12:40:08 -0800321 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_dtls_msg)) {
Tushar Mathurff8741b2015-12-02 20:28:59 +0530322 nss_warning("%p: dtls message length is invalid: %d",
323 nss_ctx, ncm->len);
324 return NSS_TX_FAILURE;
325 }
326
327 nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
328 if (unlikely(!nbuf)) {
329 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
330 nss_warning("%p: dtls msg dropped as command "
331 "allocation failed", nss_ctx);
332 return NSS_TX_FAILURE;
333 }
334
335 /*
336 * Copy the message to our skb
337 */
338 nm = (struct nss_dtls_msg *)skb_put(nbuf, sizeof(struct nss_dtls_msg));
339 memcpy(nm, msg, sizeof(struct nss_dtls_msg));
340
341 status = nss_core_send_buffer(nss_ctx, 0, nbuf,
342 NSS_IF_CMD_QUEUE,
343 H2N_BUFFER_CTRL, 0);
344 if (status != NSS_CORE_STATUS_SUCCESS) {
345 dev_kfree_skb_any(nbuf);
346 nss_warning("%p: Unable to enqueue 'dtls message'\n", nss_ctx);
347 if (status == NSS_CORE_STATUS_FAILURE_QUEUE) {
348 return NSS_TX_FAILURE_QUEUE;
349 }
350 return NSS_TX_FAILURE;
351 }
352
353 nss_hal_send_interrupt(nss_ctx->nmap, int_bit,
354 NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE);
355
356 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
357 return NSS_TX_SUCCESS;
358}
359EXPORT_SYMBOL(nss_dtls_tx_msg);
360
361/*
362 * nss_dtls_tx_msg()
363 * Transmit a DTLS message to NSS firmware synchronously.
364 */
365nss_tx_status_t nss_dtls_tx_msg_sync(struct nss_ctx_instance *nss_ctx, struct nss_dtls_msg *msg)
366{
367
368 nss_tx_status_t status;
369 int ret = 0;
370
371 down(&dtls_pvt.sem);
372 dtls_pvt.cb = (void *)msg->cm.cb;
373 dtls_pvt.app_data = (void *)msg->cm.app_data;
374
375 msg->cm.cb = (uint32_t)nss_dtls_callback;
376 msg->cm.app_data = (uint32_t)NULL;
377
378 status = nss_dtls_tx_msg(nss_ctx, msg);
379 if (status != NSS_TX_SUCCESS) {
380 nss_warning("%p: dtls_tx_msg failed\n", nss_ctx);
381 up(&dtls_pvt.sem);
382 return status;
383 }
384
385 ret = wait_for_completion_timeout(&dtls_pvt.complete, msecs_to_jiffies(NSS_DTLS_TX_TIMEOUT));
386
387 if (!ret) {
388 nss_warning("%p: DTLS msg tx failed due to timeout\n", nss_ctx);
389 dtls_pvt.response = NSS_TX_FAILURE;
390 }
391
392 status = dtls_pvt.response;
393 up(&dtls_pvt.sem);
394 return status;
395}
396EXPORT_SYMBOL(nss_dtls_tx_msg_sync);
397
398/*
399 ***********************************
400 * Register/Unregister/Miscellaneous APIs
401 ***********************************
402 */
403
404/*
405 * nss_dtls_register_if()
406 */
407struct nss_ctx_instance *nss_dtls_register_if(uint32_t if_num,
408 nss_dtls_data_callback_t cb,
409 nss_dtls_msg_callback_t ev_cb,
410 struct net_device *netdev,
411 uint32_t features,
412 void *app_ctx)
413{
414 int32_t i;
415
416 struct nss_ctx_instance *nss_ctx = nss_dtls_get_context();
417
418 BUG_ON(!nss_dtls_verify_if_num(if_num));
419
420 spin_lock_bh(&nss_dtls_session_debug_stats_lock);
421 for (i = 0; i < NSS_MAX_DTLS_SESSIONS; i++) {
422 if (!nss_dtls_session_debug_stats[i].valid) {
423 nss_dtls_session_debug_stats[i].valid = true;
424 nss_dtls_session_debug_stats[i].if_num = if_num;
425 nss_dtls_session_debug_stats[i].if_index = netdev->ifindex;
426 break;
427 }
428 }
429 spin_unlock_bh(&nss_dtls_session_debug_stats_lock);
430
431 if (i == NSS_MAX_DTLS_SESSIONS) {
432 nss_warning("%p: Cannot find free slot for "
433 "DTLS session stats, I/F:%u\n", nss_ctx, if_num);
434 return NULL;
435 }
436
437 if (nss_top_main.subsys_dp_register[if_num].ndev) {
438 nss_warning("%p: Cannot find free slot for "
439 "DTLS NSS I/F:%u\n", nss_ctx, if_num);
440
441 return NULL;
442 }
443
444 nss_top_main.subsys_dp_register[if_num].ndev = netdev;
445 nss_top_main.subsys_dp_register[if_num].cb = cb;
446 nss_top_main.subsys_dp_register[if_num].app_data = app_ctx;
447 nss_top_main.subsys_dp_register[if_num].features = features;
448
449 nss_top_main.dtls_msg_callback = ev_cb;
450 nss_core_register_handler(if_num, nss_dtls_handler, app_ctx);
451
452 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.dtls_handler_id];
453}
454EXPORT_SYMBOL(nss_dtls_register_if);
455
456/*
457 * nss_dtls_unregister_if()
458 */
459void nss_dtls_unregister_if(uint32_t if_num)
460{
461 int32_t i;
462
463 struct nss_ctx_instance *nss_ctx = nss_dtls_get_context();
464
465 BUG_ON(!nss_dtls_verify_if_num(if_num));
466
467 spin_lock_bh(&nss_dtls_session_debug_stats_lock);
468 for (i = 0; i < NSS_MAX_DTLS_SESSIONS; i++) {
469 if (nss_dtls_session_debug_stats[i].if_num == if_num) {
470 memset(&nss_dtls_session_debug_stats[i], 0,
471 sizeof(struct nss_stats_dtls_session_debug));
472 break;
473 }
474 }
475 spin_unlock_bh(&nss_dtls_session_debug_stats_lock);
476
477 if (i == NSS_MAX_DTLS_SESSIONS) {
478 nss_warning("%p: Cannot find debug stats for "
479 "DTLS session %d\n", nss_ctx, if_num);
480 return;
481 }
482
483 if (!nss_top_main.subsys_dp_register[if_num].ndev) {
484 nss_warning("%p: Cannot find registered netdev for "
485 "DTLS NSS I/F:%u\n", nss_ctx, if_num);
486
487 return;
488 }
489
490 nss_top_main.subsys_dp_register[if_num].ndev = NULL;
491 nss_top_main.subsys_dp_register[if_num].cb = NULL;
492 nss_top_main.subsys_dp_register[if_num].app_data = NULL;
493 nss_top_main.subsys_dp_register[if_num].features = 0;
494
495 nss_top_main.dtls_msg_callback = NULL;
496 nss_core_unregister_handler(if_num);
497}
498EXPORT_SYMBOL(nss_dtls_unregister_if);
499
500/*
501 * nss_get_dtls_context()
502 */
503struct nss_ctx_instance *nss_dtls_get_context(void)
504{
505 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.dtls_handler_id];
506}
507EXPORT_SYMBOL(nss_dtls_get_context);
508
509/*
510 * nss_dtls_msg_init()
511 * Initialize nss_dtls msg.
512 */
513void nss_dtls_msg_init(struct nss_dtls_msg *ncm, uint16_t if_num,
514 uint32_t type, uint32_t len, void *cb, void *app_data)
515{
516 nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
517}
518EXPORT_SYMBOL(nss_dtls_msg_init);
519
520/*
521 * nss_dtls_get_ifnum_with_coreid()
522 */
523int32_t nss_dtls_get_ifnum_with_coreid(int32_t if_num)
524{
525 struct nss_ctx_instance *nss_ctx = nss_dtls_get_context();
526
527 NSS_VERIFY_CTX_MAGIC(nss_ctx);
528 return NSS_INTERFACE_NUM_APPEND_COREID(nss_ctx, if_num);
529}
530EXPORT_SYMBOL(nss_dtls_get_ifnum_with_coreid);
531
532/*
533 * nss_dtls_register_handler()
534 */
535void nss_dtls_register_handler(void)
536{
537 sema_init(&dtls_pvt.sem, 1);
538 init_completion(&dtls_pvt.complete);
539}