1/*
2   Copyright 2012  Delta Networks, Inc.
3*/
4
5#include <linux/stddef.h>
6#include <linux/module.h>
7#include <linux/types.h>
8#include <asm/byteorder.h>
9#include <linux/init.h>
10#include <linux/errno.h>
11#include <linux/kernel.h>
12#include <linux/netdevice.h>
13#include <linux/etherdevice.h>
14#include <linux/skbuff.h>
15#include <linux/delay.h>
16#include <linux/timer.h>
17#include <linux/interrupt.h>
18#include <linux/dma-mapping.h>
19#include <linux/bitops.h>
20#include <linux/igmp.h>
21#include <asm/irq.h>
22#include <asm/io.h>
23#include <net/sch_generic.h>
24#include <linux/if_pppox.h>
25#include <linux/ip.h>
26#include <net/checksum.h>
27#include <linux/rtnetlink.h>
28
29#include "include/ipv6_pssthrgh.h"
30
31static struct net_device_ops athr_gmac_net_ops;
32
33extern int ipv6_pssthrgh_enable;
34
35int dni_enet_init(struct net_device *dev)
36{
37	/* TODO:  figure this out, maybe do nothing?? */
38	return 0;
39}
40
41void dni_enet_destruct(struct net_device *dev)
42{
43	return;
44}
45
46int dni_enet_open(struct net_device *dev)
47{
48	return 0;
49}
50
51int dni_enet_stop(struct net_device *dev)
52{
53	return 0;
54}
55
56static inline struct net_device_stats *dni_enet_get_stats(struct net_device *dev) {
57	return &(DNI_ENET_INFO(dev)->dev_stats);
58}
59
60
61int dni_enet_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
62{
63	struct net_device_stats *stats = dni_enet_get_stats(dev);
64	struct net_device *pdev;
65
66#ifdef CONFIG_PSSTHRGH
67	if (!(ipv6_pssthrgh_enable && skb->protocol == htons(ETH_P_IPV6))) {
68		kfree_skb(skb);
69		return NETDEV_TX_OK;
70	}
71#endif
72
73	pdev = DNI_ENET_INFO(dev)->real_dev;
74
75	stats->tx_packets++; /* for statics only */
76	stats->tx_bytes += skb->len;
77//	if(printk_ratelimit()) {
78//		int i;
79//		for (i=0; i<64; i++) {
80//			printk("%02x ", skb->data[i]);
81//			if (i % 16 == 15) printk("\n");
82//		}
83//		printk("skb->protocol = 0x%04x\n", ntohs(skb->protocol));
84//	}
85
86	pdev->netdev_ops->ndo_start_xmit(skb, pdev);
87
88	return NETDEV_TX_OK;
89}
90
91int dni_enet_set_mac_address(struct net_device *dev, void *addr_struct_p)
92{
93	struct sockaddr *addr = (struct sockaddr *)(addr_struct_p);
94	int i;
95
96	printk("Setting mac address\n");
97	if (netif_running(dev))
98		return -EBUSY;
99
100	memcpy(dev->dev_addr, addr->sa_data, 6);
101
102	printk("%s: Setting MAC address to ", dev->name);
103	for (i = 0; i < 6; i++)
104		printk(" %2.2x", dev->dev_addr[i]);
105	printk(".\n");
106	return 0;
107}
108
109
110static int __init
111dni_enet_load(void)
112{
113	struct net_device *real_dev;
114	struct net_device *new_dev;
115	int malloc_size;
116
117	printk("Loading DNI-ENET driver\n");
118
119// Get the WAN physical interface
120	real_dev = dev_get_by_name(&init_net, "eth0");
121	if (!real_dev) {
122		printk("Error, cannot find eth0 interface\n");
123		return -1;
124	}
125
126	rtnl_lock();
127
128	malloc_size = (sizeof(struct net_device));
129
130	new_dev = alloc_etherdev(0);
131	if (!new_dev)
132	{
133		printk("unable to allocate mac\n");
134		return 1;
135	}
136
137	sprintf(new_dev->name, "pas0");
138
139	athr_gmac_net_ops.ndo_init = dni_enet_init;
140	athr_gmac_net_ops.ndo_uninit = dni_enet_destruct;
141	athr_gmac_net_ops.ndo_get_stats = dni_enet_get_stats;
142	athr_gmac_net_ops.ndo_open = dni_enet_open;
143        athr_gmac_net_ops.ndo_stop = dni_enet_stop;
144	athr_gmac_net_ops.ndo_start_xmit = dni_enet_hard_start_xmit;
145	athr_gmac_net_ops.ndo_set_mac_address = dni_enet_set_mac_address;
146	athr_gmac_net_ops.ndo_change_mtu = NULL;
147	new_dev->tx_queue_len = 1000;
148
149	new_dev->netdev_ops = (const struct net_device_ops *)&athr_gmac_net_ops;
150
151
152//	new_dev->features |= NETIF_F_NO_CSUM ;
153
154	new_dev->mtu = real_dev->mtu;
155
156	/* TODO: maybe just assign it to be ETHERNET? */
157	new_dev->type = real_dev->type;
158	new_dev->hard_header_len = real_dev->hard_header_len;
159
160	new_dev->ml_priv = kmalloc(sizeof(struct dni_enet_info), GFP_KERNEL);
161	memset(new_dev->ml_priv, 0, sizeof(struct dni_enet_info));
162
163	memcpy(new_dev->broadcast, real_dev->broadcast, 6);
164
165	memcpy(new_dev->dev_addr, real_dev->dev_addr, 6);
166
167// XXX add addr
168//  new_dev->dev_addr[5]++;
169
170	new_dev->addr_len = real_dev->addr_len;
171
172	DNI_ENET_INFO(new_dev)->real_dev = real_dev;
173	register_netdevice(new_dev);
174
175	rtnl_unlock();
176
177	return 0;
178}
179
180module_init(dni_enet_load);
181
182static void __exit
183dni_enet_unload(void)
184{
185	printk("unloaded...\n");
186}
187
188MODULE_AUTHOR("Delta Networks, Inc.");
189MODULE_DESCRIPTION("Support for Pass Through Ethernet device");
190#ifdef MODULE_LICENSE
191MODULE_LICENSE("DNI");
192#endif
193module_exit(dni_enet_unload);
194
195