blob: b664b7efcd0116af3c6c3c4bfced12c6119dcc82 [file] [log] [blame]
Bharath M Kumar0d87e912013-08-12 18:32:57 +05301/*
2 **************************************************************************
Zac Livingston866b0e22013-10-23 18:14:17 -06003 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
Bharath M Kumar0d87e912013-08-12 18:32:57 +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_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/types.h>
26#include <linux/ip.h>
27#include <linux/tcp.h>
28#include <linux/module.h>
29#include <linux/skbuff.h>
30#include <net/ipv6.h>
31#include <net/ipip.h>
32#include <linux/if_arp.h>
33#include "nss_api_if.h"
34#include "nss_hlos_if.h"
35
36#define NSS_TUNRD_IF_NUMBER 10
37
38/*
39 * NSS tun6rd debug macros
40 */
41#if (NSS_TUN6RD_DEBUG_LEVEL < 1)
42#define nss_tun6rd_assert(fmt, args...)
43#else
44#define nss_tun6d_assert(c) if (!(c)) { BUG_ON(!(c)); }
45#endif
46
47#if (NSS_TUN6RD_DEBUG_LEVEL < 2)
48#define nss_tun6rd_error(fmt, args...)
49#else
50#define nss_tun6rd_error(fmt, args...) printk(KERN_WARNING "nss tun6rd:"fmt, ##args)
51#endif
52
53#if (NSS_TUN6RD_DEBUG_LEVEL < 3)
54#define nss_tun6rd_warning(fmt, args...)
55#else
56#define nss_tun6rd_warning(fmt, args...) printk(KERN_WARNING "nss tun6rd:"fmt, ##args)
57#endif
58
59#if (NSS_TUN6RD_DEBUG_LEVEL < 4)
60#define nss_tun6rd_info(fmt, args...)
61#else
62#define nss_tun6rd_info(fmt, args...) printk(KERN_INFO "nss tun6rd :"fmt, ##args)
63#endif
64
65#if (NSS_TUN6RD_DEBUG_LEVEL < 5)
66#define nss_tun6rd_trace(fmt, args...)
67#else
68#define nss_tun6rd_trace(fmt, args...) printk(KERN_DEBUG "nss tun6rd :"fmt, ##args)
69#endif
70
71void nss_tun6rd_exception(void *ctx, void *buf);
Radhakrishna Jiguru5ad493d2013-11-25 20:17:54 +053072void nss_tun6rd_event_receive(void *ctx, nss_tun6rd_event_t ev_type,
73 void *os_buf, uint32_t len);
Bharath M Kumar0d87e912013-08-12 18:32:57 +053074
75enum tun6rd_metadata_types {
76 TUN6RD_METADATA_TYPE_IF_UP,
77 TUN6RD_METADATA_TYPE_IF_DOWN
78};
79
80/*
81 * 6rd configuration command structure
82 */
83struct nss_tunnel_6rd_cfg{
84 uint32_t prefix[4]; /*6rd prefix */
85 uint32_t relay_prefix; /* Relay prefix */
86 uint16_t prefixlen; /* 6rd prefix len */
87 uint16_t relay_prefixlen; /* Relay prefix length*/
88 uint32_t saddr; /* Tunnel source address */
89 uint32_t daddr; /* Tunnel destination addresss */
90 uint8_t tos; /* Tunnel tos field */
91 uint8_t ttl; /* Tunnel ttl field */
92
93};
94
95/*
96 * 6rd tunnel interface down command structure
97 */
98struct tun6rd_if_down_param{
99 uint32_t prefix[4]; /*Tunnel 6rd prefix */
100};
101
102/*
103 * 6rd Tunnel generic param
104 */
105struct nss_tunnel_6rd_param {
106 enum tun6rd_metadata_types type;
107 union {
108 struct nss_tunnel_6rd_cfg cfg;
109 struct tun6rd_if_down_param ifdown_param;
110 }sub;
111};
112
113/*
114 * 6rd tunnel host instance
115 */
116struct nss_tun6rd_tunnel{
117 void *nss_ctx;
118 uint32_t if_num;
119 struct net_device *netdev;
120 uint32_t device_up;
121};
122
Radhakrishna Jiguru5ad493d2013-11-25 20:17:54 +0530123/*
124 * 6rd tunnel stats
125 */
126struct nss_tun6rd_stats{
127 uint32_t rx_packets;
128 uint32_t rx_bytes;
129 uint32_t tx_packets;
130 uint32_t tx_bytes;
131};
132
Bharath M Kumar0d87e912013-08-12 18:32:57 +0530133struct nss_tun6rd_tunnel g_tun6rd;
134
135/*
136 * Internal function
137 */
138static int
139nss_tun6rd_dev_event(struct notifier_block *nb,
140 unsigned long event,
141 void *dev);
142
143/*
144 * Linux Net device Notifier
145 */
146struct notifier_block nss_tun6rd_notifier = {
147 .notifier_call = nss_tun6rd_dev_event,
148};
149
150/*
151 * nss_tun6rd_dev_up()
152 * 6RD Tunnel device i/f up handler
153 */
154void nss_tun6rd_dev_up( struct net_device * netdev)
155{
156 struct ip_tunnel *tunnel;
157 struct ip_tunnel_6rd_parm *ip6rd;
158 const struct iphdr *tiph;
159 struct nss_tunnel_6rd_param tun6rdparam;
160 struct nss_tunnel_6rd_cfg *tun6rdcfg;
161 nss_tx_status_t status;
162
163 /*
164 * Validate netdev for ipv6-in-ipv4 Tunnel
165 */
166 if (netdev->type != ARPHRD_SIT ) {
167 return;
168 }
169
170 tunnel = (struct ip_tunnel*)netdev_priv(netdev);
171 ip6rd = &tunnel->ip6rd;
172
173 /*
174 * Valid 6rd Tunnel Check
175 * 1. 6rd Prefix len should be non zero
176 * 2. Relay prefix length should not be greater then 32
177 * 3. To allow for stateless address auto-configuration on the CE LAN side,
178 * 6rd delegated prefix SHOULD be /64 or shorter.
179 */
180 if ((ip6rd->prefixlen == 0 )
181 || (ip6rd->relay_prefixlen > 32)
182 || (ip6rd->prefixlen
183 + (32 - ip6rd->relay_prefixlen) > 64)){
184
185 nss_tun6rd_error("Invalid 6rd argument prefix len %d \
186 relayprefix len %d \n",
187 ip6rd->prefixlen,ip6rd->relay_prefixlen);
188 return;
189 }
190
191 nss_tun6rd_info(" Valid 6rd Tunnel Prefix %x %x %x %x \n \
192 prefix len %d relay_prefix %d relay_prefixlen %d \n",
193 ip6rd->prefix.s6_addr32[0],ip6rd->prefix.s6_addr32[1],
194 ip6rd->prefix.s6_addr32[2],ip6rd->prefix.s6_addr32[3],
195 ip6rd->prefixlen, ip6rd->relay_prefix,
196 ip6rd->relay_prefixlen);
197
198 /*
199 * Prepare The Tunnel configuration parameter to send to nss
200 */
201 memset( &tun6rdparam, 0, sizeof(struct nss_tunnel_6rd_param));
202 tun6rdparam.type = TUN6RD_METADATA_TYPE_IF_UP;
203 tun6rdcfg = (struct nss_tunnel_6rd_cfg *)&tun6rdparam.sub.cfg;
204
205 /*
206 * Find the Tunnel device ipHeader info
207 */
208 tiph = &tunnel->parms.iph ;
209 nss_tun6rd_trace(" Tunnel Param srcaddr %x daddr %x ttl %d tos %x\n",
210 tiph->saddr, tiph->daddr,tiph->ttl,tiph->tos);
211
212 if(tiph->saddr == 0) {
213 nss_tun6rd_error("Tunnel src address not configured %x\n",
214 tiph->saddr);
215 return;
216 }
217
218 if (tiph->daddr == 0) {
219 nss_tun6rd_error("Tunnel dest address not configured %x\n",
220 tiph->daddr);
221 return;
222 }
223
224 tun6rdcfg->prefixlen = ip6rd->prefixlen;
225 tun6rdcfg->relay_prefix = ip6rd->relay_prefix;
226 tun6rdcfg->relay_prefixlen = ip6rd->relay_prefixlen;
227 tun6rdcfg->saddr = ntohl(tiph->saddr);
228 tun6rdcfg->daddr = ntohl(tiph->daddr);
229 tun6rdcfg->prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
230 tun6rdcfg->prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
231 tun6rdcfg->prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
232 tun6rdcfg->prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
233 tun6rdcfg->ttl = tiph->ttl;
234 tun6rdcfg->tos = tiph->tos;
235
236 nss_tun6rd_trace(" 6rd Tunnel info \n");
237 nss_tun6rd_trace(" saddr %x daddr %d ttl %x tos %x \n",
238 tiph->saddr, tiph->daddr, tiph->ttl, tiph->tos);
239 nss_tun6rd_trace(" Prefix %x:%x:%x:%x Prefix len %d \n",
240 ip6rd->prefix.s6_addr32[0], ip6rd->prefix.s6_addr32[1],
241 ip6rd->prefix.s6_addr32[2], ip6rd->prefix.s6_addr32[3],
242 ip6rd->prefixlen);
243 nss_tun6rd_trace("Relay Prefix %x Len %d\n",
244 ip6rd->relay_prefix, ip6rd->relay_prefixlen);
245
246 /*
247 * Register 6rd tunnel with NSS
248 */
249 g_tun6rd.nss_ctx = nss_register_tun6rd_if(g_tun6rd.if_num,
250 nss_tun6rd_exception,
Radhakrishna Jiguru5ad493d2013-11-25 20:17:54 +0530251 nss_tun6rd_event_receive,
Bharath M Kumar0d87e912013-08-12 18:32:57 +0530252 netdev);
253 if (g_tun6rd.nss_ctx == NULL) {
254 nss_tun6rd_trace("nss_register_tun6rd_if Failed \n");
255 return;
256 } else {
257 nss_tun6rd_trace("nss_register_tun6rd_if Success \n");
258 }
259
260 nss_tun6rd_trace("Sending 6rd tunnel i/f up command to NSS %x \n",
261 (int)g_tun6rd.nss_ctx);
262
263 /*
264 * Send 6rd Tunnel UP command to NSS
265 */
266 status = nss_tx_generic_if_buf(g_tun6rd.nss_ctx,
267 g_tun6rd.if_num,
Radhakrishna Jiguru5ad493d2013-11-25 20:17:54 +0530268 (uint8_t *)&tun6rdparam,
Bharath M Kumar0d87e912013-08-12 18:32:57 +0530269 sizeof(struct nss_tunnel_6rd_param));
270
271 if (status != NSS_TX_SUCCESS) {
272 nss_tun6rd_error("Tunnel up command error %d \n", status);
273 return;
274 }
275
276 g_tun6rd.device_up = 1;
277}
278
279/*
280 * nss_tun6rd_dev_down()
281 * 6RD Tunnel device i/f down handler
282 */
283void nss_tun6rd_dev_down( struct net_device * netdev)
284{
285 struct ip_tunnel *tunnel;
286 struct ip_tunnel_6rd_parm *ip6rd;
287 struct nss_tunnel_6rd_param tun6rdparam;
288 struct tun6rd_if_down_param *ifdown;
289 nss_tx_status_t status;
290
291 /*
292 * Check if tunnel 6rd is registered ?
293 */
294 if (g_tun6rd.nss_ctx == NULL) {
295 return;
296 }
297
298 /*
299 * Validate netdev for ipv6-in-ipv4 Tunnel
300 */
301 if (netdev->type != ARPHRD_SIT ) {
302 return;
303 }
304
305 tunnel = (struct ip_tunnel*)netdev_priv(netdev);
306 ip6rd = &tunnel->ip6rd;
307
308 /*
309 * Valid 6rd Tunnel Check
310 */
311 if ((ip6rd->prefixlen == 0 )
312 || (ip6rd->relay_prefixlen > 32 )
313 || (ip6rd->prefixlen
314 + (32 - ip6rd->relay_prefixlen) > 64)){
315
316 nss_tun6rd_error("Invalid 6rd argument prefix len %d \
317 relayprefix len %d \n",
318 ip6rd->prefixlen,ip6rd->relay_prefixlen);
319 return;
320 }
321
322 memset( &tun6rdparam, 0, sizeof(struct nss_tunnel_6rd_param));
323 tun6rdparam.type = TUN6RD_METADATA_TYPE_IF_DOWN;
324 ifdown = (struct tun6rd_if_down_param *)&tun6rdparam.sub.ifdown_param;
325 ifdown->prefix[0] = ntohl(ip6rd->prefix.s6_addr32[0]);
326 ifdown->prefix[1] = ntohl(ip6rd->prefix.s6_addr32[1]);
327 ifdown->prefix[2] = ntohl(ip6rd->prefix.s6_addr32[2]);
328 ifdown->prefix[3] = ntohl(ip6rd->prefix.s6_addr32[3]);
329
330 nss_tun6rd_trace(" Prefix %x:%x:%x:%x Prefix len %d \n",
331 ip6rd->prefix.s6_addr32[0], ip6rd->prefix.s6_addr32[1],
332 ip6rd->prefix.s6_addr32[2], ip6rd->prefix.s6_addr32[3],
333 ip6rd->prefixlen);
334
335
336 nss_tun6rd_trace("Sending Tunnle 6rd Down command %x \n",g_tun6rd.if_num);
337 status = nss_tx_generic_if_buf(g_tun6rd.nss_ctx,
338 g_tun6rd.if_num,
339 (uint8_t *)&tun6rdparam,
340 sizeof(struct nss_tunnel_6rd_param));
341
342 if (status != NSS_TX_SUCCESS) {
343 nss_tun6rd_error("Tunnel down command error %d \n", status);
344 return;
345 }
346
347 /*
348 * Un-Register 6rd tunnel with NSS
349 */
350 nss_unregister_tun6rd_if(g_tun6rd.if_num);
351 g_tun6rd.nss_ctx = NULL;
352 g_tun6rd.device_up = 0;
353 return;
354}
355
356/*
357 * nss_tun6rd_dev_event()
358 * Net device notifier for 6rd module
359 */
360static int nss_tun6rd_dev_event(struct notifier_block *nb,
361 unsigned long event, void *dev)
362{
363 struct net_device *netdev = (struct net_device *)dev;
364
365 nss_tun6rd_trace("%s\n",__FUNCTION__);
366 switch (event) {
367 case NETDEV_UP:
368 nss_tun6rd_trace(" NETDEV_UP :event %lu name %s \n",
369 event,netdev->name);
370 nss_tun6rd_dev_up(netdev);
371 break;
372
373 case NETDEV_DOWN:
374 nss_tun6rd_trace(" NETDEV_DOWN :event %lu name %s \n",
375 event,netdev->name);
376 nss_tun6rd_dev_down(netdev);
377 break;
378
379 default:
380 nss_tun6rd_trace("Unhandled notifier dev %s event %x \n",
381 netdev->name,(int)event);
382 break;
383 }
384
385 return NOTIFY_DONE;
386}
387
388/*
389 * nss_tun6rd_exception()
390 * Exception handler registered to NSS driver
391 */
392void nss_tun6rd_exception(void *ctx, void *buf)
393{
394 struct net_device *dev = (struct net_device *)ctx;
395 struct sk_buff *skb = (struct sk_buff *)buf;
396 const struct iphdr *iph;
397
398 skb->dev = dev;
399 nss_tun6rd_info("received - %d bytes name %s ver %x \n",
400 skb->len,dev->name,skb->data[0]);
401
402 iph = (const struct iphdr *)skb->data;
403
404 /*
405 * Packet after Decap/Encap Did not find the Rule.
406 */
407 if (iph->version == 4) {
408 skb->protocol = htons(ETH_P_IP);
409 } else {
410 skb->protocol = htons(ETH_P_IPV6);
411 }
412
413 skb_reset_network_header(skb);
414 skb->pkt_type = PACKET_HOST;
415 skb->skb_iif = dev->ifindex;
416 skb->ip_summed = CHECKSUM_NONE;
417 netif_receive_skb(skb);
418}
419
420/*
Radhakrishna Jiguru5ad493d2013-11-25 20:17:54 +0530421 * nss_tun6rd_update_dev_stats
422 * Update the Dev stats received from NetAp
423 */
424static void nss_tun6rd_update_dev_stats(struct net_device *dev,
425 struct nss_tun6rd_stats_sync *tun6rdstats)
426{
427 void *ptr;
428 struct nss_tun6rd_stats stats;
429
430 stats.rx_packets = tun6rdstats->rx_packets;
431 stats.rx_bytes = tun6rdstats->rx_bytes;
432 stats.tx_packets = tun6rdstats->tx_packets;
433 stats.tx_bytes = tun6rdstats->tx_bytes;
434 ptr = (void *)&stats;
435 ipip6_update_offload_stats(dev, ptr);
436}
437
438/**
439 * @brief Event Callback to receive events from NSS
440 * @param[in] pointer to net device context
441 * @param[in] event type
442 * @param[in] pointer to buffer
443 * @param[in] length of buffer
444 * @return Returns void
445 */
446void nss_tun6rd_event_receive(void *if_ctx, nss_tun6rd_event_t ev_type,
447 void *os_buf, uint32_t len)
448{
449 struct net_device *netdev = NULL;
450 netdev = (struct net_device *)if_ctx;
451
452 switch (ev_type) {
453 case NSS_TUN6RD_EVENT_STATS:
454 nss_tun6rd_update_dev_stats(netdev, (struct nss_tun6rd_stats_sync *)os_buf );
455 break;
456
457 default:
458 nss_tun6rd_info("%s: Unknown Event from NSS",
459 __FUNCTION__);
460 break;
461 }
462}
463
464/*
Bharath M Kumar0d87e912013-08-12 18:32:57 +0530465 * nss_tun6rd_init_module()
466 * Tunnel 6rd module init function
467 */
468int __init nss_tun6rd_init_module(void)
469{
470 nss_tun6rd_info("module (platform - IPQ806x , Build - %s:%s) loaded\n",
471 __DATE__, __TIME__);
472
473 register_netdevice_notifier(&nss_tun6rd_notifier);
474 nss_tun6rd_trace("Netdev Notifier registerd \n");
475
476 g_tun6rd.if_num = NSS_TUNRD_IF_NUMBER;
477 g_tun6rd.netdev = NULL;
478 g_tun6rd.device_up = 0;
479 g_tun6rd.nss_ctx = NULL;
480
481 return 0;
482}
483
484/*
485 * nss_tun6rd_exit_module()
486 * Tunnel 6rd module exit function
487 */
488void __exit nss_tun6rd_exit_module(void)
489{
490
491 unregister_netdevice_notifier(&nss_tun6rd_notifier);
492 nss_tun6rd_info("module unloaded\n");
493}
494
495module_init(nss_tun6rd_init_module);
496module_exit(nss_tun6rd_exit_module);
497
498MODULE_LICENSE("Dual BSD/GPL");
499MODULE_DESCRIPTION("NSS tun6rd offload manager");