drivers/net: Remove casts of void *
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / net / ifb.c
CommitLineData
6aa20a22 1/* drivers/net/ifb.c:
253af423
JHS
2
3 The purpose of this driver is to provide a device that allows
4 for sharing of resources:
5
6 1) qdiscs/policies that are per device as opposed to system wide.
7 ifb allows for a device which can be redirected to thus providing
8 an impression of sharing.
9
10 2) Allows for queueing incoming traffic for shaping instead of
6aa20a22
JG
11 dropping.
12
253af423
JHS
13 The original concept is based on what is known as the IMQ
14 driver initially written by Martin Devera, later rewritten
15 by Patrick McHardy and then maintained by Andre Correa.
16
17 You need the tc action mirror or redirect to feed this device
18 packets.
19
20 This program is free software; you can redistribute it and/or
21 modify it under the terms of the GNU General Public License
22 as published by the Free Software Foundation; either version
23 2 of the License, or (at your option) any later version.
6aa20a22 24
253af423 25 Authors: Jamal Hadi Salim (2005)
6aa20a22 26
253af423
JHS
27*/
28
29
253af423
JHS
30#include <linux/module.h>
31#include <linux/kernel.h>
32#include <linux/netdevice.h>
33#include <linux/etherdevice.h>
34#include <linux/init.h>
a6b7a407 35#include <linux/interrupt.h>
253af423 36#include <linux/moduleparam.h>
6aa20a22 37#include <net/pkt_sched.h>
881d966b 38#include <net/net_namespace.h>
253af423 39
253af423
JHS
40#define TX_Q_LIMIT 32
41struct ifb_private {
253af423
JHS
42 struct tasklet_struct ifb_tasklet;
43 int tasklet_pending;
253af423
JHS
44 struct sk_buff_head rq;
45 struct sk_buff_head tq;
46};
47
35eaa31e 48static int numifbs = 2;
253af423
JHS
49
50static void ri_tasklet(unsigned long dev);
424efe9c 51static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev);
253af423
JHS
52static int ifb_open(struct net_device *dev);
53static int ifb_close(struct net_device *dev);
54
6aa20a22 55static void ri_tasklet(unsigned long dev)
253af423
JHS
56{
57
58 struct net_device *_dev = (struct net_device *)dev;
59 struct ifb_private *dp = netdev_priv(_dev);
09f75cd7 60 struct net_device_stats *stats = &_dev->stats;
c3f26a26 61 struct netdev_queue *txq;
253af423
JHS
62 struct sk_buff *skb;
63
c3f26a26 64 txq = netdev_get_tx_queue(_dev, 0);
253af423 65 if ((skb = skb_peek(&dp->tq)) == NULL) {
c3f26a26 66 if (__netif_tx_trylock(txq)) {
957fca95 67 skb_queue_splice_tail_init(&dp->rq, &dp->tq);
c3f26a26 68 __netif_tx_unlock(txq);
253af423
JHS
69 } else {
70 /* reschedule */
253af423
JHS
71 goto resched;
72 }
73 }
74
7edc3453 75 while ((skb = __skb_dequeue(&dp->tq)) != NULL) {
253af423
JHS
76 u32 from = G_TC_FROM(skb->tc_verd);
77
78 skb->tc_verd = 0;
79 skb->tc_verd = SET_TC_NCLS(skb->tc_verd);
80 stats->tx_packets++;
81 stats->tx_bytes +=skb->len;
c01003c2 82
05e8689c 83 rcu_read_lock();
8964be4a 84 skb->dev = dev_get_by_index_rcu(&init_net, skb->skb_iif);
c01003c2 85 if (!skb->dev) {
05e8689c 86 rcu_read_unlock();
c01003c2
PM
87 dev_kfree_skb(skb);
88 stats->tx_dropped++;
75c1c825
CG
89 if (skb_queue_len(&dp->tq) != 0)
90 goto resched;
c01003c2
PM
91 break;
92 }
05e8689c 93 rcu_read_unlock();
8964be4a 94 skb->skb_iif = _dev->ifindex;
c01003c2 95
253af423 96 if (from & AT_EGRESS) {
253af423
JHS
97 dev_queue_xmit(skb);
98 } else if (from & AT_INGRESS) {
c01003c2 99 skb_pull(skb, skb->dev->hard_header_len);
1a75972c 100 netif_receive_skb(skb);
c01003c2
PM
101 } else
102 BUG();
253af423
JHS
103 }
104
c3f26a26 105 if (__netif_tx_trylock(txq)) {
253af423
JHS
106 if ((skb = skb_peek(&dp->rq)) == NULL) {
107 dp->tasklet_pending = 0;
108 if (netif_queue_stopped(_dev))
109 netif_wake_queue(_dev);
110 } else {
c3f26a26 111 __netif_tx_unlock(txq);
253af423
JHS
112 goto resched;
113 }
c3f26a26 114 __netif_tx_unlock(txq);
253af423
JHS
115 } else {
116resched:
117 dp->tasklet_pending = 1;
118 tasklet_schedule(&dp->ifb_tasklet);
119 }
120
121}
122
8dfcdf34 123static const struct net_device_ops ifb_netdev_ops = {
8dfcdf34
SH
124 .ndo_open = ifb_open,
125 .ndo_stop = ifb_close,
00829823
SH
126 .ndo_start_xmit = ifb_xmit,
127 .ndo_validate_addr = eth_validate_addr,
8dfcdf34
SH
128};
129
39980292
ED
130#define IFB_FEATURES (NETIF_F_NO_CSUM | NETIF_F_SG | NETIF_F_FRAGLIST | \
131 NETIF_F_TSO_ECN | NETIF_F_TSO | NETIF_F_TSO6 | \
132 NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_TX)
133
9ba2cd65 134static void ifb_setup(struct net_device *dev)
253af423
JHS
135{
136 /* Initialize the device structure. */
9ba2cd65 137 dev->destructor = free_netdev;
8dfcdf34 138 dev->netdev_ops = &ifb_netdev_ops;
253af423
JHS
139
140 /* Fill in device structure with ethernet-generic values. */
141 ether_setup(dev);
142 dev->tx_queue_len = TX_Q_LIMIT;
8dfcdf34 143
39980292
ED
144 dev->features |= IFB_FEATURES;
145 dev->vlan_features |= IFB_FEATURES;
146
253af423
JHS
147 dev->flags |= IFF_NOARP;
148 dev->flags &= ~IFF_MULTICAST;
93f154b5 149 dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
253af423
JHS
150 random_ether_addr(dev->dev_addr);
151}
152
424efe9c 153static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev)
253af423
JHS
154{
155 struct ifb_private *dp = netdev_priv(dev);
09f75cd7 156 struct net_device_stats *stats = &dev->stats;
253af423
JHS
157 u32 from = G_TC_FROM(skb->tc_verd);
158
3136dcb3 159 stats->rx_packets++;
160 stats->rx_bytes+=skb->len;
253af423 161
8964be4a 162 if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->skb_iif) {
253af423
JHS
163 dev_kfree_skb(skb);
164 stats->rx_dropped++;
424efe9c 165 return NETDEV_TX_OK;
253af423
JHS
166 }
167
168 if (skb_queue_len(&dp->rq) >= dev->tx_queue_len) {
169 netif_stop_queue(dev);
170 }
171
957fca95 172 __skb_queue_tail(&dp->rq, skb);
253af423
JHS
173 if (!dp->tasklet_pending) {
174 dp->tasklet_pending = 1;
175 tasklet_schedule(&dp->ifb_tasklet);
176 }
177
424efe9c 178 return NETDEV_TX_OK;
253af423
JHS
179}
180
253af423
JHS
181static int ifb_close(struct net_device *dev)
182{
183 struct ifb_private *dp = netdev_priv(dev);
184
185 tasklet_kill(&dp->ifb_tasklet);
186 netif_stop_queue(dev);
957fca95
CG
187 __skb_queue_purge(&dp->rq);
188 __skb_queue_purge(&dp->tq);
253af423
JHS
189 return 0;
190}
191
192static int ifb_open(struct net_device *dev)
193{
194 struct ifb_private *dp = netdev_priv(dev);
195
196 tasklet_init(&dp->ifb_tasklet, ri_tasklet, (unsigned long)dev);
957fca95
CG
197 __skb_queue_head_init(&dp->rq);
198 __skb_queue_head_init(&dp->tq);
253af423
JHS
199 netif_start_queue(dev);
200
201 return 0;
202}
203
0e06877c
PM
204static int ifb_validate(struct nlattr *tb[], struct nlattr *data[])
205{
206 if (tb[IFLA_ADDRESS]) {
207 if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
208 return -EINVAL;
209 if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
210 return -EADDRNOTAVAIL;
211 }
212 return 0;
213}
214
9ba2cd65
PM
215static struct rtnl_link_ops ifb_link_ops __read_mostly = {
216 .kind = "ifb",
217 .priv_size = sizeof(struct ifb_private),
218 .setup = ifb_setup,
0e06877c 219 .validate = ifb_validate,
9ba2cd65
PM
220};
221
2d85cba2
PM
222/* Number of ifb devices to be set up by this module. */
223module_param(numifbs, int, 0);
224MODULE_PARM_DESC(numifbs, "Number of ifb devices");
225
253af423
JHS
226static int __init ifb_init_one(int index)
227{
228 struct net_device *dev_ifb;
229 int err;
230
231 dev_ifb = alloc_netdev(sizeof(struct ifb_private),
232 "ifb%d", ifb_setup);
233
234 if (!dev_ifb)
235 return -ENOMEM;
236
9ba2cd65
PM
237 dev_ifb->rtnl_link_ops = &ifb_link_ops;
238 err = register_netdevice(dev_ifb);
239 if (err < 0)
240 goto err;
94833dfb 241
9ba2cd65 242 return 0;
62b7ffca 243
9ba2cd65
PM
244err:
245 free_netdev(dev_ifb);
246 return err;
6aa20a22 247}
253af423
JHS
248
249static int __init ifb_init_module(void)
6aa20a22 250{
9ba2cd65
PM
251 int i, err;
252
253 rtnl_lock();
254 err = __rtnl_link_register(&ifb_link_ops);
62b7ffca 255
253af423 256 for (i = 0; i < numifbs && !err; i++)
6aa20a22 257 err = ifb_init_one(i);
2d85cba2 258 if (err)
9ba2cd65 259 __rtnl_link_unregister(&ifb_link_ops);
9ba2cd65 260 rtnl_unlock();
253af423
JHS
261
262 return err;
6aa20a22 263}
253af423
JHS
264
265static void __exit ifb_cleanup_module(void)
266{
2d85cba2 267 rtnl_link_unregister(&ifb_link_ops);
253af423
JHS
268}
269
270module_init(ifb_init_module);
271module_exit(ifb_cleanup_module);
272MODULE_LICENSE("GPL");
273MODULE_AUTHOR("Jamal Hadi Salim");
9ba2cd65 274MODULE_ALIAS_RTNL_LINK("ifb");