summaryrefslogtreecommitdiff
path: root/net/core/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/dev.c')
-rw-r--r--net/core/dev.c328
1 files changed, 218 insertions, 110 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 4dc93cc4d5b7..d5e42d13bd67 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -109,7 +109,7 @@
#include <linux/netpoll.h>
#include <linux/rcupdate.h>
#include <linux/delay.h>
-#include <linux/wireless.h>
+#include <net/wext.h>
#include <net/iw_handler.h>
#include <asm/current.h>
#include <linux/audit.h>
@@ -146,8 +146,8 @@
*/
static DEFINE_SPINLOCK(ptype_lock);
-static struct list_head ptype_base[16]; /* 16 way hashed list */
-static struct list_head ptype_all; /* Taps */
+static struct list_head ptype_base[16] __read_mostly; /* 16 way hashed list */
+static struct list_head ptype_all __read_mostly; /* Taps */
#ifdef CONFIG_NET_DMA
static struct dma_client *net_dma_client;
@@ -226,12 +226,6 @@ extern void netdev_unregister_sysfs(struct net_device *);
*******************************************************************************/
/*
- * For efficiency
- */
-
-static int netdev_nit;
-
-/*
* Add a protocol ID to the list. Now that the input handler is
* smarter we can dispense with all the messy stuff that used to be
* here.
@@ -265,10 +259,9 @@ void dev_add_pack(struct packet_type *pt)
int hash;
spin_lock_bh(&ptype_lock);
- if (pt->type == htons(ETH_P_ALL)) {
- netdev_nit++;
+ if (pt->type == htons(ETH_P_ALL))
list_add_rcu(&pt->list, &ptype_all);
- } else {
+ else {
hash = ntohs(pt->type) & 15;
list_add_rcu(&pt->list, &ptype_base[hash]);
}
@@ -295,10 +288,9 @@ void __dev_remove_pack(struct packet_type *pt)
spin_lock_bh(&ptype_lock);
- if (pt->type == htons(ETH_P_ALL)) {
- netdev_nit--;
+ if (pt->type == htons(ETH_P_ALL))
head = &ptype_all;
- } else
+ else
head = &ptype_base[ntohs(pt->type) & 15];
list_for_each_entry(pt1, head, list) {
@@ -817,7 +809,6 @@ static int default_rebuild_header(struct sk_buff *skb)
return 1;
}
-
/**
* dev_open - prepare an interface for use.
* @dev: device to open
@@ -1031,23 +1022,12 @@ void net_disable_timestamp(void)
atomic_dec(&netstamp_needed);
}
-void __net_timestamp(struct sk_buff *skb)
-{
- struct timeval tv;
-
- do_gettimeofday(&tv);
- skb_set_timestamp(skb, &tv);
-}
-EXPORT_SYMBOL(__net_timestamp);
-
static inline void net_timestamp(struct sk_buff *skb)
{
if (atomic_read(&netstamp_needed))
__net_timestamp(skb);
- else {
- skb->tstamp.off_sec = 0;
- skb->tstamp.off_usec = 0;
- }
+ else
+ skb->tstamp.tv64 = 0;
}
/*
@@ -1077,18 +1057,18 @@ static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
set by sender, so that the second statement is
just protection against buggy protocols.
*/
- skb2->mac.raw = skb2->data;
+ skb_reset_mac_header(skb2);
- if (skb2->nh.raw < skb2->data ||
- skb2->nh.raw > skb2->tail) {
+ if (skb_network_header(skb2) < skb2->data ||
+ skb2->network_header > skb2->tail) {
if (net_ratelimit())
printk(KERN_CRIT "protocol %04x is "
"buggy, dev %s\n",
skb2->protocol, dev->name);
- skb2->nh.raw = skb2->data;
+ skb_reset_network_header(skb2);
}
- skb2->h.raw = skb2->nh.raw;
+ skb2->transport_header = skb2->network_header;
skb2->pkt_type = PACKET_OUTGOING;
ptype->func(skb2, skb->dev, ptype, skb->dev);
}
@@ -1167,7 +1147,7 @@ EXPORT_SYMBOL(netif_device_attach);
int skb_checksum_help(struct sk_buff *skb)
{
__wsum csum;
- int ret = 0, offset = skb->h.raw - skb->data;
+ int ret = 0, offset;
if (skb->ip_summed == CHECKSUM_COMPLETE)
goto out_set_summed;
@@ -1183,15 +1163,16 @@ int skb_checksum_help(struct sk_buff *skb)
goto out;
}
+ offset = skb->csum_start - skb_headroom(skb);
BUG_ON(offset > (int)skb->len);
csum = skb_checksum(skb, offset, skb->len-offset, 0);
- offset = skb->tail - skb->h.raw;
+ offset = skb_headlen(skb) - offset;
BUG_ON(offset <= 0);
BUG_ON(skb->csum_offset + 2 > offset);
- *(__sum16*)(skb->h.raw + skb->csum_offset) = csum_fold(csum);
-
+ *(__sum16 *)(skb->head + skb->csum_start + skb->csum_offset) =
+ csum_fold(csum);
out_set_summed:
skb->ip_summed = CHECKSUM_NONE;
out:
@@ -1217,11 +1198,11 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
BUG_ON(skb_shinfo(skb)->frag_list);
- skb->mac.raw = skb->data;
- skb->mac_len = skb->nh.raw - skb->data;
+ skb_reset_mac_header(skb);
+ skb->mac_len = skb->network_header - skb->mac_header;
__skb_pull(skb, skb->mac_len);
- if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
+ if (WARN_ON(skb->ip_summed != CHECKSUM_PARTIAL)) {
if (skb_header_cloned(skb) &&
(err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
return ERR_PTR(err);
@@ -1235,7 +1216,8 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
segs = ERR_PTR(err);
if (err || skb_gso_ok(skb, features))
break;
- __skb_push(skb, skb->data - skb->nh.raw);
+ __skb_push(skb, (skb->data -
+ skb_network_header(skb)));
}
segs = ptype->gso_segment(skb, features);
break;
@@ -1243,7 +1225,7 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
}
rcu_read_unlock();
- __skb_push(skb, skb->data - skb->mac.raw);
+ __skb_push(skb, skb->data - skb_mac_header(skb));
return segs;
}
@@ -1340,7 +1322,7 @@ static int dev_gso_segment(struct sk_buff *skb)
int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
if (likely(!skb->next)) {
- if (netdev_nit)
+ if (!list_empty(&ptype_all))
dev_queue_xmit_nit(skb, dev);
if (netif_needs_gso(dev, skb)) {
@@ -1442,12 +1424,16 @@ int dev_queue_xmit(struct sk_buff *skb)
/* If packet is not checksummed and device does not support
* checksumming for this protocol, complete checksumming here.
*/
- if (skb->ip_summed == CHECKSUM_PARTIAL &&
- (!(dev->features & NETIF_F_GEN_CSUM) &&
- (!(dev->features & NETIF_F_IP_CSUM) ||
- skb->protocol != htons(ETH_P_IP))))
- if (skb_checksum_help(skb))
- goto out_kfree_skb;
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ skb_set_transport_header(skb, skb->csum_start -
+ skb_headroom(skb));
+
+ if (!(dev->features & NETIF_F_GEN_CSUM) &&
+ (!(dev->features & NETIF_F_IP_CSUM) ||
+ skb->protocol != htons(ETH_P_IP)))
+ if (skb_checksum_help(skb))
+ goto out_kfree_skb;
+ }
gso:
spin_lock_prefetch(&dev->queue_lock);
@@ -1543,9 +1529,9 @@ out:
Receiver routines
=======================================================================*/
-int netdev_max_backlog = 1000;
-int netdev_budget = 300;
-int weight_p = 64; /* old backlog weight */
+int netdev_max_backlog __read_mostly = 1000;
+int netdev_budget __read_mostly = 300;
+int weight_p __read_mostly = 64; /* old backlog weight */
DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, };
@@ -1577,7 +1563,7 @@ int netif_rx(struct sk_buff *skb)
if (netpoll_rx(skb))
return NET_RX_DROP;
- if (!skb->tstamp.off_sec)
+ if (!skb->tstamp.tv64)
net_timestamp(skb);
/*
@@ -1684,40 +1670,46 @@ static void net_tx_action(struct softirq_action *h)
}
}
-static __inline__ int deliver_skb(struct sk_buff *skb,
- struct packet_type *pt_prev,
- struct net_device *orig_dev)
+static inline int deliver_skb(struct sk_buff *skb,
+ struct packet_type *pt_prev,
+ struct net_device *orig_dev)
{
atomic_inc(&skb->users);
return pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
}
#if defined(CONFIG_BRIDGE) || defined (CONFIG_BRIDGE_MODULE)
-int (*br_handle_frame_hook)(struct net_bridge_port *p, struct sk_buff **pskb);
+/* These hooks defined here for ATM */
struct net_bridge;
struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
unsigned char *addr);
-void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
+void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent) __read_mostly;
-static __inline__ int handle_bridge(struct sk_buff **pskb,
- struct packet_type **pt_prev, int *ret,
- struct net_device *orig_dev)
+/*
+ * If bridge module is loaded call bridging hook.
+ * returns NULL if packet was consumed.
+ */
+struct sk_buff *(*br_handle_frame_hook)(struct net_bridge_port *p,
+ struct sk_buff *skb) __read_mostly;
+static inline struct sk_buff *handle_bridge(struct sk_buff *skb,
+ struct packet_type **pt_prev, int *ret,
+ struct net_device *orig_dev)
{
struct net_bridge_port *port;
- if ((*pskb)->pkt_type == PACKET_LOOPBACK ||
- (port = rcu_dereference((*pskb)->dev->br_port)) == NULL)
- return 0;
+ if (skb->pkt_type == PACKET_LOOPBACK ||
+ (port = rcu_dereference(skb->dev->br_port)) == NULL)
+ return skb;
if (*pt_prev) {
- *ret = deliver_skb(*pskb, *pt_prev, orig_dev);
+ *ret = deliver_skb(skb, *pt_prev, orig_dev);
*pt_prev = NULL;
}
- return br_handle_frame_hook(port, pskb);
+ return br_handle_frame_hook(port, skb);
}
#else
-#define handle_bridge(skb, pt_prev, ret, orig_dev) (0)
+#define handle_bridge(skb, pt_prev, ret, orig_dev) (skb)
#endif
#ifdef CONFIG_NET_CLS_ACT
@@ -1747,10 +1739,10 @@ static int ing_filter(struct sk_buff *skb)
skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS);
- spin_lock(&dev->queue_lock);
+ spin_lock(&dev->ingress_lock);
if ((q = dev->qdisc_ingress) != NULL)
result = q->enqueue(skb, q);
- spin_unlock(&dev->queue_lock);
+ spin_unlock(&dev->ingress_lock);
}
@@ -1769,7 +1761,7 @@ int netif_receive_skb(struct sk_buff *skb)
if (skb->dev->poll && netpoll_rx(skb))
return NET_RX_DROP;
- if (!skb->tstamp.off_sec)
+ if (!skb->tstamp.tv64)
net_timestamp(skb);
if (!skb->iif)
@@ -1782,8 +1774,9 @@ int netif_receive_skb(struct sk_buff *skb)
__get_cpu_var(netdev_rx_stat).total++;
- skb->h.raw = skb->nh.raw = skb->data;
- skb->mac_len = skb->nh.raw - skb->mac.raw;
+ skb_reset_network_header(skb);
+ skb_reset_transport_header(skb);
+ skb->mac_len = skb->network_header - skb->mac_header;
pt_prev = NULL;
@@ -1823,7 +1816,8 @@ int netif_receive_skb(struct sk_buff *skb)
ncls:
#endif
- if (handle_bridge(&skb, &pt_prev, &ret, orig_dev))
+ skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
+ if (!skb)
goto out;
type = skb->protocol;
@@ -2076,7 +2070,7 @@ static int dev_ifconf(char __user *arg)
* This is invoked by the /proc filesystem handler to display a device
* in detail.
*/
-static __inline__ struct net_device *dev_get_idx(loff_t pos)
+static struct net_device *dev_get_idx(loff_t pos)
{
struct net_device *dev;
loff_t i;
@@ -2105,9 +2099,9 @@ void dev_seq_stop(struct seq_file *seq, void *v)
static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
{
- if (dev->get_stats) {
- struct net_device_stats *stats = dev->get_stats(dev);
+ struct net_device_stats *stats = dev->get_stats(dev);
+ if (stats) {
seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
"%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
dev->name, stats->rx_bytes, stats->rx_packets,
@@ -2185,7 +2179,7 @@ static int softnet_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static struct seq_operations dev_seq_ops = {
+static const struct seq_operations dev_seq_ops = {
.start = dev_seq_start,
.next = dev_seq_next,
.stop = dev_seq_stop,
@@ -2205,7 +2199,7 @@ static const struct file_operations dev_seq_fops = {
.release = seq_release,
};
-static struct seq_operations softnet_seq_ops = {
+static const struct seq_operations softnet_seq_ops = {
.start = softnet_seq_start,
.next = softnet_seq_next,
.stop = softnet_seq_stop,
@@ -2225,12 +2219,135 @@ static const struct file_operations softnet_seq_fops = {
.release = seq_release,
};
-#ifdef CONFIG_WIRELESS_EXT
-extern int wireless_proc_init(void);
-#else
-#define wireless_proc_init() 0
+static void *ptype_get_idx(loff_t pos)
+{
+ struct packet_type *pt = NULL;
+ loff_t i = 0;
+ int t;
+
+ list_for_each_entry_rcu(pt, &ptype_all, list) {
+ if (i == pos)
+ return pt;
+ ++i;
+ }
+
+ for (t = 0; t < 16; t++) {
+ list_for_each_entry_rcu(pt, &ptype_base[t], list) {
+ if (i == pos)
+ return pt;
+ ++i;
+ }
+ }
+ return NULL;
+}
+
+static void *ptype_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ rcu_read_lock();
+ return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN;
+}
+
+static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct packet_type *pt;
+ struct list_head *nxt;
+ int hash;
+
+ ++*pos;
+ if (v == SEQ_START_TOKEN)
+ return ptype_get_idx(0);
+
+ pt = v;
+ nxt = pt->list.next;
+ if (pt->type == htons(ETH_P_ALL)) {
+ if (nxt != &ptype_all)
+ goto found;
+ hash = 0;
+ nxt = ptype_base[0].next;
+ } else
+ hash = ntohs(pt->type) & 15;
+
+ while (nxt == &ptype_base[hash]) {
+ if (++hash >= 16)
+ return NULL;
+ nxt = ptype_base[hash].next;
+ }
+found:
+ return list_entry(nxt, struct packet_type, list);
+}
+
+static void ptype_seq_stop(struct seq_file *seq, void *v)
+{
+ rcu_read_unlock();
+}
+
+static void ptype_seq_decode(struct seq_file *seq, void *sym)
+{
+#ifdef CONFIG_KALLSYMS
+ unsigned long offset = 0, symsize;
+ const char *symname;
+ char *modname;
+ char namebuf[128];
+
+ symname = kallsyms_lookup((unsigned long)sym, &symsize, &offset,
+ &modname, namebuf);
+
+ if (symname) {
+ char *delim = ":";
+
+ if (!modname)
+ modname = delim = "";
+ seq_printf(seq, "%s%s%s%s+0x%lx", delim, modname, delim,
+ symname, offset);
+ return;
+ }
#endif
+ seq_printf(seq, "[%p]", sym);
+}
+
+static int ptype_seq_show(struct seq_file *seq, void *v)
+{
+ struct packet_type *pt = v;
+
+ if (v == SEQ_START_TOKEN)
+ seq_puts(seq, "Type Device Function\n");
+ else {
+ if (pt->type == htons(ETH_P_ALL))
+ seq_puts(seq, "ALL ");
+ else
+ seq_printf(seq, "%04x", ntohs(pt->type));
+
+ seq_printf(seq, " %-8s ",
+ pt->dev ? pt->dev->name : "");
+ ptype_seq_decode(seq, pt->func);
+ seq_putc(seq, '\n');
+ }
+
+ return 0;
+}
+
+static const struct seq_operations ptype_seq_ops = {
+ .start = ptype_seq_start,
+ .next = ptype_seq_next,
+ .stop = ptype_seq_stop,
+ .show = ptype_seq_show,
+};
+
+static int ptype_seq_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &ptype_seq_ops);
+}
+
+static const struct file_operations ptype_seq_fops = {
+ .owner = THIS_MODULE,
+ .open = ptype_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+
static int __init dev_proc_init(void)
{
int rc = -ENOMEM;
@@ -2239,13 +2356,18 @@ static int __init dev_proc_init(void)
goto out;
if (!proc_net_fops_create("softnet_stat", S_IRUGO, &softnet_seq_fops))
goto out_dev;
- if (wireless_proc_init())
+ if (!proc_net_fops_create("ptype", S_IRUGO, &ptype_seq_fops))
+ goto out_dev2;
+
+ if (wext_proc_init())
goto out_softnet;
rc = 0;
out:
return rc;
out_softnet:
proc_net_remove("softnet_stat");
+out_dev2:
+ proc_net_remove("ptype");
out_dev:
proc_net_remove("dev");
goto out;
@@ -2795,29 +2917,9 @@ int dev_ioctl(unsigned int cmd, void __user *arg)
ret = -EFAULT;
return ret;
}
-#ifdef CONFIG_WIRELESS_EXT
/* Take care of Wireless Extensions */
- if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
- /* If command is `set a parameter', or
- * `get the encoding parameters', check if
- * the user has the right to do it */
- if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE
- || cmd == SIOCGIWENCODEEXT) {
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- }
- dev_load(ifr.ifr_name);
- rtnl_lock();
- /* Follow me in net/core/wireless.c */
- ret = wireless_process_ioctl(&ifr, cmd);
- rtnl_unlock();
- if (IW_IS_GET(cmd) &&
- copy_to_user(arg, &ifr,
- sizeof(struct ifreq)))
- ret = -EFAULT;
- return ret;
- }
-#endif /* CONFIG_WIRELESS_EXT */
+ if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)
+ return wext_handle_ioctl(&ifr, cmd, arg);
return -EINVAL;
}
}
@@ -2847,7 +2949,7 @@ static int dev_boot_phase = 1;
static DEFINE_SPINLOCK(net_todo_list_lock);
static struct list_head net_todo_list = LIST_HEAD_INIT(net_todo_list);
-static inline void net_set_todo(struct net_device *dev)
+static void net_set_todo(struct net_device *dev)
{
spin_lock(&net_todo_list_lock);
list_add_tail(&dev->todo_list, &net_todo_list);
@@ -2888,9 +2990,7 @@ int register_netdevice(struct net_device *dev)
spin_lock_init(&dev->queue_lock);
spin_lock_init(&dev->_xmit_lock);
dev->xmit_lock_owner = -1;
-#ifdef CONFIG_NET_CLS_ACT
spin_lock_init(&dev->ingress_lock);
-#endif
dev->iflink = -1;
@@ -3002,7 +3102,7 @@ out:
* chain. 0 is returned on success. A negative errno code is returned
* on a failure to set up the device, or if the name is a duplicate.
*
- * This is a wrapper around register_netdev that takes the rtnl semaphore
+ * This is a wrapper around register_netdevice that takes the rtnl semaphore
* and expands the device name if you passed a format string to
* alloc_netdev.
*/
@@ -3157,6 +3257,13 @@ out:
mutex_unlock(&net_todo_run_mutex);
}
+static struct net_device_stats *maybe_internal_stats(struct net_device *dev)
+{
+ if (dev->features & NETIF_F_INTERNAL_STATS)
+ return &dev->stats;
+ return NULL;
+}
+
/**
* alloc_netdev - allocate network device
* @sizeof_priv: size of private data to allocate space for
@@ -3192,6 +3299,7 @@ struct net_device *alloc_netdev(int sizeof_priv, const char *name,
if (sizeof_priv)
dev->priv = netdev_priv(dev);
+ dev->get_stats = maybe_internal_stats;
setup(dev);
strcpy(dev->name, name);
return dev;