blob: b874b010ee0470f636b0694d1a44063ca0000e54 [file] [log] [blame]
ratheesh kannoth7af985d2015-06-24 15:08:40 +05301/*
2 **************************************************************************
Stephen Wang3e2dbd12018-03-14 17:28:17 -07003 * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
ratheesh kannoth7af985d2015-06-24 15:08:40 +05304 * 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 <linux/l2tp.h>
18#include <net/sock.h>
19#include "nss_tx_rx_common.h"
Yu Huang8c107082017-07-24 14:58:26 -070020#include "nss_l2tpv2_stats.h"
ratheesh kannoth7af985d2015-06-24 15:08:40 +053021
22/*
23 * Data structures to store l2tpv2 nss debug stats
24 */
25static DEFINE_SPINLOCK(nss_l2tpv2_session_debug_stats_lock);
Yu Huang8c107082017-07-24 14:58:26 -070026static struct nss_l2tpv2_stats_session_debug nss_l2tpv2_session_debug_stats[NSS_MAX_L2TPV2_DYNAMIC_INTERFACES];
ratheesh kannoth7af985d2015-06-24 15:08:40 +053027
28/*
29 * nss_l2tpv2_session_debug_stats_sync
30 * Per session debug stats for l2tpv2
31 */
32void nss_l2tpv2_session_debug_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_l2tpv2_sync_session_stats_msg *stats_msg, uint16_t if_num)
33{
34 int i;
35 spin_lock_bh(&nss_l2tpv2_session_debug_stats_lock);
36 for (i = 0; i < NSS_MAX_L2TPV2_DYNAMIC_INTERFACES; i++) {
37 if (nss_l2tpv2_session_debug_stats[i].if_num == if_num) {
Yu Huang8c107082017-07-24 14:58:26 -070038 nss_l2tpv2_session_debug_stats[i].stats[NSS_L2TPV2_STATS_SESSION_RX_PPP_LCP_PKTS] += stats_msg->debug_stats.rx_ppp_lcp_pkts;
39 nss_l2tpv2_session_debug_stats[i].stats[NSS_L2TPV2_STATS_SESSION_RX_EXP_DATA_PKTS] += stats_msg->debug_stats.rx_exception_data_pkts;
40 nss_l2tpv2_session_debug_stats[i].stats[NSS_L2TPV2_STATS_SESSION_ENCAP_PBUF_ALLOC_FAIL_PKTS] += stats_msg->debug_stats.encap_pbuf_alloc_fail;
41 nss_l2tpv2_session_debug_stats[i].stats[NSS_L2TPV2_STATS_SESSION_DECAP_PBUF_ALLOC_FAIL_PKTS] += stats_msg->debug_stats.decap_pbuf_alloc_fail;
ratheesh kannoth7af985d2015-06-24 15:08:40 +053042 break;
43 }
44 }
45 spin_unlock_bh(&nss_l2tpv2_session_debug_stats_lock);
46}
47
48/*
49 * nss_l2tpv2_global_session_stats_get()
50 * Get session l2tpv2 statitics.
51 */
52void nss_l2tpv2_session_debug_stats_get(void *stats_mem)
53{
Yu Huang8c107082017-07-24 14:58:26 -070054 struct nss_l2tpv2_stats_session_debug *stats = (struct nss_l2tpv2_stats_session_debug *)stats_mem;
ratheesh kannoth7af985d2015-06-24 15:08:40 +053055 int i;
56
57 if (!stats) {
58 nss_warning("No memory to copy l2tpv2 session stats");
59 return;
60 }
61
62 spin_lock_bh(&nss_l2tpv2_session_debug_stats_lock);
63 for (i = 0; i < NSS_MAX_L2TPV2_DYNAMIC_INTERFACES; i++) {
64 if (nss_l2tpv2_session_debug_stats[i].valid) {
Yu Huang8c107082017-07-24 14:58:26 -070065 memcpy(stats, &nss_l2tpv2_session_debug_stats[i], sizeof(struct nss_l2tpv2_stats_session_debug));
ratheesh kannoth7af985d2015-06-24 15:08:40 +053066 stats++;
67 }
68 }
69 spin_unlock_bh(&nss_l2tpv2_session_debug_stats_lock);
70}
71
72/*
73 * nss_l2tpv2_handler()
74 * Handle NSS -> HLOS messages for l2tpv2 tunnel
75 */
76
77static void nss_l2tpv2_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
78{
79 struct nss_l2tpv2_msg *ntm = (struct nss_l2tpv2_msg *)ncm;
80 void *ctx;
81
82 nss_l2tpv2_msg_callback_t cb;
83
84 BUG_ON(!(nss_is_dynamic_interface(ncm->interface) || ncm->interface == NSS_L2TPV2_INTERFACE));
85
86 /*
87 * Is this a valid request/response packet?
88 */
89 if (ncm->type >= NSS_L2TPV2_MSG_MAX) {
90 nss_warning("%p: received invalid message %d for L2TP interface", nss_ctx, ncm->type);
91 return;
92 }
93
Suruchi Agarwalef8a8702016-01-08 12:40:08 -080094 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_l2tpv2_msg)) {
95 nss_warning("%p: message length is invalid: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
ratheesh kannoth7af985d2015-06-24 15:08:40 +053096 return;
97 }
98
99 switch (ntm->cm.type) {
100
101 case NSS_L2TPV2_MSG_SYNC_STATS:
102 /*
103 * session debug stats embeded in session stats msg
104 */
105 nss_l2tpv2_session_debug_stats_sync(nss_ctx, &ntm->msg.stats, ncm->interface);
106 break;
107 }
108
109 /*
110 * Update the callback and app_data for NOTIFY messages, l2tpv2 sends all notify messages
111 * to the same callback/app_data.
112 */
Suruchi Agarwale4ad24a2018-06-11 12:03:46 +0530113 if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
Stephen Wangaed46332016-12-12 17:29:03 -0800114 ncm->cb = (nss_ptr_t)nss_ctx->nss_top->l2tpv2_msg_callback;
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530115 }
116
117 /*
118 * Log failures
119 */
120 nss_core_log_msg_failures(nss_ctx, ncm);
121
122 /*
123 * Do we have a call back
124 */
125 if (!ncm->cb) {
126 return;
127 }
128
129 /*
130 * callback
131 */
132 cb = (nss_l2tpv2_msg_callback_t)ncm->cb;
Stephen Wang84e0e992016-09-07 12:31:40 -0700133 ctx = nss_ctx->subsys_dp_register[ncm->interface].ndev;
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530134
135 /*
136 * call l2tpv2 tunnel callback
137 */
138 if (!ctx) {
139 nss_warning("%p: Event received for l2tpv2 tunnel interface %d before registration", nss_ctx, ncm->interface);
140 return;
141 }
142
143 cb(ctx, ntm);
144}
145
146/*
147 * nss_l2tpv2_tx()
148 * Transmit a l2tpv2 message to NSS firmware
149 */
150nss_tx_status_t nss_l2tpv2_tx(struct nss_ctx_instance *nss_ctx, struct nss_l2tpv2_msg *msg)
151{
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530152 struct nss_cmn_msg *ncm = &msg->cm;
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530153
154 /*
155 * Sanity check the message
156 */
157 if (!nss_is_dynamic_interface(ncm->interface)) {
158 nss_warning("%p: tx request for non dynamic interface: %d", nss_ctx, ncm->interface);
159 return NSS_TX_FAILURE;
160 }
161
162 if (ncm->type > NSS_L2TPV2_MSG_MAX) {
163 nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
164 return NSS_TX_FAILURE;
165 }
166
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700167 return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530168}
169
170/*
171 ***********************************
172 * Register/Unregister/Miscellaneous APIs
173 ***********************************
174 */
175
176/*
177 * nss_register_l2tpv2_if()
178 */
179struct nss_ctx_instance *nss_register_l2tpv2_if(uint32_t if_num, nss_l2tpv2_callback_t l2tpv2_callback,
180 nss_l2tpv2_msg_callback_t event_callback, struct net_device *netdev, uint32_t features)
181{
Stephen Wang84e0e992016-09-07 12:31:40 -0700182 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.l2tpv2_handler_id];
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530183 int i = 0;
Stephen Wang84e0e992016-09-07 12:31:40 -0700184
185 nss_assert(nss_ctx);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530186 nss_assert(nss_is_dynamic_interface(if_num));
187
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700188 nss_core_register_subsys_dp(nss_ctx, if_num, l2tpv2_callback, NULL, NULL, netdev, features);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530189
190 nss_top_main.l2tpv2_msg_callback = event_callback;
191
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700192 nss_core_register_handler(nss_ctx, if_num, nss_l2tpv2_handler, NULL);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530193
194 spin_lock_bh(&nss_l2tpv2_session_debug_stats_lock);
195 for (i = 0; i < NSS_MAX_L2TPV2_DYNAMIC_INTERFACES; i++) {
196 if (!nss_l2tpv2_session_debug_stats[i].valid) {
197 nss_l2tpv2_session_debug_stats[i].valid = true;
198 nss_l2tpv2_session_debug_stats[i].if_num = if_num;
199 nss_l2tpv2_session_debug_stats[i].if_index = netdev->ifindex;
200 break;
201 }
202 }
203 spin_unlock_bh(&nss_l2tpv2_session_debug_stats_lock);
204
Stephen Wang84e0e992016-09-07 12:31:40 -0700205 return nss_ctx;
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530206}
207
208/*
209 * nss_unregister_l2tpv2_if()
210 */
211void nss_unregister_l2tpv2_if(uint32_t if_num)
212{
Stephen Wang84e0e992016-09-07 12:31:40 -0700213 struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.l2tpv2_handler_id];
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530214 int i;
Stephen Wang84e0e992016-09-07 12:31:40 -0700215
216 nss_assert(nss_ctx);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530217 nss_assert(nss_is_dynamic_interface(if_num));
218
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700219 nss_core_unregister_subsys_dp(nss_ctx, if_num);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530220
221 nss_top_main.l2tpv2_msg_callback = NULL;
222
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700223 nss_core_unregister_handler(nss_ctx, if_num);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530224
225 spin_lock_bh(&nss_l2tpv2_session_debug_stats_lock);
226 for (i = 0; i < NSS_MAX_L2TPV2_DYNAMIC_INTERFACES; i++) {
227 if (nss_l2tpv2_session_debug_stats[i].if_num == if_num) {
Yu Huang8c107082017-07-24 14:58:26 -0700228 memset(&nss_l2tpv2_session_debug_stats[i], 0, sizeof(struct nss_l2tpv2_stats_session_debug));
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530229 break;
230 }
231 }
232 spin_unlock_bh(&nss_l2tpv2_session_debug_stats_lock);
233}
234
235/*
236 * nss_get_l2tpv2_context()
237 */
238struct nss_ctx_instance *nss_l2tpv2_get_context()
239{
240 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.l2tpv2_handler_id];
241}
242
243/*
244 * nss_l2tpv2_msg_init()
Yu Huang8c107082017-07-24 14:58:26 -0700245 * Initialize nss_l2tpv2 msg.
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530246 */
247void nss_l2tpv2_msg_init(struct nss_l2tpv2_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
248{
249 nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
250}
251
252/* nss_l2tpv2_register_handler()
253 * debugfs stats msg handler received on static l2tpv2 interface
254 */
255void nss_l2tpv2_register_handler(void)
256{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700257 struct nss_ctx_instance *nss_ctx = nss_l2tpv2_get_context();
258
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530259 nss_info("nss_l2tpv2_register_handler");
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700260 nss_core_register_handler(nss_ctx, NSS_L2TPV2_INTERFACE, nss_l2tpv2_handler, NULL);
Yu Huang8c107082017-07-24 14:58:26 -0700261
262 nss_l2tpv2_stats_dentry_create();
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530263}
264
265EXPORT_SYMBOL(nss_l2tpv2_get_context);
266EXPORT_SYMBOL(nss_l2tpv2_tx);
267EXPORT_SYMBOL(nss_unregister_l2tpv2_if);
268EXPORT_SYMBOL(nss_l2tpv2_msg_init);
269EXPORT_SYMBOL(nss_register_l2tpv2_if);