blob: af39b9d6ae4629e57154e52ce8ddde401feb4578 [file] [log] [blame]
ratheesh kannoth7af985d2015-06-24 15:08:40 +05301/*
2 **************************************************************************
Stephen Wangaed46332016-12-12 17:29:03 -08003 * Copyright (c) 2015-2017, 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 */
113 if (ncm->response == NSS_CMM_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{
152 struct nss_l2tpv2_msg *nm;
153 struct nss_cmn_msg *ncm = &msg->cm;
154 struct sk_buff *nbuf;
155 int32_t status;
156
157 NSS_VERIFY_CTX_MAGIC(nss_ctx);
158 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
159 nss_warning("%p: l2tpv2 msg dropped as core not ready", nss_ctx);
160 return NSS_TX_FAILURE_NOT_READY;
161 }
162
163 /*
164 * Sanity check the message
165 */
166 if (!nss_is_dynamic_interface(ncm->interface)) {
167 nss_warning("%p: tx request for non dynamic interface: %d", nss_ctx, ncm->interface);
168 return NSS_TX_FAILURE;
169 }
170
171 if (ncm->type > NSS_L2TPV2_MSG_MAX) {
172 nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
173 return NSS_TX_FAILURE;
174 }
175
Suruchi Agarwalef8a8702016-01-08 12:40:08 -0800176 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_l2tpv2_msg)) {
177 nss_warning("%p: message length is invalid: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530178 return NSS_TX_FAILURE;
179 }
180
181 nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
182 if (unlikely(!nbuf)) {
183 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]);
184 nss_warning("%p: msg dropped as command allocation failed", nss_ctx);
185 return NSS_TX_FAILURE;
186 }
187
188 /*
189 * Copy the message to our skb
190 */
191 nm = (struct nss_l2tpv2_msg *)skb_put(nbuf, sizeof(struct nss_l2tpv2_msg));
192 memcpy(nm, msg, sizeof(struct nss_l2tpv2_msg));
193
194 status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
195 if (status != NSS_CORE_STATUS_SUCCESS) {
196 dev_kfree_skb_any(nbuf);
197 nss_warning("%p: Unable to enqueue 'l2tpv2 message'\n", nss_ctx);
198 if (status == NSS_CORE_STATUS_FAILURE_QUEUE) {
199 return NSS_TX_FAILURE_QUEUE;
200 }
201 return NSS_TX_FAILURE;
202 }
203
Stephen Wang90c67de2016-04-26 15:15:59 -0700204 nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530205
206 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
207 return NSS_TX_SUCCESS;
208}
209
210/*
211 ***********************************
212 * Register/Unregister/Miscellaneous APIs
213 ***********************************
214 */
215
216/*
217 * nss_register_l2tpv2_if()
218 */
219struct nss_ctx_instance *nss_register_l2tpv2_if(uint32_t if_num, nss_l2tpv2_callback_t l2tpv2_callback,
220 nss_l2tpv2_msg_callback_t event_callback, struct net_device *netdev, uint32_t features)
221{
Stephen Wang84e0e992016-09-07 12:31:40 -0700222 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 +0530223 int i = 0;
Stephen Wang84e0e992016-09-07 12:31:40 -0700224
225 nss_assert(nss_ctx);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530226 nss_assert(nss_is_dynamic_interface(if_num));
227
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700228 nss_core_register_subsys_dp(nss_ctx, if_num, l2tpv2_callback, NULL, NULL, netdev, features);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530229
230 nss_top_main.l2tpv2_msg_callback = event_callback;
231
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700232 nss_core_register_handler(nss_ctx, if_num, nss_l2tpv2_handler, NULL);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530233
234 spin_lock_bh(&nss_l2tpv2_session_debug_stats_lock);
235 for (i = 0; i < NSS_MAX_L2TPV2_DYNAMIC_INTERFACES; i++) {
236 if (!nss_l2tpv2_session_debug_stats[i].valid) {
237 nss_l2tpv2_session_debug_stats[i].valid = true;
238 nss_l2tpv2_session_debug_stats[i].if_num = if_num;
239 nss_l2tpv2_session_debug_stats[i].if_index = netdev->ifindex;
240 break;
241 }
242 }
243 spin_unlock_bh(&nss_l2tpv2_session_debug_stats_lock);
244
Stephen Wang84e0e992016-09-07 12:31:40 -0700245 return nss_ctx;
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530246}
247
248/*
249 * nss_unregister_l2tpv2_if()
250 */
251void nss_unregister_l2tpv2_if(uint32_t if_num)
252{
Stephen Wang84e0e992016-09-07 12:31:40 -0700253 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 +0530254 int i;
Stephen Wang84e0e992016-09-07 12:31:40 -0700255
256 nss_assert(nss_ctx);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530257 nss_assert(nss_is_dynamic_interface(if_num));
258
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700259 nss_core_unregister_subsys_dp(nss_ctx, if_num);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530260
261 nss_top_main.l2tpv2_msg_callback = NULL;
262
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700263 nss_core_unregister_handler(nss_ctx, if_num);
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530264
265 spin_lock_bh(&nss_l2tpv2_session_debug_stats_lock);
266 for (i = 0; i < NSS_MAX_L2TPV2_DYNAMIC_INTERFACES; i++) {
267 if (nss_l2tpv2_session_debug_stats[i].if_num == if_num) {
Yu Huang8c107082017-07-24 14:58:26 -0700268 memset(&nss_l2tpv2_session_debug_stats[i], 0, sizeof(struct nss_l2tpv2_stats_session_debug));
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530269 break;
270 }
271 }
272 spin_unlock_bh(&nss_l2tpv2_session_debug_stats_lock);
273}
274
275/*
276 * nss_get_l2tpv2_context()
277 */
278struct nss_ctx_instance *nss_l2tpv2_get_context()
279{
280 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.l2tpv2_handler_id];
281}
282
283/*
284 * nss_l2tpv2_msg_init()
Yu Huang8c107082017-07-24 14:58:26 -0700285 * Initialize nss_l2tpv2 msg.
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530286 */
287void nss_l2tpv2_msg_init(struct nss_l2tpv2_msg *ncm, uint16_t if_num, uint32_t type, uint32_t len, void *cb, void *app_data)
288{
289 nss_cmn_msg_init(&ncm->cm, if_num, type, len, cb, app_data);
290}
291
292/* nss_l2tpv2_register_handler()
293 * debugfs stats msg handler received on static l2tpv2 interface
294 */
295void nss_l2tpv2_register_handler(void)
296{
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700297 struct nss_ctx_instance *nss_ctx = nss_l2tpv2_get_context();
298
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530299 nss_info("nss_l2tpv2_register_handler");
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700300 nss_core_register_handler(nss_ctx, NSS_L2TPV2_INTERFACE, nss_l2tpv2_handler, NULL);
Yu Huang8c107082017-07-24 14:58:26 -0700301
302 nss_l2tpv2_stats_dentry_create();
ratheesh kannoth7af985d2015-06-24 15:08:40 +0530303}
304
305EXPORT_SYMBOL(nss_l2tpv2_get_context);
306EXPORT_SYMBOL(nss_l2tpv2_tx);
307EXPORT_SYMBOL(nss_unregister_l2tpv2_if);
308EXPORT_SYMBOL(nss_l2tpv2_msg_init);
309EXPORT_SYMBOL(nss_register_l2tpv2_if);