1/*
2 **************************************************************************
3 * Copyright (c) 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_tun6rd.c
19 *
20 * This file is the NSS 6rd tunnel module
21 * ------------------------REVISION HISTORY-----------------------------
22 * Qualcomm Atheros         15/sep/2013              Created
23 */
24
25#include <linux/version.h>
26#include <linux/types.h>
27#include <linux/ip.h>
28#include <linux/tcp.h>
29#include <linux/module.h>
30#include <linux/skbuff.h>
31#include <net/ipv6.h>
32#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,9,0))
33#include <net/ipip.h>
34#else
35#include <net/ip_tunnels.h>
36#endif
37#include <linux/if_arp.h>
38#include <nss_api_if.h>
39#include <nss_dynamic_interface.h>
40
41/*
42 * NSS tun6rd debug macros
43 */
44#if (NSS_TUN6RD_DEBUG_LEVEL < 1)
45#define nss_tun6rd_assert(fmt, args...)
46#else
47#define nss_tun6rd_assert(c) if (!(c)) { BUG_ON(!(c)); }
48#endif
49
50#if defined(CONFIG_DYNAMIC_DEBUG)
51/*
52 * Compile messages for dynamic enable/disable
53 */
54#define nss_tun6rd_warning(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
55#define nss_tun6rd_info(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
56#define nss_tun6rd_trace(s, ...) pr_debug("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
57#else
58
59/*
60 * Statically compile messages at different levels
61 */
62#if (NSS_TUN6RD_DEBUG_LEVEL < 2)
63#define nss_tun6rd_warning(s, ...)
64#else
65#define nss_tun6rd_warning(s, ...) pr_warn("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
66#endif
67
68#if (NSS_TUN6RD_DEBUG_LEVEL < 3)
69#define nss_tun6rd_info(s, ...)
70#else
71#define nss_tun6rd_info(s, ...)   pr_notice("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
72#endif
73
74#if (NSS_TUN6RD_DEBUG_LEVEL < 4)
75#define nss_tun6rd_trace(s, ...)
76#else
77#define nss_tun6rd_trace(s, ...)  pr_info("%s[%d]:" s, __FUNCTION__, __LINE__, ##__VA_ARGS__)
78#endif
79#endif
80
81/*
82 * 6rd tunnel stats
83 */
84struct nss_tun6rd_stats {
85	uint32_t rx_packets;	/* Number of received packets */
86	uint32_t rx_bytes;	/* Number of received bytes */
87	uint32_t tx_packets;	/* Number of transmitted packets */
88	uint32_t tx_bytes;	/* Number of transmitted bytes */
89};
90
91/*
92 * nss_tun6rd_update_dev_stats
93 *	Update the Dev stats received from NetAp
94 */
95static void nss_tun6rd_update_dev_stats(struct net_device *dev,
96					struct nss_tun6rd_sync_stats_msg *sync_stats)
97{
98#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,14,0))
99	struct pcpu_sw_netstats stats;
100
101	u64_stats_init(&stats.syncp);
102	u64_stats_update_begin(&stats.syncp);
103	stats.rx_packets = sync_stats->node_stats.rx_packets;
104	stats.rx_bytes = sync_stats->node_stats.rx_bytes;
105	stats.tx_packets = sync_stats->node_stats.tx_packets;
106	stats.tx_bytes = sync_stats->node_stats.tx_bytes;
107	u64_stats_update_end(&stats.syncp);
108#else
109	struct nss_tun6rd_stats stats;
110
111	stats.rx_packets = sync_stats->node_stats.rx_packets;
112	stats.rx_bytes = sync_stats->node_stats.rx_bytes;
113	stats.tx_packets = sync_stats->node_stats.tx_packets;
114	stats.tx_bytes = sync_stats->node_stats.tx_bytes;
115#endif
116
117	ipip6_update_offload_stats(dev, (void *)&stats);
118}
119
120/*
121 * nss_tun6rd_event_receive()
122 *	Event Callback to receive events from NSS
123 */
124static void nss_tun6rd_event_receive(void *if_ctx, struct nss_tun6rd_msg *tnlmsg)
125{
126	struct net_device *netdev = if_ctx;
127
128	switch (tnlmsg->cm.type) {
129	case NSS_TUN6RD_RX_STATS_SYNC:
130		nss_tun6rd_update_dev_stats(netdev, (struct nss_tun6rd_sync_stats_msg *)&tnlmsg->msg.stats);
131		break;
132
133	default:
134		nss_tun6rd_info("Unknown Event from NSS\n");
135		break;
136	}
137}
138
139/*
140 * nss_tun6rd_exception()
141 *	Exception handler registered to NSS driver
142 */
143static void nss_tun6rd_exception(struct net_device *dev, struct sk_buff *skb, __attribute__((unused)) struct napi_struct *napi)
144{
145	const struct iphdr *iph;
146
147	skb->dev = dev;
148	nss_tun6rd_info("received - %d bytes name %s ver %x\n",
149			skb->len,dev->name,skb->data[0]);
150
151	iph = (const struct iphdr *)skb->data;
152
153	/*
154	 * Packet after Decap/Encap Did not find the Rule.
155	 */
156	if (iph->version != 4) {
157		skb->protocol = htons(ETH_P_IPV6);
158	} else {
159		if (iph->protocol == IPPROTO_IPV6) {
160			skb_pull(skb, sizeof(struct iphdr));
161			skb->protocol = htons(ETH_P_IPV6);
162			skb_reset_network_header(skb);
163			skb->pkt_type = PACKET_HOST;
164			skb->ip_summed = CHECKSUM_NONE;
165			dev_queue_xmit(skb);
166			return;
167		}
168		skb->protocol = htons(ETH_P_IP);
169	}
170
171	skb_reset_network_header(skb);
172	skb->pkt_type = PACKET_HOST;
173	skb->skb_iif = dev->ifindex;
174	skb->ip_summed = CHECKSUM_NONE;
175	netif_receive_skb(skb);
176}
177
178/*
179 * nss_tun6rd_dev_up()
180 *	6RD Tunnel device i/f up handler
181 */
182static int nss_tun6rd_dev_up(struct net_device *netdev)
183{
184	struct ip_tunnel *tunnel;
185	struct ip_tunnel_6rd_parm *ip6rd;
186	const struct iphdr  *tiph;
187	struct nss_tun6rd_msg tun6rdmsg;
188	struct nss_tun6rd_attach_tunnel_msg *tun6rdcfg;
189	uint32_t if_number;
190	nss_tx_status_t status;
191	struct nss_ctx_instance *nss_ctx;
192	uint32_t features = 0; /* features denote the skb types supported by this interface */
193
194	/*
195	 * Validate netdev for ipv6-in-ipv4  Tunnel
196	 */
197	if (netdev->type != ARPHRD_SIT) {
198		return NOTIFY_DONE;
199	}
200
201	tunnel = (struct ip_tunnel *)netdev_priv(netdev);
202	ip6rd =  &tunnel->ip6rd;
203
204	/*
205	 * Valid 6rd Tunnel Check
206	 * 1. 6rd Prefix len should be non zero
207	 * 2. Relay prefix length should not be greater then 32
208	 * 3. To allow for stateless address auto-configuration on the CE LAN side,
209	 *    6rd delegated prefix SHOULD be /64 or shorter.
210	 */
211	if ((ip6rd->prefixlen == 0 )
212			|| (ip6rd->relay_prefixlen > 32)
213			|| (ip6rd->prefixlen
214				+ (32 - ip6rd->relay_prefixlen) > 64)) {
215
216		nss_tun6rd_warning("Invalid 6rd argument prefix len %d relayprefix len %d \n",
217				ip6rd->prefixlen,ip6rd->relay_prefixlen);
218		return NOTIFY_BAD;
219	}
220
221	nss_tun6rd_info("Valid 6rd Tunnel Prefix %x %x %x %x\n Prefix len %d relay_prefix %d relay_prefixlen %d \n",
222			ip6rd->prefix.s6_addr32[0],ip6rd->prefix.s6_addr32[1],
223			ip6rd->prefix.s6_addr32[2],ip6rd->prefix.s6_addr32[3],
224			ip6rd->prefixlen, ip6rd->relay_prefix,
225			ip6rd->relay_prefixlen);
226
227	/*
228	 * Find the Tunnel device IP header info
229	 */
230	tiph = &tunnel->parms.iph ;
231	nss_tun6rd_trace("Tunnel Param srcaddr %x daddr %x ttl %d tos %x\n",
232			tiph->saddr, tiph->daddr,tiph->ttl,tiph->tos);
233
234	if (tiph->saddr == 0) {
235		nss_tun6rd_warning("Tunnel src address not configured %x\n",
236				tiph->saddr);
237		return NOTIFY_BAD;
238	}
239
240	if_number = nss_dynamic_interface_alloc_node(NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD);
241	if (-1 == if_number) {
242		nss_tun6rd_warning("Request interface number failed\n");
243		return NOTIFY_BAD;
244	}
245
246	/*
247	 * Register 6rd tunnel with NSS
248	 */
249	nss_ctx = nss_register_tun6rd_if(if_number,
250				nss_tun6rd_exception,
251				nss_tun6rd_event_receive,
252				netdev,
253				features);
254	if (!nss_ctx) {
255		status = nss_dynamic_interface_dealloc_node(if_number, NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD);
256		if (status != NSS_TX_SUCCESS) {
257			nss_tun6rd_warning("Unable to dealloc the node[%d] in the NSS fw!\n", if_number);
258		}
259		nss_tun6rd_trace("nss_register_tun6rd_if failed \n");
260		return NOTIFY_BAD;
261	}
262
263	/*
264	 * Prepare The Tunnel configuration parameter to send to nss
265	 */
266	memset(&tun6rdmsg, 0, sizeof(struct nss_tun6rd_msg));
267	tun6rdcfg = &tun6rdmsg.msg.tunnel;
268	tun6rdcfg->prefixlen = ip6rd->prefixlen;
269	tun6rdcfg->relay_prefix = ip6rd->relay_prefix;
270	tun6rdcfg->relay_prefixlen = ip6rd->relay_prefixlen;
271	tun6rdcfg->saddr = ntohl(tiph->saddr);
272	tun6rdcfg->daddr = ntohl(tiph->daddr);
273	tun6rdcfg->prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
274	tun6rdcfg->prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
275	tun6rdcfg->prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
276	tun6rdcfg->prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
277	tun6rdcfg->ttl = tiph->ttl;
278	tun6rdcfg->tos = tiph->tos;
279
280	nss_tun6rd_trace(" 6rd Tunnel info\n");
281	nss_tun6rd_trace(" saddr %x daddr %d ttl %x  tos %x\n",
282			tiph->saddr, tiph->daddr, tiph->ttl, tiph->tos);
283	nss_tun6rd_trace(" Prefix %x:%x:%x:%x  Prefix len %d\n",
284			ip6rd->prefix.s6_addr32[0], ip6rd->prefix.s6_addr32[1],
285			ip6rd->prefix.s6_addr32[2], ip6rd->prefix.s6_addr32[3],
286			ip6rd->prefixlen);
287	nss_tun6rd_trace("Relay Prefix %x Len %d\n",
288			ip6rd->relay_prefix, ip6rd->relay_prefixlen);
289
290	nss_tun6rd_trace("Sending 6rd tunnel i/f up command to NSS %x\n",
291			(int)nss_ctx);
292
293	/*
294	 * Send 6rd Tunnel UP command to NSS
295	 */
296	nss_tun6rd_msg_init(&tun6rdmsg, if_number, NSS_TUN6RD_ATTACH_PNODE,
297			sizeof(struct nss_tun6rd_attach_tunnel_msg), NULL, NULL);
298
299	status = nss_tun6rd_tx(nss_ctx, &tun6rdmsg);
300	if (status != NSS_TX_SUCCESS) {
301		nss_unregister_tun6rd_if(if_number);
302		status = nss_dynamic_interface_dealloc_node(if_number, NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD);
303		if (status != NSS_TX_SUCCESS) {
304			nss_tun6rd_warning("Unable to dealloc the node[%d] in the NSS fw!\n", if_number);
305		}
306		nss_tun6rd_warning("Tunnel up command error %d\n", status);
307		return NOTIFY_BAD;
308	}
309
310	return NOTIFY_DONE;
311}
312
313/*
314 * nss_tun6rd_dev_down()
315 *	6RD Tunnel device i/f down handler
316 */
317static int nss_tun6rd_dev_down(struct net_device *netdev)
318{
319	struct ip_tunnel *tunnel;
320	struct ip_tunnel_6rd_parm *ip6rd;
321	int32_t if_number;
322	nss_tx_status_t status;
323
324	/*
325	 * Validate netdev for ipv6-in-ipv4  Tunnel
326	 */
327	if (netdev->type != ARPHRD_SIT) {
328		return NOTIFY_DONE;
329	}
330
331	/*
332	 * Check if tunnel 6rd is registered ?
333	 */
334	if_number = nss_cmn_get_interface_number_by_dev(netdev);
335	if (if_number < 0) {
336		nss_tun6rd_warning("Net device:%p is not registered \n",netdev);
337		return NOTIFY_BAD;
338	}
339
340
341	tunnel = (struct ip_tunnel *)netdev_priv(netdev);
342	ip6rd =  &tunnel->ip6rd;
343
344	/*
345	 * Valid 6rd Tunnel Check
346	 */
347	if ((ip6rd->prefixlen == 0 )
348			|| (ip6rd->relay_prefixlen > 32 )
349			|| (ip6rd->prefixlen
350				+ (32 - ip6rd->relay_prefixlen) > 64)) {
351
352		nss_tun6rd_warning("Invalid 6rd argument prefix len %d relayprefix len %d \n",
353				ip6rd->prefixlen,ip6rd->relay_prefixlen);
354		return NOTIFY_BAD;
355	}
356
357	/*
358	 * Un-Register 6rd tunnel with NSS
359	 */
360	nss_unregister_tun6rd_if(if_number);
361	status = nss_dynamic_interface_dealloc_node(if_number, NSS_DYNAMIC_INTERFACE_TYPE_TUN6RD);
362	if (status != NSS_TX_SUCCESS) {
363		nss_tun6rd_warning("Dealloc node failure\n");
364		return NOTIFY_BAD;
365	}
366
367	return NOTIFY_DONE;
368}
369
370
371/*
372 * nss_tun6rd_dev_event()
373 *	Net device notifier for 6rd module
374 */
375static int nss_tun6rd_dev_event(struct notifier_block  *nb,
376		unsigned long event, void  *dev)
377{
378#if (LINUX_VERSION_CODE <= KERNEL_VERSION(3,10,0))
379	struct net_device *netdev = (struct net_device *)dev;
380#else
381	struct net_device *netdev = netdev_notifier_info_to_dev(dev);
382#endif
383
384	switch (event) {
385	case NETDEV_UP:
386		nss_tun6rd_trace("NETDEV_UP: event %lu name %s\n", event, netdev->name);
387		return nss_tun6rd_dev_up(netdev);
388
389	case NETDEV_DOWN:
390		nss_tun6rd_trace("NETDEV_DOWN: event %lu name %s\n", event, netdev->name);
391		return nss_tun6rd_dev_down(netdev);
392
393	default:
394		nss_tun6rd_trace("Unhandled notifier event %lu name %s\n",event, netdev->name);
395		break;
396	}
397
398	return NOTIFY_DONE;
399}
400
401/*
402 * Linux Net device Notifier
403 */
404struct notifier_block nss_tun6rd_notifier = {
405	.notifier_call = nss_tun6rd_dev_event,
406};
407
408
409/*
410 * nss_tun6rd_init_module()
411 *	Tunnel 6rd module init function
412 */
413int __init nss_tun6rd_init_module(void)
414{
415	nss_tun6rd_info("module (platform - IPQ806x , Build - %s:%s) loaded\n",
416			__DATE__, __TIME__);
417
418	register_netdevice_notifier(&nss_tun6rd_notifier);
419	nss_tun6rd_trace("Netdev Notifier registerd \n");
420
421	return 0;
422}
423
424/*
425 * nss_tun6rd_exit_module()
426 *	Tunnel 6rd module exit function
427 */
428void __exit nss_tun6rd_exit_module(void)
429{
430	unregister_netdevice_notifier(&nss_tun6rd_notifier);
431	nss_tun6rd_info("module unloaded\n");
432}
433
434module_init(nss_tun6rd_init_module);
435module_exit(nss_tun6rd_exit_module);
436
437MODULE_LICENSE("Dual BSD/GPL");
438MODULE_DESCRIPTION("NSS tun6rd offload manager");
439