blob: 6ce5a229f8cb54591ccc0adee148c854962f98ed [file] [log] [blame]
Rakesh Nair28212a42015-08-31 14:51:49 +05301/*
2 **************************************************************************
Cemil Coskun58d27732019-05-22 13:39:14 -07003 * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
Rakesh Nair28212a42015-08-31 14:51:49 +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_tstamp.c
19 * NSS Tstamp APIs
20 */
21
mandrewc00308f2016-11-15 23:25:08 +053022#include <linux/ip.h>
23#include <linux/ipv6.h>
Rakesh Nair28212a42015-08-31 14:51:49 +053024#include <linux/etherdevice.h>
mandrewc00308f2016-11-15 23:25:08 +053025#include <linux/netdevice.h>
26#include <net/route.h>
27#include <net/ip6_route.h>
28#include "nss_tx_rx_common.h"
29#include "nss_tstamp.h"
Cemil Coskun58d27732019-05-22 13:39:14 -070030#include "nss_tstamp_stats.h"
mandrewc00308f2016-11-15 23:25:08 +053031
32#define NSS_TSTAMP_HEADER_SIZE max(sizeof(struct nss_tstamp_h2n_pre_hdr), sizeof(struct nss_tstamp_n2h_pre_hdr))
Rakesh Nair28212a42015-08-31 14:51:49 +053033
Cemil Coskun58d27732019-05-22 13:39:14 -070034/*
35 * Notify data structure
36 */
37struct nss_tstamp_notify_data {
38 nss_tstamp_msg_callback_t tstamp_callback;
39 void *app_data;
40};
41
42static struct nss_tstamp_notify_data nss_tstamp_notify = {
43 .tstamp_callback = NULL,
44 .app_data = NULL,
45};
46
Rakesh Nair28212a42015-08-31 14:51:49 +053047static struct net_device_stats *nss_tstamp_ndev_stats(struct net_device *ndev);
48
mandrewc00308f2016-11-15 23:25:08 +053049/*
50 * dummy netdevice ops
51 */
Rakesh Nair28212a42015-08-31 14:51:49 +053052static const struct net_device_ops nss_tstamp_ndev_ops = {
53 .ndo_get_stats = nss_tstamp_ndev_stats,
54};
55
Rakesh Nair28212a42015-08-31 14:51:49 +053056/*
57 * nss_tstamp_ndev_setup()
58 * Dummy setup for net_device handler
59 */
60static void nss_tstamp_ndev_setup(struct net_device *ndev)
61{
62 return;
63}
64
65/*
66 * nss_tstamp_ndev_stats()
67 * Return net device stats
68 */
69static struct net_device_stats *nss_tstamp_ndev_stats(struct net_device *ndev)
70{
71 return &ndev->stats;
mandrewc00308f2016-11-15 23:25:08 +053072}
Rakesh Nair28212a42015-08-31 14:51:49 +053073
74/*
Cemil Coskun58d27732019-05-22 13:39:14 -070075 * nss_tstamp_verify_if_num()
76 * Verify if_num passed to us.
77 */
78static bool nss_tstamp_verify_if_num(uint32_t if_num)
79{
80 return (if_num == NSS_TSTAMP_TX_INTERFACE) || (if_num == NSS_TSTAMP_RX_INTERFACE);
81}
82
83
84/*
85 * nss_tstamp_interface_handler()
86 * Handle NSS -> HLOS messages for TSTAMP Statistics
87 */
88static void nss_tstamp_interface_handler(struct nss_ctx_instance *nss_ctx,
89 struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
90{
91 struct nss_tstamp_msg *ntm = (struct nss_tstamp_msg *)ncm;
92 nss_tstamp_msg_callback_t cb;
93
94 if (!nss_tstamp_verify_if_num(ncm->interface)) {
95 nss_warning("%p: invalid interface %d for tstamp_tx", nss_ctx, ncm->interface);
96 return;
97 }
98
99 /*
100 * Is this a valid request/response packet?
101 */
102 if (ncm->type >= NSS_TSTAMP_MSG_TYPE_MAX) {
103 nss_warning("%p: received invalid message %d for tstamp", nss_ctx, ncm->type);
104 return;
105 }
106
107 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_tstamp_msg)) {
108 nss_warning("%p: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
109 return;
110 }
111
112 /*
113 * Log failures
114 */
115 nss_core_log_msg_failures(nss_ctx, ncm);
116
117 switch (ntm->cm.type) {
118 case NSS_TSTAMP_MSG_TYPE_SYNC_STATS:
119 nss_tstamp_stats_sync(nss_ctx, &ntm->msg.stats, ncm->interface);
120 break;
121 default:
122 nss_warning("%p: Unknown message type %d",
123 nss_ctx, ncm->type);
124 return;
125 }
126
127 /*
128 * Update the callback and app_data for NOTIFY messages
129 */
130 if (ncm->response == NSS_CMN_RESPONSE_NOTIFY) {
131 ncm->cb = (nss_ptr_t)nss_tstamp_notify.tstamp_callback;
132 ncm->app_data = (nss_ptr_t)nss_tstamp_notify.app_data;
133 }
134
135 /*
136 * Do we have a callback?
137 */
138 if (!ncm->cb) {
139 return;
140 }
141
142 /*
143 * callback
144 */
145 cb = (nss_tstamp_msg_callback_t)ncm->cb;
146 cb((void *)ncm->app_data, ntm);
147}
148
149/*
Rakesh Nair28212a42015-08-31 14:51:49 +0530150 * nss_tstamp_copy_data()
151 * Copy timestamps from received nss frame into skb
152 */
mandrewc00308f2016-11-15 23:25:08 +0530153static void nss_tstamp_copy_data(struct nss_tstamp_n2h_pre_hdr *ntm, struct sk_buff *skb)
Rakesh Nair28212a42015-08-31 14:51:49 +0530154{
155 struct skb_shared_hwtstamps *tstamp;
156
157 tstamp = skb_hwtstamps(skb);
158 tstamp->hwtstamp = ktime_set(ntm->ts_data_hi, ntm->ts_data_lo);
Stephen Wang90c67de2016-04-26 15:15:59 -0700159#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 16, 0))
Rakesh Nair28212a42015-08-31 14:51:49 +0530160 tstamp->syststamp = ktime_set(ntm->ts_data_hi, ntm->ts_data_lo);
Stephen Wang90c67de2016-04-26 15:15:59 -0700161#endif
Rakesh Nair28212a42015-08-31 14:51:49 +0530162}
163
164/*
mandrewc00308f2016-11-15 23:25:08 +0530165 * nss_tstamp_get_dev()
166 * Get the net_device associated with the packet.
167 */
168static struct net_device *nss_tstamp_get_dev(struct sk_buff *skb)
169{
170 struct dst_entry *dst;
171 struct net_device *dev;
172 struct rtable *rt;
173 struct flowi6 fl6;
174 uint32_t ip_addr;
175
176 /*
177 * It seems like the data came over IPsec, hence indicate
178 * it to the Linux over this interface
179 */
180 skb_reset_network_header(skb);
181 skb_reset_mac_header(skb);
182
183 skb->pkt_type = PACKET_HOST;
184
185 switch (ip_hdr(skb)->version) {
186 case IPVERSION:
187 ip_addr = ip_hdr(skb)->saddr;
188
189 rt = ip_route_output(&init_net, ip_addr, 0, 0, 0);
190 if (IS_ERR(rt)) {
191 return NULL;
192 }
193
194 dst = (struct dst_entry *)rt;
195 skb->protocol = cpu_to_be16(ETH_P_IP);
196 break;
197
198 case 6:
199 memset(&fl6, 0, sizeof(fl6));
200 memcpy(&fl6.daddr, &ipv6_hdr(skb)->saddr, sizeof(fl6.daddr));
201
202 dst = ip6_route_output(&init_net, NULL, &fl6);
203 if (IS_ERR(dst)) {
204 return NULL;
205 }
206
207 skb->protocol = cpu_to_be16(ETH_P_IPV6);
208 break;
209
210 default:
211 nss_warning("%p:could not get dev for the skb\n", skb);
212 return NULL;
213 }
214
215 dev = dst->dev;
216 dev_hold(dev);
217
218 dst_release(dst);
219 return dev;
220}
221
222/*
Rakesh Nair28212a42015-08-31 14:51:49 +0530223 * nss_tstamp_buf_receive()
Cemil Coskun58d27732019-05-22 13:39:14 -0700224 * Receive nss exception packets.
Rakesh Nair28212a42015-08-31 14:51:49 +0530225 */
226static void nss_tstamp_buf_receive(struct net_device *ndev, struct sk_buff *skb, struct napi_struct *napi)
227{
mandrewc00308f2016-11-15 23:25:08 +0530228 struct nss_tstamp_n2h_pre_hdr *n2h_hdr = (struct nss_tstamp_n2h_pre_hdr *)skb->data;
Rakesh Nair28212a42015-08-31 14:51:49 +0530229 struct nss_ctx_instance *nss_ctx;
Rakesh Nair7c43b542015-12-03 16:45:24 +0530230 struct net_device *dev;
Rakesh Nair28212a42015-08-31 14:51:49 +0530231 uint32_t tstamp_sz;
232
mandrewc00308f2016-11-15 23:25:08 +0530233 BUG_ON(!n2h_hdr);
234
235 tstamp_sz = n2h_hdr->ts_hdr_sz;
Cemil Coskun58d27732019-05-22 13:39:14 -0700236 if (tstamp_sz > (NSS_TSTAMP_HEADER_SIZE)) {
mandrewc00308f2016-11-15 23:25:08 +0530237 goto free;
238 }
Rakesh Nair28212a42015-08-31 14:51:49 +0530239
240 nss_ctx = &nss_top_main.nss[nss_top_main.tstamp_handler_id];
241 BUG_ON(!nss_ctx);
242
mandrewc00308f2016-11-15 23:25:08 +0530243 skb_pull_inline(skb, tstamp_sz);
Rakesh Nair28212a42015-08-31 14:51:49 +0530244
245 /*
246 * copy the time stamp and convert into ktime_t
247 */
mandrewc00308f2016-11-15 23:25:08 +0530248 nss_tstamp_copy_data(n2h_hdr, skb);
249 if (unlikely(n2h_hdr->ts_tx)) {
Rakesh Nair28212a42015-08-31 14:51:49 +0530250 /*
251 * We are in TX Path
252 */
253 skb_tstamp_tx(skb, skb_hwtstamps(skb));
254
255 ndev->stats.tx_packets++;
256 ndev->stats.tx_bytes += skb->len;
mandrewc00308f2016-11-15 23:25:08 +0530257 goto free;
Rakesh Nair28212a42015-08-31 14:51:49 +0530258 }
259
260 /*
mandrewc00308f2016-11-15 23:25:08 +0530261 * We are in RX path.
Rakesh Nair28212a42015-08-31 14:51:49 +0530262 */
mandrewc00308f2016-11-15 23:25:08 +0530263 dev = nss_cmn_get_interface_dev(nss_ctx, n2h_hdr->ts_ifnum);
264 if (!dev) {
265 ndev->stats.rx_dropped++;
266 goto free;
267 }
268
269 /*
270 * Hold the dev until we finish
271 */
272 dev_hold(dev);
273
Rakesh Nair7c43b542015-12-03 16:45:24 +0530274 switch(dev->type) {
275 case NSS_IPSEC_ARPHRD_IPSEC:
276 /*
mandrewc00308f2016-11-15 23:25:08 +0530277 * Release the prev dev reference
Rakesh Nair7c43b542015-12-03 16:45:24 +0530278 */
mandrewc00308f2016-11-15 23:25:08 +0530279 dev_put(dev);
Rakesh Nair7c43b542015-12-03 16:45:24 +0530280
mandrewc00308f2016-11-15 23:25:08 +0530281 /*
282 * find the actual IPsec tunnel device
283 */
284 dev = nss_tstamp_get_dev(skb);
Rakesh Nair7c43b542015-12-03 16:45:24 +0530285 break;
286
287 default:
288 /*
289 * This is a plain non-encrypted data packet.
290 */
291 skb->protocol = eth_type_trans(skb, dev);
292 break;
293 }
Rakesh Nair28212a42015-08-31 14:51:49 +0530294
mandrewc00308f2016-11-15 23:25:08 +0530295 skb->skb_iif = dev->ifindex;
296 skb->dev = dev;
Rakesh Nair28212a42015-08-31 14:51:49 +0530297
298 ndev->stats.rx_packets++;
299 ndev->stats.rx_bytes += skb->len;
mandrewc00308f2016-11-15 23:25:08 +0530300
301 netif_receive_skb(skb);
302
303 /*
304 * release the device as we are done
305 */
306 dev_put(dev);
307 return;
308free:
309 dev_kfree_skb_any(skb);
310 return;
Rakesh Nair28212a42015-08-31 14:51:49 +0530311}
312
313/*
Cemil Coskun58d27732019-05-22 13:39:14 -0700314 * nss_tstamp_tx_buf()
315 * Send data packet for tstamp processing
316 */
317nss_tx_status_t nss_tstamp_tx_buf(struct nss_ctx_instance *nss_ctx, struct sk_buff *skb, uint32_t if_num)
318{
319 struct nss_tstamp_h2n_pre_hdr *h2n_hdr;
320 int extra_head;
321 int extra_tail = 0;
322 char *align_data;
323 uint32_t hdr_sz;
324
325 nss_trace("%p: Tstamp If Tx packet, id:%d, data=%p", nss_ctx, NSS_TSTAMP_RX_INTERFACE, skb->data);
326
327 /*
328 * header size + alignment size
329 */
330 hdr_sz = NSS_TSTAMP_HEADER_SIZE;
331 extra_head = hdr_sz - skb_headroom(skb);
332
333 /*
334 * Expand the head for h2n_hdr
335 */
336 if (extra_head > 0) {
337 /*
338 * Try to accommodate using available tailroom.
339 */
340 if (skb->end - skb->tail >= extra_head)
341 extra_tail = -extra_head;
342 if (pskb_expand_head(skb, extra_head, extra_tail, GFP_KERNEL)) {
343 nss_trace("%p: expand head room failed", nss_ctx);
344 return NSS_TX_FAILURE;
345 }
346 }
347
348 align_data = PTR_ALIGN((skb->data - hdr_sz), sizeof(uint32_t));
349 hdr_sz = (nss_ptr_t)skb->data - (nss_ptr_t)align_data;
350
351 h2n_hdr = (struct nss_tstamp_h2n_pre_hdr *)skb_push(skb, hdr_sz);
352 h2n_hdr->ts_ifnum = if_num;
353 h2n_hdr->ts_tx_hdr_sz = hdr_sz;
354
355 return nss_core_send_packet(nss_ctx, skb, NSS_TSTAMP_RX_INTERFACE, H2N_BIT_FLAG_VIRTUAL_BUFFER);
356}
357EXPORT_SYMBOL(nss_tstamp_tx_buf);
358
359
360/*
Rakesh Nairf0140c82015-12-02 17:49:06 +0530361 * nss_tstamp_register_netdev()
mandrewc00308f2016-11-15 23:25:08 +0530362 * register dummy netdevice for tstamp interface
Rakesh Nair28212a42015-08-31 14:51:49 +0530363 */
Rakesh Nairf0140c82015-12-02 17:49:06 +0530364struct net_device *nss_tstamp_register_netdev(void)
Rakesh Nair28212a42015-08-31 14:51:49 +0530365{
366 struct net_device *ndev;
367 uint32_t err = 0;
Rakesh Nair28212a42015-08-31 14:51:49 +0530368
Stephen Wang90c67de2016-04-26 15:15:59 -0700369#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 16, 0))
Rakesh Nairf0140c82015-12-02 17:49:06 +0530370 ndev = alloc_netdev(sizeof(struct netdev_priv_instance), "qca-nss-tstamp", nss_tstamp_ndev_setup);
Stephen Wang90c67de2016-04-26 15:15:59 -0700371#else
372 ndev = alloc_netdev(sizeof(struct netdev_priv_instance), "qca-nss-tstamp", NET_NAME_ENUM, nss_tstamp_ndev_setup);
373#endif
Rakesh Nair28212a42015-08-31 14:51:49 +0530374 if (!ndev) {
375 nss_warning("Tstamp: Could not allocate tstamp net_device ");
Rakesh Nairf0140c82015-12-02 17:49:06 +0530376 return NULL;
Rakesh Nair28212a42015-08-31 14:51:49 +0530377 }
378
379 ndev->netdev_ops = &nss_tstamp_ndev_ops;
380
381 err = register_netdev(ndev);
382 if (err) {
383 nss_warning("Tstamp: Could not register tstamp net_device ");
384 free_netdev(ndev);
Rakesh Nairf0140c82015-12-02 17:49:06 +0530385 return NULL;
Rakesh Nair28212a42015-08-31 14:51:49 +0530386 }
387
Rakesh Nairf0140c82015-12-02 17:49:06 +0530388 return ndev;
389}
390
391/*
Cemil Coskun58d27732019-05-22 13:39:14 -0700392 * nss_tstamp_notify_register()
393 * Register to receive tstamp notify messages.
394 */
395struct nss_ctx_instance *nss_tstamp_notify_register(nss_tstamp_msg_callback_t cb, void *app_data)
396{
397 struct nss_ctx_instance *nss_ctx;
398
399 nss_ctx = &nss_top_main.nss[nss_top_main.tstamp_handler_id];
400
401 nss_tstamp_notify.tstamp_callback = cb;
402 nss_tstamp_notify.app_data = app_data;
403
404 return nss_ctx;
405}
406EXPORT_SYMBOL(nss_tstamp_notify_register);
407
408/*
Rakesh Nairf0140c82015-12-02 17:49:06 +0530409 * nss_tstamp_register_handler()
410 */
411void nss_tstamp_register_handler(struct net_device *ndev)
412{
413 uint32_t features = 0;
414 struct nss_ctx_instance *nss_ctx;
415
416 nss_ctx = &nss_top_main.nss[nss_top_main.tstamp_handler_id];
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700417
Cemil Coskun58d27732019-05-22 13:39:14 -0700418 nss_core_register_subsys_dp(nss_ctx, NSS_TSTAMP_TX_INTERFACE, nss_tstamp_buf_receive, NULL, NULL, ndev, features);
419
420 nss_core_register_handler(nss_ctx, NSS_TSTAMP_TX_INTERFACE, nss_tstamp_interface_handler, NULL);
421
422 nss_core_register_handler(nss_ctx, NSS_TSTAMP_RX_INTERFACE, nss_tstamp_interface_handler, NULL);
423
424 nss_tstamp_stats_dentry_create();
Rakesh Nair28212a42015-08-31 14:51:49 +0530425}