blob: bb951a5a66724537f8cb239f2d013659be7a9c1d [file] [log] [blame]
Samarjeet Banerjeed99d9d02014-04-08 18:51:00 +05301/*
2 **************************************************************************
3 * Copyright (c) 2013 - 2014, 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/*
18 * nss_ipsec.c
19 * NSS IPsec APIs
20 */
21
22#include "nss_tx_rx_common.h"
Murat Sezginea1a4352014-04-15 19:09:51 -070023#include "nss_ipsec.h"
Samarjeet Banerjeed99d9d02014-04-08 18:51:00 +053024
25/*
26 **********************************
27 General APIs
28 **********************************
29 */
30
31#define nss_ipsec_warning(fmt, arg...) nss_warning("IPsec:"fmt, ##arg)
32#define nss_ipsec_info(fmt, arg...) nss_info("IPsec:"fmt, ##arg)
33#define nss_ipsec_trace(fmt, arg...) nss_trace("IPsec:"fmt, ##arg)
34
35/*
36 * nss_ipsec_set_msg_callback()
37 * this sets the message callback handler and its associated context
38 */
39static inline nss_tx_status_t nss_ipsec_set_msg_callback(struct nss_ctx_instance *nss_ctx, uint32_t if_num,
40 nss_ipsec_msg_callback_t cb, void *ipsec_ctx)
41{
42 struct nss_top_instance *nss_top;
43
44 nss_top = nss_ctx->nss_top;
45
46 switch (if_num) {
47 case NSS_IPSEC_ENCAP_IF_NUMBER:
48 nss_top->ipsec_encap_ctx = ipsec_ctx;
49 nss_top->ipsec_encap_callback = cb;
50
51 case NSS_IPSEC_DECAP_IF_NUMBER:
52 nss_top->ipsec_decap_ctx = ipsec_ctx;
53 nss_top->ipsec_decap_callback = cb;
54
55 default:
56 nss_ipsec_warning("%p: cannot 'set' message callback, incorrect I/F: %d", nss_ctx, if_num);
57 return NSS_TX_FAILURE;
58 }
59
60 return NSS_TX_SUCCESS;
61}
62
63/*
64 * nss_ipsec_get_msg_callback()
65 * this gets the message callback handler and its associated context
66 */
67static inline nss_ipsec_msg_callback_t nss_ipsec_get_msg_callback(struct nss_ctx_instance *nss_ctx, uint32_t if_num, void **ipsec_ctx)
68{
69 struct nss_top_instance *nss_top;
70
71 nss_top = nss_ctx->nss_top;
72
73 switch (if_num) {
74 case NSS_IPSEC_ENCAP_IF_NUMBER:
75 *ipsec_ctx = nss_top->ipsec_encap_ctx;
76 return nss_top->ipsec_encap_callback;
77
78 case NSS_IPSEC_DECAP_IF_NUMBER:
79 *ipsec_ctx = nss_top->ipsec_decap_ctx;
80 return nss_top->ipsec_decap_callback;
81
82 default:
83 *ipsec_ctx = NULL;
84 nss_ipsec_warning("%p: cannot 'get' message callback, incorrect I/F: %d", nss_ctx, if_num);
85 return NULL;
86 }
87}
88
89/*
90 **********************************
91 Rx APIs
92 **********************************
93 */
94
95/*
96 * nss_ipsec_msg_handler()
97 * this handles all the IPsec events and responses
98 */
99static void nss_ipsec_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, void *app_data __attribute((unused)))
100{
101 struct nss_ipsec_msg *nim = (struct nss_ipsec_msg *)ncm;
102 nss_ipsec_msg_callback_t cb = NULL;
103 uint32_t if_num = ncm->interface;
104 void *ipsec_ctx;
105
106 /*
107 * Sanity check the message type
108 */
109 if (ncm->type > NSS_IPSEC_MSG_TYPE_MAX) {
110 nss_ipsec_warning("%p: rx message type out of range: %d", nss_ctx, ncm->type);
111 return;
112 }
113
114 if (ncm->len > sizeof(struct nss_ipsec_msg)) {
115 nss_ipsec_warning("%p: rx request for another interface: %d", nss_ctx, ncm->interface);
116 return;
117 }
118
119 if ((ncm->interface != NSS_IPSEC_ENCAP_IF_NUMBER) && (ncm->interface != NSS_IPSEC_DECAP_IF_NUMBER)) {
120 nss_ipsec_warning("%p: rx message request for another interface: %d", nss_ctx, ncm->interface);
121 return;
122 }
123
124 if (ncm->response == NSS_CMN_RESPONSE_LAST) {
125 nss_ipsec_warning("%p: rx message response for if %d, type %d, is invalid: %d", nss_ctx, ncm->interface,
126 ncm->type, ncm->response);
127 return;
128 }
129
130 /*
131 * Is this a notification? if, yes then fill up the callback and app_data from
132 * locally stored state
133 */
134 if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) {
135 ncm->cb = (uint32_t)nss_ipsec_get_msg_callback(nss_ctx, if_num, &ipsec_ctx);
136 ncm->app_data = (uint32_t)ipsec_ctx;
137 }
138
139
140 nss_core_log_msg_failures(nss_ctx, ncm);
141
142 /*
143 * load, test & call
144 */
145 cb = (nss_ipsec_msg_callback_t)ncm->cb;
146 if (unlikely(!cb)) {
147 nss_ipsec_trace("%p: rx handler has been unregistered for i/f: %d", nss_ctx, ncm->interface);
148 return;
149 }
150 cb((void *)ncm->app_data, nim);
151}
152
153/*
154 **********************************
155 Tx APIs
156 **********************************
157 */
158
159/*
160 * nss_ipsec_tx_msg
161 * Send ipsec rule to NSS.
162 */
163nss_tx_status_t nss_ipsec_tx_msg(struct nss_ctx_instance *nss_ctx, struct nss_ipsec_msg *msg)
164{
165 struct nss_cmn_msg *ncm = &msg->cm;
166 struct nss_ipsec_msg *nim;
167 struct sk_buff *nbuf;
168 int32_t status;
169
170 nss_ipsec_info("%p: message %d for if %d\n", nss_ctx, ncm->type, ncm->interface);
171
172 NSS_VERIFY_CTX_MAGIC(nss_ctx);
173
174 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
175 nss_ipsec_warning("%p: tx message dropped as core not ready", nss_ctx);
176 return NSS_TX_FAILURE_NOT_READY;
177 }
178
179 if (NSS_NBUF_PAYLOAD_SIZE < sizeof(struct nss_ipsec_msg)) {
180 nss_ipsec_warning("%p: tx message request is too large: %d (desired), %d (requested)", nss_ctx,
181 NSS_NBUF_PAYLOAD_SIZE, sizeof(struct nss_ipsec_msg));
182 return NSS_TX_FAILURE_TOO_LARGE;
183 }
184
185 if ((ncm->interface != NSS_IPSEC_ENCAP_IF_NUMBER) && (ncm->interface != NSS_IPSEC_DECAP_IF_NUMBER)) {
186 nss_ipsec_warning("%p: tx message request for another interface: %d", nss_ctx, ncm->interface);
187 return NSS_TX_FAILURE;
188 }
189
190 if (ncm->type > NSS_IPSEC_MSG_TYPE_MAX) {
191 nss_ipsec_warning("%p: tx message type out of range: %d", nss_ctx, ncm->type);
192 return NSS_TX_FAILURE;
193 }
194
195 if (ncm->len > sizeof(struct nss_ipsec_msg)) {
196 nss_ipsec_warning("%p: tx message request len for if %d, is bad: %d", nss_ctx, ncm->interface, ncm->len);
197 return NSS_TX_FAILURE_BAD_PARAM;
198 }
199
200 nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
201 if (unlikely(!nbuf)) {
202 spin_lock_bh(&nss_ctx->nss_top->stats_lock);
203 nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]++;
204 spin_unlock_bh(&nss_ctx->nss_top->stats_lock);
205 nss_ipsec_warning("%p: tx rule dropped as command allocation failed", nss_ctx);
206 return NSS_TX_FAILURE;
207 }
208
209 nim = (struct nss_ipsec_msg *)skb_put(nbuf, sizeof(struct nss_ipsec_msg));
210 memcpy(nim, msg, sizeof(struct nss_ipsec_msg));
211
212 status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
213 if (status != NSS_CORE_STATUS_SUCCESS) {
214 dev_kfree_skb_any(nbuf);
215 nss_ipsec_warning("%p: tx Unable to enqueue message \n", nss_ctx);
216 return NSS_TX_FAILURE;
217 }
218
219 nss_hal_send_interrupt(nss_ctx->nmap, nss_ctx->h2n_desc_rings[NSS_IF_CMD_QUEUE].desc_ring.int_bit,
220 NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE);
221
222 return NSS_TX_SUCCESS;
223}
224
225/*
226 **********************************
227 Register APIs
228 **********************************
229 */
230
231/*
232 * nss_ipsec_msg_notify_register()
233 * register message notifier for the given interface (if_num)
234 */
235struct nss_ctx_instance *nss_ipsec_notify_register(uint32_t if_num, nss_ipsec_msg_callback_t cb, void *app_data)
236{
237 struct nss_ctx_instance *nss_ctx;
238
239 nss_ctx = &nss_top_main.nss[nss_top_main.ipsec_handler_id];
240
241 if (if_num >= NSS_MAX_NET_INTERFACES) {
242 nss_ipsec_warning("%p: notfiy register received for invalid interface %d", nss_ctx, if_num);
243 return NULL;
244 }
245
246 if (nss_ipsec_set_msg_callback(nss_ctx, if_num, cb, app_data) != NSS_TX_SUCCESS) {
247 nss_ipsec_warning("%p: register failed\n", nss_ctx);
248 return NULL;
249 }
250
251 return nss_ctx;
252}
253
254/*
255 * nss_ipsec_msg_notify_unregister()
256 * unregister the IPsec notifier for the given interface number (if_num)
257 */
258void nss_ipsec_notify_unregister(struct nss_ctx_instance *nss_ctx, uint32_t if_num)
259{
260 if (if_num >= NSS_MAX_NET_INTERFACES) {
261 nss_ipsec_warning("%p: notify unregister received for invalid interface %d", nss_ctx, if_num);
262 return;
263 }
264
265 if (nss_ipsec_set_msg_callback(nss_ctx, if_num, NULL, NULL) != NSS_TX_SUCCESS) {
266 nss_ipsec_warning("%p: unregister failed\n", nss_ctx);
267 return;
268 }
269}
270
271/*
272 * nss_ipsec_data_notify_register()
273 * register a data callback routine
274 */
275struct nss_ctx_instance *nss_ipsec_data_register(uint32_t if_num, nss_ipsec_buf_callback_t cb, void *app_data)
276{
277 struct nss_ctx_instance *nss_ctx;
278
279 nss_ctx = &nss_top_main.nss[nss_top_main.ipsec_handler_id];
280
281 if ((if_num >= NSS_MAX_NET_INTERFACES) && (if_num < NSS_MAX_PHYSICAL_INTERFACES)){
282 nss_ipsec_warning("%p: data register received for invalid interface %d", nss_ctx, if_num);
283 return NULL;
284 }
285
286 nss_ctx->nss_top->if_ctx[if_num] = app_data;
287 nss_ctx->nss_top->if_rx_callback[if_num] = cb;
288
289 return nss_ctx;
290}
291
292/*
293 * nss_ipsec_data_notify_unregister()
294 * unregister a data callback routine
295 */
296void nss_ipsec_data_unregister(struct nss_ctx_instance *nss_ctx, uint32_t if_num)
297{
298 if ((if_num >= NSS_MAX_NET_INTERFACES) && (if_num < NSS_MAX_PHYSICAL_INTERFACES)){
299 nss_ipsec_warning("%p: data unregister received for invalid interface %d", nss_ctx, if_num);
300 return;
301 }
302
303 nss_ctx->nss_top->if_ctx[if_num] = NULL;
304 nss_ctx->nss_top->if_rx_callback[if_num] = NULL;
305}
306
307/*
308 * nss_ipsec_register_handler()
309 */
310void nss_ipsec_register_handler()
311{
312 struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.ipsec_handler_id];
313
314 nss_ipsec_set_msg_callback(nss_ctx, NSS_IPSEC_ENCAP_IF_NUMBER, NULL, NULL);
315 nss_core_register_handler(NSS_IPSEC_ENCAP_IF_NUMBER, nss_ipsec_msg_handler, NULL);
316
317 nss_ipsec_set_msg_callback(nss_ctx, NSS_IPSEC_DECAP_IF_NUMBER, NULL, NULL);
318 nss_core_register_handler(NSS_IPSEC_DECAP_IF_NUMBER, nss_ipsec_msg_handler, NULL);
319}
320
321EXPORT_SYMBOL(nss_ipsec_notify_register);
322EXPORT_SYMBOL(nss_ipsec_notify_unregister);
323EXPORT_SYMBOL(nss_ipsec_data_register);
324EXPORT_SYMBOL(nss_ipsec_data_unregister);
325EXPORT_SYMBOL(nss_ipsec_tx_msg);