blob: 7605d44b22e8527b8b93b3ea36eec60581ef33fe [file] [log] [blame]
Bharath M Kumar614bbf82013-08-31 20:18:44 +05301/*
2 **************************************************************************
3 * Copyright (c) 2013, Qualcomm Atheros, Inc.
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_tunipip6.c
19 *
20 * This file is the NSS DS-lit and IPP6 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 <net/ip6_tunnel.h>
33#include <linux/if_arp.h>
34#include "nss_api_if.h"
35#include "nss_hlos_if.h"
36
37#define NSS_TUNIPIP6_IF_NUMBER 11
38
39/*
40 * NSS tunipip6 debug macros
41 */
42#if (NSS_TUNIPIP6_DEBUG_LEVEL < 1)
43#define nss_tunipip6_assert(fmt, args...)
44#else
45#define nss_tunipip6_assert(c) if (!(c)) { BUG_ON(!(c)); }
46#endif
47
48#if (NSS_TUNIPIP6_DEBUG_LEVEL < 2)
49#define nss_tunipip6_error(fmt, args...)
50#else
51#define nss_tunipip6_error(fmt, args...) printk(KERN_WARNING "nss tunipip6:"fmt, ##args)
52#endif
53
54#if (NSS_TUNIPIP6_DEBUG_LEVEL < 3)
55#define nss_tunipip6_warning(fmt, args...)
56#else
57#define nss_tunipip6_warning(fmt, args...) printk(KERN_WARNING "nss tunipip6:"fmt, ##args)
58#endif
59
60#if (NSS_TUNIPIP6_DEBUG_LEVEL < 4)
61#define nss_tunipip6_info(fmt, args...)
62#else
63#define nss_tunipip6_info(fmt, args...) printk(KERN_INFO "nss tunipip6 :"fmt, ##args)
64#endif
65
66#if (NSS_TUNIPIP6_DEBUG_LEVEL < 5)
67#define nss_tunipip6_trace(fmt, args...)
68#else
69#define nss_tunipip6_trace(fmt, args...) printk(KERN_DEBUG "nss tunipip6 :"fmt, ##args)
70#endif
71
72void nss_tunipip6_exception(void *ctx, void *buf);
73
74enum tunipip6_metadata_types {
75 TUNIPIP6_METADATA_TYPE_IF_UP,
76 TUNIPIP6_METADATA_TYPE_IF_DOWN
77};
78
79/*
80 * DS-lite and ipip6 configuration command structure
81 */
82struct nss_tunnel_ipip6_cfg{
83 uint32_t saddr[4]; /* Tunnel source address */
84 uint32_t daddr[4]; /* Tunnel destination address */
85 uint32_t flowlabel; /* Tunnel ipv6 flowlabel */
86 uint32_t flags; /* Tunnel additional flags */
87 uint8_t hop_limit; /* Tunnel ipv6 hop limit */
88
89};
90
91/*
92 * DS-lite and ipip6 interface down command structure
93 */
94struct tunipip6_if_down_param{
95 uint32_t dummy[4]; /* dummy parameter */
96};
97
98/*
99 * DS-lite and ipip6 tunnel generic param
100 */
101struct nss_tunnel_ipip6_param {
102 enum tunipip6_metadata_types type;
103 union {
104 struct nss_tunnel_ipip6_cfg cfg;
105 struct tunipip6_if_down_param ifdown_param;
106 }sub;
107};
108
109/*
110 * nss_tunipip6_tunnel
111 * DS-lite and ipip 6tunnel host instance
112 */
113struct nss_tunipip6_tunnel{
114 void *nss_ctx;
115 uint32_t if_num;
116 struct net_device *netdev;
117 uint32_t device_up;
118};
119
120struct nss_tunipip6_tunnel g_tunipip6;
121
122/*
123 * Internal function
124 */
125static int
126nss_tunipip6_dev_event(struct notifier_block *nb,
127 unsigned long event,
128 void *dev);
129
130/*
131 * Linux Net device Notifier
132 */
133struct notifier_block nss_tunipip6_notifier = {
134 .notifier_call = nss_tunipip6_dev_event,
135};
136
137/*
138 * nss_tunipip6_dev_up()
139 * IPIP6 Tunnel device i/f up handler
140 */
141void nss_tunipip6_dev_up( struct net_device * netdev)
142{
143 struct ip6_tnl *tunnel;
144 struct nss_tunnel_ipip6_param tnlparam;
145 struct nss_tunnel_ipip6_cfg *tnlcfg;
146 struct flowi6 *fl6;
147 nss_tx_status_t status;
148
149 /*
150 * Validate netdev for ipv6-in-ipv4 Tunnel
151 */
152 if (netdev->type != ARPHRD_TUNNEL6 ) {
153 return;
154 }
155
156 tunnel = (struct ip6_tnl *)netdev_priv(netdev);
157
158 /*
159 * Find he Tunnel device flow information
160 */
161
162 fl6 = &tunnel->fl.u.ip6;
163
164 nss_tunipip6_trace(" Tunnel Param srcaddr %x:%x:%x:%x daddr %x:%x:%x:%x \n",
165 fl6->saddr.s6_addr32[0], fl6->saddr.s6_addr32[1],
166 fl6->saddr.s6_addr32[2], fl6->saddr.s6_addr32[3],
167 fl6->daddr.s6_addr32[0], fl6->daddr.s6_addr32[1],
168 fl6->daddr.s6_addr32[2], fl6->daddr.s6_addr32[3] );
169 nss_tunipip6_trace(" hop limit %d \n", tunnel->parms.hop_limit);
170 nss_tunipip6_trace(" tunnel param flag %x fl6.flowlabel %x \n", tunnel->parms.flags, fl6->flowlabel);
171
172 /*
173 *Prepare The Tunnel configuration parameter to send to nss
174 */
175 memset( &tnlparam, 0, sizeof(struct nss_tunnel_ipip6_param));
176 tnlparam.type = TUNIPIP6_METADATA_TYPE_IF_UP;
177 tnlcfg = (struct nss_tunnel_ipip6_cfg *)&tnlparam.sub.cfg;
178
179 tnlcfg->saddr[0] = ntohl(fl6->saddr.s6_addr32[0]);
180 tnlcfg->saddr[1] = ntohl(fl6->saddr.s6_addr32[1]);
181 tnlcfg->saddr[2] = ntohl(fl6->saddr.s6_addr32[2]);
182 tnlcfg->saddr[3] = ntohl(fl6->saddr.s6_addr32[3]);
183 tnlcfg->daddr[0] = ntohl(fl6->daddr.s6_addr32[0]);
184 tnlcfg->daddr[1] = ntohl(fl6->daddr.s6_addr32[1]);
185 tnlcfg->daddr[2] = ntohl(fl6->daddr.s6_addr32[2]);
186 tnlcfg->daddr[3] = ntohl(fl6->daddr.s6_addr32[3]);
187 tnlcfg->hop_limit = tunnel->parms.hop_limit;
188 tnlcfg->flags = ntohl(tunnel->parms.flags);
189 tnlcfg->flowlabel = fl6->flowlabel; /*flow Label In kernel is stored in big endian format*/
190 nss_tunipip6_trace(" Tunnel Param srcaddr %x:%x:%x:%x daddr %x:%x:%x:%x \n",
191 tnlcfg->saddr[0], tnlcfg->saddr[1],
192 tnlcfg->saddr[2], tnlcfg->saddr[3],
193 tnlcfg->daddr[0], tnlcfg->daddr[1],
194 tnlcfg->daddr[2], tnlcfg->daddr[3] );
195
196 /*
197 * Register ipip6 tunnel with NSS
198 */
199 g_tunipip6.nss_ctx = nss_register_tunipip6_if(g_tunipip6.if_num,
200 nss_tunipip6_exception,
201 netdev);
202 if (g_tunipip6.nss_ctx == NULL) {
203 nss_tunipip6_trace("nss_register_tunipip6_if Failed \n");
204 return;
205 } else {
206 nss_tunipip6_trace("nss_register_tunipip6_if Success \n");
207 }
208
209 nss_tunipip6_trace("Sending IPIP6 tunnel i/f up command to NSS %x \n",
210 (int)g_tunipip6.nss_ctx);
211
212 /*
213 * Send IPIP6 Tunnel UP command to NSS
214 */
215 status = nss_tx_generic_if_buf(g_tunipip6.nss_ctx,
216 g_tunipip6.if_num,
217 (uint8_t *)&tnlparam,
218 sizeof(struct nss_tunnel_ipip6_param));
219 if (status != NSS_TX_SUCCESS) {
220 nss_tunipip6_error("Tunnel up command error %d \n", status);
221 return;
222 }
223
224 g_tunipip6.device_up = 1;
225}
226
227/*
228 * nss_tunipip6_dev_down()
229 * IPP6 Tunnel device i/f down handler
230 */
231void nss_tunipip6_dev_down( struct net_device * netdev)
232{
233 struct nss_tunnel_ipip6_param tnlparam;
234 nss_tx_status_t status;
235
236 /*
237 * Check if tunnel ipip6 is registered ?
238 */
239 if(g_tunipip6.nss_ctx == NULL){
240 return;
241 }
242
243 /*
244 * Validate netdev for ipv6-in-ipv4 Tunnel
245 */
246 if (netdev->type != ARPHRD_TUNNEL6 ) {
247 return;
248 }
249
250 /*
251 * TODO: Strick check required if its the same tunnel
252 * registerd with us
253 */
254
255 memset( &tnlparam, 0, sizeof(struct nss_tunnel_ipip6_param));
256 tnlparam.type = TUNIPIP6_METADATA_TYPE_IF_DOWN;
257
258 nss_tunipip6_trace("Sending Tunnel ipip6 Down command %x \n",g_tunipip6.if_num);
259 status = nss_tx_generic_if_buf(g_tunipip6.nss_ctx,
260 g_tunipip6.if_num,
261 (uint8_t *)&tnlparam,
262 sizeof(struct nss_tunnel_ipip6_param));
263 if (status != NSS_TX_SUCCESS) {
264 nss_tunipip6_error("Tunnel down command error %d \n", status);
265 return;
266 }
267
268 /*
269 * Un-Register IPIP6 tunnel with NSS
270 */
271 nss_unregister_tunipip6_if(g_tunipip6.if_num);
272 g_tunipip6.nss_ctx = NULL;
273 g_tunipip6.device_up = 0;
274}
275
276/*
277 * nss_tun6rd_dev_event()
278 * Net device notifier for ipip6 module
279 */
280static int nss_tunipip6_dev_event(struct notifier_block *nb,
281 unsigned long event, void *dev)
282{
283 struct net_device *netdev = (struct net_device *)dev;
284
285 nss_tunipip6_trace("%s\n",__FUNCTION__);
286 switch (event) {
287 case NETDEV_UP:
288 nss_tunipip6_trace(" NETDEV_UP :event %lu name %s \n",
289 event,netdev->name);
290 nss_tunipip6_dev_up(netdev);
291 break;
292
293 case NETDEV_DOWN:
294 nss_tunipip6_trace(" NETDEV_DOWN :event %lu name %s \n",
295 event,netdev->name);
296 nss_tunipip6_dev_down(netdev);
297 break;
298
299 default:
300 nss_tunipip6_trace("Unhandled notifier dev %s event %x \n",
301 netdev->name,(int)event);
302 break;
303 }
304
305 return NOTIFY_DONE;
306}
307
308/*
309 * nss_tunipip6_exception()
310 * Exception handler registered to NSS driver
311 */
312void nss_tunipip6_exception(void *ctx, void *buf)
313{
314 struct net_device *dev = (struct net_device *)ctx;
315 struct sk_buff *skb = (struct sk_buff *)buf;
316 const struct iphdr *iph;
317
318 skb->dev = dev;
319 nss_tunipip6_info("received - %d bytes name %s ver %x \n",
320 skb->len,dev->name,skb->data[0]);
321
322 iph = (const struct iphdr *)skb->data;
323
324 /*
325 *Packet after Decap/Encap Did not find the Rule.
326 */
327 if (iph->version == 4) {
328 skb->protocol = htons(ETH_P_IP);
329 } else {
330 skb->protocol = htons(ETH_P_IPV6);
331 }
332
333 skb_reset_network_header(skb);
334 skb->pkt_type = PACKET_HOST;
335 skb->skb_iif = dev->ifindex;
336 skb->ip_summed = CHECKSUM_NONE;
337 netif_receive_skb(skb);
338}
339
340/*
341 * nss_tunipip6_init_module()
342 * Tunnel ipip6 module init function
343 */
344int __init nss_tunipip6_init_module(void)
345{
346 nss_tunipip6_info("module (platform - IPQ806x , Build - %s:%s) loaded\n",
347 __DATE__, __TIME__);
348
349 register_netdevice_notifier(&nss_tunipip6_notifier);
350 nss_tunipip6_trace("Netdev Notifier registerd \n");
351
352 g_tunipip6.if_num = NSS_TUNIPIP6_IF_NUMBER;
353 g_tunipip6.netdev = NULL;
354 g_tunipip6.device_up = 0;
355 g_tunipip6.nss_ctx = NULL;
356
357 return 0;
358}
359
360/*
361 * nss_tunipip6_exit_module()
362 * Tunnel ipip6 module exit function
363 */
364void __exit nss_tunipip6_exit_module(void)
365{
366
367 unregister_netdevice_notifier(&nss_tunipip6_notifier);
368 nss_tunipip6_info("module unloaded\n");
369}
370
371module_init(nss_tunipip6_init_module);
372module_exit(nss_tunipip6_exit_module);
373
374MODULE_LICENSE("Dual BSD/GPL");
375MODULE_DESCRIPTION("NSS tunipip6 offload manager");