blob: 5a0c4b378bdf090f0d5d9c1a5bf1f20e84260388 [file] [log] [blame]
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +05301/*
2 **************************************************************************
Stephen Wang3e2dbd12018-03-14 17:28:17 -07003 * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +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/*
18 * nss_pppoe.c
19 * NSS PPPoE APIs
20 */
21
22#include "nss_tx_rx_common.h"
Yu Huang8c107082017-07-24 14:58:26 -070023#include "nss_pppoe_stats.h"
Sachin Shashidhar626131e2018-08-08 11:29:58 -070024#include "nss_pppoe_log.h"
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +053025
Murat Sezgin4abd88c2017-05-24 17:00:59 -070026#define NSS_PPPOE_TX_TIMEOUT 3000 /* 3 Seconds */
27
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +053028/*
Murat Sezgin4abd88c2017-05-24 17:00:59 -070029 * Data structures to store pppoe nss debug stats
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +053030 */
Murat Sezgin4abd88c2017-05-24 17:00:59 -070031static DEFINE_SPINLOCK(nss_pppoe_lock);
32static struct nss_pppoe_stats_session_debug nss_pppoe_debug_stats[NSS_MAX_PPPOE_DYNAMIC_INTERFACES];
33
34/*
35 * Private data structure
36 */
37static struct nss_pppoe_pvt {
38 struct semaphore sem;
39 struct completion complete;
40 int response;
41 void *cb;
42 void *app_data;
43} pppoe_pvt;
44
45/*
46 * nss_pppoe_debug_stats_sync
47 * Per session debug stats for pppoe
48 */
49static void nss_pppoe_debug_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_pppoe_sync_stats_msg *stats_msg, uint16_t if_num)
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +053050{
Murat Sezgin4abd88c2017-05-24 17:00:59 -070051 int i;
52 spin_lock_bh(&nss_pppoe_lock);
53 for (i = 0; i < NSS_MAX_PPPOE_DYNAMIC_INTERFACES; i++) {
54 if (nss_pppoe_debug_stats[i].if_num == if_num) {
55 nss_pppoe_debug_stats[i].stats[NSS_PPPOE_STATS_RX_PACKETS] += stats_msg->stats.rx_packets;
56 nss_pppoe_debug_stats[i].stats[NSS_PPPOE_STATS_RX_BYTES] += stats_msg->stats.rx_bytes;
57 nss_pppoe_debug_stats[i].stats[NSS_PPPOE_STATS_TX_PACKETS] += stats_msg->stats.tx_packets;
58 nss_pppoe_debug_stats[i].stats[NSS_PPPOE_STATS_TX_BYTES] += stats_msg->stats.tx_bytes;
59 nss_pppoe_debug_stats[i].stats[NSS_PPPOE_STATS_SESSION_WRONG_VERSION_OR_TYPE] += stats_msg->exception_events[NSS_PPPOE_EXCEPTION_EVENT_WRONG_VERSION_OR_TYPE];
60 nss_pppoe_debug_stats[i].stats[NSS_PPPOE_STATS_SESSION_WRONG_CODE] += stats_msg->exception_events[NSS_PPPOE_EXCEPTION_EVENT_WRONG_CODE];
61 nss_pppoe_debug_stats[i].stats[NSS_PPPOE_STATS_SESSION_UNSUPPORTED_PPP_PROTOCOL] += stats_msg->exception_events[NSS_PPPOE_EXCEPTION_EVENT_UNSUPPORTED_PPP_PROTOCOL];
62 break;
63 }
64 }
65 spin_unlock_bh(&nss_pppoe_lock);
66}
67/*
68 * nss_pppoe_get_context()
69 */
70struct nss_ctx_instance *nss_pppoe_get_context(void)
71{
72 return (struct nss_ctx_instance *)&nss_top_main.nss[nss_top_main.pppoe_handler_id];
73}
74EXPORT_SYMBOL(nss_pppoe_get_context);
75
76/*
77 * nss_pppoe_tx_msg()
78 * Transmit a PPPoE message to NSS firmware
79 */
80static nss_tx_status_t nss_pppoe_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_pppoe_msg *msg)
81{
82 struct nss_cmn_msg *ncm = &msg->cm;
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +053083
84 /*
Sachin Shashidhar626131e2018-08-08 11:29:58 -070085 * Trace Messages
86 */
87 nss_pppoe_log_tx_msg(msg);
88
89 /*
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +053090 * Sanity check the message
91 */
Murat Sezgin4abd88c2017-05-24 17:00:59 -070092 if (!nss_is_dynamic_interface(ncm->interface)) {
93 nss_warning("%p: tx request for non dynamic interface: %d\n", nss_ctx, ncm->interface);
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +053094 return NSS_TX_FAILURE;
95 }
96
Murat Sezgin4abd88c2017-05-24 17:00:59 -070097 if (nss_dynamic_interface_get_type(nss_pppoe_get_context(), ncm->interface) != NSS_DYNAMIC_INTERFACE_TYPE_PPPOE) {
98 nss_warning("%p: tx request for not PPPoE interface: %d\n", nss_ctx, ncm->interface);
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +053099 return NSS_TX_FAILURE;
100 }
101
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700102 if (ncm->type >= NSS_PPPOE_MSG_MAX) {
103 nss_warning("%p: message type out of range: %d\n", nss_ctx, ncm->type);
104 return NSS_TX_FAILURE;
105 }
106
107 return nss_core_send_cmd(nss_ctx, msg, sizeof(*msg), NSS_NBUF_PAYLOAD_SIZE);
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530108}
109
110/*
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700111 * nss_pppoe_sync_msg_callback()
112 * Callback to handle the completion of NSS->HLOS messages.
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530113 */
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700114static void nss_pppoe_sync_msg_callback(void *app_data, struct nss_pppoe_msg *npm)
115{
116 nss_pppoe_msg_callback_t callback = (nss_pppoe_msg_callback_t)pppoe_pvt.cb;
117 void *data = pppoe_pvt.app_data;
118
119 pppoe_pvt.cb = NULL;
120 pppoe_pvt.app_data = NULL;
121
122 pppoe_pvt.response = NSS_TX_SUCCESS;
123 if (npm->cm.response != NSS_CMN_RESPONSE_ACK) {
124 nss_warning("pppoe Error response %d\n", npm->cm.response);
125 pppoe_pvt.response = NSS_TX_FAILURE;
126 }
127
128 if (callback) {
129 callback(data, npm);
130 }
131
132 complete(&pppoe_pvt.complete);
133}
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530134
135/*
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700136 * nss_pppoe_handler()
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530137 * Handle NSS -> HLOS messages for PPPoE
138 */
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700139static void nss_pppoe_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530140{
141 struct nss_pppoe_msg *nim = (struct nss_pppoe_msg *)ncm;
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700142 void *ctx;
143 nss_pppoe_msg_callback_t cb;
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530144
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700145 BUG_ON(!(nss_is_dynamic_interface(ncm->interface) || ncm->interface == NSS_PPPOE_INTERFACE));
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530146
147 /*
Sachin Shashidhar626131e2018-08-08 11:29:58 -0700148 * Trace Messages
149 */
150 nss_pppoe_log_rx_msg(nim);
151
152 /*
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530153 * Sanity check the message type
154 */
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700155 if (ncm->type >= NSS_PPPOE_MSG_MAX) {
156 nss_warning("%p: message type out of range: %d\n", nss_ctx, ncm->type);
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530157 return;
158 }
159
Suruchi Agarwalef8a8702016-01-08 12:40:08 -0800160 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_pppoe_msg)) {
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700161 nss_warning("%p: message length is invalid: %d\n", nss_ctx, nss_cmn_get_msg_len(ncm));
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530162 return;
163 }
164
165 /*
166 * Log failures
167 */
168 nss_core_log_msg_failures(nss_ctx, ncm);
169
170 /*
171 * Handling PPPoE messages coming from NSS fw.
172 */
173 switch (nim->cm.type) {
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700174 case NSS_PPPOE_MSG_SYNC_STATS:
175 nss_pppoe_debug_stats_sync(nss_ctx, &nim->msg.sync_stats, ncm->interface);
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530176 break;
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530177 default:
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700178 nss_warning("%p: Received response %d for type %d, interface %d\n",
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530179 nss_ctx, ncm->response, ncm->type, ncm->interface);
180 }
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700181
182 /*
183 * Update the callback and app_data for NOTIFY messages, pppoe sends all notify messages
184 * to the same callback/app_data.
185 */
186 if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
187 ncm->cb = (nss_ptr_t)nss_ctx->nss_top->pppoe_msg_callback;
188 ncm->app_data = (nss_ptr_t)nss_ctx->subsys_dp_register[ncm->interface].app_data;
189 }
190
191 /*
192 * Log failures
193 */
194 nss_core_log_msg_failures(nss_ctx, ncm);
195
196 /*
197 * Do we have a call back
198 */
199 if (!ncm->cb) {
200 return;
201 }
202
203 /*
204 * callback
205 */
206 cb = (nss_pppoe_msg_callback_t)ncm->cb;
207 ctx = (void *)ncm->app_data;
208
209 cb(ctx, nim);
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530210}
211
212/*
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700213 * nss_pppoe_debug_stats_get()
214 * Get session pppoe statistics.
215 */
216void nss_pppoe_debug_stats_get(void *stats_mem)
217{
218 struct nss_pppoe_stats_session_debug *stats = (struct nss_pppoe_stats_session_debug *)stats_mem;
219 int i;
220
221 if (!stats) {
222 nss_warning("No memory to copy pppoe session stats\n");
223 return;
224 }
225
226 spin_lock_bh(&nss_pppoe_lock);
227 for (i = 0; i < NSS_MAX_PPPOE_DYNAMIC_INTERFACES; i++) {
228 if (nss_pppoe_debug_stats[i].valid) {
229 memcpy(stats, &nss_pppoe_debug_stats[i], sizeof(struct nss_pppoe_stats_session_debug));
230 stats++;
231 }
232 }
233 spin_unlock_bh(&nss_pppoe_lock);
234}
235
236/*
237 * nss_pppoe_tx_msg_sync()
238 */
239nss_tx_status_t nss_pppoe_tx_msg_sync(struct nss_ctx_instance *nss_ctx,
240 struct nss_pppoe_msg *msg)
241{
242 nss_tx_status_t status;
243 int ret = 0;
244
245 down(&pppoe_pvt.sem);
246 pppoe_pvt.cb = (void *)msg->cm.cb;
247 pppoe_pvt.app_data = (void *)msg->cm.app_data;
248
249 msg->cm.cb = (nss_ptr_t)nss_pppoe_sync_msg_callback;
250 msg->cm.app_data = (nss_ptr_t)NULL;
251
252 status = nss_pppoe_tx_msg(nss_ctx, msg);
253 if (status != NSS_TX_SUCCESS) {
254 nss_warning("%p: nss_pppoe_tx_msg failed\n", nss_ctx);
255 up(&pppoe_pvt.sem);
256 return status;
257 }
258
259 ret = wait_for_completion_timeout(&pppoe_pvt.complete, msecs_to_jiffies(NSS_PPPOE_TX_TIMEOUT));
260 if (!ret) {
261 nss_warning("%p: PPPoE msg tx failed due to timeout\n", nss_ctx);
262 pppoe_pvt.response = NSS_TX_FAILURE;
263 }
264
265 status = pppoe_pvt.response;
266 up(&pppoe_pvt.sem);
267 return status;
268}
269EXPORT_SYMBOL(nss_pppoe_tx_msg_sync);
270
271/*
272 * nss_register_pppoe_session_if()
273 */
274struct nss_ctx_instance *nss_register_pppoe_session_if(uint32_t if_num,
275 nss_pppoe_msg_callback_t notification_callback,
276 struct net_device *netdev, uint32_t features, void *app_ctx)
277{
278 struct nss_ctx_instance *nss_ctx = nss_pppoe_get_context();
279 int i = 0;
280
281 nss_assert(nss_ctx);
282 nss_assert(nss_is_dynamic_interface(if_num));
283
284 spin_lock_bh(&nss_pppoe_lock);
285 for (i = 0; i < NSS_MAX_PPPOE_DYNAMIC_INTERFACES; i++) {
286 if (!nss_pppoe_debug_stats[i].valid) {
287 nss_pppoe_debug_stats[i].valid = true;
288 nss_pppoe_debug_stats[i].if_num = if_num;
289 nss_pppoe_debug_stats[i].if_index = netdev->ifindex;
290 break;
291 }
292 }
293 spin_unlock_bh(&nss_pppoe_lock);
294
295 if (i == NSS_MAX_PPPOE_DYNAMIC_INTERFACES) {
296 return NULL;
297 }
298
299 nss_core_register_subsys_dp(nss_ctx, if_num, NULL, NULL, app_ctx, netdev, features);
300
301 nss_top_main.pppoe_msg_callback = notification_callback;
302
303 nss_core_register_handler(nss_ctx, if_num, nss_pppoe_handler, NULL);
304
305 return nss_ctx;
306}
307EXPORT_SYMBOL(nss_register_pppoe_session_if);
308
309/*
310 * nss_unregister_pppoe_session_if()
311 */
312void nss_unregister_pppoe_session_if(uint32_t if_num)
313{
314 struct nss_ctx_instance *nss_ctx = nss_pppoe_get_context();
315 int i;
316
317 nss_assert(nss_ctx);
318 nss_assert(nss_is_dynamic_interface(if_num));
319
320 spin_lock_bh(&nss_pppoe_lock);
321 for (i = 0; i < NSS_MAX_PPPOE_DYNAMIC_INTERFACES; i++) {
322 if (nss_pppoe_debug_stats[i].if_num == if_num) {
323 nss_pppoe_debug_stats[i].valid = false;
324 nss_pppoe_debug_stats[i].if_num = 0;
325 nss_pppoe_debug_stats[i].if_index = 0;
326 }
327 }
328 spin_unlock_bh(&nss_pppoe_lock);
329
330 nss_core_unregister_subsys_dp(nss_ctx, if_num);
331
332 nss_top_main.pppoe_msg_callback = NULL;
333
334 nss_core_unregister_handler(nss_ctx, if_num);
335
336}
337EXPORT_SYMBOL(nss_unregister_pppoe_session_if);
338
339/*
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530340 * nss_pppoe_register_handler()
341 */
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700342void nss_pppoe_register_handler(void)
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530343{
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700344 int i;
345
346 nss_info("nss_pppoe_register_handler\n");
347 nss_core_register_handler(nss_pppoe_get_context(), NSS_PPPOE_INTERFACE, nss_pppoe_handler, NULL);
348
349 spin_lock_bh(&nss_pppoe_lock);
350 for (i = 0; i < NSS_MAX_PPPOE_DYNAMIC_INTERFACES; i++) {
351 nss_pppoe_debug_stats[i].valid = false;
352 nss_pppoe_debug_stats[i].if_num = 0;
353 nss_pppoe_debug_stats[i].if_index = 0;
354 }
355 spin_unlock_bh(&nss_pppoe_lock);
356
357 sema_init(&pppoe_pvt.sem, 1);
358 init_completion(&pppoe_pvt.complete);
Yu Huang8c107082017-07-24 14:58:26 -0700359
360 nss_pppoe_stats_dentry_create();
Ankit Dhanukaa1569ce2014-05-13 19:58:06 +0530361}
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700362
363/*
364 * nss_pppoe_msg_init()
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700365 */
366void nss_pppoe_msg_init(struct nss_pppoe_msg *npm, uint16_t if_num, uint32_t type, uint32_t len,
Thomas Wu91f4bdf2017-06-09 12:03:02 -0700367 void *cb, void *app_data)
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700368{
369 nss_cmn_msg_init(&npm->cm, if_num, type, len, (void *)cb, app_data);
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700370
Sundarajan Srinivasan02e6c2b2014-10-06 11:51:12 -0700371}
Murat Sezgin4abd88c2017-05-24 17:00:59 -0700372EXPORT_SYMBOL(nss_pppoe_msg_init);