blob: 46f700c417166ee33aff7ee0c1fc14879f71d793 [file] [log] [blame]
Rakesh Nair28212a42015-08-31 14:51:49 +05301/*
2 **************************************************************************
Stephen Wang3e2dbd12018-03-14 17:28:17 -07003 * Copyright (c) 2015-2018, 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"
30
31#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 +053032
33static struct net_device_stats *nss_tstamp_ndev_stats(struct net_device *ndev);
34
mandrewc00308f2016-11-15 23:25:08 +053035/*
36 * dummy netdevice ops
37 */
Rakesh Nair28212a42015-08-31 14:51:49 +053038static const struct net_device_ops nss_tstamp_ndev_ops = {
39 .ndo_get_stats = nss_tstamp_ndev_stats,
40};
41
Rakesh Nair28212a42015-08-31 14:51:49 +053042/*
43 * nss_tstamp_ndev_setup()
44 * Dummy setup for net_device handler
45 */
46static void nss_tstamp_ndev_setup(struct net_device *ndev)
47{
48 return;
49}
50
51/*
52 * nss_tstamp_ndev_stats()
53 * Return net device stats
54 */
55static struct net_device_stats *nss_tstamp_ndev_stats(struct net_device *ndev)
56{
57 return &ndev->stats;
mandrewc00308f2016-11-15 23:25:08 +053058}
Rakesh Nair28212a42015-08-31 14:51:49 +053059
60/*
61 * nss_tstamp_copy_data()
62 * Copy timestamps from received nss frame into skb
63 */
mandrewc00308f2016-11-15 23:25:08 +053064static void nss_tstamp_copy_data(struct nss_tstamp_n2h_pre_hdr *ntm, struct sk_buff *skb)
Rakesh Nair28212a42015-08-31 14:51:49 +053065{
66 struct skb_shared_hwtstamps *tstamp;
67
68 tstamp = skb_hwtstamps(skb);
69 tstamp->hwtstamp = ktime_set(ntm->ts_data_hi, ntm->ts_data_lo);
Stephen Wang90c67de2016-04-26 15:15:59 -070070#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 16, 0))
Rakesh Nair28212a42015-08-31 14:51:49 +053071 tstamp->syststamp = ktime_set(ntm->ts_data_hi, ntm->ts_data_lo);
Stephen Wang90c67de2016-04-26 15:15:59 -070072#endif
Rakesh Nair28212a42015-08-31 14:51:49 +053073}
74
75/*
mandrewc00308f2016-11-15 23:25:08 +053076 * nss_tstamp_get_dev()
77 * Get the net_device associated with the packet.
78 */
79static struct net_device *nss_tstamp_get_dev(struct sk_buff *skb)
80{
81 struct dst_entry *dst;
82 struct net_device *dev;
83 struct rtable *rt;
84 struct flowi6 fl6;
85 uint32_t ip_addr;
86
87 /*
88 * It seems like the data came over IPsec, hence indicate
89 * it to the Linux over this interface
90 */
91 skb_reset_network_header(skb);
92 skb_reset_mac_header(skb);
93
94 skb->pkt_type = PACKET_HOST;
95
96 switch (ip_hdr(skb)->version) {
97 case IPVERSION:
98 ip_addr = ip_hdr(skb)->saddr;
99
100 rt = ip_route_output(&init_net, ip_addr, 0, 0, 0);
101 if (IS_ERR(rt)) {
102 return NULL;
103 }
104
105 dst = (struct dst_entry *)rt;
106 skb->protocol = cpu_to_be16(ETH_P_IP);
107 break;
108
109 case 6:
110 memset(&fl6, 0, sizeof(fl6));
111 memcpy(&fl6.daddr, &ipv6_hdr(skb)->saddr, sizeof(fl6.daddr));
112
113 dst = ip6_route_output(&init_net, NULL, &fl6);
114 if (IS_ERR(dst)) {
115 return NULL;
116 }
117
118 skb->protocol = cpu_to_be16(ETH_P_IPV6);
119 break;
120
121 default:
122 nss_warning("%p:could not get dev for the skb\n", skb);
123 return NULL;
124 }
125
126 dev = dst->dev;
127 dev_hold(dev);
128
129 dst_release(dst);
130 return dev;
131}
132
133/*
Rakesh Nair28212a42015-08-31 14:51:49 +0530134 * nss_tstamp_buf_receive()
135 * Receive nss exception packets.
136 */
137static void nss_tstamp_buf_receive(struct net_device *ndev, struct sk_buff *skb, struct napi_struct *napi)
138{
mandrewc00308f2016-11-15 23:25:08 +0530139 struct nss_tstamp_n2h_pre_hdr *n2h_hdr = (struct nss_tstamp_n2h_pre_hdr *)skb->data;
Rakesh Nair28212a42015-08-31 14:51:49 +0530140 struct nss_ctx_instance *nss_ctx;
Rakesh Nair7c43b542015-12-03 16:45:24 +0530141 struct net_device *dev;
Rakesh Nair28212a42015-08-31 14:51:49 +0530142 uint32_t tstamp_sz;
143
mandrewc00308f2016-11-15 23:25:08 +0530144 BUG_ON(!n2h_hdr);
145
146 tstamp_sz = n2h_hdr->ts_hdr_sz;
147 if (tstamp_sz > (NSS_TSTAMP_HEADER_SIZE + sizeof(uint32_t))) {
148 goto free;
149 }
Rakesh Nair28212a42015-08-31 14:51:49 +0530150
151 nss_ctx = &nss_top_main.nss[nss_top_main.tstamp_handler_id];
152 BUG_ON(!nss_ctx);
153
mandrewc00308f2016-11-15 23:25:08 +0530154 skb_pull_inline(skb, tstamp_sz);
Rakesh Nair28212a42015-08-31 14:51:49 +0530155
156 /*
157 * copy the time stamp and convert into ktime_t
158 */
mandrewc00308f2016-11-15 23:25:08 +0530159 nss_tstamp_copy_data(n2h_hdr, skb);
160 if (unlikely(n2h_hdr->ts_tx)) {
Rakesh Nair28212a42015-08-31 14:51:49 +0530161 /*
162 * We are in TX Path
163 */
164 skb_tstamp_tx(skb, skb_hwtstamps(skb));
165
166 ndev->stats.tx_packets++;
167 ndev->stats.tx_bytes += skb->len;
mandrewc00308f2016-11-15 23:25:08 +0530168 goto free;
Rakesh Nair28212a42015-08-31 14:51:49 +0530169 }
170
171 /*
mandrewc00308f2016-11-15 23:25:08 +0530172 * We are in RX path.
Rakesh Nair28212a42015-08-31 14:51:49 +0530173 */
mandrewc00308f2016-11-15 23:25:08 +0530174 dev = nss_cmn_get_interface_dev(nss_ctx, n2h_hdr->ts_ifnum);
175 if (!dev) {
176 ndev->stats.rx_dropped++;
177 goto free;
178 }
179
180 /*
181 * Hold the dev until we finish
182 */
183 dev_hold(dev);
184
Rakesh Nair7c43b542015-12-03 16:45:24 +0530185 switch(dev->type) {
186 case NSS_IPSEC_ARPHRD_IPSEC:
187 /*
mandrewc00308f2016-11-15 23:25:08 +0530188 * Release the prev dev reference
Rakesh Nair7c43b542015-12-03 16:45:24 +0530189 */
mandrewc00308f2016-11-15 23:25:08 +0530190 dev_put(dev);
Rakesh Nair7c43b542015-12-03 16:45:24 +0530191
mandrewc00308f2016-11-15 23:25:08 +0530192 /*
193 * find the actual IPsec tunnel device
194 */
195 dev = nss_tstamp_get_dev(skb);
Rakesh Nair7c43b542015-12-03 16:45:24 +0530196 break;
197
198 default:
199 /*
200 * This is a plain non-encrypted data packet.
201 */
202 skb->protocol = eth_type_trans(skb, dev);
203 break;
204 }
Rakesh Nair28212a42015-08-31 14:51:49 +0530205
mandrewc00308f2016-11-15 23:25:08 +0530206 skb->skb_iif = dev->ifindex;
207 skb->dev = dev;
Rakesh Nair28212a42015-08-31 14:51:49 +0530208
209 ndev->stats.rx_packets++;
210 ndev->stats.rx_bytes += skb->len;
mandrewc00308f2016-11-15 23:25:08 +0530211
212 netif_receive_skb(skb);
213
214 /*
215 * release the device as we are done
216 */
217 dev_put(dev);
218 return;
219free:
220 dev_kfree_skb_any(skb);
221 return;
Rakesh Nair28212a42015-08-31 14:51:49 +0530222}
223
224/*
Rakesh Nairf0140c82015-12-02 17:49:06 +0530225 * nss_tstamp_register_netdev()
mandrewc00308f2016-11-15 23:25:08 +0530226 * register dummy netdevice for tstamp interface
Rakesh Nair28212a42015-08-31 14:51:49 +0530227 */
Rakesh Nairf0140c82015-12-02 17:49:06 +0530228struct net_device *nss_tstamp_register_netdev(void)
Rakesh Nair28212a42015-08-31 14:51:49 +0530229{
230 struct net_device *ndev;
231 uint32_t err = 0;
Rakesh Nair28212a42015-08-31 14:51:49 +0530232
Stephen Wang90c67de2016-04-26 15:15:59 -0700233#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3, 16, 0))
Rakesh Nairf0140c82015-12-02 17:49:06 +0530234 ndev = alloc_netdev(sizeof(struct netdev_priv_instance), "qca-nss-tstamp", nss_tstamp_ndev_setup);
Stephen Wang90c67de2016-04-26 15:15:59 -0700235#else
236 ndev = alloc_netdev(sizeof(struct netdev_priv_instance), "qca-nss-tstamp", NET_NAME_ENUM, nss_tstamp_ndev_setup);
237#endif
Rakesh Nair28212a42015-08-31 14:51:49 +0530238 if (!ndev) {
239 nss_warning("Tstamp: Could not allocate tstamp net_device ");
Rakesh Nairf0140c82015-12-02 17:49:06 +0530240 return NULL;
Rakesh Nair28212a42015-08-31 14:51:49 +0530241 }
242
243 ndev->netdev_ops = &nss_tstamp_ndev_ops;
244
245 err = register_netdev(ndev);
246 if (err) {
247 nss_warning("Tstamp: Could not register tstamp net_device ");
248 free_netdev(ndev);
Rakesh Nairf0140c82015-12-02 17:49:06 +0530249 return NULL;
Rakesh Nair28212a42015-08-31 14:51:49 +0530250 }
251
Rakesh Nairf0140c82015-12-02 17:49:06 +0530252 return ndev;
253}
254
255/*
256 * nss_tstamp_register_handler()
257 */
258void nss_tstamp_register_handler(struct net_device *ndev)
259{
260 uint32_t features = 0;
261 struct nss_ctx_instance *nss_ctx;
262
263 nss_ctx = &nss_top_main.nss[nss_top_main.tstamp_handler_id];
Jackson Bockus7ca70ec2017-07-17 13:47:29 -0700264
265 nss_core_register_subsys_dp(nss_ctx, NSS_TSTAMP_INTERFACE, nss_tstamp_buf_receive, NULL, NULL, ndev, features);
Rakesh Nair28212a42015-08-31 14:51:49 +0530266}
267
mandrewc00308f2016-11-15 23:25:08 +0530268/*
269 * nss_tstamp_tx_buf()
270 * Send data packet for tstamp processing
271 */
272nss_tx_status_t nss_tstamp_tx_buf(struct nss_ctx_instance *nss_ctx, struct sk_buff *skb, uint32_t if_num)
273{
274 struct nss_tstamp_h2n_pre_hdr *h2n_hdr;
mandrewc00308f2016-11-15 23:25:08 +0530275 bool expand_head;
276 char *align_data;
277 uint32_t hdr_sz;
278
279 nss_trace("%p: Tstamp If Tx packet, id:%d, data=%p", nss_ctx, NSS_TSTAMP_INTERFACE, skb->data);
280
mandrewc00308f2016-11-15 23:25:08 +0530281 /*
282 * header size + alignment size
283 */
284 hdr_sz = NSS_TSTAMP_HEADER_SIZE + sizeof(uint32_t);
285 expand_head = (hdr_sz > skb_headroom(skb));
286
287 /*
288 * Expand the head for h2n_hdr
289 */
290 if (expand_head && pskb_expand_head(skb, hdr_sz, 0, GFP_KERNEL)) {
291 nss_trace("%p: expand head room failed", nss_ctx);
292 return NSS_TX_FAILURE;
293 }
294
295 align_data = PTR_ALIGN((skb->data - hdr_sz), sizeof(uint32_t));
296 hdr_sz = (nss_ptr_t)skb->data - (nss_ptr_t)align_data;
297
298 h2n_hdr = (struct nss_tstamp_h2n_pre_hdr *)skb_push(skb, hdr_sz);
299 h2n_hdr->ts_ifnum = if_num;
300 h2n_hdr->ts_tx_hdr_sz = hdr_sz;
301
Stephen Wang3e2dbd12018-03-14 17:28:17 -0700302 return nss_core_send_packet(nss_ctx, skb, NSS_TSTAMP_INTERFACE, H2N_BIT_FLAG_VIRTUAL_BUFFER);
mandrewc00308f2016-11-15 23:25:08 +0530303}
304EXPORT_SYMBOL(nss_tstamp_tx_buf);