From 5811769c788edbf379c8b3fc65f62394d52df748 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:45:00 -0800 Subject: [IPV4]: Remove check for ifa->ifa_dev != NULL. This is a callback registered to inet address notifier chain. The check is useless as: - ifa->ifa_dev is always != NULL - similar checks are abscent in all other notifiers. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/atm/clip.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'net') diff --git a/net/atm/clip.c b/net/atm/clip.c index d30167c0b48e..d45971bd286c 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -648,10 +648,6 @@ static int clip_inet_event(struct notifier_block *this, unsigned long event, struct in_device *in_dev; in_dev = ((struct in_ifaddr *)ifa)->ifa_dev; - if (!in_dev || !in_dev->dev) { - printk(KERN_WARNING "clip_inet_event: no device\n"); - return NOTIFY_DONE; - } /* * Transitions are of the down-change-up type, so it's sufficient to * handle the change on up. -- cgit v1.2.3-59-g8ed1b From 6fc68624e524014fcd95faf726f855eb348f2e87 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:45:41 -0800 Subject: [NETFILTER]: Consolidate masq_inet_event and masq_device_event. They do exactly the same job. Signed-off-by: Denis V. Lunev Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_MASQUERADE.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index d80fee8327e4..313b3fcf387e 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -139,18 +139,8 @@ static int masq_inet_event(struct notifier_block *this, unsigned long event, void *ptr) { - const struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; - - if (event == NETDEV_DOWN) { - /* IP address was deleted. Search entire table for - conntracks which were associated with that device, - and forget them. */ - NF_CT_ASSERT(dev->ifindex != 0); - - nf_ct_iterate_cleanup(device_cmp, (void *)(long)dev->ifindex); - } - - return NOTIFY_DONE; + struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; + return masq_device_event(this, event, dev); } static struct notifier_block masq_dev_notifier = { -- cgit v1.2.3-59-g8ed1b From 6133fb1aa137b35a8fa91ec17977ebf6a41456ec Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:46:17 -0800 Subject: [NETNS]: Disable inetaddr notifiers in namespaces other than initial. ip_fib_init is kept enabled. It is already namespace-aware. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 3 +++ drivers/net/via-velocity.c | 3 +++ drivers/s390/net/qeth_main.c | 3 +++ net/sctp/protocol.c | 3 +++ 4 files changed, 12 insertions(+) (limited to 'net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 0942d82f7cbf..966643473da7 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3511,6 +3511,9 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, struct bonding *bond, *bond_next; struct vlan_entry *vlan, *vlan_next; + if (ifa->ifa_dev->dev->nd_net != &init_net) + return NOTIFY_DONE; + list_for_each_entry_safe(bond, bond_next, &bond_dev_list, bond_list) { if (bond->dev == event_dev) { switch (event) { diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index c50fdeed9e85..1525e8a89844 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -3464,6 +3464,9 @@ static int velocity_netdev_event(struct notifier_block *nb, unsigned long notifi struct velocity_info *vptr; unsigned long flags; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + spin_lock_irqsave(&velocity_dev_list_lock, flags); list_for_each_entry(vptr, &velocity_dev_list, list) { if (vptr->dev == dev) { diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 62606ce26e55..d063e9ecf804 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -8622,6 +8622,9 @@ qeth_ip_event(struct notifier_block *this, struct qeth_ipaddr *addr; struct qeth_card *card; + if (dev->nd_net != &init_net) + return NOTIFY_DONE; + QETH_DBF_TEXT(trace,3,"ipevent"); card = qeth_get_card_from_dev(dev); if (!card) diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 688546dccd82..8d9d929f6cea 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -629,6 +629,9 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, struct sctp_sockaddr_entry *addr = NULL; struct sctp_sockaddr_entry *temp; + if (ifa->ifa_dev->dev->nd_net != &init_net) + return NOTIFY_DONE; + switch (ev) { case NETDEV_UP: addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC); -- cgit v1.2.3-59-g8ed1b From 4ab438fcd7373da9e559576e418e890b7cfd94f4 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:48:01 -0800 Subject: [NETNS]: Register neighbour table parameters in the correct namespace. neigh_sysctl_register should register sysctl entries inside correct namespace to avoid naming conflict. Typical example is a loopback. Entries for it present in all namespaces. Required to make inetdev_event working. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/core/neighbour.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/neighbour.c b/net/core/neighbour.c index aef01533dfb6..be8b264b29bf 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2741,7 +2741,8 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, neigh_path[NEIGH_CTL_PATH_PROTO].procname = p_name; neigh_path[NEIGH_CTL_PATH_PROTO].ctl_name = p_id; - t->sysctl_header = register_sysctl_paths(neigh_path, t->neigh_vars); + t->sysctl_header = + register_net_sysctl_table(p->net, neigh_path, t->neigh_vars); if (!t->sysctl_header) goto free_procname; -- cgit v1.2.3-59-g8ed1b From 0c65babd6ce758dd06330b3d9d677b7624f9e3fa Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:48:25 -0800 Subject: [NETNS]: Default arp parameters lookup. Default ARP parameters should be findable regardless of the context. Required to make inetdev_event working. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/core/neighbour.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'net') diff --git a/net/core/neighbour.c b/net/core/neighbour.c index be8b264b29bf..31b6567f0b6a 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1284,9 +1284,7 @@ static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, struct neigh_parms *p; for (p = &tbl->parms; p; p = p->next) { - if (p->net != net) - continue; - if ((p->dev && p->dev->ifindex == ifindex) || + if ((p->dev && p->dev->ifindex == ifindex && p->net == net) || (!p->dev && !ifindex)) return p; } -- cgit v1.2.3-59-g8ed1b From 2430aa85de8343662e8496dac9f9e4dade680023 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:48:49 -0800 Subject: [NETNS]: Disable multicaststing configuration inside non-initial namespace. Do not calls hooks from device notifiers and disallow configuration from ioctl/netlink layer. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/igmp.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'net') diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 732cd07e6071..d3f34a772f3b 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1198,6 +1198,9 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) ASSERT_RTNL(); + if (in_dev->dev->nd_net != &init_net) + return; + for (im=in_dev->mc_list; im; im=im->next) { if (im->multiaddr == addr) { im->users++; @@ -1277,6 +1280,9 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) ASSERT_RTNL(); + if (in_dev->dev->nd_net != &init_net) + return; + for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) { if (i->multiaddr==addr) { if (--i->users == 0) { @@ -1304,6 +1310,9 @@ void ip_mc_down(struct in_device *in_dev) ASSERT_RTNL(); + if (in_dev->dev->nd_net != &init_net) + return; + for (i=in_dev->mc_list; i; i=i->next) igmp_group_dropped(i); @@ -1324,6 +1333,9 @@ void ip_mc_init_dev(struct in_device *in_dev) { ASSERT_RTNL(); + if (in_dev->dev->nd_net != &init_net) + return; + in_dev->mc_tomb = NULL; #ifdef CONFIG_IP_MULTICAST in_dev->mr_gq_running = 0; @@ -1347,6 +1359,9 @@ void ip_mc_up(struct in_device *in_dev) ASSERT_RTNL(); + if (in_dev->dev->nd_net != &init_net) + return; + ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS); for (i=in_dev->mc_list; i; i=i->next) @@ -1363,6 +1378,9 @@ void ip_mc_destroy_dev(struct in_device *in_dev) ASSERT_RTNL(); + if (in_dev->dev->nd_net != &init_net) + return; + /* Deactivate timers */ ip_mc_down(in_dev); @@ -1744,6 +1762,9 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) if (!ipv4_is_multicast(addr)) return -EINVAL; + if (sk->sk_net != &init_net) + return -EPROTONOSUPPORT; + rtnl_lock(); in_dev = ip_mc_find_dev(imr); @@ -1812,6 +1833,9 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) u32 ifindex; int ret = -EADDRNOTAVAIL; + if (sk->sk_net != &init_net) + return -EPROTONOSUPPORT; + rtnl_lock(); in_dev = ip_mc_find_dev(imr); ifindex = imr->imr_ifindex; @@ -1857,6 +1881,9 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct if (!ipv4_is_multicast(addr)) return -EINVAL; + if (sk->sk_net != &init_net) + return -EPROTONOSUPPORT; + rtnl_lock(); imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr; @@ -1990,6 +2017,9 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) msf->imsf_fmode != MCAST_EXCLUDE) return -EINVAL; + if (sk->sk_net != &init_net) + return -EPROTONOSUPPORT; + rtnl_lock(); imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; @@ -2070,6 +2100,9 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, if (!ipv4_is_multicast(addr)) return -EINVAL; + if (sk->sk_net != &init_net) + return -EPROTONOSUPPORT; + rtnl_lock(); imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; @@ -2132,6 +2165,9 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, if (!ipv4_is_multicast(addr)) return -EINVAL; + if (sk->sk_net != &init_net) + return -EPROTONOSUPPORT; + rtnl_lock(); err = -EADDRNOTAVAIL; @@ -2216,6 +2252,9 @@ void ip_mc_drop_socket(struct sock *sk) if (inet->mc_list == NULL) return; + if (sk->sk_net != &init_net) + return; + rtnl_lock(); while ((iml = inet->mc_list) != NULL) { struct in_device *in_dev; -- cgit v1.2.3-59-g8ed1b From be162d6288053305c32588c0596eb5e8dd90c564 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:49:13 -0800 Subject: [NETNS]: Enable inetdev_event notifier. After all these preparations it is time to enable main IPv4 device initialization routine inside namespace. It is safe do this now. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 87490f7bb0f7..90210a74d638 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1045,9 +1045,6 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; struct in_device *in_dev = __in_dev_get_rtnl(dev); - if (dev->nd_net != &init_net) - return NOTIFY_DONE; - ASSERT_RTNL(); if (!in_dev) { -- cgit v1.2.3-59-g8ed1b From 9de8f76d200342f1e9495861c2c9ce87a6bc26d0 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:49:44 -0800 Subject: [NETNS]: DST cleanup routines should be called inside namespace. Device inside the namespace can be started and downed. So, active routing cache should be cleaned up on device stop. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/core/dst.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net') diff --git a/net/core/dst.c b/net/core/dst.c index 7deef483c79f..3a01a819ba47 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -295,9 +295,6 @@ static int dst_dev_event(struct notifier_block *this, unsigned long event, void struct net_device *dev = ptr; struct dst_entry *dst, *last = NULL; - if (dev->nd_net != &init_net) - return NOTIFY_DONE; - switch (event) { case NETDEV_UNREGISTER: case NETDEV_DOWN: -- cgit v1.2.3-59-g8ed1b From 317805b8f875ca1bd43d594c0a210e24fab7d177 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:50:06 -0800 Subject: [NETNS]: Process ip_rt_redirect in the correct namespace. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/route.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 7b5e8e1d94be..ad6eadd12b4a 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1131,10 +1131,12 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, __be32 skeys[2] = { saddr, 0 }; int ikeys[2] = { dev->ifindex, 0 }; struct netevent_redirect netevent; + struct net *net; if (!in_dev) return; + net = dev->nd_net; if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev) || ipv4_is_multicast(new_gw) || ipv4_is_lbcast(new_gw) || ipv4_is_zeronet(new_gw)) @@ -1146,7 +1148,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, if (IN_DEV_SEC_REDIRECTS(in_dev) && ip_fib_check_default(new_gw, dev)) goto reject_redirect; } else { - if (inet_addr_type(&init_net, new_gw) != RTN_UNICAST) + if (inet_addr_type(net, new_gw) != RTN_UNICAST) goto reject_redirect; } @@ -1164,7 +1166,8 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, rth->fl.fl4_src != skeys[i] || rth->fl.oif != ikeys[k] || rth->fl.iif != 0 || - rth->rt_genid != atomic_read(&rt_genid)) { + rth->rt_genid != atomic_read(&rt_genid) || + rth->u.dst.dev->nd_net != net) { rthp = &rth->u.dst.rt_next; continue; } -- cgit v1.2.3-59-g8ed1b From 642d6318119af60ac019524bd4edcfbd19d9d211 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:50:33 -0800 Subject: [IPV4]: rt_cache_get_next should take rt_genid into account. In the other case /proc/net/rt_cache will look inconsistent in respect to genid. Signed-off-by: Denis V. Lunev Acked-by: Alexey Kuznetsov Signed-off-by: David S. Miller --- net/ipv4/route.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index ad6eadd12b4a..f9654f2ae5b3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -294,7 +294,8 @@ static struct rtable *rt_cache_get_first(struct rt_cache_iter_state *st) return r; } -static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, struct rtable *r) +static struct rtable *__rt_cache_get_next(struct rt_cache_iter_state *st, + struct rtable *r) { r = r->u.dst.rt_next; while (!r) { @@ -307,16 +308,23 @@ static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, struct r return rcu_dereference(r); } +static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, + struct rtable *r) +{ + while ((r = __rt_cache_get_next(st, r)) != NULL) { + if (r->rt_genid == st->genid) + break; + } + return r; +} + static struct rtable *rt_cache_get_idx(struct rt_cache_iter_state *st, loff_t pos) { struct rtable *r = rt_cache_get_first(st); if (r) - while (pos && (r = rt_cache_get_next(st, r))) { - if (r->rt_genid != st->genid) - continue; + while (pos && (r = rt_cache_get_next(st, r))) --pos; - } return pos ? NULL : r; } -- cgit v1.2.3-59-g8ed1b From a75e936f2f1ba8428f70b204f3ddd3a7ff17d281 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:50:55 -0800 Subject: [NETNS]: Process /proc/net/rt_cache inside a namespace. Show routing cache for a particular namespace only. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/route.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index f9654f2ae5b3..af0b23ad93ba 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -273,6 +273,7 @@ static unsigned int rt_hash_code(u32 daddr, u32 saddr) #ifdef CONFIG_PROC_FS struct rt_cache_iter_state { + struct seq_net_private p; int bucket; int genid; }; @@ -285,7 +286,8 @@ static struct rtable *rt_cache_get_first(struct rt_cache_iter_state *st) rcu_read_lock_bh(); r = rcu_dereference(rt_hash_table[st->bucket].chain); while (r) { - if (r->rt_genid == st->genid) + if (r->u.dst.dev->nd_net == st->p.net && + r->rt_genid == st->genid) return r; r = rcu_dereference(r->u.dst.rt_next); } @@ -312,6 +314,8 @@ static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, struct rtable *r) { while ((r = __rt_cache_get_next(st, r)) != NULL) { + if (r->u.dst.dev->nd_net != st->p.net) + continue; if (r->rt_genid == st->genid) break; } @@ -398,7 +402,7 @@ static const struct seq_operations rt_cache_seq_ops = { static int rt_cache_seq_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &rt_cache_seq_ops, + return seq_open_net(inode, file, &rt_cache_seq_ops, sizeof(struct rt_cache_iter_state)); } @@ -407,7 +411,7 @@ static const struct file_operations rt_cache_seq_fops = { .open = rt_cache_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; -- cgit v1.2.3-59-g8ed1b From 73b3871165e45ea6d57775c6bfb1a1760ad6e36b Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:51:18 -0800 Subject: [NETNS]: Register /proc/net/rt_cache for each namespace. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/route.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index af0b23ad93ba..b1a311eb18e5 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -545,7 +545,7 @@ static int ip_rt_acct_read(char *buffer, char **start, off_t offset, } #endif -static __init int ip_rt_proc_init(struct net *net) +static int __net_init ip_rt_do_proc_init(struct net *net) { struct proc_dir_entry *pde; @@ -576,8 +576,26 @@ err2: err1: return -ENOMEM; } + +static void __net_exit ip_rt_do_proc_exit(struct net *net) +{ + remove_proc_entry("rt_cache", net->proc_net_stat); + remove_proc_entry("rt_cache", net->proc_net); + remove_proc_entry("rt_acct", net->proc_net); +} + +static struct pernet_operations ip_rt_proc_ops __net_initdata = { + .init = ip_rt_do_proc_init, + .exit = ip_rt_do_proc_exit, +}; + +static int __init ip_rt_proc_init(void) +{ + return register_pernet_subsys(&ip_rt_proc_ops); +} + #else -static inline int ip_rt_proc_init(struct net *net) +static inline int ip_rt_proc_init(void) { return 0; } @@ -3055,7 +3073,7 @@ int __init ip_rt_init(void) ip_rt_secret_interval; add_timer(&rt_secret_timer); - if (ip_rt_proc_init(&init_net)) + if (ip_rt_proc_init()) printk(KERN_ERR "Unable to create route proc files\n"); #ifdef CONFIG_XFRM xfrm_init(); -- cgit v1.2.3-59-g8ed1b From e5b13cb10de209f924fdf9478214bcf7e4008d6d Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:51:43 -0800 Subject: [NETNS]: Process devinet ioctl in the correct namespace. Add namespace parameter to devinet_ioctl and locate device inside it for state changes. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 2 +- net/ipv4/af_inet.c | 7 ++++--- net/ipv4/devinet.c | 6 +++--- net/ipv4/ipconfig.c | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index fc4e3db649e8..da05ab47ff2f 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -129,7 +129,7 @@ extern int unregister_inetaddr_notifier(struct notifier_block *nb); extern struct net_device *ip_dev_find(struct net *net, __be32 addr); extern int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b); -extern int devinet_ioctl(unsigned int cmd, void __user *); +extern int devinet_ioctl(struct net *net, unsigned int cmd, void __user *); extern void devinet_init(void); extern struct in_device *inetdev_by_index(struct net *, int); extern __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 09ca5293d08f..c270080f370e 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -784,6 +784,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; int err = 0; + struct net *net = sk->sk_net; switch (cmd) { case SIOCGSTAMP: @@ -795,12 +796,12 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCADDRT: case SIOCDELRT: case SIOCRTMSG: - err = ip_rt_ioctl(sk->sk_net, cmd, (void __user *)arg); + err = ip_rt_ioctl(net, cmd, (void __user *)arg); break; case SIOCDARP: case SIOCGARP: case SIOCSARP: - err = arp_ioctl(sk->sk_net, cmd, (void __user *)arg); + err = arp_ioctl(net, cmd, (void __user *)arg); break; case SIOCGIFADDR: case SIOCSIFADDR: @@ -813,7 +814,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCSIFPFLAGS: case SIOCGIFPFLAGS: case SIOCSIFFLAGS: - err = devinet_ioctl(cmd, (void __user *)arg); + err = devinet_ioctl(net, cmd, (void __user *)arg); break; default: if (sk->sk_prot->ioctl) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 90210a74d638..af752fc5d0ab 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -595,7 +595,7 @@ static __inline__ int inet_abc_len(__be32 addr) } -int devinet_ioctl(unsigned int cmd, void __user *arg) +int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) { struct ifreq ifr; struct sockaddr_in sin_orig; @@ -624,7 +624,7 @@ int devinet_ioctl(unsigned int cmd, void __user *arg) *colon = 0; #ifdef CONFIG_KMOD - dev_load(&init_net, ifr.ifr_name); + dev_load(net, ifr.ifr_name); #endif switch (cmd) { @@ -665,7 +665,7 @@ int devinet_ioctl(unsigned int cmd, void __user *arg) rtnl_lock(); ret = -ENODEV; - if ((dev = __dev_get_by_name(&init_net, ifr.ifr_name)) == NULL) + if ((dev = __dev_get_by_name(net, ifr.ifr_name)) == NULL) goto done; if (colon) diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 10013ccee8dd..c90e75a66e81 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -291,7 +291,7 @@ static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) mm_segment_t oldfs = get_fs(); set_fs(get_ds()); - res = devinet_ioctl(cmd, (struct ifreq __user *) arg); + res = devinet_ioctl(&init_net, cmd, (struct ifreq __user *) arg); set_fs(oldfs); return res; } -- cgit v1.2.3-59-g8ed1b From 1937504dd156573a1883f10a5a167f3f78c6cb4a Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:52:04 -0800 Subject: [NETNS]: Enable all routing manipulation via netlink inside namespace. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/route.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index b1a311eb18e5..8c3e165f0034 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2701,9 +2701,6 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void int err; struct sk_buff *skb; - if (net != &init_net) - return -EINVAL; - err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy); if (err < 0) goto errout; @@ -2733,7 +2730,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void if (iif) { struct net_device *dev; - dev = __dev_get_by_index(&init_net, iif); + dev = __dev_get_by_index(net, iif); if (dev == NULL) { err = -ENODEV; goto errout_free; @@ -2759,7 +2756,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void }, .oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0, }; - err = ip_route_output_key(&init_net, &rt, &fl); + err = ip_route_output_key(net, &rt, &fl); } if (err) @@ -2770,11 +2767,11 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void rt->rt_flags |= RTCF_NOTIFY; err = rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, - RTM_NEWROUTE, 0, 0); + RTM_NEWROUTE, 0, 0); if (err <= 0) goto errout_free; - err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid); + err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid); errout: return err; @@ -2788,6 +2785,9 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) struct rtable *rt; int h, s_h; int idx, s_idx; + struct net *net; + + net = skb->sk->sk_net; s_h = cb->args[0]; if (s_h < 0) @@ -2797,7 +2797,7 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) rcu_read_lock_bh(); for (rt = rcu_dereference(rt_hash_table[h].chain), idx = 0; rt; rt = rcu_dereference(rt->u.dst.rt_next), idx++) { - if (idx < s_idx) + if (rt->u.dst.dev->nd_net != net || idx < s_idx) continue; if (rt->rt_genid != atomic_read(&rt_genid)) continue; -- cgit v1.2.3-59-g8ed1b From 3776c8891a2d3c5892fa50ab9e2a3b68f5674be6 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:52:25 -0800 Subject: [NETNS]: Enable IPv4 address manipulations inside namespace. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'net') diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index af752fc5d0ab..dfae59bfaa2c 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -446,9 +446,6 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg ASSERT_RTNL(); - if (net != &init_net) - return -EINVAL; - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy); if (err < 0) goto errout; @@ -560,9 +557,6 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg ASSERT_RTNL(); - if (net != &init_net) - return -EINVAL; - ifa = rtm_to_ifaddr(net, nlh); if (IS_ERR(ifa)) return PTR_ERR(ifa); @@ -1170,9 +1164,6 @@ static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) struct in_ifaddr *ifa; int s_ip_idx, s_idx = cb->args[0]; - if (net != &init_net) - return 0; - s_ip_idx = ip_idx = cb->args[1]; idx = 0; for_each_netdev(net, dev) { -- cgit v1.2.3-59-g8ed1b From c4544c724322984923b3331a4319ae60a62b7803 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 28 Feb 2008 20:52:54 -0800 Subject: [NETNS]: Process inet_select_addr inside a namespace. The context is available from a network device passed in. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/devinet.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index dfae59bfaa2c..4a10dbbbe0a1 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -872,6 +872,7 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) { __be32 addr = 0; struct in_device *in_dev; + struct net *net = dev->nd_net; rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); @@ -900,7 +901,7 @@ no_in_dev: */ read_lock(&dev_base_lock); rcu_read_lock(); - for_each_netdev(&init_net, dev) { + for_each_netdev(net, dev) { if ((in_dev = __in_dev_get_rcu(dev)) == NULL) continue; -- cgit v1.2.3-59-g8ed1b From 5fe47b8a65f8b4104e41dc46092dfcf942ce0758 Mon Sep 17 00:00:00 2001 From: Juha-Matti Tapio Date: Thu, 28 Feb 2008 20:55:02 -0800 Subject: [IPV6]: Add ORCHID prefix to address label table Add a new label for Overlay Routable Cryptographic Hash Identifiers (RFC 4843) prefix 2001:10::/28 to help proper source address selection. ORCHID addresses are used by for example Host Identity Protocol. They are global and routable, but they currently need support from both endpoints and therefore mixing regular and ORCHID addresses for source and destination is a bad idea in general case. Signed-off-by: Juha-Matti Tapio Signed-off-by: David S. Miller --- net/ipv6/addrlabel.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net') diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index a3c5a72218fd..3a8b3f52da35 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c @@ -58,6 +58,7 @@ static struct ip6addrlbl_table * ::ffff:0:0/96 V4MAPPED 4 * fc00::/7 N/A 5 ULA (RFC 4193) * 2001::/32 N/A 6 Teredo (RFC 4380) + * 2001:10::/28 N/A 7 ORCHID (RFC 4843) * * Note: 0xffffffff is used if we do not have any policies. */ @@ -85,6 +86,10 @@ static const __initdata struct ip6addrlbl_init_table .prefix = &(struct in6_addr){{{ 0x20, 0x01 }}}, .prefixlen = 32, .label = 6, + },{ /* 2001:10::/28 */ + .prefix = &(struct in6_addr){{{ 0x20, 0x01, 0x00, 0x10 }}}, + .prefixlen = 28, + .label = 7, },{ /* ::ffff:0:0 */ .prefix = &(struct in6_addr){{{ [10] = 0xff, [11] = 0xff }}}, .prefixlen = 96, -- cgit v1.2.3-59-g8ed1b From 99cd07a537bf4c7c954f31611e30064407104410 Mon Sep 17 00:00:00 2001 From: Juha-Matti Tapio Date: Thu, 28 Feb 2008 20:55:46 -0800 Subject: [IPV6]: Fix source address selection for ORCHID addresses Skip the prefix length matching in source address selection for orchid -> non-orchid addresses. Overlay Routable Cryptographic Hash IDentifiers (RFC 4843, 2001:10::/28) are currenty not globally reachable. Without this check a host with an ORCHID address can end up preferring those over regular addresses when talking to other regular hosts in the 2001::/16 range thus breaking non-orchid connections. Signed-off-by: Juha-Matti Tapio Signed-off-by: David S. Miller --- include/net/ipv6.h | 10 ++++++++++ net/ipv6/addrconf.c | 5 +++++ 2 files changed, 15 insertions(+) (limited to 'net') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index c0c019f72ba9..8b05c65415cb 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -383,6 +383,16 @@ static inline int ipv6_addr_v4mapped(const struct in6_addr *a) a->s6_addr32[2] == htonl(0x0000ffff)); } +/* + * Check for a RFC 4843 ORCHID address + * (Overlay Routable Cryptographic Hash Identifiers) + */ +static inline int ipv6_addr_orchid(const struct in6_addr *a) +{ + return ((a->s6_addr32[0] & htonl(0xfffffff0)) + == htonl(0x20010010)); +} + /* * find the first different bit between two addresses * length of address must be a multiple of 32bits diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 101e0e70ba27..18e3a9825d81 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1125,6 +1125,11 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, if (hiscore.rule < 7) hiscore.rule++; #endif + + /* Skip rule 8 for orchid -> non-orchid address pairs. */ + if (ipv6_addr_orchid(&ifa->addr) && !ipv6_addr_orchid(daddr)) + continue; + /* Rule 8: Use longest matching prefix */ if (hiscore.rule < 8) { hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr); -- cgit v1.2.3-59-g8ed1b From 1e04d530705280770e003ac8db516722cca54758 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Thu, 28 Feb 2008 21:27:35 -0800 Subject: [IPV6]: Unexport ip6_find_1stfragopt This patch removes the no longer used EXPORT_SYMBOL_GPL(ip6_find_1stfragopt). Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- net/ipv6/ip6_output.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 8b67ca07467d..a59d259cf97e 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -596,7 +596,6 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) return offset; } -EXPORT_SYMBOL_GPL(ip6_find_1stfragopt); static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) { -- cgit v1.2.3-59-g8ed1b From 4c563f7669c10a12354b72b518c2287ffc6ebfb3 Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Thu, 28 Feb 2008 21:31:08 -0800 Subject: [XFRM]: Speed up xfrm_policy and xfrm_state walking Change xfrm_policy and xfrm_state walking algorithm from O(n^2) to O(n). This is achieved adding the entries to one more list which is used solely for walking the entries. This also fixes some races where the dump can have duplicate or missing entries when the SPD/SADB is modified during an ongoing dump. Dumping SADB with 20000 entries using "time ip xfrm state" the sys time dropped from 1.012s to 0.080s. Signed-off-by: Timo Teras Signed-off-by: David S. Miller --- include/linux/xfrm.h | 3 +- include/net/xfrm.h | 52 +++++++++++++++++++++++++++++++-- net/key/af_key.c | 24 ++++++++++++--- net/xfrm/xfrm_policy.c | 79 +++++++++++++++++++++++++++++--------------------- net/xfrm/xfrm_state.c | 53 ++++++++++++++++++++++----------- net/xfrm/xfrm_user.c | 71 +++++++++++++++++++++++++++------------------ 6 files changed, 197 insertions(+), 85 deletions(-) (limited to 'net') diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index e31b8c84f2c9..0c82c80b277f 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -113,7 +113,8 @@ enum { XFRM_POLICY_TYPE_MAIN = 0, XFRM_POLICY_TYPE_SUB = 1, - XFRM_POLICY_TYPE_MAX = 2 + XFRM_POLICY_TYPE_MAX = 2, + XFRM_POLICY_TYPE_ANY = 255 }; enum diff --git a/include/net/xfrm.h b/include/net/xfrm.h index eea7785cc757..9b6205665190 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -121,6 +121,7 @@ extern struct mutex xfrm_cfg_mutex; struct xfrm_state { /* Note: bydst is re-used during gc */ + struct list_head all; struct hlist_node bydst; struct hlist_node bysrc; struct hlist_node byspi; @@ -424,6 +425,7 @@ struct xfrm_tmpl struct xfrm_policy { struct xfrm_policy *next; + struct list_head bytype; struct hlist_node bydst; struct hlist_node byidx; @@ -1160,6 +1162,18 @@ struct xfrm6_tunnel { int priority; }; +struct xfrm_state_walk { + struct xfrm_state *state; + int count; + u8 proto; +}; + +struct xfrm_policy_walk { + struct xfrm_policy *policy; + int count; + u8 type, cur_type; +}; + extern void xfrm_init(void); extern void xfrm4_init(void); extern void xfrm_state_init(void); @@ -1184,7 +1198,23 @@ static inline void xfrm6_fini(void) extern int xfrm_proc_init(void); #endif -extern int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), void *); +static inline void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto) +{ + walk->proto = proto; + walk->state = NULL; + walk->count = 0; +} + +static inline void xfrm_state_walk_done(struct xfrm_state_walk *walk) +{ + if (walk->state != NULL) { + xfrm_state_put(walk->state); + walk->state = NULL; + } +} + +extern int xfrm_state_walk(struct xfrm_state_walk *walk, + int (*func)(struct xfrm_state *, int, void*), void *); extern struct xfrm_state *xfrm_state_alloc(void); extern struct xfrm_state *xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, struct flowi *fl, struct xfrm_tmpl *tmpl, @@ -1306,7 +1336,25 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb) #endif struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); -extern int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *); + +static inline void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type) +{ + walk->cur_type = XFRM_POLICY_TYPE_MAIN; + walk->type = type; + walk->policy = NULL; + walk->count = 0; +} + +static inline void xfrm_policy_walk_done(struct xfrm_policy_walk *walk) +{ + if (walk->policy != NULL) { + xfrm_pol_put(walk->policy); + walk->policy = NULL; + } +} + +extern int xfrm_policy_walk(struct xfrm_policy_walk *walk, + int (*func)(struct xfrm_policy *, int, int, void*), void *); int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, struct xfrm_selector *sel, diff --git a/net/key/af_key.c b/net/key/af_key.c index 8b5f486ac80f..7cb6f1213360 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -1742,12 +1742,18 @@ static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr { u8 proto; struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; + struct xfrm_state_walk walk; + int rc; proto = pfkey_satype2proto(hdr->sadb_msg_satype); if (proto == 0) return -EINVAL; - return xfrm_state_walk(proto, dump_sa, &data); + xfrm_state_walk_init(&walk, proto); + rc = xfrm_state_walk(&walk, dump_sa, &data); + xfrm_state_walk_done(&walk); + + return rc; } static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) @@ -1780,7 +1786,9 @@ static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr) static u32 gen_reqid(void) { + struct xfrm_policy_walk walk; u32 start; + int rc; static u32 reqid = IPSEC_MANUAL_REQID_MAX; start = reqid; @@ -1788,8 +1796,10 @@ static u32 gen_reqid(void) ++reqid; if (reqid == 0) reqid = IPSEC_MANUAL_REQID_MAX+1; - if (xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, check_reqid, - (void*)&reqid) != -EEXIST) + xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); + rc = xfrm_policy_walk(&walk, check_reqid, (void*)&reqid); + xfrm_policy_walk_done(&walk); + if (rc != -EEXIST) return reqid; } while (reqid != start); return 0; @@ -2665,8 +2675,14 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; + struct xfrm_policy_walk walk; + int rc; + + xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); + rc = xfrm_policy_walk(&walk, dump_sp, &data); + xfrm_policy_walk_done(&walk); - return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data); + return rc; } static int key_notify_policy_flush(struct km_event *c) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 9fc4c315f6cd..bae94a8031a2 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -46,6 +46,7 @@ EXPORT_SYMBOL(xfrm_cfg_mutex); static DEFINE_RWLOCK(xfrm_policy_lock); +static struct list_head xfrm_policy_bytype[XFRM_POLICY_TYPE_MAX]; unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; EXPORT_SYMBOL(xfrm_policy_count); @@ -208,6 +209,7 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp) policy = kzalloc(sizeof(struct xfrm_policy), gfp); if (policy) { + INIT_LIST_HEAD(&policy->bytype); INIT_HLIST_NODE(&policy->bydst); INIT_HLIST_NODE(&policy->byidx); rwlock_init(&policy->lock); @@ -230,6 +232,10 @@ void xfrm_policy_destroy(struct xfrm_policy *policy) if (del_timer(&policy->timer)) BUG(); + write_lock_bh(&xfrm_policy_lock); + list_del(&policy->bytype); + write_unlock_bh(&xfrm_policy_lock); + security_xfrm_policy_free(policy); kfree(policy); } @@ -584,6 +590,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) policy->curlft.use_time = 0; if (!mod_timer(&policy->timer, jiffies + HZ)) xfrm_pol_hold(policy); + list_add_tail(&policy->bytype, &xfrm_policy_bytype[policy->type]); write_unlock_bh(&xfrm_policy_lock); if (delpol) @@ -822,57 +829,60 @@ out: } EXPORT_SYMBOL(xfrm_policy_flush); -int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), +int xfrm_policy_walk(struct xfrm_policy_walk *walk, + int (*func)(struct xfrm_policy *, int, int, void*), void *data) { - struct xfrm_policy *pol, *last = NULL; - struct hlist_node *entry; - int dir, last_dir = 0, count, error; + struct xfrm_policy *old, *pol, *last = NULL; + int error = 0; + + if (walk->type >= XFRM_POLICY_TYPE_MAX && + walk->type != XFRM_POLICY_TYPE_ANY) + return -EINVAL; + if (walk->policy == NULL && walk->count != 0) + return 0; + + old = pol = walk->policy; + walk->policy = NULL; read_lock_bh(&xfrm_policy_lock); - count = 0; - for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { - struct hlist_head *table = xfrm_policy_bydst[dir].table; - int i; + for (; walk->cur_type < XFRM_POLICY_TYPE_MAX; walk->cur_type++) { + if (walk->type != walk->cur_type && + walk->type != XFRM_POLICY_TYPE_ANY) + continue; - hlist_for_each_entry(pol, entry, - &xfrm_policy_inexact[dir], bydst) { - if (pol->type != type) + if (pol == NULL) { + pol = list_first_entry(&xfrm_policy_bytype[walk->cur_type], + struct xfrm_policy, bytype); + } + list_for_each_entry_from(pol, &xfrm_policy_bytype[walk->cur_type], bytype) { + if (pol->dead) continue; if (last) { - error = func(last, last_dir % XFRM_POLICY_MAX, - count, data); - if (error) + error = func(last, xfrm_policy_id2dir(last->index), + walk->count, data); + if (error) { + xfrm_pol_hold(last); + walk->policy = last; goto out; - } - last = pol; - last_dir = dir; - count++; - } - for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { - hlist_for_each_entry(pol, entry, table + i, bydst) { - if (pol->type != type) - continue; - if (last) { - error = func(last, last_dir % XFRM_POLICY_MAX, - count, data); - if (error) - goto out; } - last = pol; - last_dir = dir; - count++; } + last = pol; + walk->count++; } + pol = NULL; } - if (count == 0) { + if (walk->count == 0) { error = -ENOENT; goto out; } - error = func(last, last_dir % XFRM_POLICY_MAX, 0, data); + if (last) + error = func(last, xfrm_policy_id2dir(last->index), 0, data); out: read_unlock_bh(&xfrm_policy_lock); + if (old != NULL) + xfrm_pol_put(old); return error; } EXPORT_SYMBOL(xfrm_policy_walk); @@ -2365,6 +2375,9 @@ static void __init xfrm_policy_init(void) panic("XFRM: failed to allocate bydst hash\n"); } + for (dir = 0; dir < XFRM_POLICY_TYPE_MAX; dir++) + INIT_LIST_HEAD(&xfrm_policy_bytype[dir]); + INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); register_netdevice_notifier(&xfrm_dev_notifier); } diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 7ba65e82941c..9880b792e6a5 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -50,6 +50,7 @@ static DEFINE_SPINLOCK(xfrm_state_lock); * Main use is finding SA after policy selected tunnel or transport mode. * Also, it can be used by ah/esp icmp error handler to find offending SA. */ +static LIST_HEAD(xfrm_state_all); static struct hlist_head *xfrm_state_bydst __read_mostly; static struct hlist_head *xfrm_state_bysrc __read_mostly; static struct hlist_head *xfrm_state_byspi __read_mostly; @@ -510,6 +511,7 @@ struct xfrm_state *xfrm_state_alloc(void) if (x) { atomic_set(&x->refcnt, 1); atomic_set(&x->tunnel_users, 0); + INIT_LIST_HEAD(&x->all); INIT_HLIST_NODE(&x->bydst); INIT_HLIST_NODE(&x->bysrc); INIT_HLIST_NODE(&x->byspi); @@ -533,6 +535,10 @@ void __xfrm_state_destroy(struct xfrm_state *x) { BUG_TRAP(x->km.state == XFRM_STATE_DEAD); + spin_lock_bh(&xfrm_state_lock); + list_del(&x->all); + spin_unlock_bh(&xfrm_state_lock); + spin_lock_bh(&xfrm_state_gc_lock); hlist_add_head(&x->bydst, &xfrm_state_gc_list); spin_unlock_bh(&xfrm_state_gc_lock); @@ -909,6 +915,8 @@ static void __xfrm_state_insert(struct xfrm_state *x) x->genid = ++xfrm_state_genid; + list_add_tail(&x->all, &xfrm_state_all); + h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, x->props.reqid, x->props.family); hlist_add_head(&x->bydst, xfrm_state_bydst+h); @@ -1518,36 +1526,47 @@ unlock: } EXPORT_SYMBOL(xfrm_alloc_spi); -int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), +int xfrm_state_walk(struct xfrm_state_walk *walk, + int (*func)(struct xfrm_state *, int, void*), void *data) { - int i; - struct xfrm_state *x, *last = NULL; - struct hlist_node *entry; - int count = 0; + struct xfrm_state *old, *x, *last = NULL; int err = 0; + if (walk->state == NULL && walk->count != 0) + return 0; + + old = x = walk->state; + walk->state = NULL; spin_lock_bh(&xfrm_state_lock); - for (i = 0; i <= xfrm_state_hmask; i++) { - hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { - if (!xfrm_id_proto_match(x->id.proto, proto)) - continue; - if (last) { - err = func(last, count, data); - if (err) - goto out; + if (x == NULL) + x = list_first_entry(&xfrm_state_all, struct xfrm_state, all); + list_for_each_entry_from(x, &xfrm_state_all, all) { + if (x->km.state == XFRM_STATE_DEAD) + continue; + if (!xfrm_id_proto_match(x->id.proto, walk->proto)) + continue; + if (last) { + err = func(last, walk->count, data); + if (err) { + xfrm_state_hold(last); + walk->state = last; + goto out; } - last = x; - count++; } + last = x; + walk->count++; } - if (count == 0) { + if (walk->count == 0) { err = -ENOENT; goto out; } - err = func(last, 0, data); + if (last) + err = func(last, 0, data); out: spin_unlock_bh(&xfrm_state_lock); + if (old != NULL) + xfrm_state_put(old); return err; } EXPORT_SYMBOL(xfrm_state_walk); diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index f971ca5645f8..f5fd5b3147cc 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -532,8 +532,6 @@ struct xfrm_dump_info { struct sk_buff *out_skb; u32 nlmsg_seq; u16 nlmsg_flags; - int start_idx; - int this_idx; }; static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) @@ -600,9 +598,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) struct nlmsghdr *nlh; int err; - if (sp->this_idx < sp->start_idx) - goto out; - nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags); if (nlh == NULL) @@ -615,8 +610,6 @@ static int dump_one_state(struct xfrm_state *x, int count, void *ptr) goto nla_put_failure; nlmsg_end(skb, nlh); -out: - sp->this_idx++; return 0; nla_put_failure: @@ -624,18 +617,32 @@ nla_put_failure: return err; } +static int xfrm_dump_sa_done(struct netlink_callback *cb) +{ + struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; + xfrm_state_walk_done(walk); + return 0; +} + static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) { + struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; struct xfrm_dump_info info; + BUILD_BUG_ON(sizeof(struct xfrm_state_walk) > + sizeof(cb->args) - sizeof(cb->args[0])); + info.in_skb = cb->skb; info.out_skb = skb; info.nlmsg_seq = cb->nlh->nlmsg_seq; info.nlmsg_flags = NLM_F_MULTI; - info.this_idx = 0; - info.start_idx = cb->args[0]; - (void) xfrm_state_walk(0, dump_one_state, &info); - cb->args[0] = info.this_idx; + + if (!cb->args[0]) { + cb->args[0] = 1; + xfrm_state_walk_init(walk, 0); + } + + (void) xfrm_state_walk(walk, dump_one_state, &info); return skb->len; } @@ -654,7 +661,6 @@ static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, info.out_skb = skb; info.nlmsg_seq = seq; info.nlmsg_flags = 0; - info.this_idx = info.start_idx = 0; if (dump_one_state(x, 0, &info)) { kfree_skb(skb); @@ -1232,9 +1238,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr struct sk_buff *skb = sp->out_skb; struct nlmsghdr *nlh; - if (sp->this_idx < sp->start_idx) - goto out; - nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags); if (nlh == NULL) @@ -1250,8 +1253,6 @@ static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr goto nlmsg_failure; nlmsg_end(skb, nlh); -out: - sp->this_idx++; return 0; nlmsg_failure: @@ -1259,21 +1260,33 @@ nlmsg_failure: return -EMSGSIZE; } +static int xfrm_dump_policy_done(struct netlink_callback *cb) +{ + struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; + + xfrm_policy_walk_done(walk); + return 0; +} + static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) { + struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; struct xfrm_dump_info info; + BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) > + sizeof(cb->args) - sizeof(cb->args[0])); + info.in_skb = cb->skb; info.out_skb = skb; info.nlmsg_seq = cb->nlh->nlmsg_seq; info.nlmsg_flags = NLM_F_MULTI; - info.this_idx = 0; - info.start_idx = cb->args[0]; - (void) xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_one_policy, &info); -#ifdef CONFIG_XFRM_SUB_POLICY - (void) xfrm_policy_walk(XFRM_POLICY_TYPE_SUB, dump_one_policy, &info); -#endif - cb->args[0] = info.this_idx; + + if (!cb->args[0]) { + cb->args[0] = 1; + xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); + } + + (void) xfrm_policy_walk(walk, dump_one_policy, &info); return skb->len; } @@ -1293,7 +1306,6 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, info.out_skb = skb; info.nlmsg_seq = seq; info.nlmsg_flags = 0; - info.this_idx = info.start_idx = 0; if (dump_one_policy(xp, dir, 0, &info) < 0) { kfree_skb(skb); @@ -1891,15 +1903,18 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { static struct xfrm_link { int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); int (*dump)(struct sk_buff *, struct netlink_callback *); + int (*done)(struct netlink_callback *); } xfrm_dispatch[XFRM_NR_MSGTYPES] = { [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa }, [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa, - .dump = xfrm_dump_sa }, + .dump = xfrm_dump_sa, + .done = xfrm_dump_sa_done }, [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, - .dump = xfrm_dump_policy }, + .dump = xfrm_dump_policy, + .done = xfrm_dump_policy_done }, [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, @@ -1938,7 +1953,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (link->dump == NULL) return -EINVAL; - return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, NULL); + return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, link->done); } err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX, -- cgit v1.2.3-59-g8ed1b From 9b0f976f27f00a81cf47643d90854659626795b4 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 11:13:15 -0800 Subject: [INET]: Remove struct net_proto_family* from _init calls. struct net_proto_family* is not used in icmp[v6]_init, ndisc_init, igmp_init and tcp_v4_init. Remove it. Signed-off-by: Denis V. Lunev Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/linux/icmpv6.h | 2 +- include/net/icmp.h | 2 +- include/net/ndisc.h | 4 ++-- include/net/tcp.h | 2 +- net/ipv4/af_inet.c | 4 ++-- net/ipv4/icmp.c | 2 +- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/af_inet6.c | 6 +++--- net/ipv6/icmp.c | 2 +- net/ipv6/mcast.c | 2 +- net/ipv6/ndisc.c | 2 +- 11 files changed, 15 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index 7c5e9817e998..8f86d6b621c8 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -176,7 +176,7 @@ extern void icmpv6_send(struct sk_buff *skb, __u32 info, struct net_device *dev); -extern int icmpv6_init(struct net_proto_family *ops); +extern int icmpv6_init(void); extern int icmpv6_err_convert(int type, int code, int *err); extern void icmpv6_cleanup(void); diff --git a/include/net/icmp.h b/include/net/icmp.h index 9f7ef3c8baef..7bf714d9d7c7 100644 --- a/include/net/icmp.h +++ b/include/net/icmp.h @@ -48,7 +48,7 @@ struct sk_buff; extern void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info); extern int icmp_rcv(struct sk_buff *skb); extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg); -extern void icmp_init(struct net_proto_family *ops); +extern void icmp_init(void); extern void icmp_out_count(unsigned char type); /* Move into dst.h ? */ diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 59b70624b056..5aedf324de66 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -77,7 +77,7 @@ struct nd_opt_hdr { } __attribute__((__packed__)); -extern int ndisc_init(struct net_proto_family *ops); +extern int ndisc_init(void); extern void ndisc_cleanup(void); @@ -107,7 +107,7 @@ extern int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *d /* * IGMP */ -extern int igmp6_init(struct net_proto_family *ops); +extern int igmp6_init(void); extern void igmp6_cleanup(void); diff --git a/include/net/tcp.h b/include/net/tcp.h index 7de4ea3a04d9..ae9774b478f5 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1373,7 +1373,7 @@ struct tcp_request_sock_ops { #endif }; -extern void tcp_v4_init(struct net_proto_family *ops); +extern void tcp_v4_init(void); extern void tcp_init(void); #endif /* _TCP_H */ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index c270080f370e..a7a99ac856dc 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1415,7 +1415,7 @@ static int __init inet_init(void) ip_init(); - tcp_v4_init(&inet_family_ops); + tcp_v4_init(); /* Setup TCP slab cache for open requests. */ tcp_init(); @@ -1430,7 +1430,7 @@ static int __init inet_init(void) * Set the ICMP layer up */ - icmp_init(&inet_family_ops); + icmp_init(); /* * Initialise the multicast router diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index a13c074dac09..98372db66c66 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -1139,7 +1139,7 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { }, }; -void __init icmp_init(struct net_proto_family *ops) +void __init icmp_init(void) { struct inet_sock *inet; int i; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 00156bf421ca..256032a41069 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2443,7 +2443,7 @@ struct proto tcp_prot = { REF_PROTO_INUSE(tcp) }; -void __init tcp_v4_init(struct net_proto_family *ops) +void __init tcp_v4_init(void) { if (inet_csk_ctl_sock_create(&tcp_socket, PF_INET, SOCK_RAW, IPPROTO_TCP) < 0) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index f0aa97738746..9869f87243cf 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -808,13 +808,13 @@ static int __init inet6_init(void) if (err) goto sysctl_fail; #endif - err = icmpv6_init(&inet6_family_ops); + err = icmpv6_init(); if (err) goto icmp_fail; - err = ndisc_init(&inet6_family_ops); + err = ndisc_init(); if (err) goto ndisc_fail; - err = igmp6_init(&inet6_family_ops); + err = igmp6_init(); if (err) goto igmp_fail; err = ipv6_netfilter_init(); diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 121d517bf91c..b9b13a77ba30 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -780,7 +780,7 @@ drop_no_count: */ static struct lock_class_key icmpv6_socket_sk_dst_lock_key; -int __init icmpv6_init(struct net_proto_family *ops) +int __init icmpv6_init(void) { struct sock *sk; int err, i, j; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index ab228d1ea114..8ce894d90063 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2597,7 +2597,7 @@ static const struct file_operations igmp6_mcf_seq_fops = { }; #endif -int __init igmp6_init(struct net_proto_family *ops) +int __init igmp6_init(void) { struct ipv6_pinfo *np; struct sock *sk; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 0d33a7d32125..1fc33c8c7232 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1733,7 +1733,7 @@ static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name, #endif -int __init ndisc_init(struct net_proto_family *ops) +int __init ndisc_init(void) { struct ipv6_pinfo *np; struct sock *sk; -- cgit v1.2.3-59-g8ed1b From a5710d6582868a96cf0fe02eac11d34cfbc783c9 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 11:14:50 -0800 Subject: [ICMP]: Add return code to icmp_init. icmp_init could fail and this is normal for namespace other than initial. So, the panic should be triggered only on init_net initialization path. Additionally create rollback path for icmp_init as a separate function. It will also be used later during namespace destruction. Signed-off-by: Denis V. Lunev Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/net/icmp.h | 2 +- net/ipv4/af_inet.c | 3 ++- net/ipv4/icmp.c | 26 ++++++++++++++++++++++---- 3 files changed, 25 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/include/net/icmp.h b/include/net/icmp.h index 7bf714d9d7c7..faba64db8ff0 100644 --- a/include/net/icmp.h +++ b/include/net/icmp.h @@ -48,7 +48,7 @@ struct sk_buff; extern void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info); extern int icmp_rcv(struct sk_buff *skb); extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg); -extern void icmp_init(void); +extern int icmp_init(void); extern void icmp_out_count(unsigned char type); /* Move into dst.h ? */ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index a7a99ac856dc..4f539bd48718 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1430,7 +1430,8 @@ static int __init inet_init(void) * Set the ICMP layer up */ - icmp_init(); + if (icmp_init() < 0) + panic("Failed to create the ICMP control socket.\n"); /* * Initialise the multicast router diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 98372db66c66..b345b3d9bcaa 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -1139,19 +1139,32 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { }, }; -void __init icmp_init(void) +static void __exit icmp_exit(void) { - struct inet_sock *inet; int i; for_each_possible_cpu(i) { - int err; + struct socket *sock; + + sock = per_cpu(__icmp_socket, i); + if (sock == NULL) + continue; + per_cpu(__icmp_socket, i) = NULL; + sock_release(sock); + } +} +int __init icmp_init(void) +{ + struct inet_sock *inet; + int i, err; + + for_each_possible_cpu(i) { err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP, &per_cpu(__icmp_socket, i)); if (err < 0) - panic("Failed to create the ICMP control socket.\n"); + goto fail; per_cpu(__icmp_socket, i)->sk->sk_allocation = GFP_ATOMIC; @@ -1171,6 +1184,11 @@ void __init icmp_init(void) */ per_cpu(__icmp_socket, i)->sk->sk_prot->unhash(per_cpu(__icmp_socket, i)->sk); } + return 0; + +fail: + icmp_exit(); + return err; } EXPORT_SYMBOL(icmp_err_convert); -- cgit v1.2.3-59-g8ed1b From 1e3cf6834e7db1eac94314338c9e30c2103ac409 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 11:15:42 -0800 Subject: [ICMP]: Optimize icmp_socket usage. Use this macro only once in a function to save a bit of space. add/remove: 0/0 grow/shrink: 0/3 up/down: 0/-98 (-98) function old new delta icmp_reply 562 561 -1 icmp_push_reply 305 258 -47 icmp_init 273 223 -50 Signed-off-by: Denis V. Lunev Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index b345b3d9bcaa..831b6adbe4e0 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -346,19 +346,21 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd, static void icmp_push_reply(struct icmp_bxm *icmp_param, struct ipcm_cookie *ipc, struct rtable *rt) { + struct sock *sk; struct sk_buff *skb; - if (ip_append_data(icmp_socket->sk, icmp_glue_bits, icmp_param, + sk = icmp_socket->sk; + if (ip_append_data(sk, icmp_glue_bits, icmp_param, icmp_param->data_len+icmp_param->head_len, icmp_param->head_len, ipc, rt, MSG_DONTWAIT) < 0) - ip_flush_pending_frames(icmp_socket->sk); - else if ((skb = skb_peek(&icmp_socket->sk->sk_write_queue)) != NULL) { + ip_flush_pending_frames(sk); + else if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { struct icmphdr *icmph = icmp_hdr(skb); __wsum csum = 0; struct sk_buff *skb1; - skb_queue_walk(&icmp_socket->sk->sk_write_queue, skb1) { + skb_queue_walk(&sk->sk_write_queue, skb1) { csum = csum_add(csum, skb1->csum); } csum = csum_partial_copy_nocheck((void *)&icmp_param->data, @@ -366,7 +368,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, icmp_param->head_len, csum); icmph->checksum = csum_fold(csum); skb->ip_summed = CHECKSUM_NONE; - ip_push_pending_frames(icmp_socket->sk); + ip_push_pending_frames(sk); } } @@ -1156,25 +1158,28 @@ static void __exit icmp_exit(void) int __init icmp_init(void) { - struct inet_sock *inet; int i, err; for_each_possible_cpu(i) { - err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP, - &per_cpu(__icmp_socket, i)); + struct sock *sk; + struct socket *sock; + struct inet_sock *inet; + err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP, &sock); if (err < 0) goto fail; - per_cpu(__icmp_socket, i)->sk->sk_allocation = GFP_ATOMIC; + per_cpu(__icmp_socket, i) = sock; + sk = sock->sk; + sk->sk_allocation = GFP_ATOMIC; /* Enough space for 2 64K ICMP packets, including * sk_buff struct overhead. */ - per_cpu(__icmp_socket, i)->sk->sk_sndbuf = + sk->sk_sndbuf = (2 * ((64 * 1024) + sizeof(struct sk_buff))); - inet = inet_sk(per_cpu(__icmp_socket, i)->sk); + inet = inet_sk(sk); inet->uc_ttl = -1; inet->pmtudisc = IP_PMTUDISC_DONT; @@ -1182,7 +1187,7 @@ int __init icmp_init(void) * see it, we do not wish this socket to see incoming * packets. */ - per_cpu(__icmp_socket, i)->sk->sk_prot->unhash(per_cpu(__icmp_socket, i)->sk); + sk->sk_prot->unhash(sk); } return 0; -- cgit v1.2.3-59-g8ed1b From b7e729c4b4778aac4dbbec9dc070acde93071f4d Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 11:16:08 -0800 Subject: [ICMP]: Store sock rather than socket for ICMP flow control. Basically, there is no difference, what to store: socket or sock. Though, sock looks better as there will be 1 less dereferrence on the fast path. Signed-off-by: Denis V. Lunev Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 27 +++++++++++++-------------- net/ipv6/icmp.c | 25 +++++++++++++------------ 2 files changed, 26 insertions(+), 26 deletions(-) (limited to 'net') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 831b6adbe4e0..3a4da43d8309 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -229,14 +229,14 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES+1]; * * On SMP we have one ICMP socket per-cpu. */ -static DEFINE_PER_CPU(struct socket *, __icmp_socket) = NULL; -#define icmp_socket __get_cpu_var(__icmp_socket) +static DEFINE_PER_CPU(struct sock *, __icmp_sk) = NULL; +#define icmp_sk __get_cpu_var(__icmp_sk) static inline int icmp_xmit_lock(void) { local_bh_disable(); - if (unlikely(!spin_trylock(&icmp_socket->sk->sk_lock.slock))) { + if (unlikely(!spin_trylock(&icmp_sk->sk_lock.slock))) { /* This can happen if the output path signals a * dst_link_failure() for an outgoing ICMP packet. */ @@ -248,7 +248,7 @@ static inline int icmp_xmit_lock(void) static inline void icmp_xmit_unlock(void) { - spin_unlock_bh(&icmp_socket->sk->sk_lock.slock); + spin_unlock_bh(&icmp_sk->sk_lock.slock); } /* @@ -349,7 +349,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, struct sock *sk; struct sk_buff *skb; - sk = icmp_socket->sk; + sk = icmp_sk; if (ip_append_data(sk, icmp_glue_bits, icmp_param, icmp_param->data_len+icmp_param->head_len, icmp_param->head_len, @@ -378,7 +378,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) { - struct sock *sk = icmp_socket->sk; + struct sock *sk = icmp_sk; struct inet_sock *inet = inet_sk(sk); struct ipcm_cookie ipc; struct rtable *rt = (struct rtable *)skb->dst; @@ -546,7 +546,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) icmp_param.data.icmph.checksum = 0; icmp_param.skb = skb_in; icmp_param.offset = skb_network_offset(skb_in); - inet_sk(icmp_socket->sk)->tos = tos; + inet_sk(icmp_sk)->tos = tos; ipc.addr = iph->saddr; ipc.opt = &icmp_param.replyopts; @@ -1146,13 +1146,13 @@ static void __exit icmp_exit(void) int i; for_each_possible_cpu(i) { - struct socket *sock; + struct sock *sk; - sock = per_cpu(__icmp_socket, i); - if (sock == NULL) + sk = per_cpu(__icmp_sk, i); + if (sk == NULL) continue; - per_cpu(__icmp_socket, i) = NULL; - sock_release(sock); + per_cpu(__icmp_sk, i) = NULL; + sock_release(sk->sk_socket); } } @@ -1169,8 +1169,7 @@ int __init icmp_init(void) if (err < 0) goto fail; - per_cpu(__icmp_socket, i) = sock; - sk = sock->sk; + per_cpu(__icmp_sk, i) = sk = sock->sk; sk->sk_allocation = GFP_ATOMIC; /* Enough space for 2 64K ICMP packets, including diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index b9b13a77ba30..875bdc725dc4 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -80,8 +80,8 @@ EXPORT_SYMBOL(icmpv6msg_statistics); * * On SMP we have one ICMP socket per-cpu. */ -static DEFINE_PER_CPU(struct socket *, __icmpv6_socket) = NULL; -#define icmpv6_socket __get_cpu_var(__icmpv6_socket) +static DEFINE_PER_CPU(struct sock *, __icmpv6_sk) = NULL; +#define icmpv6_sk __get_cpu_var(__icmpv6_sk) static int icmpv6_rcv(struct sk_buff *skb); @@ -94,7 +94,7 @@ static __inline__ int icmpv6_xmit_lock(void) { local_bh_disable(); - if (unlikely(!spin_trylock(&icmpv6_socket->sk->sk_lock.slock))) { + if (unlikely(!spin_trylock(&icmpv6_sk->sk_lock.slock))) { /* This can happen if the output path (f.e. SIT or * ip6ip6 tunnel) signals dst_link_failure() for an * outgoing ICMP6 packet. @@ -107,7 +107,7 @@ static __inline__ int icmpv6_xmit_lock(void) static __inline__ void icmpv6_xmit_unlock(void) { - spin_unlock_bh(&icmpv6_socket->sk->sk_lock.slock); + spin_unlock_bh(&icmpv6_sk->sk_lock.slock); } /* @@ -392,7 +392,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, if (icmpv6_xmit_lock()) return; - sk = icmpv6_socket->sk; + sk = icmpv6_sk; np = inet6_sk(sk); if (!icmpv6_xrlim_allow(sk, type, &fl)) @@ -538,7 +538,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) if (icmpv6_xmit_lock()) return; - sk = icmpv6_socket->sk; + sk = icmpv6_sk; np = inet6_sk(sk); if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) @@ -776,7 +776,7 @@ drop_no_count: } /* - * Special lock-class for __icmpv6_socket: + * Special lock-class for __icmpv6_sk: */ static struct lock_class_key icmpv6_socket_sk_dst_lock_key; @@ -786,8 +786,9 @@ int __init icmpv6_init(void) int err, i, j; for_each_possible_cpu(i) { + struct socket *sock; err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, - &per_cpu(__icmpv6_socket, i)); + &sock); if (err < 0) { printk(KERN_ERR "Failed to initialize the ICMP6 control socket " @@ -796,12 +797,12 @@ int __init icmpv6_init(void) goto fail; } - sk = per_cpu(__icmpv6_socket, i)->sk; + per_cpu(__icmpv6_sk, i) = sk = sock->sk; sk->sk_allocation = GFP_ATOMIC; /* * Split off their lock-class, because sk->sk_dst_lock * gets used from softirqs, which is safe for - * __icmpv6_socket (because those never get directly used + * __icmpv6_sk (because those never get directly used * via userspace syscalls), but unsafe for normal sockets. */ lockdep_set_class(&sk->sk_dst_lock, @@ -829,7 +830,7 @@ int __init icmpv6_init(void) for (j = 0; j < i; j++) { if (!cpu_possible(j)) continue; - sock_release(per_cpu(__icmpv6_socket, j)); + sock_release(per_cpu(__icmpv6_sk, j)->sk_socket); } return err; @@ -840,7 +841,7 @@ void icmpv6_cleanup(void) int i; for_each_possible_cpu(i) { - sock_release(per_cpu(__icmpv6_socket, i)); + sock_release(per_cpu(__icmpv6_sk, i)->sk_socket); } inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); } -- cgit v1.2.3-59-g8ed1b From 405666db84b984b68fc75794069f424c02e5796c Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 11:16:46 -0800 Subject: [ICMP]: Pass proper ICMP socket into icmp(v6)_xmit_(un)lock. We have to get socket lock inside icmp(v6)_xmit_lock/unlock. The socket is get from global variable now. When this code became namespaces, one should pass a namespace and get socket from it. Though, above is useless. Socket is available in the caller, just pass it inside. This saves a bit of code now and saves more later. add/remove: 0/0 grow/shrink: 1/3 up/down: 1/-169 (-168) function old new delta icmp_rcv 718 719 +1 icmpv6_rcv 2343 2303 -40 icmp_send 1566 1518 -48 icmp_reply 549 468 -81 Signed-off-by: Denis V. Lunev Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 19 ++++++++++--------- net/ipv6/icmp.c | 24 ++++++++++++------------ 2 files changed, 22 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 3a4da43d8309..9bcf263f06ca 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -232,11 +232,11 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES+1]; static DEFINE_PER_CPU(struct sock *, __icmp_sk) = NULL; #define icmp_sk __get_cpu_var(__icmp_sk) -static inline int icmp_xmit_lock(void) +static inline int icmp_xmit_lock(struct sock *sk) { local_bh_disable(); - if (unlikely(!spin_trylock(&icmp_sk->sk_lock.slock))) { + if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { /* This can happen if the output path signals a * dst_link_failure() for an outgoing ICMP packet. */ @@ -246,9 +246,9 @@ static inline int icmp_xmit_lock(void) return 0; } -static inline void icmp_xmit_unlock(void) +static inline void icmp_xmit_unlock(struct sock *sk) { - spin_unlock_bh(&icmp_sk->sk_lock.slock); + spin_unlock_bh(&sk->sk_lock.slock); } /* @@ -387,7 +387,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) if (ip_options_echo(&icmp_param->replyopts, skb)) return; - if (icmp_xmit_lock()) + if (icmp_xmit_lock(sk)) return; icmp_param->data.icmph.checksum = 0; @@ -415,7 +415,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) icmp_push_reply(icmp_param, &ipc, rt); ip_rt_put(rt); out_unlock: - icmp_xmit_unlock(); + icmp_xmit_unlock(sk); } @@ -440,6 +440,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) __be32 saddr; u8 tos; struct net *net; + struct sock *sk = icmp_sk; if (!rt) goto out; @@ -507,7 +508,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) } } - if (icmp_xmit_lock()) + if (icmp_xmit_lock(sk)) return; /* @@ -546,7 +547,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) icmp_param.data.icmph.checksum = 0; icmp_param.skb = skb_in; icmp_param.offset = skb_network_offset(skb_in); - inet_sk(icmp_sk)->tos = tos; + inet_sk(sk)->tos = tos; ipc.addr = iph->saddr; ipc.opt = &icmp_param.replyopts; @@ -654,7 +655,7 @@ route_done: ende: ip_rt_put(rt); out_unlock: - icmp_xmit_unlock(); + icmp_xmit_unlock(sk); out:; } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 875bdc725dc4..18f220a04486 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -90,11 +90,11 @@ static struct inet6_protocol icmpv6_protocol = { .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; -static __inline__ int icmpv6_xmit_lock(void) +static __inline__ int icmpv6_xmit_lock(struct sock *sk) { local_bh_disable(); - if (unlikely(!spin_trylock(&icmpv6_sk->sk_lock.slock))) { + if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { /* This can happen if the output path (f.e. SIT or * ip6ip6 tunnel) signals dst_link_failure() for an * outgoing ICMP6 packet. @@ -105,9 +105,9 @@ static __inline__ int icmpv6_xmit_lock(void) return 0; } -static __inline__ void icmpv6_xmit_unlock(void) +static __inline__ void icmpv6_xmit_unlock(struct sock *sk) { - spin_unlock_bh(&icmpv6_sk->sk_lock.slock); + spin_unlock_bh(&sk->sk_lock.slock); } /* @@ -389,12 +389,12 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, fl.fl_icmp_code = code; security_skb_classify_flow(skb, &fl); - if (icmpv6_xmit_lock()) - return; - sk = icmpv6_sk; np = inet6_sk(sk); + if (icmpv6_xmit_lock(sk)) + return; + if (!icmpv6_xrlim_allow(sk, type, &fl)) goto out; @@ -498,7 +498,7 @@ out_put: out_dst_release: dst_release(dst); out: - icmpv6_xmit_unlock(); + icmpv6_xmit_unlock(sk); } EXPORT_SYMBOL(icmpv6_send); @@ -535,12 +535,12 @@ static void icmpv6_echo_reply(struct sk_buff *skb) fl.fl_icmp_type = ICMPV6_ECHO_REPLY; security_skb_classify_flow(skb, &fl); - if (icmpv6_xmit_lock()) - return; - sk = icmpv6_sk; np = inet6_sk(sk); + if (icmpv6_xmit_lock(sk)) + return; + if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) fl.oif = np->mcast_oif; @@ -584,7 +584,7 @@ out_put: in6_dev_put(idev); dst_release(dst); out: - icmpv6_xmit_unlock(); + icmpv6_xmit_unlock(sk); } static void icmpv6_notify(struct sk_buff *skb, int type, int code, __be32 info) -- cgit v1.2.3-59-g8ed1b From 79c911595390c8fdc8d8a487ac1951d854b1cd09 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 11:17:11 -0800 Subject: [ICMP]: Allocate data for __icmp(v6)_sk dynamically. Own __icmp(v6)_sk should be present in each namespace. So, it should be allocated dynamically. Though, alloc_percpu does not fit the case as it implies additional dereferrence for no bonus. Allocate data for pointers just like __percpu_alloc_mask does and place pointers to struct sock into this array. Signed-off-by: Denis V. Lunev Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 15 ++++++++++----- net/ipv6/icmp.c | 14 +++++++++----- 2 files changed, 19 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 9bcf263f06ca..7c62a0da5264 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -229,8 +229,8 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES+1]; * * On SMP we have one ICMP socket per-cpu. */ -static DEFINE_PER_CPU(struct sock *, __icmp_sk) = NULL; -#define icmp_sk __get_cpu_var(__icmp_sk) +static struct sock **__icmp_sk = NULL; +#define icmp_sk (__icmp_sk[smp_processor_id()]) static inline int icmp_xmit_lock(struct sock *sk) { @@ -1149,18 +1149,23 @@ static void __exit icmp_exit(void) for_each_possible_cpu(i) { struct sock *sk; - sk = per_cpu(__icmp_sk, i); + sk = __icmp_sk[i]; if (sk == NULL) continue; - per_cpu(__icmp_sk, i) = NULL; sock_release(sk->sk_socket); } + kfree(__icmp_sk); + __icmp_sk = NULL; } int __init icmp_init(void) { int i, err; + __icmp_sk = kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL); + if (__icmp_sk == NULL) + return -ENOMEM; + for_each_possible_cpu(i) { struct sock *sk; struct socket *sock; @@ -1170,7 +1175,7 @@ int __init icmp_init(void) if (err < 0) goto fail; - per_cpu(__icmp_sk, i) = sk = sock->sk; + __icmp_sk[i] = sk = sock->sk; sk->sk_allocation = GFP_ATOMIC; /* Enough space for 2 64K ICMP packets, including diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 18f220a04486..3368f32fe226 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -80,8 +80,8 @@ EXPORT_SYMBOL(icmpv6msg_statistics); * * On SMP we have one ICMP socket per-cpu. */ -static DEFINE_PER_CPU(struct sock *, __icmpv6_sk) = NULL; -#define icmpv6_sk __get_cpu_var(__icmpv6_sk) +static struct sock **__icmpv6_sk = NULL; +#define icmpv6_sk (__icmpv6_sk[smp_processor_id()]) static int icmpv6_rcv(struct sk_buff *skb); @@ -785,6 +785,10 @@ int __init icmpv6_init(void) struct sock *sk; int err, i, j; + __icmpv6_sk = kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL); + if (__icmpv6_sk == NULL) + return -ENOMEM; + for_each_possible_cpu(i) { struct socket *sock; err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, @@ -797,7 +801,7 @@ int __init icmpv6_init(void) goto fail; } - per_cpu(__icmpv6_sk, i) = sk = sock->sk; + __icmpv6_sk[i] = sk = sock->sk; sk->sk_allocation = GFP_ATOMIC; /* * Split off their lock-class, because sk->sk_dst_lock @@ -830,7 +834,7 @@ int __init icmpv6_init(void) for (j = 0; j < i; j++) { if (!cpu_possible(j)) continue; - sock_release(per_cpu(__icmpv6_sk, j)->sk_socket); + sock_release(__icmpv6_sk[j]->sk_socket); } return err; @@ -841,7 +845,7 @@ void icmpv6_cleanup(void) int i; for_each_possible_cpu(i) { - sock_release(per_cpu(__icmpv6_sk, i)->sk_socket); + sock_release(__icmpv6_sk[i]->sk_socket); } inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); } -- cgit v1.2.3-59-g8ed1b From 9dfbec1fb2bedff6b118504055cd9f0485edba45 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 11:17:56 -0800 Subject: [NETLINK]: No need for a separate __netlink_release call. Merge it to netlink_kernel_release. Signed-off-by: Denis V. Lunev Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 1ab0da2632e1..e6b636d53633 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1344,22 +1344,6 @@ static void netlink_data_ready(struct sock *sk, int len) * queueing. */ -static void __netlink_release(struct sock *sk) -{ - /* - * Last sock_put should drop referrence to sk->sk_net. It has already - * been dropped in netlink_kernel_create. Taking referrence to stopping - * namespace is not an option. - * Take referrence to a socket to remove it from netlink lookup table - * _alive_ and after that destroy it in the context of init_net. - */ - - sock_hold(sk); - sock_release(sk->sk_socket); - sk->sk_net = get_net(&init_net); - sock_put(sk); -} - struct sock * netlink_kernel_create(struct net *net, int unit, unsigned int groups, void (*input)(struct sk_buff *skb), @@ -1424,7 +1408,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, out_sock_release: kfree(listeners); - __netlink_release(sk); + netlink_kernel_release(sk); return NULL; out_sock_release_nosk: @@ -1437,10 +1421,20 @@ EXPORT_SYMBOL(netlink_kernel_create); void netlink_kernel_release(struct sock *sk) { + /* + * Last sock_put should drop referrence to sk->sk_net. It has already + * been dropped in netlink_kernel_create. Taking referrence to stopping + * namespace is not an option. + * Take referrence to a socket to remove it from netlink lookup table + * _alive_ and after that destroy it in the context of init_net. + */ if (sk == NULL || sk->sk_socket == NULL) return; - __netlink_release(sk); + sock_hold(sk); + sock_release(sk->sk_socket); + sk->sk_net = get_net(&init_net); + sock_put(sk); } EXPORT_SYMBOL(netlink_kernel_release); -- cgit v1.2.3-59-g8ed1b From edf0208702007ec1f6a36756fdd005f771a4cf17 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 11:18:32 -0800 Subject: [NET]: Make netlink_kernel_release publically available as sk_release_kernel. This staff will be needed for non-netlink kernel sockets, which should also not pin a namespace like tcp_socket and icmp_socket. Signed-off-by: Denis V. Lunev Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/net/sock.h | 13 +++++++++++++ net/core/sock.c | 18 ++++++++++++++++++ net/netlink/af_netlink.c | 18 ++---------------- 3 files changed, 33 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/net/sock.h b/include/net/sock.h index fd9876087651..39112e75411c 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -850,6 +850,7 @@ extern struct sock *sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot); extern void sk_free(struct sock *sk); +extern void sk_release_kernel(struct sock *sk); extern struct sock *sk_clone(const struct sock *sk, const gfp_t priority); @@ -1333,6 +1334,18 @@ static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, int copied_e } #endif +/* + * Kernel sockets, f.e. rtnl or icmp_socket, are a part of a namespace. + * They should not hold a referrence to a namespace in order to allow + * to stop it. + * Sockets after sk_change_net should be released using sk_release_kernel + */ +static inline void sk_change_net(struct sock *sk, struct net *net) +{ + put_net(sk->sk_net); + sk->sk_net = net; +} + extern void sock_enable_timestamp(struct sock *sk); extern int sock_get_timestamp(struct sock *, struct timeval __user *); extern int sock_get_timestampns(struct sock *, struct timespec __user *); diff --git a/net/core/sock.c b/net/core/sock.c index 09cb3a74de7f..c71b645a78f0 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -987,6 +987,24 @@ void sk_free(struct sock *sk) sk_prot_free(sk->sk_prot_creator, sk); } +/* + * Last sock_put should drop referrence to sk->sk_net. It has already + * been dropped in sk_change_net. Taking referrence to stopping namespace + * is not an option. + * Take referrence to a socket to remove it from hash _alive_ and after that + * destroy it in the context of init_net. + */ +void sk_release_kernel(struct sock *sk) +{ + if (sk == NULL || sk->sk_socket == NULL) + return; + + sock_hold(sk); + sock_release(sk->sk_socket); + sk->sk_net = get_net(&init_net); + sock_put(sk); +} + struct sock *sk_clone(const struct sock *sk, const gfp_t priority) { struct sock *newsk; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index e6b636d53633..524e826bb976 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1372,8 +1372,7 @@ netlink_kernel_create(struct net *net, int unit, unsigned int groups, goto out_sock_release_nosk; sk = sock->sk; - put_net(sk->sk_net); - sk->sk_net = net; + sk_change_net(sk, net); if (groups < 32) groups = 32; @@ -1421,20 +1420,7 @@ EXPORT_SYMBOL(netlink_kernel_create); void netlink_kernel_release(struct sock *sk) { - /* - * Last sock_put should drop referrence to sk->sk_net. It has already - * been dropped in netlink_kernel_create. Taking referrence to stopping - * namespace is not an option. - * Take referrence to a socket to remove it from netlink lookup table - * _alive_ and after that destroy it in the context of init_net. - */ - if (sk == NULL || sk->sk_socket == NULL) - return; - - sock_hold(sk); - sock_release(sk->sk_socket); - sk->sk_net = get_net(&init_net); - sock_put(sk); + sk_release_kernel(sk); } EXPORT_SYMBOL(netlink_kernel_release); -- cgit v1.2.3-59-g8ed1b From 5c8cafd65e1448b1d55cad3fb1e42ad42607e5be Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 11:19:22 -0800 Subject: [NETNS]: icmp(v6)_sk should not pin a namespace. So, change icmp(v6)_sk creation/disposal to the scheme used in the netlink for rtnl, i.e. create a socket in the context of the init_net and assign the namespace without getting a referrence later. Also use sk_release_kernel instead of sock_release to properly destroy such sockets. Signed-off-by: Denis V. Lunev Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 12 ++++-------- net/ipv6/icmp.c | 11 +++++------ 2 files changed, 9 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 7c62a0da5264..97d97ada4ce6 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -1146,14 +1146,8 @@ static void __exit icmp_exit(void) { int i; - for_each_possible_cpu(i) { - struct sock *sk; - - sk = __icmp_sk[i]; - if (sk == NULL) - continue; - sock_release(sk->sk_socket); - } + for_each_possible_cpu(i) + sk_release_kernel(__icmp_sk[i]); kfree(__icmp_sk); __icmp_sk = NULL; } @@ -1176,6 +1170,8 @@ int __init icmp_init(void) goto fail; __icmp_sk[i] = sk = sock->sk; + sk_change_net(sk, &init_net); + sk->sk_allocation = GFP_ATOMIC; /* Enough space for 2 64K ICMP packets, including diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 3368f32fe226..3eb594d54172 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -802,6 +802,8 @@ int __init icmpv6_init(void) } __icmpv6_sk[i] = sk = sock->sk; + sk_change_net(sk, &init_net); + sk->sk_allocation = GFP_ATOMIC; /* * Split off their lock-class, because sk->sk_dst_lock @@ -831,11 +833,8 @@ int __init icmpv6_init(void) return 0; fail: - for (j = 0; j < i; j++) { - if (!cpu_possible(j)) - continue; - sock_release(__icmpv6_sk[j]->sk_socket); - } + for (j = 0; j < i; j++) + sk_release_kernel(__icmpv6_sk[j]); return err; } @@ -845,7 +844,7 @@ void icmpv6_cleanup(void) int i; for_each_possible_cpu(i) { - sock_release(__icmpv6_sk[i]->sk_socket); + sk_release_kernel(__icmpv6_sk[i]); } inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); } -- cgit v1.2.3-59-g8ed1b From 4a6ad7a141cbee2cf074e6cf8dc527b231b69ece Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 11:19:58 -0800 Subject: [NETNS]: Make icmp_sk per namespace. All preparations are done. Now just add a hook to perform an initialization on namespace startup and replace icmp_sk macro with proper inline call. Signed-off-by: Denis V. Lunev Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/net/netns/ipv4.h | 2 ++ net/ipv4/icmp.c | 49 +++++++++++++++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index a9b4f6086294..504fde174525 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -26,6 +26,8 @@ struct netns_ipv4 { struct hlist_head *fib_table_hash; struct sock *fibnl; + struct sock **icmp_sk; + struct netns_frags frags; #ifdef CONFIG_NETFILTER struct xt_table *iptable_filter; diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 97d97ada4ce6..b51f4b0a3264 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -229,8 +229,10 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES+1]; * * On SMP we have one ICMP socket per-cpu. */ -static struct sock **__icmp_sk = NULL; -#define icmp_sk (__icmp_sk[smp_processor_id()]) +static struct sock *icmp_sk(struct net *net) +{ + return net->ipv4.icmp_sk[smp_processor_id()]; +} static inline int icmp_xmit_lock(struct sock *sk) { @@ -349,7 +351,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, struct sock *sk; struct sk_buff *skb; - sk = icmp_sk; + sk = icmp_sk(rt->u.dst.dev->nd_net); if (ip_append_data(sk, icmp_glue_bits, icmp_param, icmp_param->data_len+icmp_param->head_len, icmp_param->head_len, @@ -378,10 +380,11 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) { - struct sock *sk = icmp_sk; - struct inet_sock *inet = inet_sk(sk); struct ipcm_cookie ipc; struct rtable *rt = (struct rtable *)skb->dst; + struct net *net = rt->u.dst.dev->nd_net; + struct sock *sk = icmp_sk(net); + struct inet_sock *inet = inet_sk(sk); __be32 daddr; if (ip_options_echo(&icmp_param->replyopts, skb)) @@ -407,7 +410,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) .tos = RT_TOS(ip_hdr(skb)->tos) } }, .proto = IPPROTO_ICMP }; security_skb_classify_flow(skb, &fl); - if (ip_route_output_key(rt->u.dst.dev->nd_net, &rt, &fl)) + if (ip_route_output_key(net, &rt, &fl)) goto out_unlock; } if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type, @@ -440,11 +443,12 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) __be32 saddr; u8 tos; struct net *net; - struct sock *sk = icmp_sk; + struct sock *sk; if (!rt) goto out; net = rt->u.dst.dev->nd_net; + sk = icmp_sk(net); /* * Find the original header. It is expected to be valid, of course. @@ -1142,22 +1146,23 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { }, }; -static void __exit icmp_exit(void) +static void __net_exit icmp_sk_exit(struct net *net) { int i; for_each_possible_cpu(i) - sk_release_kernel(__icmp_sk[i]); - kfree(__icmp_sk); - __icmp_sk = NULL; + sk_release_kernel(net->ipv4.icmp_sk[i]); + kfree(net->ipv4.icmp_sk); + net->ipv4.icmp_sk = NULL; } -int __init icmp_init(void) +int __net_init icmp_sk_init(struct net *net) { int i, err; - __icmp_sk = kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL); - if (__icmp_sk == NULL) + net->ipv4.icmp_sk = + kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL); + if (net->ipv4.icmp_sk == NULL) return -ENOMEM; for_each_possible_cpu(i) { @@ -1169,8 +1174,8 @@ int __init icmp_init(void) if (err < 0) goto fail; - __icmp_sk[i] = sk = sock->sk; - sk_change_net(sk, &init_net); + net->ipv4.icmp_sk[i] = sk = sock->sk; + sk_change_net(sk, net); sk->sk_allocation = GFP_ATOMIC; @@ -1193,10 +1198,20 @@ int __init icmp_init(void) return 0; fail: - icmp_exit(); + icmp_sk_exit(net); return err; } +static struct pernet_operations __net_initdata icmp_sk_ops = { + .init = icmp_sk_init, + .exit = icmp_sk_exit, +}; + +int __init icmp_init(void) +{ + return register_pernet_device(&icmp_sk_ops); +} + EXPORT_SYMBOL(icmp_err_convert); EXPORT_SYMBOL(icmp_send); EXPORT_SYMBOL(icmp_statistics); -- cgit v1.2.3-59-g8ed1b From 98c6d1b261e74750e6c56ede26dc295201c4a8b2 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 11:21:22 -0800 Subject: [NETNS]: Make icmpv6_sk per namespace. All preparations are done. Now just add a hook to perform an initialization on namespace startup and replace icmpv6_sk macro with proper inline call. Actual namespace the packet belongs too will be passed later along with the one for the routing. Signed-off-by: Denis V. Lunev Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/net/netns/ipv6.h | 1 + net/ipv6/icmp.c | 68 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 1dd7de4e4195..82623d3a8e35 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -36,5 +36,6 @@ struct netns_ipv6 { struct xt_table *ip6table_mangle; struct xt_table *ip6table_raw; #endif + struct sock **icmp_sk; }; #endif diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 3eb594d54172..9f55a965c884 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -80,8 +80,10 @@ EXPORT_SYMBOL(icmpv6msg_statistics); * * On SMP we have one ICMP socket per-cpu. */ -static struct sock **__icmpv6_sk = NULL; -#define icmpv6_sk (__icmpv6_sk[smp_processor_id()]) +static inline struct sock *icmpv6_sk(struct net *net) +{ + return net->ipv6.icmp_sk[smp_processor_id()]; +} static int icmpv6_rcv(struct sk_buff *skb); @@ -389,7 +391,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, fl.fl_icmp_code = code; security_skb_classify_flow(skb, &fl); - sk = icmpv6_sk; + sk = icmpv6_sk(&init_net); np = inet6_sk(sk); if (icmpv6_xmit_lock(sk)) @@ -535,7 +537,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) fl.fl_icmp_type = ICMPV6_ECHO_REPLY; security_skb_classify_flow(skb, &fl); - sk = icmpv6_sk; + sk = icmpv6_sk(&init_net); np = inet6_sk(sk); if (icmpv6_xmit_lock(sk)) @@ -780,13 +782,14 @@ drop_no_count: */ static struct lock_class_key icmpv6_socket_sk_dst_lock_key; -int __init icmpv6_init(void) +static int __net_init icmpv6_sk_init(struct net *net) { struct sock *sk; int err, i, j; - __icmpv6_sk = kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL); - if (__icmpv6_sk == NULL) + net->ipv6.icmp_sk = + kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL); + if (net->ipv6.icmp_sk == NULL) return -ENOMEM; for_each_possible_cpu(i) { @@ -801,8 +804,8 @@ int __init icmpv6_init(void) goto fail; } - __icmpv6_sk[i] = sk = sock->sk; - sk_change_net(sk, &init_net); + net->ipv6.icmp_sk[i] = sk = sock->sk; + sk_change_net(sk, net); sk->sk_allocation = GFP_ATOMIC; /* @@ -822,33 +825,56 @@ int __init icmpv6_init(void) sk->sk_prot->unhash(sk); } - - - if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) { - printk(KERN_ERR "Failed to register ICMP6 protocol\n"); - err = -EAGAIN; - goto fail; - } - return 0; fail: for (j = 0; j < i; j++) - sk_release_kernel(__icmpv6_sk[j]); - + sk_release_kernel(net->ipv6.icmp_sk[j]); + kfree(net->ipv6.icmp_sk); return err; } -void icmpv6_cleanup(void) +static void __net_exit icmpv6_sk_exit(struct net *net) { int i; for_each_possible_cpu(i) { - sk_release_kernel(__icmpv6_sk[i]); + sk_release_kernel(net->ipv6.icmp_sk[i]); } + kfree(net->ipv6.icmp_sk); +} + +static struct pernet_operations __net_initdata icmpv6_sk_ops = { + .init = icmpv6_sk_init, + .exit = icmpv6_sk_exit, +}; + +int __init icmpv6_init(void) +{ + int err; + + err = register_pernet_subsys(&icmpv6_sk_ops); + if (err < 0) + return err; + + err = -EAGAIN; + if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) + goto fail; + return 0; + +fail: + printk(KERN_ERR "Failed to register ICMP6 protocol\n"); + unregister_pernet_subsys(&icmpv6_sk_ops); + return err; +} + +void __exit icmpv6_cleanup(void) +{ + unregister_pernet_subsys(&icmpv6_sk_ops); inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); } + static const struct icmp6_err { int err; int fatal; -- cgit v1.2.3-59-g8ed1b From 45af1754bc09926b5e062bda24f789d7b320939f Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 29 Feb 2008 11:33:19 -0800 Subject: [NET]: sk_release_kernel needs to be exported to modules Fixes: ERROR: "sk_release_kernel" [net/ipv6/ipv6.ko] undefined! Signed-off-by: David S. Miller --- net/core/sock.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/core/sock.c b/net/core/sock.c index c71b645a78f0..0ca069738021 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1004,6 +1004,7 @@ void sk_release_kernel(struct sock *sk) sk->sk_net = get_net(&init_net); sock_put(sk); } +EXPORT_SYMBOL(sk_release_kernel); struct sock *sk_clone(const struct sock *sk, const gfp_t priority) { -- cgit v1.2.3-59-g8ed1b From 9a8c09e73bf6c8b1720b1172cdcabb14fc823cf8 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 29 Feb 2008 11:37:02 -0800 Subject: [ATM]: Use seq_open/release_privade instead of manual manipulations. lec_seq_open/lec_seq_release and __vcc_seq_open/vcc_seq_release do seq_open/release_private's job. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/atm/lec.c | 29 ++--------------------------- net/atm/proc.c | 32 +++++++------------------------- 2 files changed, 9 insertions(+), 52 deletions(-) (limited to 'net') diff --git a/net/atm/lec.c b/net/atm/lec.c index 0e450d12f035..e2d800d818e3 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -1169,32 +1169,7 @@ static const struct seq_operations lec_seq_ops = { static int lec_seq_open(struct inode *inode, struct file *file) { - struct lec_state *state; - struct seq_file *seq; - int rc = -EAGAIN; - - state = kmalloc(sizeof(*state), GFP_KERNEL); - if (!state) { - rc = -ENOMEM; - goto out; - } - - rc = seq_open(file, &lec_seq_ops); - if (rc) - goto out_kfree; - seq = file->private_data; - seq->private = state; -out: - return rc; - -out_kfree: - kfree(state); - goto out; -} - -static int lec_seq_release(struct inode *inode, struct file *file) -{ - return seq_release_private(inode, file); + return seq_open_private(file, &lec_seq_ops, sizeof(struct lec_state)); } static const struct file_operations lec_seq_fops = { @@ -1202,7 +1177,7 @@ static const struct file_operations lec_seq_fops = { .open = lec_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = lec_seq_release, + .release = seq_release_private, }; #endif diff --git a/net/atm/proc.c b/net/atm/proc.c index e9693aed7ef8..b995b66b5585 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c @@ -114,31 +114,13 @@ static int __vcc_seq_open(struct inode *inode, struct file *file, int family, const struct seq_operations *ops) { struct vcc_state *state; - struct seq_file *seq; - int rc = -ENOMEM; - state = kmalloc(sizeof(*state), GFP_KERNEL); - if (!state) - goto out; - - rc = seq_open(file, ops); - if (rc) - goto out_kfree; + state = __seq_open_private(file, ops, sizeof(*state)); + if (state == NULL) + return -ENOMEM; state->family = family; - - seq = file->private_data; - seq->private = state; -out: - return rc; -out_kfree: - kfree(state); - goto out; -} - -static int vcc_seq_release(struct inode *inode, struct file *file) -{ - return seq_release_private(inode, file); + return 0; } static void *vcc_seq_start(struct seq_file *seq, loff_t *pos) @@ -314,7 +296,7 @@ static const struct file_operations pvc_seq_fops = { .open = pvc_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = vcc_seq_release, + .release = seq_release_private, }; static int vcc_seq_show(struct seq_file *seq, void *v) @@ -348,7 +330,7 @@ static const struct file_operations vcc_seq_fops = { .open = vcc_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = vcc_seq_release, + .release = seq_release_private, }; static int svc_seq_show(struct seq_file *seq, void *v) @@ -383,7 +365,7 @@ static const struct file_operations svc_seq_fops = { .open = svc_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = vcc_seq_release, + .release = seq_release_private, }; static ssize_t proc_dev_atm_read(struct file *file, char __user *buf, -- cgit v1.2.3-59-g8ed1b From c20932d2c9ba24838a102ac501bf7371b0fe0794 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 29 Feb 2008 11:38:24 -0800 Subject: [ATALK/DECNET]: Use seq_open_private in appletalk and decnet. These two also perform manual seq_open_private, so patch them both at once. But unlike ATM code, these already use the seq_release_private, so I splitted this patch from the previous one. Signed-off-by: Pavel Emelyanov Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/appletalk/aarp.c | 21 ++------------------- net/decnet/af_decnet.c | 21 ++------------------- 2 files changed, 4 insertions(+), 38 deletions(-) (limited to 'net') diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 18058bbc7962..61166f66479f 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -1033,25 +1033,8 @@ static const struct seq_operations aarp_seq_ops = { static int aarp_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct aarp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &aarp_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; - memset(s, 0, sizeof(*s)); -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &aarp_seq_ops, + sizeof(struct aarp_iter_state)); } const struct file_operations atalk_seq_arp_fops = { diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index acd48ee522d6..23fd95a7ad15 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -2320,25 +2320,8 @@ static const struct seq_operations dn_socket_seq_ops = { static int dn_socket_seq_open(struct inode *inode, struct file *file) { - struct seq_file *seq; - int rc = -ENOMEM; - struct dn_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; - - rc = seq_open(file, &dn_socket_seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; - memset(s, 0, sizeof(*s)); -out: - return rc; -out_kfree: - kfree(s); - goto out; + return seq_open_private(file, &dn_socket_seq_ops, + sizeof(struct dn_iter_state)); } static const struct file_operations dn_socket_seq_fops = { -- cgit v1.2.3-59-g8ed1b From 665bba10872fe995773b10c491519f148110576d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 29 Feb 2008 11:39:17 -0800 Subject: [NETFILTER/RXRPC]: Don't use seq_release_private where inappropriate. Some netfilter code and rxrpc one use seq_open() to open a proc file, but seq_release_private to release one. This is harmless, but ambiguous. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c | 2 +- net/netfilter/nf_conntrack_standalone.c | 2 +- net/rxrpc/ar-proc.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c index 089252e82c01..9668c3a23efe 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c @@ -379,7 +379,7 @@ static const struct file_operations ct_cpu_seq_fops = { .open = ct_cpu_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release, }; int __init nf_conntrack_ipv4_compat_init(void) diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index e88e96af613d..a9bf6e4fd0cc 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -293,7 +293,7 @@ static const struct file_operations ct_cpu_seq_fops = { .open = ct_cpu_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release, }; #endif /* CONFIG_PROC_FS */ diff --git a/net/rxrpc/ar-proc.c b/net/rxrpc/ar-proc.c index 83eda247fe48..017322e2786d 100644 --- a/net/rxrpc/ar-proc.c +++ b/net/rxrpc/ar-proc.c @@ -103,7 +103,7 @@ const struct file_operations rxrpc_call_seq_fops = { .open = rxrpc_call_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release, }; /* @@ -188,5 +188,5 @@ const struct file_operations rxrpc_connection_seq_fops = { .open = rxrpc_connection_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release, }; -- cgit v1.2.3-59-g8ed1b From 58fbbed4fbc0094fc808a568fe99a915f85402ee Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Fri, 29 Feb 2008 11:40:56 -0800 Subject: [SCTP]: extend exported data in /proc/net/sctp/assoc RFC 3873 specifies several MIB objects that can't be obtained by the current data set exported by /proc/sys/net/sctp/assoc. This patch adds the missing pieces of data that allow us to compute all the objects in the sctpAssocTable object. Signed-off-by: Neil Horman Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 8 ++++++++ net/sctp/outqueue.c | 3 +++ net/sctp/proc.c | 20 ++++++++++++++------ net/sctp/sm_statefuns.c | 2 ++ 4 files changed, 27 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 9c827a749b6f..8966599ddb9f 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1661,6 +1661,9 @@ struct sctp_association { /* Transport to which SHUTDOWN chunk was last sent. */ struct sctp_transport *shutdown_last_sent_to; + /* How many times have we resent a SHUTDOWN */ + int shutdown_retries; + /* Transport to which INIT chunk was last sent. */ struct sctp_transport *init_last_sent_to; @@ -1695,6 +1698,11 @@ struct sctp_association { */ __u16 unack_data; + /* The total number of data chunks that we've had to retransmit + * as the result of a T3 timer expiration + */ + __u32 rtx_data_chunks; + /* This is the association's receive buffer space. This value is used * to set a_rwnd field in an INIT or a SACK chunk. */ diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 1bb3c5c35d2a..fd4deefab3cf 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -494,6 +494,8 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, */ if (transport == transport->asoc->peer.retran_path) sctp_assoc_update_retran_path(transport->asoc); + transport->asoc->rtx_data_chunks += + transport->asoc->unack_data; break; case SCTP_RTXR_FAST_RTX: SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS); @@ -504,6 +506,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, break; case SCTP_RTXR_T1_RTX: SCTP_INC_STATS(SCTP_MIB_T1_RETRANSMITS); + transport->asoc->init_retries++; break; default: BUG(); diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 9e214da82d9e..82bea300308d 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -281,8 +281,10 @@ static void * sctp_assocs_seq_start(struct seq_file *seq, loff_t *pos) *pos = 0; if (*pos == 0) - seq_printf(seq, " ASSOC SOCK STY SST ST HBKT ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT " - "RPORT LADDRS <-> RADDRS\n"); + seq_printf(seq, " ASSOC SOCK STY SST ST HBKT " + "ASSOC-ID TX_QUEUE RX_QUEUE UID INODE LPORT " + "RPORT LADDRS <-> RADDRS " + "HBINT INS OUTS MAXRT T1X T2X RTXC\n"); return (void *)pos; } @@ -321,15 +323,21 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) assoc = sctp_assoc(epb); sk = epb->sk; seq_printf(seq, - "%8p %8p %-3d %-3d %-2d %-4d %4d %8d %8d %7d %5lu %-5d %5d ", + "%8p %8p %-3d %-3d %-2d %-4d " + "%4d %8d %8d %7d %5lu %-5d %5d " + "%8d %5d %5d %4d %4d %4d %8d ", assoc, sk, sctp_sk(sk)->type, sk->sk_state, - assoc->state, hash, assoc->assoc_id, + assoc->state, hash, + assoc->assoc_id, assoc->sndbuf_used, atomic_read(&assoc->rmem_alloc), sock_i_uid(sk), sock_i_ino(sk), epb->bind_addr.port, - assoc->peer.port); - + assoc->peer.port, + assoc->hbinterval, assoc->c.sinit_max_instreams, + assoc->c.sinit_num_ostreams, assoc->max_retrans, + assoc->init_retries, assoc->shutdown_retries, + assoc->rtx_data_chunks); seq_printf(seq, " "); sctp_seq_dump_local_addrs(seq, epb); seq_printf(seq, "<-> "); diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index f2ed6473feef..ade0cbd3a52b 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -5312,6 +5312,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep, SCTP_DEBUG_PRINTK("Timer T2 expired.\n"); SCTP_INC_STATS(SCTP_MIB_T2_SHUTDOWN_EXPIREDS); + ((struct sctp_association *)asoc)->shutdown_retries++; + if (asoc->overall_error_count >= asoc->max_retrans) { sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ETIMEDOUT)); -- cgit v1.2.3-59-g8ed1b From fd80eb942ad9761f241c9b287b3b9a342b20690d Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 11:43:03 -0800 Subject: [INET]: Remove struct dst_entry *dst from request_sock_ops.rtx_syn_ack. It looks like dst parameter is used in this API due to historical reasons. Actually, it is really used in the direct call to tcp_v4_send_synack only. So, create a wrapper for tcp_v4_send_synack and remove dst from rtx_syn_ack. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/request_sock.h | 3 +-- net/dccp/ipv4.c | 11 +++++------ net/dccp/ipv6.c | 38 ++++++++++++++++++-------------------- net/dccp/minisocks.c | 2 +- net/ipv4/inet_connection_sock.c | 2 +- net/ipv4/tcp_ipv4.c | 14 +++++++++----- net/ipv4/tcp_minisocks.c | 2 +- net/ipv6/tcp_ipv6.c | 36 +++++++++++++++++------------------- 8 files changed, 53 insertions(+), 55 deletions(-) (limited to 'net') diff --git a/include/net/request_sock.h b/include/net/request_sock.h index cff4608179c1..040780add355 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -31,8 +31,7 @@ struct request_sock_ops { int obj_size; struct kmem_cache *slab; int (*rtx_syn_ack)(struct sock *sk, - struct request_sock *req, - struct dst_entry *dst); + struct request_sock *req); void (*send_ack)(struct sk_buff *skb, struct request_sock *req); void (*send_reset)(struct sock *sk, diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 474075adbde4..514a40b7fc7f 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -471,15 +471,14 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk, return &rt->u.dst; } -static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, - struct dst_entry *dst) +static int dccp_v4_send_response(struct sock *sk, struct request_sock *req) { int err = -1; struct sk_buff *skb; + struct dst_entry *dst; - /* First, grab a route. */ - - if (dst == NULL && (dst = inet_csk_route_req(sk, req)) == NULL) + dst = inet_csk_route_req(sk, req); + if (dst == NULL) goto out; skb = dccp_make_response(sk, dst, req); @@ -620,7 +619,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) dreq->dreq_iss = dccp_v4_init_sequence(skb); dreq->dreq_service = service; - if (dccp_v4_send_response(sk, req, NULL)) + if (dccp_v4_send_response(sk, req)) goto drop_and_free; inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 490333d47c7b..1a5e50b90677 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -224,8 +224,7 @@ out: } -static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, - struct dst_entry *dst) +static int dccp_v6_send_response(struct sock *sk, struct request_sock *req) { struct inet6_request_sock *ireq6 = inet6_rsk(req); struct ipv6_pinfo *np = inet6_sk(sk); @@ -234,6 +233,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, struct in6_addr *final_p = NULL, final; struct flowi fl; int err = -1; + struct dst_entry *dst; memset(&fl, 0, sizeof(fl)); fl.proto = IPPROTO_DCCP; @@ -245,28 +245,26 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, fl.fl_ip_sport = inet_sk(sk)->sport; security_req_classify_flow(req, &fl); - if (dst == NULL) { - opt = np->opt; + opt = np->opt; - if (opt != NULL && opt->srcrt != NULL) { - const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt; + if (opt != NULL && opt->srcrt != NULL) { + const struct rt0_hdr *rt0 = (struct rt0_hdr *)opt->srcrt; - ipv6_addr_copy(&final, &fl.fl6_dst); - ipv6_addr_copy(&fl.fl6_dst, rt0->addr); - final_p = &final; - } + ipv6_addr_copy(&final, &fl.fl6_dst); + ipv6_addr_copy(&fl.fl6_dst, rt0->addr); + final_p = &final; + } - err = ip6_dst_lookup(sk, &dst, &fl); - if (err) - goto done; + err = ip6_dst_lookup(sk, &dst, &fl); + if (err) + goto done; - if (final_p) - ipv6_addr_copy(&fl.fl6_dst, final_p); + if (final_p) + ipv6_addr_copy(&fl.fl6_dst, final_p); - err = xfrm_lookup(&dst, &fl, sk, 0); - if (err < 0) - goto done; - } + err = xfrm_lookup(&dst, &fl, sk, 0); + if (err < 0) + goto done; skb = dccp_make_response(sk, dst, req); if (skb != NULL) { @@ -448,7 +446,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) dreq->dreq_iss = dccp_v6_init_sequence(skb); dreq->dreq_service = service; - if (dccp_v6_send_response(sk, req, NULL)) + if (dccp_v6_send_response(sk, req)) goto drop_and_free; inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 027d1814e1ab..33ad48321b08 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -216,7 +216,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, * counter (backoff, monitored by dccp_response_timer). */ req->retrans++; - req->rsk_ops->rtx_syn_ack(sk, req, NULL); + req->rsk_ops->rtx_syn_ack(sk, req); } /* Network Duplicate, discard packet */ return NULL; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index b189278c7bc1..c0e0fa03fce1 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -463,7 +463,7 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, if (time_after_eq(now, req->expires)) { if ((req->retrans < thresh || (inet_rsk(req)->acked && req->retrans < max_retries)) - && !req->rsk_ops->rtx_syn_ack(parent, req, NULL)) { + && !req->rsk_ops->rtx_syn_ack(parent, req)) { unsigned long timeo; if (req->retrans++ == 0) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 256032a41069..3b26f9586dcb 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -723,8 +723,8 @@ static void tcp_v4_reqsk_send_ack(struct sk_buff *skb, * This still operates on a request_sock only, not on a big * socket. */ -static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req, - struct dst_entry *dst) +static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req, + struct dst_entry *dst) { const struct inet_request_sock *ireq = inet_rsk(req); int err = -1; @@ -732,7 +732,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req, /* First, grab a route. */ if (!dst && (dst = inet_csk_route_req(sk, req)) == NULL) - goto out; + return -1; skb = tcp_make_synack(sk, dst, req); @@ -751,11 +751,15 @@ static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req, err = net_xmit_eval(err); } -out: dst_release(dst); return err; } +static int tcp_v4_send_synack(struct sock *sk, struct request_sock *req) +{ + return __tcp_v4_send_synack(sk, req, NULL); +} + /* * IPv4 request_sock destructor. */ @@ -1380,7 +1384,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) } tcp_rsk(req)->snt_isn = isn; - if (tcp_v4_send_synack(sk, req, dst)) + if (__tcp_v4_send_synack(sk, req, dst)) goto drop_and_free; if (want_cookie) { diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index b61b76847ad9..0fdd1db641ac 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -536,7 +536,7 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, * Enforce "SYN-ACK" according to figure 8, figure 6 * of RFC793, fixed by RFC1122. */ - req->rsk_ops->rtx_syn_ack(sk, req, NULL); + req->rsk_ops->rtx_syn_ack(sk, req); return NULL; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 12750f2b05ab..1cbbb87dbad2 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -455,8 +455,7 @@ out: } -static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, - struct dst_entry *dst) +static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req) { struct inet6_request_sock *treq = inet6_rsk(req); struct ipv6_pinfo *np = inet6_sk(sk); @@ -464,6 +463,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, struct ipv6_txoptions *opt = NULL; struct in6_addr * final_p = NULL, final; struct flowi fl; + struct dst_entry *dst; int err = -1; memset(&fl, 0, sizeof(fl)); @@ -476,24 +476,22 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req, fl.fl_ip_sport = inet_sk(sk)->sport; security_req_classify_flow(req, &fl); - if (dst == NULL) { - opt = np->opt; - if (opt && opt->srcrt) { - struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; - ipv6_addr_copy(&final, &fl.fl6_dst); - ipv6_addr_copy(&fl.fl6_dst, rt0->addr); - final_p = &final; - } - - err = ip6_dst_lookup(sk, &dst, &fl); - if (err) - goto done; - if (final_p) - ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) - goto done; + opt = np->opt; + if (opt && opt->srcrt) { + struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; + ipv6_addr_copy(&final, &fl.fl6_dst); + ipv6_addr_copy(&fl.fl6_dst, rt0->addr); + final_p = &final; } + err = ip6_dst_lookup(sk, &dst, &fl); + if (err) + goto done; + if (final_p) + ipv6_addr_copy(&fl.fl6_dst, final_p); + if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) + goto done; + skb = tcp_make_synack(sk, dst, req); if (skb) { struct tcphdr *th = tcp_hdr(skb); @@ -1294,7 +1292,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) security_inet_conn_request(sk, skb, req); - if (tcp_v6_send_synack(sk, req, NULL)) + if (tcp_v6_send_synack(sk, req)) goto drop; inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); -- cgit v1.2.3-59-g8ed1b From 95a363582b69bec53bc73ff2100dfc344bd23098 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 29 Feb 2008 11:44:14 -0800 Subject: [NET]: Use existing device list walker for /proc/dev_mcast. The seq_file_operations' dev_mc_seq_xxx callbacks do the same thing as the dev_seq_xxx ones do, but skip the SEQ_START_TOKEN. So use the existing exported dev_seq_xxx calls and handle the SEQ_START_TOKEN in the dev_mc_seq_show(). Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/core/dev_mcast.c | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) (limited to 'net') diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index cec582563e0d..f8a3455f4493 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -156,39 +156,14 @@ void dev_mc_unsync(struct net_device *to, struct net_device *from) EXPORT_SYMBOL(dev_mc_unsync); #ifdef CONFIG_PROC_FS -static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(dev_base_lock) -{ - struct net *net = seq_file_net(seq); - struct net_device *dev; - loff_t off = 0; - - read_lock(&dev_base_lock); - for_each_netdev(net, dev) { - if (off++ == *pos) - return dev; - } - return NULL; -} - -static void *dev_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - return next_net_device((struct net_device *)v); -} - -static void dev_mc_seq_stop(struct seq_file *seq, void *v) - __releases(dev_base_lock) -{ - read_unlock(&dev_base_lock); -} - - static int dev_mc_seq_show(struct seq_file *seq, void *v) { struct dev_addr_list *m; struct net_device *dev = v; + if (v == SEQ_START_TOKEN) + return 0; + netif_tx_lock_bh(dev); for (m = dev->mc_list; m; m = m->next) { int i; @@ -206,9 +181,9 @@ static int dev_mc_seq_show(struct seq_file *seq, void *v) } static const struct seq_operations dev_mc_seq_ops = { - .start = dev_mc_seq_start, - .next = dev_mc_seq_next, - .stop = dev_mc_seq_stop, + .start = dev_seq_start, + .next = dev_seq_next, + .stop = dev_seq_stop, .show = dev_mc_seq_show, }; -- cgit v1.2.3-59-g8ed1b From b22052569657925d6de33b19b2c7b7562900defb Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Sun, 27 Jan 2008 16:18:22 +0200 Subject: mac80211: set assoc flag to bss_conf Only BSS_CHANGED_ASSOC was set in the 'changed' bitmask. Assignment to bss_conf.assoc was absent. This patch assign value to bss_conf.assoc according the association state. Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 9aeed5320228..79dadd2976cd 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -492,6 +492,7 @@ static void ieee80211_set_associated(struct net_device *dev, ifsta->last_probe = jiffies; ieee80211_led_assoc(local, assoc); + sdata->bss_conf.assoc = assoc; ieee80211_bss_info_change_notify(sdata, changed); } -- cgit v1.2.3-59-g8ed1b From 7d185b8bb17eac9e9d673eb483ded0fbf0b28b97 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 28 Jan 2008 17:11:43 +0100 Subject: mac80211: allow sending multicast frames through virtual ports When reworking the port access control code, I forgot multicast frames and those are now always rejected because the destination station is not known. This changes the code to allow through multicast frames and also avoid the sta hash lookup (which is bound to fail) for them. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/tx.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 67b509edd431..85d01646abf5 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1409,10 +1409,17 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, goto fail; } - sta = sta_info_get(local, hdr.addr1); - if (sta) { - sta_flags = sta->flags; - sta_info_put(sta); + /* + * There's no need to try to look up the destination + * if it is a multicast address (which can only happen + * in AP mode) + */ + if (!is_multicast_ether_addr(hdr.addr1)) { + sta = sta_info_get(local, hdr.addr1); + if (sta) { + sta_flags = sta->flags; + sta_info_put(sta); + } } /* receiver is QoS enabled, use a QoS type frame */ @@ -1422,10 +1429,12 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, } /* - * If port access control is enabled, drop frames to unauthorised - * stations unless they are EAPOL frames from the local station. + * If port access control is enabled, drop unicast frames to + * unauthorised stations unless they are EAPOL frames from the + * local station. */ if (unlikely(sdata->ieee802_1x_pac && + !is_multicast_ether_addr(hdr.addr1) && !(sta_flags & WLAN_STA_AUTHORIZED) && !(ethertype == ETH_P_PAE && compare_ether_addr(dev->dev_addr, -- cgit v1.2.3-59-g8ed1b From 0df3ef45a3d7b59cc53ce4e3611033c6e3b51a1b Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 28 Jan 2008 14:07:15 +0200 Subject: mac80211: A-MPDU Tx add session's and low level driver's API This patch adds the API for 3 stages in A-MPDU Tx session flow: - request mac80211 to start/stop A-MPDU Tx session for specific TID. such a request should be issued by a load aware element, either mac80211 itself or external element. - requests by mac80211 to low-level driver to start/stop Tx aggregation. notice that low level driver responds now with Starting Sequence Number. - async feedback by low-level to mac80211 to inform that HW is ready for next A-MPDU Tx state. Changes in API to Rx A-MPDU were also made, reflected in iwlwifi changes as well. Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965.c | 4 +- drivers/net/wireless/iwlwifi/iwl-4965.h | 2 +- include/net/mac80211.h | 86 ++++++++++++++++++++++++++++++++- net/mac80211/ieee80211_sta.c | 4 +- 4 files changed, 89 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index d727de8b96fe..cd4f5e383e60 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -4732,7 +4732,7 @@ static void iwl4965_sta_modify_del_ba_tid(struct iwl4965_priv *priv, int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, - const u8 *addr, u16 tid, u16 ssn) + const u8 *addr, u16 tid, u16 *ssn) { struct iwl4965_priv *priv = hw->priv; int sta_id; @@ -4744,7 +4744,7 @@ int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: IWL_DEBUG_HT("start Rx\n"); - iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, ssn); + iwl4965_sta_modify_add_ba_tid(priv, sta_id, tid, *ssn); break; case IEEE80211_AMPDU_RX_STOP: IWL_DEBUG_HT("stop Rx\n"); diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index 9cb82be0ff80..6edf869d4d54 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -777,7 +777,7 @@ extern void iwl4965_set_ht_add_station(struct iwl4965_priv *priv, u8 index, struct ieee80211_ht_info *sta_ht_inf); extern int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, - const u8 *addr, u16 tid, u16 ssn); + const u8 *addr, u16 tid, u16 *ssn); #ifdef CONFIG_IWL4965_HT_AGG extern int iwl4965_mac_ht_tx_agg_start(struct ieee80211_hw *hw, u8 *da, u16 tid, u16 *start_seq_num); diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 9083bafb63ca..3bbc33cc2b96 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -967,10 +967,14 @@ enum ieee80211_filter_flags { * &struct ieee80211_ops to indicate which action is needed. * @IEEE80211_AMPDU_RX_START: start Rx aggregation * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation + * @IEEE80211_AMPDU_TX_START: start Tx aggregation + * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation */ enum ieee80211_ampdu_mlme_action { IEEE80211_AMPDU_RX_START, IEEE80211_AMPDU_RX_STOP, + IEEE80211_AMPDU_TX_START, + IEEE80211_AMPDU_TX_STOP, }; /** @@ -1111,7 +1115,8 @@ enum ieee80211_ampdu_mlme_action { * The RA/TID combination determines the destination and TID we want * the ampdu action to be performed for. The action is defined through * ieee80211_ampdu_mlme_action. Starting sequence number (@ssn) - * is the first frame we expect to perform the action on. + * is the first frame we expect to perform the action on. notice + * that TX/RX_STOP can pass NULL for this parameter. */ struct ieee80211_ops { int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb, @@ -1162,7 +1167,7 @@ struct ieee80211_ops { int (*conf_ht)(struct ieee80211_hw *hw, struct ieee80211_conf *conf); int (*ampdu_action)(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, - const u8 *ra, u16 tid, u16 ssn); + const u8 *addr, u16 tid, u16 *ssn); }; /** @@ -1574,4 +1579,81 @@ void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw, struct ieee80211_vif *vif), void *data); +/** + * ieee80211_start_tx_ba_session - Start a tx Block Ack session. + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @ra: receiver address of the BA session recipient + * @tid: the TID to BA on. + * @return: success if addBA request was sent, failure otherwise + * + * Although mac80211/low level driver/user space application can estimate + * the need to start aggregation on a certain RA/TID, the session level + * will be managed by the mac80211. + */ +int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid); + +/** + * ieee80211_start_tx_ba_cb - low level driver ready to aggregate. + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @ra: receiver address of the BA session recipient. + * @tid: the TID to BA on. + * + * This function must be called by low level driver once it has + * finished with preparations for the BA session. + */ +void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid); + +/** + * ieee80211_start_tx_ba_cb_irqsafe - low level driver ready to aggregate. + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @ra: receiver address of the BA session recipient. + * @tid: the TID to BA on. + * + * This function must be called by low level driver once it has + * finished with preparations for the BA session. + * This version of the function is irq safe. + */ +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, + u16 tid); + +/** + * ieee80211_stop_tx_ba_session - Stop a Block Ack session. + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @ra: receiver address of the BA session recipient + * @tid: the TID to stop BA. + * @initiator: if indicates initiator DELBA frame will be sent. + * @return: error if no sta with matching da found, success otherwise + * + * Although mac80211/low level driver/user space application can estimate + * the need to stop aggregation on a certain RA/TID, the session level + * will be managed by the mac80211. + */ +int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, + u8 *ra, u16 tid, + enum ieee80211_back_parties initiator); + +/** + * ieee80211_stop_tx_ba_cb - low level driver ready to stop aggregate. + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @ra: receiver address of the BA session recipient. + * @tid: the desired TID to BA on. + * + * This function must be called by low level driver once it has + * finished with preparations for the BA session tear down. + */ +void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid); + +/** + * ieee80211_stop_tx_ba_cb_irqsafe - low level driver ready to stop aggregate. + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @ra: receiver address of the BA session recipient. + * @tid: the desired TID to BA on. + * + * This function must be called by low level driver once it has + * finished with preparations for the BA session tear down. + * This version of the function is irq safe. + */ +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, + u16 tid); + #endif /* MAC80211_H */ diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 79dadd2976cd..d5d5610db1bd 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1128,7 +1128,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, if (local->ops->ampdu_action) ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, - sta->addr, tid, start_seq_num); + sta->addr, tid, &start_seq_num); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Rx A-MPDU on tid %d result %d", tid, ret); #endif /* CONFIG_MAC80211_HT_DEBUG */ @@ -1230,7 +1230,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, BUG_ON(!local->ops->ampdu_action); ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, - ra, tid, EINVAL); + ra, tid, NULL); if (ret) printk(KERN_DEBUG "HW problem - can not stop rx " "aggergation for tid %d\n", tid); -- cgit v1.2.3-59-g8ed1b From 80656c20315558a9bc5c5b7f7c6949fa72277afd Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 28 Jan 2008 14:07:16 +0200 Subject: mac80211: A-MPDU Tx add MLME structures This patch adds the needed structures to describe the Tx aggregation MLME per STA new: - struct tid_ampdu_tx: TID aggregation information (Tx) changed: - struct sta_ampdu_mlme: Tx aggregation information per TID and dialog token creator were added - struct sta_info: tid_to_tx_q added for tid<->tx queue mapping Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- net/mac80211/sta_info.h | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 96fe3ed95038..48a620a4e1a6 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -33,13 +33,36 @@ #define STA_TID_NUM 16 #define ADDBA_RESP_INTERVAL HZ +#define HT_AGG_MAX_RETRIES (0x3) #define HT_AGG_STATE_INITIATOR_SHIFT (4) +#define HT_ADDBA_REQUESTED_MSK BIT(0) +#define HT_ADDBA_DRV_READY_MSK BIT(1) +#define HT_ADDBA_RECEIVED_MSK BIT(2) #define HT_AGG_STATE_REQ_STOP_BA_MSK BIT(3) - +#define HT_AGG_STATE_INITIATOR_MSK BIT(HT_AGG_STATE_INITIATOR_SHIFT) #define HT_AGG_STATE_IDLE (0x0) -#define HT_AGG_STATE_OPERATIONAL (0x7) +#define HT_AGG_STATE_OPERATIONAL (HT_ADDBA_REQUESTED_MSK | \ + HT_ADDBA_DRV_READY_MSK | \ + HT_ADDBA_RECEIVED_MSK) + +/** + * struct tid_ampdu_tx - TID aggregation information (Tx). + * + * @state: TID's state in session state machine. + * @dialog_token: dialog token for aggregation session + * @ssn: Starting Sequence Number expected to be aggregated. + * @addba_resp_timer: timer for peer's response to addba request + * @addba_req_num: number of times addBA request has been sent. + */ +struct tid_ampdu_tx { + u8 state; + u8 dialog_token; + u16 ssn; + struct timer_list addba_resp_timer; + u8 addba_req_num; +}; /** * struct tid_ampdu_rx - TID aggregation information (Rx). @@ -69,12 +92,18 @@ struct tid_ampdu_rx { /** * struct sta_ampdu_mlme - STA aggregation information. * - * @tid_agg_info_rx: aggregation info for Rx per TID + * @tid_rx: aggregation info for Rx per TID + * @tid_tx: aggregation info for Tx per TID * @ampdu_rx: for locking sections in aggregation Rx flow + * @ampdu_tx: for locking sectionsi in aggregation Tx flow + * @dialog_token_allocator: dialog token enumerator for each new session; */ struct sta_ampdu_mlme { struct tid_ampdu_rx tid_rx[STA_TID_NUM]; + struct tid_ampdu_tx tid_tx[STA_TID_NUM]; spinlock_t ampdu_rx; + spinlock_t ampdu_tx; + u8 dialog_token_allocator; }; struct sta_info { @@ -148,6 +177,7 @@ struct sta_info { of this STA */ struct sta_ampdu_mlme ampdu_mlme; u8 timer_to_tid[STA_TID_NUM]; /* convert timer id to tid */ + u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */ #ifdef CONFIG_MAC80211_DEBUGFS struct sta_info_debugfsdentries { -- cgit v1.2.3-59-g8ed1b From eadc8d9e9047266a8914eb2ed4d36e797ce540d1 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 28 Jan 2008 14:07:17 +0200 Subject: mac80211: A-MPDU Tx adding basic functionality This patch adds the following abilities to mac80211: - start A-MPDU Tx session - stop A-MPDU Tx session - call backs to start/stop A-MPDU Tx session - sending addBA request - processing addBA response Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 336 +++++++++++++++++++++++++++++++++++++++++++ net/mac80211/ieee80211_i.h | 14 ++ net/mac80211/ieee80211_sta.c | 182 ++++++++++++++++++++++- 3 files changed, 530 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 28bcdf9fc3df..c323c9af9b8f 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -414,6 +414,329 @@ static int ieee80211_stop(struct net_device *dev) return 0; } +int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + struct ieee80211_sub_if_data *sdata; + u16 start_seq_num = 0; + u8 *state; + int ret; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) + return -EINVAL; + +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Open BA session requested for %s tid %u\n", + print_mac(mac, ra), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + sta = sta_info_get(local, ra); + if (!sta) { + printk(KERN_DEBUG "Could not find the station\n"); + return -ENOENT; + } + + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + /* we have tried too many times, receiver does not want A-MPDU */ + if (sta->ampdu_mlme.tid_tx[tid].addba_req_num > HT_AGG_MAX_RETRIES) { + ret = -EBUSY; + goto start_ba_exit; + } + + state = &sta->ampdu_mlme.tid_tx[tid].state; + /* check if the TID is not in aggregation flow already */ + if (*state != HT_AGG_STATE_IDLE) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - session is not " + "idle on tid %u\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + ret = -EAGAIN; + goto start_ba_exit; + } + + /* ensure that TX flow won't interrupt us + * until the end of the call to requeue function */ + spin_lock_bh(&local->mdev->queue_lock); + + /* create a new queue for this aggregation */ + /* ret = ieee80211_ht_agg_queue_add(local, sta, tid); */ + + /* case no queue is available to aggregation + * don't switch to aggregation */ + if (ret) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - no queue available for" + " tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + spin_unlock_bh(&local->mdev->queue_lock); + goto start_ba_exit; + } + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + + /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the + * call back right away, it must see that the flow has begun */ + *state |= HT_ADDBA_REQUESTED_MSK; + + if (local->ops->ampdu_action) + ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, + ra, tid, &start_seq_num); + + if (ret) { + /* No need to requeue the packets in the agg queue, since we + * held the tx lock: no packet could be enqueued to the newly + * allocated queue */ + /* ieee80211_ht_agg_queue_remove(local, sta, tid, 0); */ +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - HW or queue unavailable" + " for tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + spin_unlock_bh(&local->mdev->queue_lock); + *state = HT_AGG_STATE_IDLE; + goto start_ba_exit; + } + + /* Will put all the packets in the new SW queue */ + /* ieee80211_requeue(local, ieee802_1d_to_ac[tid]); */ + spin_unlock_bh(&local->mdev->queue_lock); + + /* We have most probably almost emptied the legacy queue */ + /* ieee80211_wake_queue(local_to_hw(local), ieee802_1d_to_ac[tid]); */ + + /* send an addBA request */ + sta->ampdu_mlme.dialog_token_allocator++; + sta->ampdu_mlme.tid_tx[tid].dialog_token = + sta->ampdu_mlme.dialog_token_allocator; + sta->ampdu_mlme.tid_tx[tid].ssn = start_seq_num; + + ieee80211_send_addba_request(sta->dev, ra, tid, + sta->ampdu_mlme.tid_tx[tid].dialog_token, + sta->ampdu_mlme.tid_tx[tid].ssn, + 0x40, 5000); + + /* activate the timer for the recipient's addBA response */ + sta->ampdu_mlme.tid_tx[tid].addba_resp_timer.expires = + jiffies + ADDBA_RESP_INTERVAL; + add_timer(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer); + printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); + +start_ba_exit: + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + sta_info_put(sta); + return ret; +} +EXPORT_SYMBOL(ieee80211_start_tx_ba_session); + +int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, + u8 *ra, u16 tid, + enum ieee80211_back_parties initiator) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + u8 *state; + int ret = 0; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) + return -EINVAL; + +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Stop a BA session requested for %s tid %u\n", + print_mac(mac, ra), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + sta = sta_info_get(local, ra); + if (!sta) + return -ENOENT; + + /* check if the TID is in aggregation */ + state = &sta->ampdu_mlme.tid_tx[tid].state; + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + if (*state != HT_AGG_STATE_OPERATIONAL) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Try to stop Tx aggregation on" + " non active TID\n"); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + ret = -ENOENT; + goto stop_BA_exit; + } + + ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); + + *state = HT_AGG_STATE_REQ_STOP_BA_MSK | + (initiator << HT_AGG_STATE_INITIATOR_SHIFT); + + if (local->ops->ampdu_action) + ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP, + ra, tid, NULL); + + /* case HW denied going back to legacy */ + if (ret) { + WARN_ON(ret != -EBUSY); + *state = HT_AGG_STATE_OPERATIONAL; + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + goto stop_BA_exit; + } + +stop_BA_exit: + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + sta_info_put(sta); + return ret; +} +EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); + +void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + u8 *state; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) { + printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", + tid, STA_TID_NUM); + return; + } + + sta = sta_info_get(local, ra); + if (!sta) { + printk(KERN_DEBUG "Could not find station: %s\n", + print_mac(mac, ra)); + return; + } + + state = &sta->ampdu_mlme.tid_tx[tid].state; + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", + *state); + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + sta_info_put(sta); + return; + } + + WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); + + *state |= HT_ADDBA_DRV_READY_MSK; + + if (*state == HT_AGG_STATE_OPERATIONAL) { + printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + } + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + sta_info_put(sta); +} +EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); + +void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + u8 *state; + int agg_queue; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) { + printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", + tid, STA_TID_NUM); + return; + } + + printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n", + print_mac(mac, ra), tid); + + sta = sta_info_get(local, ra); + if (!sta) { + printk(KERN_DEBUG "Could not find station: %s\n", + print_mac(mac, ra)); + return; + } + state = &sta->ampdu_mlme.tid_tx[tid].state; + + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { + printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); + sta_info_put(sta); + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + return; + } + + if (*state & HT_AGG_STATE_INITIATOR_MSK) + ieee80211_send_delba(sta->dev, ra, tid, + WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); + + agg_queue = sta->tid_to_tx_q[tid]; + + /* avoid ordering issues: we are the only one that can modify + * the content of the qdiscs */ + spin_lock_bh(&local->mdev->queue_lock); + /* remove the queue for this aggregation */ + /* ieee80211_ht_agg_queue_remove(local, sta, tid, 1); */ + spin_unlock_bh(&local->mdev->queue_lock); + + /* we just requeued the all the frames that were in the removed + * queue, and since we might miss a softirq we do netif_schedule. + * ieee80211_wake_queue is not used here as this queue is not + * necessarily stopped */ + netif_schedule(local->mdev); + *state = HT_AGG_STATE_IDLE; + sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + + sta_info_put(sta); +} +EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); + +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, + const u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_ra_tid *ra_tid; + struct sk_buff *skb = dev_alloc_skb(0); + + if (unlikely(!skb)) { + if (net_ratelimit()) + printk(KERN_WARNING "%s: Not enough memory, " + "dropping start BA session", skb->dev->name); + return; + } + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + memcpy(&ra_tid->ra, ra, ETH_ALEN); + ra_tid->tid = tid; + + skb->pkt_type = IEEE80211_ADDBA_MSG; + skb_queue_tail(&local->skb_queue, skb); + tasklet_schedule(&local->tasklet); +} +EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); + +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, + const u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_ra_tid *ra_tid; + struct sk_buff *skb = dev_alloc_skb(0); + + if (unlikely(!skb)) { + if (net_ratelimit()) + printk(KERN_WARNING "%s: Not enough memory, " + "dropping stop BA session", skb->dev->name); + return; + } + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + memcpy(&ra_tid->ra, ra, ETH_ALEN); + ra_tid->tid = tid; + + skb->pkt_type = IEEE80211_DELBA_MSG; + skb_queue_tail(&local->skb_queue, skb); + tasklet_schedule(&local->tasklet); +} +EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); + static void ieee80211_set_multicast_list(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -713,6 +1036,7 @@ static void ieee80211_tasklet_handler(unsigned long data) struct sk_buff *skb; struct ieee80211_rx_status rx_status; struct ieee80211_tx_status *tx_status; + struct ieee80211_ra_tid *ra_tid; while ((skb = skb_dequeue(&local->skb_queue)) || (skb = skb_dequeue(&local->skb_queue_unreliable))) { @@ -733,6 +1057,18 @@ static void ieee80211_tasklet_handler(unsigned long data) skb, tx_status); kfree(tx_status); break; + case IEEE80211_DELBA_MSG: + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + ieee80211_stop_tx_ba_cb(local_to_hw(local), + ra_tid->ra, ra_tid->tid); + dev_kfree_skb(skb); + break; + case IEEE80211_ADDBA_MSG: + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + ieee80211_start_tx_ba_cb(local_to_hw(local), + ra_tid->ra, ra_tid->tid); + dev_kfree_skb(skb); + break ; default: /* should never get here! */ printk(KERN_ERR "%s: Unknown message type (%d)\n", wiphy_name(local->hw.wiphy), skb->pkt_type); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 72ecbf7bf962..8a24c2c6ebc1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -407,6 +407,8 @@ struct ieee80211_sub_if_data *vif_to_sdata(struct ieee80211_vif *p) enum { IEEE80211_RX_MSG = 1, IEEE80211_TX_STATUS_MSG = 2, + IEEE80211_DELBA_MSG = 3, + IEEE80211_ADDBA_MSG = 4, }; struct ieee80211_local { @@ -627,6 +629,12 @@ struct ieee80211_local { #endif }; +/* this struct represents 802.11n's RA/TID combination */ +struct ieee80211_ra_tid { + u8 ra[ETH_ALEN]; + u16 tid; +}; + static inline struct ieee80211_local *hw_to_local( struct ieee80211_hw *hw) { @@ -782,9 +790,15 @@ int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, int ieee80211_ht_addt_info_ie_to_ht_bss_info( struct ieee80211_ht_addt_info *ht_add_info_ie, struct ieee80211_ht_bss_info *bss_info); +void ieee80211_send_addba_request(struct net_device *dev, const u8 *da, + u16 tid, u8 dialog_token, u16 start_seq_num, + u16 agg_size, u16 timeout); +void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, + u16 initiator, u16 reason_code); void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da, u16 tid, u16 initiator, u16 reason); void sta_rx_agg_session_timer_expired(unsigned long data); +void sta_addba_resp_timer_expired(unsigned long data); /* ieee80211_iface.c */ int ieee80211_if_add(struct net_device *dev, const char *name, struct net_device **new_dev, int type); diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index d5d5610db1bd..c4d57346eacf 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1045,6 +1045,58 @@ static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid, return; } +void ieee80211_send_addba_request(struct net_device *dev, const u8 *da, + u16 tid, u8 dialog_token, u16 start_seq_num, + u16 agg_size, u16 timeout) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u16 capab; + + skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + + sizeof(mgmt->u.action.u.addba_req)); + + + if (!skb) { + printk(KERN_ERR "%s: failed to allocate buffer " + "for addba request frame\n", dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, da, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) + memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN); + else + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_ACTION); + + skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req)); + + mgmt->u.action.category = WLAN_CATEGORY_BACK; + mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; + + mgmt->u.action.u.addba_req.dialog_token = dialog_token; + capab = (u16)(1 << 1); /* bit 1 aggregation policy */ + capab |= (u16)(tid << 2); /* bit 5:2 TID number */ + capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */ + + mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); + + mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout); + mgmt->u.action.u.addba_req.start_seq_num = + cpu_to_le16(start_seq_num << 4); + + ieee80211_sta_tx(dev, skb, 0); +} + static void ieee80211_sta_process_addba_request(struct net_device *dev, struct ieee80211_mgmt *mgmt, size_t len) @@ -1156,8 +1208,80 @@ end_no_lock: sta_info_put(sta); } -static void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, - u16 initiator, u16 reason_code) +static void ieee80211_sta_process_addba_resp(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = &local->hw; + struct sta_info *sta; + u16 capab; + u16 tid; + u8 *state; + + sta = sta_info_get(local, mgmt->sa); + if (!sta) + return; + + capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); + tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + + state = &sta->ampdu_mlme.tid_tx[tid].state; + + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + if (mgmt->u.action.u.addba_resp.dialog_token != + sta->ampdu_mlme.tid_tx[tid].dialog_token) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + sta_info_put(sta); + return; + } + + del_timer_sync(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) + == WLAN_STATUS_SUCCESS) { + if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" + "%d\n", *state); + sta_info_put(sta); + return; + } + + if (*state & HT_ADDBA_RECEIVED_MSK) + printk(KERN_DEBUG "double addBA response\n"); + + *state |= HT_ADDBA_RECEIVED_MSK; + sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0; + + if (*state == HT_AGG_STATE_OPERATIONAL) { + printk(KERN_DEBUG "Aggregation on for tid %d \n", tid); + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + } + + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid); + } else { + printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid); + + sta->ampdu_mlme.tid_tx[tid].addba_req_num++; + /* this will allow the state check in stop_BA_session */ + *state = HT_AGG_STATE_OPERATIONAL; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + ieee80211_stop_tx_ba_session(hw, sta->addr, tid, + WLAN_BACK_INITIATOR); + } + sta_info_put(sta); +} + +void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, + u16 initiator, u16 reason_code) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -1259,6 +1383,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, sta_info_put(sta); } + static void ieee80211_sta_process_delba(struct net_device *dev, struct ieee80211_mgmt *mgmt, size_t len) { @@ -1289,6 +1414,53 @@ static void ieee80211_sta_process_delba(struct net_device *dev, sta_info_put(sta); } +/* + * After sending add Block Ack request we activated a timer until + * add Block Ack response will arrive from the recipient. + * If this timer expires sta_addba_resp_timer_expired will be executed. + */ +void sta_addba_resp_timer_expired(unsigned long data) +{ + /* not an elegant detour, but there is no choice as the timer passes + * only one argument, and both sta_info and TID are needed, so init + * flow in sta_info_add gives the TID as data, while the timer_to_id + * array gives the sta through container_of */ + u16 tid = *(int *)data; + struct sta_info *temp_sta = container_of((void *)data, + struct sta_info, timer_to_tid[tid]); + + struct ieee80211_local *local = temp_sta->local; + struct ieee80211_hw *hw = &local->hw; + struct sta_info *sta; + u8 *state; + + sta = sta_info_get(local, temp_sta->addr); + if (!sta) + return; + + state = &sta->ampdu_mlme.tid_tx[tid].state; + /* check if the TID waits for addBA response */ + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + *state = HT_AGG_STATE_IDLE; + printk(KERN_DEBUG "timer expired on tid %d but we are not " + "expecting addBA response there", tid); + goto timer_expired_exit; + } + + printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); + + /* go through the state check in stop_BA_session */ + *state = HT_AGG_STATE_OPERATIONAL; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid, + WLAN_BACK_INITIATOR); + +timer_expired_exit: + sta_info_put(sta); +} + /* * After receiving Block Ack Request (BAR) we activated a * timer after each frame arrives from the originator. @@ -2236,6 +2408,12 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev, break; ieee80211_sta_process_addba_request(dev, mgmt, len); break; + case WLAN_ACTION_ADDBA_RESP: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.addba_resp))) + break; + ieee80211_sta_process_addba_resp(dev, mgmt, len); + break; case WLAN_ACTION_DELBA: if (len < (IEEE80211_MIN_ACTION_SIZE + sizeof(mgmt->u.action.u.delba))) -- cgit v1.2.3-59-g8ed1b From 9e7234923789897858e1a475c579b5e2e6ad5b74 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 28 Jan 2008 14:07:18 +0200 Subject: mac80211: A-MPDU Tx adding qdisc support This patch allows qdisc support in A-MPDU Tx. a method to handle QoS <-> TID switches is present in this patch. Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- include/net/mac80211.h | 8 ++- net/mac80211/ieee80211.c | 8 +-- net/mac80211/ieee80211_i.h | 5 +- net/mac80211/tx.c | 2 + net/mac80211/wme.c | 135 +++++++++++++++++++++++++++++++++++++++++---- net/mac80211/wme.h | 23 +++++++- 6 files changed, 161 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 3bbc33cc2b96..0ce2e94dc844 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -246,6 +246,7 @@ struct ieee80211_tx_queue_stats_data { * @IEEE80211_TX_QUEUE_AFTER_BEACON: transmit queue for frames to be * sent after a beacon * @IEEE80211_TX_QUEUE_BEACON: transmit queue for beacon frames + * @NUM_TX_DATA_QUEUES_AMPDU: adding more queues for A-MPDU */ enum ieee80211_tx_queue { IEEE80211_TX_QUEUE_DATA0, @@ -261,11 +262,12 @@ enum ieee80211_tx_queue { * this struct need to have fixed values. As soon as it is removed, we can * fix these entries. */ IEEE80211_TX_QUEUE_AFTER_BEACON = 6, - IEEE80211_TX_QUEUE_BEACON = 7 + IEEE80211_TX_QUEUE_BEACON = 7, + NUM_TX_DATA_QUEUES_AMPDU = 16 }; struct ieee80211_tx_queue_stats { - struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES]; + struct ieee80211_tx_queue_stats_data data[NUM_TX_DATA_QUEUES_AMPDU]; }; struct ieee80211_low_level_stats { @@ -348,6 +350,8 @@ struct ieee80211_tx_control { #define IEEE80211_TXCTL_EAPOL_FRAME (1<<11) /* internal to mac80211 */ #define IEEE80211_TXCTL_SEND_AFTER_DTIM (1<<12) /* send this frame after DTIM * beacon */ +#define IEEE80211_TXCTL_AMPDU (1<<13) /* this frame should be sent + * as part of an A-MPDU */ u32 flags; /* tx control flags defined * above */ u8 key_idx; /* keyidx from hw->set_key(), undefined if diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index c323c9af9b8f..f8e734f0da1a 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -462,7 +462,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) spin_lock_bh(&local->mdev->queue_lock); /* create a new queue for this aggregation */ - /* ret = ieee80211_ht_agg_queue_add(local, sta, tid); */ + ret = ieee80211_ht_agg_queue_add(local, sta, tid); /* case no queue is available to aggregation * don't switch to aggregation */ @@ -488,7 +488,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) /* No need to requeue the packets in the agg queue, since we * held the tx lock: no packet could be enqueued to the newly * allocated queue */ - /* ieee80211_ht_agg_queue_remove(local, sta, tid, 0); */ + ieee80211_ht_agg_queue_remove(local, sta, tid, 0); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "BA request denied - HW or queue unavailable" " for tid %d\n", tid); @@ -499,7 +499,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) } /* Will put all the packets in the new SW queue */ - /* ieee80211_requeue(local, ieee802_1d_to_ac[tid]); */ + ieee80211_requeue(local, ieee802_1d_to_ac[tid]); spin_unlock_bh(&local->mdev->queue_lock); /* We have most probably almost emptied the legacy queue */ @@ -675,7 +675,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) * the content of the qdiscs */ spin_lock_bh(&local->mdev->queue_lock); /* remove the queue for this aggregation */ - /* ieee80211_ht_agg_queue_remove(local, sta, tid, 1); */ + ieee80211_ht_agg_queue_remove(local, sta, tid, 1); spin_unlock_bh(&local->mdev->queue_lock); /* we just requeued the all the frames that were in the removed diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8a24c2c6ebc1..cfd0717c0033 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -165,6 +165,7 @@ struct ieee80211_txrx_data { #define IEEE80211_TXPD_DO_NOT_ENCRYPT BIT(1) #define IEEE80211_TXPD_REQUEUE BIT(2) #define IEEE80211_TXPD_EAPOL_FRAME BIT(3) +#define IEEE80211_TXPD_AMPDU BIT(4) /* Stored in sk_buff->cb */ struct ieee80211_tx_packet_data { int ifindex; @@ -452,8 +453,8 @@ struct ieee80211_local { struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; - unsigned long state[NUM_TX_DATA_QUEUES]; - struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES]; + unsigned long state[NUM_TX_DATA_QUEUES_AMPDU]; + struct ieee80211_tx_stored_packet pending_packet[NUM_TX_DATA_QUEUES_AMPDU]; struct tasklet_struct tx_pending_tasklet; /* number of interfaces with corresponding IFF_ flags */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 85d01646abf5..38e1b2bd8245 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1260,6 +1260,8 @@ int ieee80211_master_start_xmit(struct sk_buff *skb, control.flags |= IEEE80211_TXCTL_REQUEUE; if (pkt_data->flags & IEEE80211_TXPD_EAPOL_FRAME) control.flags |= IEEE80211_TXCTL_EAPOL_FRAME; + if (pkt_data->flags & IEEE80211_TXPD_AMPDU) + control.flags |= IEEE80211_TXCTL_AMPDU; control.queue = pkt_data->queue; ret = ieee80211_tx(odev, skb, &control); diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 4e236599dd31..425aa8588ea0 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -19,10 +19,13 @@ #include "wme.h" /* maximum number of hardware queues we support. */ -#define TC_80211_MAX_QUEUES 8 +#define TC_80211_MAX_QUEUES 16 + +const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; struct ieee80211_sched_data { + unsigned long qdisc_pool; struct tcf_proto *filter_list; struct Qdisc *queues[TC_80211_MAX_QUEUES]; struct sk_buff_head requeued[TC_80211_MAX_QUEUES]; @@ -98,7 +101,6 @@ static inline int classify80211(struct sk_buff *skb, struct Qdisc *qd) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; unsigned short fc = le16_to_cpu(hdr->frame_control); int qos; - const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; /* see if frame is data or non data frame */ if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) { @@ -146,9 +148,25 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) unsigned short fc = le16_to_cpu(hdr->frame_control); struct Qdisc *qdisc; int err, queue; + struct sta_info *sta; + u8 tid; if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { - skb_queue_tail(&q->requeued[pkt_data->queue], skb); + queue = pkt_data->queue; + sta = sta_info_get(local, hdr->addr1); + tid = skb->priority & QOS_CONTROL_TAG1D_MASK; + if (sta) { + int ampdu_queue = sta->tid_to_tx_q[tid]; + if ((ampdu_queue < local->hw.queues) && + test_bit(ampdu_queue, &q->qdisc_pool)) { + queue = ampdu_queue; + pkt_data->flags |= IEEE80211_TXPD_AMPDU; + } else { + pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; + } + sta_info_put(sta); + } + skb_queue_tail(&q->requeued[queue], skb); qd->q.qlen++; return 0; } @@ -159,14 +177,28 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) */ if (WLAN_FC_IS_QOS_DATA(fc)) { u8 *p = skb->data + ieee80211_get_hdrlen(fc) - 2; - u8 qos_hdr = skb->priority & QOS_CONTROL_TAG1D_MASK; + u8 ack_policy = 0; + tid = skb->priority & QOS_CONTROL_TAG1D_MASK; if (local->wifi_wme_noack_test) - qos_hdr |= QOS_CONTROL_ACK_POLICY_NOACK << + ack_policy |= QOS_CONTROL_ACK_POLICY_NOACK << QOS_CONTROL_ACK_POLICY_SHIFT; /* qos header is 2 bytes, second reserved */ - *p = qos_hdr; + *p = ack_policy | tid; p++; *p = 0; + + sta = sta_info_get(local, hdr->addr1); + if (sta) { + int ampdu_queue = sta->tid_to_tx_q[tid]; + if ((ampdu_queue < local->hw.queues) && + test_bit(ampdu_queue, &q->qdisc_pool)) { + queue = ampdu_queue; + pkt_data->flags |= IEEE80211_TXPD_AMPDU; + } else { + pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; + } + sta_info_put(sta); + } } if (unlikely(queue >= local->hw.queues)) { @@ -184,6 +216,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) kfree_skb(skb); err = NET_XMIT_DROP; } else { + tid = skb->priority & QOS_CONTROL_TAG1D_MASK; pkt_data->queue = (unsigned int) queue; qdisc = q->queues[queue]; err = qdisc->enqueue(skb, qdisc); @@ -235,10 +268,11 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd) /* check all the h/w queues in numeric/priority order */ for (queue = 0; queue < hw->queues; queue++) { /* see if there is room in this hardware queue */ - if (test_bit(IEEE80211_LINK_STATE_XOFF, - &local->state[queue]) || - test_bit(IEEE80211_LINK_STATE_PENDING, - &local->state[queue])) + if ((test_bit(IEEE80211_LINK_STATE_XOFF, + &local->state[queue])) || + (test_bit(IEEE80211_LINK_STATE_PENDING, + &local->state[queue])) || + (!test_bit(queue, &q->qdisc_pool))) continue; /* there is space - try and get a frame */ @@ -360,6 +394,10 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) } } + /* reserve all legacy QoS queues */ + for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++) + set_bit(i, &q->qdisc_pool); + return err; } @@ -605,3 +643,80 @@ void ieee80211_wme_unregister(void) { unregister_qdisc(&wme_qdisc_ops); } + +int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, + struct sta_info *sta, u16 tid) +{ + int i; + struct ieee80211_sched_data *q = + qdisc_priv(local->mdev->qdisc_sleeping); + DECLARE_MAC_BUF(mac); + + /* prepare the filter and save it for the SW queue + * matching the recieved HW queue */ + + /* try to get a Qdisc from the pool */ + for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++) + if (!test_and_set_bit(i, &q->qdisc_pool)) { + ieee80211_stop_queue(local_to_hw(local), i); + sta->tid_to_tx_q[tid] = i; + + /* IF there are already pending packets + * on this tid first we need to drain them + * on the previous queue + * since HT is strict in order */ +#ifdef CONFIG_MAC80211_HT_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "allocated aggregation queue" + " %d tid %d addr %s pool=0x%lX\n", + i, tid, print_mac(mac, sta->addr), + q->qdisc_pool); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + return 0; + } + + return -EAGAIN; +} + +/** + * the caller needs to hold local->mdev->queue_lock + */ +void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, + struct sta_info *sta, u16 tid, + u8 requeue) +{ + struct ieee80211_sched_data *q = + qdisc_priv(local->mdev->qdisc_sleeping); + int agg_queue = sta->tid_to_tx_q[tid]; + + /* return the qdisc to the pool */ + clear_bit(agg_queue, &q->qdisc_pool); + sta->tid_to_tx_q[tid] = local->hw.queues; + + if (requeue) + ieee80211_requeue(local, agg_queue); + else + q->queues[agg_queue]->ops->reset(q->queues[agg_queue]); +} + +void ieee80211_requeue(struct ieee80211_local *local, int queue) +{ + struct Qdisc *root_qd = local->mdev->qdisc_sleeping; + struct ieee80211_sched_data *q = qdisc_priv(root_qd); + struct Qdisc *qdisc = q->queues[queue]; + struct sk_buff *skb = NULL; + u32 len = qdisc->q.qlen; + + if (!qdisc || !qdisc->dequeue) + return; + + printk(KERN_DEBUG "requeue: qlen = %d\n", qdisc->q.qlen); + for (len = qdisc->q.qlen; len > 0; len--) { + skb = qdisc->dequeue(qdisc); + root_qd->q.qlen--; + /* packet will be classified again and */ + /* skb->packet_data->queue will be overridden if needed */ + if (skb) + wme_qdiscop_enqueue(skb, root_qd); + } +} diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index 76c713a6450c..fcc6b05508cc 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -24,6 +24,8 @@ #define QOS_CONTROL_TAG1D_MASK 0x07 +extern const int ieee802_1d_to_ac[8]; + static inline int WLAN_FC_IS_QOS_DATA(u16 fc) { return (fc & 0x8C) == 0x88; @@ -32,7 +34,12 @@ static inline int WLAN_FC_IS_QOS_DATA(u16 fc) #ifdef CONFIG_NET_SCHED void ieee80211_install_qdisc(struct net_device *dev); int ieee80211_qdisc_installed(struct net_device *dev); - +int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, + struct sta_info *sta, u16 tid); +void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, + struct sta_info *sta, u16 tid, + u8 requeue); +void ieee80211_requeue(struct ieee80211_local *local, int queue); int ieee80211_wme_register(void); void ieee80211_wme_unregister(void); #else @@ -43,7 +50,19 @@ static inline int ieee80211_qdisc_installed(struct net_device *dev) { return 0; } - +static inline int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, + struct sta_info *sta, u16 tid) +{ + return -EAGAIN; +} +static inline void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, + struct sta_info *sta, u16 tid, + u8 requeue) +{ +} +static inline void ieee80211_requeue(struct ieee80211_local *local, int queue) +{ +} static inline int ieee80211_wme_register(void) { return 0; -- cgit v1.2.3-59-g8ed1b From fe3bf0f59e97193f8619707f5d9458ce71a4f8d8 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 28 Jan 2008 14:07:19 +0200 Subject: mac80211: A-MPDU Tx MLME data initialization This patch initialize A-MPDU MLME data for Tx sessions. Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 1f74bd296357..ddc1f47194dd 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -117,8 +117,10 @@ static void sta_info_release(struct kref *kref) while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { dev_kfree_skb_any(skb); } - for (i = 0; i < STA_TID_NUM; i++) + for (i = 0; i < STA_TID_NUM; i++) { del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); + del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); + } rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); rate_control_put(sta->rate_ctrl); kfree(sta); @@ -157,17 +159,26 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, sta->local = local; sta->dev = dev; spin_lock_init(&sta->ampdu_mlme.ampdu_rx); + spin_lock_init(&sta->ampdu_mlme.ampdu_tx); for (i = 0; i < STA_TID_NUM; i++) { /* timer_to_tid must be initialized with identity mapping to * enable session_timer's data differentiation. refer to * sta_rx_agg_session_timer_expired for useage */ sta->timer_to_tid[i] = i; + /* tid to tx queue: initialize according to HW (0 is valid) */ + sta->tid_to_tx_q[i] = local->hw.queues; /* rx timers */ sta->ampdu_mlme.tid_rx[i].session_timer.function = sta_rx_agg_session_timer_expired; sta->ampdu_mlme.tid_rx[i].session_timer.data = (unsigned long)&sta->timer_to_tid[i]; init_timer(&sta->ampdu_mlme.tid_rx[i].session_timer); + /* tx timers */ + sta->ampdu_mlme.tid_tx[i].addba_resp_timer.function = + sta_addba_resp_timer_expired; + sta->ampdu_mlme.tid_tx[i].addba_resp_timer.data = + (unsigned long)&sta->timer_to_tid[i]; + init_timer(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); } skb_queue_head_init(&sta->ps_tx_buf); skb_queue_head_init(&sta->tx_filtered); -- cgit v1.2.3-59-g8ed1b From eb2ba62ee547b5ae7ca0339c75cd697f96060ca2 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 28 Jan 2008 14:07:20 +0200 Subject: mac80211: A-MPDU add debugfs support This patch adds A-MPDU status report per STA to the debugfs. The option to de/activate A-MPDU through debugfs is also present. Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- net/mac80211/debugfs_sta.c | 116 +++++++++++++++++++++++++++++++++++++++++++++ net/mac80211/sta_info.h | 1 + 2 files changed, 117 insertions(+) (limited to 'net') diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 8f5944c53d4e..df25abf63137 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -55,6 +55,13 @@ static const struct file_operations sta_ ##name## _ops = { \ .open = mac80211_open_file_generic, \ } +#define STA_OPS_WR(name) \ +static const struct file_operations sta_ ##name## _ops = { \ + .read = sta_##name##_read, \ + .write = sta_##name##_write, \ + .open = mac80211_open_file_generic, \ +} + #define STA_FILE(name, field, format) \ STA_READ_##format(name, field) \ STA_OPS(name) @@ -191,6 +198,113 @@ static ssize_t sta_wme_tx_queue_read(struct file *file, char __user *userbuf, STA_OPS(wme_tx_queue); #endif +static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + char buf[768], *p = buf; + int i; + struct sta_info *sta = file->private_data; + p += scnprintf(p, sizeof(buf)+buf-p, "Agg state for STA is:\n"); + p += scnprintf(p, sizeof(buf)+buf-p, " STA next dialog_token is %d \n " + "TIDs info is: \n TID :", + (sta->ampdu_mlme.dialog_token_allocator + 1)); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", i); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n RX :"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_rx[i].state); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_rx[i].dialog_token); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n TX :"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_tx[i].state); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_tx[i].dialog_token); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :"); + for (i = 0; i < STA_TID_NUM; i++) + p += scnprintf(p, sizeof(buf)+buf-p, "%5d", + sta->ampdu_mlme.tid_tx[i].ssn); + + p += scnprintf(p, sizeof(buf)+buf-p, "\n"); + + return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); +} + +static ssize_t sta_agg_status_write(struct file *file, + const char __user *user_buf, size_t count, loff_t *ppos) +{ + struct sta_info *sta = file->private_data; + struct net_device *dev = sta->dev; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = &local->hw; + u8 *da = sta->addr; + static int tid_static_tx[16] = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0}; + static int tid_static_rx[16] = {1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1}; + char *endp; + char buf[32]; + int buf_size, rs; + unsigned int tid_num; + char state[4]; + + memset(buf, 0x00, sizeof(buf)); + buf_size = min(count, (sizeof(buf)-1)); + if (copy_from_user(buf, user_buf, buf_size)) + return -EFAULT; + + tid_num = simple_strtoul(buf, &endp, 0); + if (endp == buf) + return -EINVAL; + + if ((tid_num >= 100) && (tid_num <= 115)) { + /* toggle Rx aggregation command */ + tid_num = tid_num - 100; + if (tid_static_rx[tid_num] == 1) { + strcpy(state, "off "); + ieee80211_sta_stop_rx_ba_session(dev, da, tid_num, 0, + WLAN_REASON_QSTA_REQUIRE_SETUP); + sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0xFF; + tid_static_rx[tid_num] = 0; + } else { + strcpy(state, "on "); + sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0x00; + tid_static_rx[tid_num] = 1; + } + printk(KERN_DEBUG "debugfs - try switching tid %u %s\n", + tid_num, state); + } else if ((tid_num >= 0) && (tid_num <= 15)) { + /* toggle Tx aggregation command */ + if (tid_static_tx[tid_num] == 0) { + strcpy(state, "on "); + rs = ieee80211_start_tx_ba_session(hw, da, tid_num); + if (rs == 0) + tid_static_tx[tid_num] = 1; + } else { + strcpy(state, "off"); + rs = ieee80211_stop_tx_ba_session(hw, da, tid_num, 1); + if (rs == 0) + tid_static_tx[tid_num] = 0; + } + printk(KERN_DEBUG "debugfs - switching tid %u %s, return=%d\n", + tid_num, state, rs); + } + + return count; +} +STA_OPS_WR(agg_status); + #define DEBUGFS_ADD(name) \ sta->debugfs.name = debugfs_create_file(#name, 0444, \ sta->debugfs.dir, sta, &sta_ ##name## _ops); @@ -224,6 +338,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(wme_rx_queue); DEBUGFS_ADD(wme_tx_queue); #endif + DEBUGFS_ADD(agg_status); } void ieee80211_sta_debugfs_remove(struct sta_info *sta) @@ -238,6 +353,7 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta) DEBUGFS_DEL(wme_rx_queue); DEBUGFS_DEL(wme_tx_queue); #endif + DEBUGFS_DEL(agg_status); debugfs_remove(sta->debugfs.dir); sta->debugfs.dir = NULL; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 48a620a4e1a6..75573dc79d7a 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -192,6 +192,7 @@ struct sta_info { struct dentry *wme_rx_queue; struct dentry *wme_tx_queue; #endif + struct dentry *agg_status; } debugfs; #endif }; -- cgit v1.2.3-59-g8ed1b From d92684e66091c0f0101819619b315b4bb8b5bcc5 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 28 Jan 2008 14:07:22 +0200 Subject: mac80211: A-MPDU Tx add delBA from recipient support This patch adds the ability to handle delBA from recipient to initiator during an A-MPDU session Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index c4d57346eacf..d0273ccbdbae 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1403,14 +1403,23 @@ static void ieee80211_sta_process_delba(struct net_device *dev, #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) - printk(KERN_DEBUG "delba from %s on tid %d reason code %d\n", - print_mac(mac, mgmt->sa), tid, + printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n", + print_mac(mac, mgmt->sa), + initiator ? "recipient" : "initiator", tid, mgmt->u.action.u.delba.reason_code); #endif /* CONFIG_MAC80211_HT_DEBUG */ if (initiator == WLAN_BACK_INITIATOR) ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid, WLAN_BACK_INITIATOR, 0); + else { /* WLAN_BACK_RECIPIENT */ + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + sta->ampdu_mlme.tid_tx[tid].state = + HT_AGG_STATE_OPERATIONAL; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, + WLAN_BACK_RECIPIENT); + } sta_info_put(sta); } -- cgit v1.2.3-59-g8ed1b From 38f3714d66b5679aee2a4fe23b1235c3829fcce4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 29 Jan 2008 17:07:43 +0100 Subject: mac80211: dissolve pre-rx handlers These handlers do not really return a status and the compiler can do a much better job when they're simply static functions that it can inline if appropriate. Also makes the code shorter. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 1 - net/mac80211/ieee80211_i.h | 2 - net/mac80211/rx.c | 96 ++++++++++++++++++---------------------------- 3 files changed, 37 insertions(+), 62 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index f8e734f0da1a..3961d4c4320c 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -1407,7 +1407,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.queues = 1; /* default */ local->mdev = mdev; - local->rx_pre_handlers = ieee80211_rx_pre_handlers; local->rx_handlers = ieee80211_rx_handlers; local->tx_handlers = ieee80211_tx_handlers; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index cfd0717c0033..9d09ba8cc02b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -480,7 +480,6 @@ struct ieee80211_local { * deliver multicast frames both back to wireless * media and to the local net stack */ - ieee80211_rx_handler *rx_pre_handlers; ieee80211_rx_handler *rx_handlers; ieee80211_tx_handler *tx_handlers; @@ -816,7 +815,6 @@ void ieee80211_regdomain_init(void); void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode); /* rx handling */ -extern ieee80211_rx_handler ieee80211_rx_pre_handlers[]; extern ieee80211_rx_handler ieee80211_rx_handlers[]; /* tx handling */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 535407d07fa4..3aae8e9e4e0a 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -249,15 +249,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, } -/* pre-rx handlers - * - * these don't have dev/sdata fields in the rx data - * The sta value should also not be used because it may - * be NULL even though a STA (in IBSS mode) will be added. - */ - -static ieee80211_txrx_result -ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx) +static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx) { u8 *data = rx->skb->data; int tid; @@ -290,8 +282,40 @@ ieee80211_rx_h_parse_qos(struct ieee80211_txrx_data *rx) /* Set skb->priority to 1d tag if highest order bit of TID is not set. * For now, set skb->priority to 0 for other cases. */ rx->skb->priority = (tid > 7) ? 0 : tid; +} - return TXRX_CONTINUE; +static void ieee80211_verify_ip_alignment(struct ieee80211_txrx_data *rx) +{ +#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT + int hdrlen; + + if (!WLAN_FC_DATA_PRESENT(rx->fc)) + return; + + /* + * Drivers are required to align the payload data in a way that + * guarantees that the contained IP header is aligned to a four- + * byte boundary. In the case of regular frames, this simply means + * aligning the payload to a four-byte boundary (because either + * the IP header is directly contained, or IV/RFC1042 headers that + * have a length divisible by four are in front of it. + * + * With A-MSDU frames, however, the payload data address must + * yield two modulo four because there are 14-byte 802.3 headers + * within the A-MSDU frames that push the IP header further back + * to a multiple of four again. Thankfully, the specs were sane + * enough this time around to require padding each A-MSDU subframe + * to a length that is a multiple of four. + * + * Padding like atheros hardware adds which is inbetween the 802.11 + * header and the payload is not supported, the driver is required + * to move the 802.11 header further back in that case. + */ + hdrlen = ieee80211_get_hdrlen(rx->fc); + if (rx->flags & IEEE80211_TXRXD_RX_AMSDU) + hdrlen += ETH_HLEN; + WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3); +#endif } @@ -340,52 +364,6 @@ static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, return load; } -#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT -static ieee80211_txrx_result -ieee80211_rx_h_verify_ip_alignment(struct ieee80211_txrx_data *rx) -{ - int hdrlen; - - if (!WLAN_FC_DATA_PRESENT(rx->fc)) - return TXRX_CONTINUE; - - /* - * Drivers are required to align the payload data in a way that - * guarantees that the contained IP header is aligned to a four- - * byte boundary. In the case of regular frames, this simply means - * aligning the payload to a four-byte boundary (because either - * the IP header is directly contained, or IV/RFC1042 headers that - * have a length divisible by four are in front of it. - * - * With A-MSDU frames, however, the payload data address must - * yield two modulo four because there are 14-byte 802.3 headers - * within the A-MSDU frames that push the IP header further back - * to a multiple of four again. Thankfully, the specs were sane - * enough this time around to require padding each A-MSDU subframe - * to a length that is a multiple of four. - * - * Padding like atheros hardware adds which is inbetween the 802.11 - * header and the payload is not supported, the driver is required - * to move the 802.11 header further back in that case. - */ - hdrlen = ieee80211_get_hdrlen(rx->fc); - if (rx->flags & IEEE80211_TXRXD_RX_AMSDU) - hdrlen += ETH_HLEN; - WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3); - - return TXRX_CONTINUE; -} -#endif - -ieee80211_rx_handler ieee80211_rx_pre_handlers[] = -{ - ieee80211_rx_h_parse_qos, -#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT - ieee80211_rx_h_verify_ip_alignment, -#endif - NULL -}; - /* rx handlers */ static ieee80211_txrx_result @@ -1747,9 +1725,9 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning)) rx.flags |= IEEE80211_TXRXD_RXIN_SCAN; - if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx, - sta) != TXRX_CONTINUE) - goto end; + ieee80211_parse_qos(&rx); + ieee80211_verify_ip_alignment(&rx); + skb = rx.skb; if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) && -- cgit v1.2.3-59-g8ed1b From 8318d78a44d49ac1edf2bdec7299de3617c4232e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 24 Jan 2008 19:38:38 +0100 Subject: cfg80211 API for channels/bitrates, mac80211 and driver conversion This patch creates new cfg80211 wiphy API for channel and bitrate registration and converts mac80211 and drivers to the new API. The old mac80211 API is completely ripped out. All drivers (except ath5k) are updated to the new API, in many cases I expect that optimisations can be done. Along with the regulatory code I've also ripped out the IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED flag, I believe it to be unnecessary if the hardware simply gives us whatever channels it wants to support and we then enable/disable them as required, which is pretty much required for travelling. Additionally, the patch adds proper "basic" rate handling for STA mode interface, AP mode interface will have to have new API added to allow userspace to set the basic rate set, currently it'll be empty... However, the basic rate handling will need to be moved to the BSS conf stuff. I do expect there to be bugs in this, especially wrt. transmit power handling where I'm basically clueless about how it should work. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 1 + drivers/net/wireless/adm8211.c | 80 ++--- drivers/net/wireless/adm8211.h | 65 +--- drivers/net/wireless/b43/b43.h | 5 - drivers/net/wireless/b43/main.c | 119 +++---- drivers/net/wireless/b43/sysfs.c | 89 +----- drivers/net/wireless/b43/xmit.c | 81 ++--- drivers/net/wireless/b43legacy/b43legacy.h | 4 - drivers/net/wireless/b43legacy/main.c | 159 +++++----- drivers/net/wireless/b43legacy/xmit.c | 64 ++-- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 88 +++--- drivers/net/wireless/iwlwifi/iwl-3945.c | 35 +-- drivers/net/wireless/iwlwifi/iwl-3945.h | 13 +- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 82 ++--- drivers/net/wireless/iwlwifi/iwl-4965.c | 43 ++- drivers/net/wireless/iwlwifi/iwl-4965.h | 16 +- drivers/net/wireless/iwlwifi/iwl3945-base.c | 445 ++++++++------------------- drivers/net/wireless/iwlwifi/iwl4965-base.c | 438 +++++++------------------- drivers/net/wireless/p54.h | 4 - drivers/net/wireless/p54common.c | 74 +++-- drivers/net/wireless/p54common.h | 75 ----- drivers/net/wireless/rt2x00/rt2x00.h | 11 +- drivers/net/wireless/rt2x00/rt2x00config.c | 33 +- drivers/net/wireless/rt2x00/rt2x00dev.c | 149 ++++----- drivers/net/wireless/rt2x00/rt61pci.c | 23 +- drivers/net/wireless/rt2x00/rt73usb.c | 23 +- drivers/net/wireless/rtl8180.h | 2 +- drivers/net/wireless/rtl8180_dev.c | 93 ++++-- drivers/net/wireless/rtl8180_grf5101.c | 5 +- drivers/net/wireless/rtl8180_max2820.c | 5 +- drivers/net/wireless/rtl8180_rtl8225.c | 15 +- drivers/net/wireless/rtl8180_sa2400.c | 5 +- drivers/net/wireless/rtl8187.h | 2 +- drivers/net/wireless/rtl8187_dev.c | 82 +++-- drivers/net/wireless/rtl8187_rtl8225.c | 15 +- drivers/net/wireless/rtl818x.h | 70 ----- drivers/net/wireless/zd1211rw/zd_chip.c | 15 +- drivers/net/wireless/zd1211rw/zd_ieee80211.c | 11 +- drivers/net/wireless/zd1211rw/zd_mac.c | 170 +++++----- drivers/net/wireless/zd1211rw/zd_mac.h | 2 +- include/net/mac80211.h | 197 ++---------- include/net/wireless.h | 168 ++++++++++ net/mac80211/Makefile | 1 - net/mac80211/cfg.c | 11 +- net/mac80211/debugfs.c | 47 +-- net/mac80211/debugfs_sta.c | 18 -- net/mac80211/ieee80211.c | 112 +++---- net/mac80211/ieee80211_i.h | 63 +--- net/mac80211/ieee80211_iface.c | 2 + net/mac80211/ieee80211_ioctl.c | 127 ++++---- net/mac80211/ieee80211_rate.c | 15 +- net/mac80211/ieee80211_rate.h | 28 +- net/mac80211/ieee80211_sta.c | 384 ++++++++++++----------- net/mac80211/rc80211_pid_algo.c | 76 ++--- net/mac80211/rc80211_simple.c | 66 ++-- net/mac80211/regdomain.c | 152 --------- net/mac80211/rx.c | 82 ++--- net/mac80211/sta_info.c | 24 -- net/mac80211/sta_info.h | 10 +- net/mac80211/tx.c | 164 ++++++---- net/mac80211/util.c | 142 ++------- net/wireless/Makefile | 2 +- net/wireless/core.c | 41 +++ net/wireless/core.h | 3 + net/wireless/reg.c | 153 +++++++++ net/wireless/util.c | 98 ++++++ 66 files changed, 2116 insertions(+), 2781 deletions(-) delete mode 100644 net/mac80211/regdomain.c create mode 100644 net/wireless/reg.c create mode 100644 net/wireless/util.c (limited to 'net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 714a6ca30ad2..cd5fcc67e954 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -735,6 +735,7 @@ config P54_PCI config ATH5K tristate "Atheros 5xxx wireless cards support" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + depends on BROKEN ---help--- This module adds support for wireless adapters based on Atheros 5xxx chipset. diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 79796186713e..7d4218206c47 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -48,6 +48,32 @@ static struct pci_device_id adm8211_pci_id_table[] __devinitdata = { { 0 } }; +static struct ieee80211_rate adm8211_rates[] = { + { .bitrate = 10, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 20, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 220, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, /* XX ?? */ +}; + +static const struct ieee80211_channel adm8211_channels[] = { + { .center_freq = 2412}, + { .center_freq = 2417}, + { .center_freq = 2422}, + { .center_freq = 2427}, + { .center_freq = 2432}, + { .center_freq = 2437}, + { .center_freq = 2442}, + { .center_freq = 2447}, + { .center_freq = 2452}, + { .center_freq = 2457}, + { .center_freq = 2462}, + { .center_freq = 2467}, + { .center_freq = 2472}, + { .center_freq = 2484}, +}; + + static void adm8211_eeprom_register_read(struct eeprom_93cx6 *eeprom) { struct adm8211_priv *priv = eeprom->data; @@ -155,17 +181,17 @@ static int adm8211_read_eeprom(struct ieee80211_hw *dev) printk(KERN_DEBUG "%s (adm8211): Channel range: %d - %d\n", pci_name(priv->pdev), (int)chan_range.min, (int)chan_range.max); - priv->modes[0].num_channels = chan_range.max - chan_range.min + 1; - priv->modes[0].channels = priv->channels; + BUILD_BUG_ON(sizeof(priv->channels) != sizeof(adm8211_channels)); - memcpy(priv->channels, adm8211_channels, sizeof(adm8211_channels)); + memcpy(priv->channels, adm8211_channels, sizeof(priv->channels)); + priv->band.channels = priv->channels; + priv->band.n_channels = ARRAY_SIZE(adm8211_channels); + priv->band.bitrates = adm8211_rates; + priv->band.n_bitrates = ARRAY_SIZE(adm8211_rates); for (i = 1; i <= ARRAY_SIZE(adm8211_channels); i++) - if (i >= chan_range.min && i <= chan_range.max) - priv->channels[i - 1].flag = - IEEE80211_CHAN_W_SCAN | - IEEE80211_CHAN_W_ACTIVE_SCAN | - IEEE80211_CHAN_W_IBSS; + if (i < chan_range.min || i > chan_range.max) + priv->channels[i - 1].flags |= IEEE80211_CHAN_DISABLED; switch (priv->eeprom->specific_bbptype) { case ADM8211_BBP_RFMD3000: @@ -347,7 +373,6 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev) unsigned int pktlen; struct sk_buff *skb, *newskb; unsigned int limit = priv->rx_ring_size; - static const u8 rate_tbl[] = {10, 20, 55, 110, 220}; u8 rssi, rate; while (!(priv->rx_ring[entry].status & cpu_to_le32(RDES0_STATUS_OWN))) { @@ -425,12 +450,10 @@ static void adm8211_interrupt_rci(struct ieee80211_hw *dev) else rx_status.ssi = 100 - rssi; - if (rate <= 4) - rx_status.rate = rate_tbl[rate]; + rx_status.rate_idx = rate; - rx_status.channel = priv->channel; - rx_status.freq = adm8211_channels[priv->channel - 1].freq; - rx_status.phymode = MODE_IEEE80211B; + rx_status.freq = adm8211_channels[priv->channel - 1].center_freq; + rx_status.band = IEEE80211_BAND_2GHZ; ieee80211_rx_irqsafe(dev, skb, &rx_status); } @@ -1054,7 +1077,7 @@ static int adm8211_set_rate(struct ieee80211_hw *dev) if (priv->pdev->revision != ADM8211_REV_BA) { rate_buf[0] = ARRAY_SIZE(adm8211_rates); for (i = 0; i < ARRAY_SIZE(adm8211_rates); i++) - rate_buf[i + 1] = (adm8211_rates[i].rate / 5) | 0x80; + rate_buf[i + 1] = (adm8211_rates[i].bitrate / 5) | 0x80; } else { /* workaround for rev BA specific bug */ rate_buf[0] = 0x04; @@ -1303,9 +1326,10 @@ static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len) static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct adm8211_priv *priv = dev->priv; + int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); - if (conf->channel != priv->channel) { - priv->channel = conf->channel; + if (channel != priv->channel) { + priv->channel = channel; adm8211_rf_set_channel(dev, priv->channel); } @@ -1680,10 +1704,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb, if (control->tx_rate < 0) { short_preamble = 1; - plcp_signal = -control->tx_rate; + plcp_signal = -control->tx_rate->bitrate; } else { short_preamble = 0; - plcp_signal = control->tx_rate; + plcp_signal = control->tx_rate->bitrate; } hdr = (struct ieee80211_hdr *)skb->data; @@ -1880,18 +1904,11 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, SET_IEEE80211_PERM_ADDR(dev, perm_addr); dev->extra_tx_headroom = sizeof(struct adm8211_tx_hdr); - dev->flags = IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED; - /* IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */ + /* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS in promisc mode */ dev->channel_change_time = 1000; dev->max_rssi = 100; /* FIXME: find better value */ - priv->modes[0].mode = MODE_IEEE80211B; - /* channel info filled in by adm8211_read_eeprom */ - memcpy(priv->rates, adm8211_rates, sizeof(adm8211_rates)); - priv->modes[0].num_rates = ARRAY_SIZE(adm8211_rates); - priv->modes[0].rates = priv->rates; - dev->queues = 1; /* ADM8211C supports more, maybe ADM8211B too */ priv->retry_limit = 3; @@ -1917,14 +1934,7 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, goto err_free_desc; } - priv->channel = priv->modes[0].channels[0].chan; - - err = ieee80211_register_hwmode(dev, &priv->modes[0]); - if (err) { - printk(KERN_ERR "%s (adm8211): Can't register hwmode\n", - pci_name(pdev)); - goto err_free_desc; - } + priv->channel = 1; err = ieee80211_register_hw(dev); if (err) { diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h index ef326fed42e4..8d7c564b3b04 100644 --- a/drivers/net/wireless/adm8211.h +++ b/drivers/net/wireless/adm8211.h @@ -534,61 +534,6 @@ struct adm8211_eeprom { u8 cis_data[0]; /* 0x80, 384 bytes */ } __attribute__ ((packed)); -static const struct ieee80211_rate adm8211_rates[] = { - { .rate = 10, - .val = 10, - .val2 = -10, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 20, - .val = 20, - .val2 = -20, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 55, - .val = 55, - .val2 = -55, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 110, - .val = 110, - .val2 = -110, - .flags = IEEE80211_RATE_CCK_2 } -}; - -struct ieee80211_chan_range { - u8 min; - u8 max; -}; - -static const struct ieee80211_channel adm8211_channels[] = { - { .chan = 1, - .freq = 2412}, - { .chan = 2, - .freq = 2417}, - { .chan = 3, - .freq = 2422}, - { .chan = 4, - .freq = 2427}, - { .chan = 5, - .freq = 2432}, - { .chan = 6, - .freq = 2437}, - { .chan = 7, - .freq = 2442}, - { .chan = 8, - .freq = 2447}, - { .chan = 9, - .freq = 2452}, - { .chan = 10, - .freq = 2457}, - { .chan = 11, - .freq = 2462}, - { .chan = 12, - .freq = 2467}, - { .chan = 13, - .freq = 2472}, - { .chan = 14, - .freq = 2484}, -}; - struct adm8211_priv { struct pci_dev *pdev; spinlock_t lock; @@ -603,9 +548,8 @@ struct adm8211_priv { unsigned int cur_tx, dirty_tx, cur_rx; struct ieee80211_low_level_stats stats; - struct ieee80211_hw_mode modes[1]; - struct ieee80211_channel channels[ARRAY_SIZE(adm8211_channels)]; - struct ieee80211_rate rates[ARRAY_SIZE(adm8211_rates)]; + struct ieee80211_supported_band band; + struct ieee80211_channel channels[14]; int mode; int channel; @@ -643,6 +587,11 @@ struct adm8211_priv { } transceiver_type; }; +struct ieee80211_chan_range { + u8 min; + u8 max; +}; + static const struct ieee80211_chan_range cranges[] = { {1, 11}, /* FCC */ {1, 11}, /* IC */ diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index f13346ba9dd2..3e40323cd43f 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -468,10 +468,6 @@ struct b43_phy { u8 possible_phymodes; /* GMODE bit enabled? */ bool gmode; - /* Possible ieee80211 subsystem hwmodes for this PHY. - * Which mode is selected, depends on thr GMODE enabled bit */ -#define B43_MAX_PHYHWMODES 2 - struct ieee80211_hw_mode hwmodes[B43_MAX_PHYHWMODES]; /* Analog Type */ u8 analog; @@ -727,7 +723,6 @@ struct b43_wldev { bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */ bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ - bool short_preamble; /* TRUE, if short preamble is enabled. */ bool short_slot; /* TRUE, if short slot timing is enabled. */ bool radio_hw_enable; /* saved state of radio hardware enabled state */ bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */ diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 51dfce16178a..017a041d07d0 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -96,25 +96,29 @@ MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl); * data in there. This data is the same for all devices, so we don't * get concurrency issues */ #define RATETAB_ENT(_rateid, _flags) \ - { \ - .rate = B43_RATE_TO_BASE100KBPS(_rateid), \ - .val = (_rateid), \ - .val2 = (_rateid), \ - .flags = (_flags), \ + { \ + .bitrate = B43_RATE_TO_BASE100KBPS(_rateid), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ } + +/* + * NOTE: When changing this, sync with xmit.c's + * b43_plcp_get_bitrate_idx_* functions! + */ static struct ieee80211_rate __b43_ratetable[] = { - RATETAB_ENT(B43_CCK_RATE_1MB, IEEE80211_RATE_CCK), - RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43_OFDM_RATE_6MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_9MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_12MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_18MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_24MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_36MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_48MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43_OFDM_RATE_54MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43_CCK_RATE_1MB, 0), + RATETAB_ENT(B43_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43_OFDM_RATE_6MB, 0), + RATETAB_ENT(B43_OFDM_RATE_9MB, 0), + RATETAB_ENT(B43_OFDM_RATE_12MB, 0), + RATETAB_ENT(B43_OFDM_RATE_18MB, 0), + RATETAB_ENT(B43_OFDM_RATE_24MB, 0), + RATETAB_ENT(B43_OFDM_RATE_36MB, 0), + RATETAB_ENT(B43_OFDM_RATE_48MB, 0), + RATETAB_ENT(B43_OFDM_RATE_54MB, 0), }; #define b43_a_ratetable (__b43_ratetable + 4) @@ -126,14 +130,8 @@ static struct ieee80211_rate __b43_ratetable[] = { #define CHANTAB_ENT(_chanid, _freq) \ { \ - .chan = (_chanid), \ - .freq = (_freq), \ - .val = (_chanid), \ - .flag = IEEE80211_CHAN_W_SCAN | \ - IEEE80211_CHAN_W_ACTIVE_SCAN | \ - IEEE80211_CHAN_W_IBSS, \ - .power_level = 0xFF, \ - .antenna_max = 0xFF, \ + .center_freq = (_freq), \ + .hw_value = (_chanid), \ } static struct ieee80211_channel b43_2ghz_chantable[] = { CHANTAB_ENT(1, 2412), @@ -151,9 +149,8 @@ static struct ieee80211_channel b43_2ghz_chantable[] = { CHANTAB_ENT(13, 2472), CHANTAB_ENT(14, 2484), }; -#define b43_2ghz_chantable_size ARRAY_SIZE(b43_2ghz_chantable) -#if 0 +#ifdef NOTYET static struct ieee80211_channel b43_5ghz_chantable[] = { CHANTAB_ENT(36, 5180), CHANTAB_ENT(40, 5200), @@ -169,9 +166,22 @@ static struct ieee80211_channel b43_5ghz_chantable[] = { CHANTAB_ENT(161, 5805), CHANTAB_ENT(165, 5825), }; -#define b43_5ghz_chantable_size ARRAY_SIZE(b43_5ghz_chantable) + +static struct ieee80211_supported_band b43_band_5GHz = { + .channels = b43_5ghz_chantable, + .n_channels = ARRAY_SIZE(b43_5ghz_chantable), + .bitrates = b43_a_ratetable, + .n_bitrates = b43_a_ratetable_size, +}; #endif +static struct ieee80211_supported_band b43_band_2GHz = { + .channels = b43_2ghz_chantable, + .n_channels = ARRAY_SIZE(b43_2ghz_chantable), + .bitrates = b43_g_ratetable, + .n_bitrates = b43_g_ratetable_size, +}; + static void b43_wireless_core_exit(struct b43_wldev *dev); static int b43_wireless_core_init(struct b43_wldev *dev); static void b43_wireless_core_stop(struct b43_wldev *dev); @@ -1222,17 +1232,18 @@ static void b43_write_beacon_template(struct b43_wldev *dev, } static void b43_write_probe_resp_plcp(struct b43_wldev *dev, - u16 shm_offset, u16 size, u8 rate) + u16 shm_offset, u16 size, + struct ieee80211_rate *rate) { struct b43_plcp_hdr4 plcp; u32 tmp; __le16 dur; plcp.data = 0; - b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); + b43_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->hw_value); dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->vif, size, - B43_RATE_TO_BASE100KBPS(rate)); + rate); /* Write PLCP in two parts and timing for packet transfer */ tmp = le32_to_cpu(plcp.data); b43_shm_write16(dev, B43_SHM_SHARED, shm_offset, tmp & 0xFFFF); @@ -1247,7 +1258,8 @@ static void b43_write_probe_resp_plcp(struct b43_wldev *dev, * 3) Stripping TIM */ static const u8 * b43_generate_probe_resp(struct b43_wldev *dev, - u16 *dest_size, u8 rate) + u16 *dest_size, + struct ieee80211_rate *rate) { const u8 *src_data; u8 *dest_data; @@ -1292,7 +1304,7 @@ static const u8 * b43_generate_probe_resp(struct b43_wldev *dev, IEEE80211_STYPE_PROBE_RESP); dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->vif, *dest_size, - B43_RATE_TO_BASE100KBPS(rate)); + rate); hdr->duration_id = dur; return dest_data; @@ -1300,7 +1312,8 @@ static const u8 * b43_generate_probe_resp(struct b43_wldev *dev, static void b43_write_probe_resp_template(struct b43_wldev *dev, u16 ram_offset, - u16 shm_size_offset, u8 rate) + u16 shm_size_offset, + struct ieee80211_rate *rate) { const u8 *probe_resp_data; u16 size; @@ -1313,14 +1326,15 @@ static void b43_write_probe_resp_template(struct b43_wldev *dev, /* Looks like PLCP headers plus packet timings are stored for * all possible basic rates */ - b43_write_probe_resp_plcp(dev, 0x31A, size, B43_CCK_RATE_1MB); - b43_write_probe_resp_plcp(dev, 0x32C, size, B43_CCK_RATE_2MB); - b43_write_probe_resp_plcp(dev, 0x33E, size, B43_CCK_RATE_5MB); - b43_write_probe_resp_plcp(dev, 0x350, size, B43_CCK_RATE_11MB); + b43_write_probe_resp_plcp(dev, 0x31A, size, &b43_b_ratetable[0]); + b43_write_probe_resp_plcp(dev, 0x32C, size, &b43_b_ratetable[1]); + b43_write_probe_resp_plcp(dev, 0x33E, size, &b43_b_ratetable[2]); + b43_write_probe_resp_plcp(dev, 0x350, size, &b43_b_ratetable[3]); size = min((size_t) size, 0x200 - sizeof(struct b43_plcp_hdr6)); b43_write_template_common(dev, probe_resp_data, - size, ram_offset, shm_size_offset, rate); + size, ram_offset, shm_size_offset, + rate->hw_value); kfree(probe_resp_data); } @@ -1388,7 +1402,7 @@ static void handle_irq_beacon(struct b43_wldev *dev) b43_write_beacon_template(dev, 0x68, 0x18, B43_CCK_RATE_1MB); b43_write_probe_resp_template(dev, 0x268, 0x4A, - B43_CCK_RATE_11MB); + &__b43_ratetable[3]); wl->beacon0_uploaded = 1; } cmd |= B43_MACCMD_BEACON0_VALID; @@ -2830,14 +2844,11 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) mutex_lock(&wl->mutex); /* Switch the PHY mode (if necessary). */ - switch (conf->phymode) { - case MODE_IEEE80211A: + switch (conf->channel->band) { + case IEEE80211_BAND_5GHZ: new_phymode = B43_PHYMODE_A; break; - case MODE_IEEE80211B: - new_phymode = B43_PHYMODE_B; - break; - case MODE_IEEE80211G: + case IEEE80211_BAND_2GHZ: new_phymode = B43_PHYMODE_G; break; default: @@ -2863,8 +2874,8 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) /* Switch to the requested channel. * The firmware takes care of races with the TX handler. */ - if (conf->channel_val != phy->channel) - b43_radio_selectchannel(dev, conf->channel_val, 0); + if (conf->channel->hw_value != phy->channel) + b43_radio_selectchannel(dev, conf->channel->hw_value, 0); /* Enable/Disable ShortSlot timing. */ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) != @@ -3810,9 +3821,7 @@ static int b43_setup_modes(struct b43_wldev *dev, bool have_2ghz_phy, bool have_5ghz_phy) { struct ieee80211_hw *hw = dev->wl->hw; - struct ieee80211_hw_mode *mode; struct b43_phy *phy = &dev->phy; - int err; /* XXX: This function will go away soon, when mac80211 * band stuff is rewritten. So this is just a hack. @@ -3821,15 +3830,7 @@ static int b43_setup_modes(struct b43_wldev *dev, * This assumption is OK, as any B, N or A PHY will already * have died a horrible sanity check death earlier. */ - mode = &phy->hwmodes[0]; - mode->mode = MODE_IEEE80211G; - mode->num_channels = b43_2ghz_chantable_size; - mode->channels = b43_2ghz_chantable; - mode->num_rates = b43_g_ratetable_size; - mode->rates = b43_g_ratetable; - err = ieee80211_register_hwmode(hw, mode); - if (err) - return err; + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &b43_band_2GHz; phy->possible_phymodes |= B43_PHYMODE_G; return 0; diff --git a/drivers/net/wireless/b43/sysfs.c b/drivers/net/wireless/b43/sysfs.c index f4faff6a7d6c..275095b8cbe7 100644 --- a/drivers/net/wireless/b43/sysfs.c +++ b/drivers/net/wireless/b43/sysfs.c @@ -47,29 +47,6 @@ static int get_integer(const char *buf, size_t count) return ret; } -static int get_boolean(const char *buf, size_t count) -{ - if (count != 0) { - if (buf[0] == '1') - return 1; - if (buf[0] == '0') - return 0; - if (count >= 4 && memcmp(buf, "true", 4) == 0) - return 1; - if (count >= 5 && memcmp(buf, "false", 5) == 0) - return 0; - if (count >= 3 && memcmp(buf, "yes", 3) == 0) - return 1; - if (count >= 2 && memcmp(buf, "no", 2) == 0) - return 0; - if (count >= 2 && memcmp(buf, "on", 2) == 0) - return 1; - if (count >= 3 && memcmp(buf, "off", 3) == 0) - return 0; - } - return -EINVAL; -} - static ssize_t b43_attr_interfmode_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -155,82 +132,18 @@ static ssize_t b43_attr_interfmode_store(struct device *dev, static DEVICE_ATTR(interference, 0644, b43_attr_interfmode_show, b43_attr_interfmode_store); -static ssize_t b43_attr_preamble_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct b43_wldev *wldev = dev_to_b43_wldev(dev); - ssize_t count; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - mutex_lock(&wldev->wl->mutex); - - if (wldev->short_preamble) - count = - snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); - else - count = - snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); - - mutex_unlock(&wldev->wl->mutex); - - return count; -} - -static ssize_t b43_attr_preamble_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct b43_wldev *wldev = dev_to_b43_wldev(dev); - unsigned long flags; - int value; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - value = get_boolean(buf, count); - if (value < 0) - return value; - mutex_lock(&wldev->wl->mutex); - spin_lock_irqsave(&wldev->wl->irq_lock, flags); - - wldev->short_preamble = !!value; - - spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); - mutex_unlock(&wldev->wl->mutex); - - return count; -} - -static DEVICE_ATTR(shortpreamble, 0644, - b43_attr_preamble_show, b43_attr_preamble_store); - int b43_sysfs_register(struct b43_wldev *wldev) { struct device *dev = wldev->dev->dev; - int err; B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED); - err = device_create_file(dev, &dev_attr_interference); - if (err) - goto out; - err = device_create_file(dev, &dev_attr_shortpreamble); - if (err) - goto err_remove_interfmode; - - out: - return err; - err_remove_interfmode: - device_remove_file(dev, &dev_attr_interference); - goto out; + return device_create_file(dev, &dev_attr_interference); } void b43_sysfs_unregister(struct b43_wldev *wldev) { struct device *dev = wldev->dev->dev; - device_remove_file(dev, &dev_attr_shortpreamble); device_remove_file(dev, &dev_attr_interference); } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 7caa26eb4105..4014b6c8272b 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -32,46 +32,48 @@ #include "dma.h" -/* Extract the bitrate out of a CCK PLCP header. */ -static u8 b43_plcp_get_bitrate_cck(struct b43_plcp_hdr6 *plcp) +/* Extract the bitrate index out of a CCK PLCP header. */ +static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp) { switch (plcp->raw[0]) { case 0x0A: - return B43_CCK_RATE_1MB; + return 0; case 0x14: - return B43_CCK_RATE_2MB; + return 1; case 0x37: - return B43_CCK_RATE_5MB; + return 2; case 0x6E: - return B43_CCK_RATE_11MB; + return 3; } B43_WARN_ON(1); - return 0; + return -1; } -/* Extract the bitrate out of an OFDM PLCP header. */ -static u8 b43_plcp_get_bitrate_ofdm(struct b43_plcp_hdr6 *plcp) +/* Extract the bitrate index out of an OFDM PLCP header. */ +static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy) { + int base = aphy ? 0 : 4; + switch (plcp->raw[0] & 0xF) { case 0xB: - return B43_OFDM_RATE_6MB; + return base + 0; case 0xF: - return B43_OFDM_RATE_9MB; + return base + 1; case 0xA: - return B43_OFDM_RATE_12MB; + return base + 2; case 0xE: - return B43_OFDM_RATE_18MB; + return base + 3; case 0x9: - return B43_OFDM_RATE_24MB; + return base + 4; case 0xD: - return B43_OFDM_RATE_36MB; + return base + 5; case 0x8: - return B43_OFDM_RATE_48MB; + return base + 6; case 0xC: - return B43_OFDM_RATE_54MB; + return base + 7; } B43_WARN_ON(1); - return 0; + return -1; } u8 b43_plcp_get_ratecode_cck(const u8 bitrate) @@ -191,6 +193,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, (const struct ieee80211_hdr *)fragment_data; int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); u16 fctl = le16_to_cpu(wlhdr->frame_control); + struct ieee80211_rate *fbrate; u8 rate, rate_fb; int rate_ofdm, rate_fb_ofdm; unsigned int plcp_fragment_len; @@ -200,9 +203,11 @@ int b43_generate_txhdr(struct b43_wldev *dev, memset(txhdr, 0, sizeof(*txhdr)); - rate = txctl->tx_rate; + WARN_ON(!txctl->tx_rate); + rate = txctl->tx_rate ? txctl->tx_rate->hw_value : B43_CCK_RATE_1MB; rate_ofdm = b43_is_ofdm_rate(rate); - rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate; + fbrate = txctl->alt_retry_rate ? : txctl->tx_rate; + rate_fb = fbrate->hw_value; rate_fb_ofdm = b43_is_ofdm_rate(rate_fb); if (rate_ofdm) @@ -221,11 +226,10 @@ int b43_generate_txhdr(struct b43_wldev *dev, * use the original dur_id field. */ txhdr->dur_fb = wlhdr->duration_id; } else { - int fbrate_base100kbps = B43_RATE_TO_BASE100KBPS(rate_fb); txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, txctl->vif, fragment_len, - fbrate_base100kbps); + fbrate); } plcp_fragment_len = fragment_len + FCS_LEN; @@ -287,7 +291,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, phy_ctl |= B43_TXH_PHY_ENC_OFDM; else phy_ctl |= B43_TXH_PHY_ENC_CCK; - if (dev->short_preamble) + if (txctl->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) phy_ctl |= B43_TXH_PHY_SHORTPRMBL; switch (b43_ieee80211_antenna_sanitize(dev, txctl->antenna_sel_tx)) { @@ -332,7 +336,8 @@ int b43_generate_txhdr(struct b43_wldev *dev, int rts_rate_ofdm, rts_rate_fb_ofdm; struct b43_plcp_hdr6 *plcp; - rts_rate = txctl->rts_cts_rate; + WARN_ON(!txctl->rts_cts_rate); + rts_rate = txctl->rts_cts_rate ? txctl->rts_cts_rate->hw_value : B43_CCK_RATE_1MB; rts_rate_ofdm = b43_is_ofdm_rate(rts_rate); rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); @@ -506,6 +511,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) u16 phystat0, phystat3, chanstat, mactime; u32 macstat; u16 chanid; + u16 phytype; u8 jssi; int padding; @@ -518,6 +524,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) macstat = le32_to_cpu(rxhdr->mac_status); mactime = le16_to_cpu(rxhdr->mac_time); chanstat = le16_to_cpu(rxhdr->channel); + phytype = chanstat & B43_RX_CHAN_PHYTYPE; if (macstat & B43_RX_MAC_FCSERR) dev->wl->ieee_stats.dot11FCSErrorCount++; @@ -575,9 +582,10 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) /* the next line looks wrong, but is what mac80211 wants */ status.signal = (jssi * 100) / B43_RX_MAX_SSI; if (phystat0 & B43_RX_PHYST0_OFDM) - status.rate = b43_plcp_get_bitrate_ofdm(plcp); + status.rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp, + phytype == B43_PHYTYPE_A); else - status.rate = b43_plcp_get_bitrate_cck(plcp); + status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp); status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT); /* @@ -601,29 +609,28 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT; switch (chanstat & B43_RX_CHAN_PHYTYPE) { case B43_PHYTYPE_A: - status.phymode = MODE_IEEE80211A; + status.band = IEEE80211_BAND_5GHZ; B43_WARN_ON(1); /* FIXME: We don't really know which value the "chanid" contains. * So the following assignment might be wrong. */ - status.channel = chanid; - status.freq = b43_channel_to_freq_5ghz(status.channel); + status.freq = b43_channel_to_freq_5ghz(chanid); break; case B43_PHYTYPE_G: - status.phymode = MODE_IEEE80211G; + status.band = IEEE80211_BAND_2GHZ; /* chanid is the radio channel cookie value as used * to tune the radio. */ status.freq = chanid + 2400; - status.channel = b43_freq_to_channel_2ghz(status.freq); break; case B43_PHYTYPE_N: - status.phymode = 0xDEAD /*FIXME MODE_IEEE80211N*/; /* chanid is the SHM channel cookie. Which is the plain * channel number in b43. */ - status.channel = chanid; - if (chanstat & B43_RX_CHAN_5GHZ) - status.freq = b43_freq_to_channel_5ghz(status.freq); - else - status.freq = b43_freq_to_channel_2ghz(status.freq); + if (chanstat & B43_RX_CHAN_5GHZ) { + status.band = IEEE80211_BAND_5GHZ; + status.freq = b43_freq_to_channel_5ghz(chanid); + } else { + status.band = IEEE80211_BAND_2GHZ; + status.freq = b43_freq_to_channel_2ghz(chanid); + } break; default: B43_WARN_ON(1); diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index 93d45b71799a..5f217d6d2e6a 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -392,10 +392,6 @@ struct b43legacy_phy { u8 possible_phymodes; /* GMODE bit enabled in MACCTL? */ bool gmode; - /* Possible ieee80211 subsystem hwmodes for this PHY. - * Which mode is selected, depends on thr GMODE enabled bit */ -#define B43legacy_MAX_PHYHWMODES 2 - struct ieee80211_hw_mode hwmodes[B43legacy_MAX_PHYHWMODES]; /* Analog Type */ u8 analog; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index c39de422e220..d2a72a2cd178 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -95,28 +95,29 @@ MODULE_DEVICE_TABLE(ssb, b43legacy_ssb_tbl); * data in there. This data is the same for all devices, so we don't * get concurrency issues */ #define RATETAB_ENT(_rateid, _flags) \ - { \ - .rate = B43legacy_RATE_TO_100KBPS(_rateid), \ - .val = (_rateid), \ - .val2 = (_rateid), \ - .flags = (_flags), \ + { \ + .bitrate = B43legacy_RATE_TO_100KBPS(_rateid), \ + .hw_value = (_rateid), \ + .flags = (_flags), \ } +/* + * NOTE: When changing this, sync with xmit.c's + * b43legacy_plcp_get_bitrate_idx_* functions! + */ static struct ieee80211_rate __b43legacy_ratetable[] = { - RATETAB_ENT(B43legacy_CCK_RATE_1MB, IEEE80211_RATE_CCK), - RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_CCK_2), - RATETAB_ENT(B43legacy_OFDM_RATE_6MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_9MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_12MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_18MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_24MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_36MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_48MB, IEEE80211_RATE_OFDM), - RATETAB_ENT(B43legacy_OFDM_RATE_54MB, IEEE80211_RATE_OFDM), + RATETAB_ENT(B43legacy_CCK_RATE_1MB, 0), + RATETAB_ENT(B43legacy_CCK_RATE_2MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43legacy_CCK_RATE_5MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43legacy_CCK_RATE_11MB, IEEE80211_RATE_SHORT_PREAMBLE), + RATETAB_ENT(B43legacy_OFDM_RATE_6MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_9MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_12MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_18MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_24MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_36MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_48MB, 0), + RATETAB_ENT(B43legacy_OFDM_RATE_54MB, 0), }; -#define b43legacy_a_ratetable (__b43legacy_ratetable + 4) -#define b43legacy_a_ratetable_size 8 #define b43legacy_b_ratetable (__b43legacy_ratetable + 0) #define b43legacy_b_ratetable_size 4 #define b43legacy_g_ratetable (__b43legacy_ratetable + 0) @@ -124,14 +125,8 @@ static struct ieee80211_rate __b43legacy_ratetable[] = { #define CHANTAB_ENT(_chanid, _freq) \ { \ - .chan = (_chanid), \ - .freq = (_freq), \ - .val = (_chanid), \ - .flag = IEEE80211_CHAN_W_SCAN | \ - IEEE80211_CHAN_W_ACTIVE_SCAN | \ - IEEE80211_CHAN_W_IBSS, \ - .power_level = 0x0A, \ - .antenna_max = 0xFF, \ + .center_freq = (_freq), \ + .hw_value = (_chanid), \ } static struct ieee80211_channel b43legacy_bg_chantable[] = { CHANTAB_ENT(1, 2412), @@ -149,7 +144,20 @@ static struct ieee80211_channel b43legacy_bg_chantable[] = { CHANTAB_ENT(13, 2472), CHANTAB_ENT(14, 2484), }; -#define b43legacy_bg_chantable_size ARRAY_SIZE(b43legacy_bg_chantable) + +static struct ieee80211_supported_band b43legacy_band_2GHz_BPHY = { + .channels = b43legacy_bg_chantable, + .n_channels = ARRAY_SIZE(b43legacy_bg_chantable), + .bitrates = b43legacy_b_ratetable, + .n_bitrates = b43legacy_b_ratetable_size, +}; + +static struct ieee80211_supported_band b43legacy_band_2GHz_GPHY = { + .channels = b43legacy_bg_chantable, + .n_channels = ARRAY_SIZE(b43legacy_bg_chantable), + .bitrates = b43legacy_g_ratetable, + .n_bitrates = b43legacy_g_ratetable_size, +}; static void b43legacy_wireless_core_exit(struct b43legacy_wldev *dev); static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev); @@ -969,18 +977,18 @@ static void b43legacy_write_beacon_template(struct b43legacy_wldev *dev, static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, u16 shm_offset, u16 size, - u8 rate) + struct ieee80211_rate *rate) { struct b43legacy_plcp_hdr4 plcp; u32 tmp; __le16 dur; plcp.data = 0; - b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate); + b43legacy_generate_plcp_hdr(&plcp, size + FCS_LEN, rate->bitrate); dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->vif, size, - B43legacy_RATE_TO_100KBPS(rate)); + rate); /* Write PLCP in two parts and timing for packet transfer */ tmp = le32_to_cpu(plcp.data); b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, shm_offset, @@ -998,7 +1006,8 @@ static void b43legacy_write_probe_resp_plcp(struct b43legacy_wldev *dev, * 3) Stripping TIM */ static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, - u16 *dest_size, u8 rate) + u16 *dest_size, + struct ieee80211_rate *rate) { const u8 *src_data; u8 *dest_data; @@ -1046,7 +1055,7 @@ static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, dur = ieee80211_generic_frame_duration(dev->wl->hw, dev->wl->vif, *dest_size, - B43legacy_RATE_TO_100KBPS(rate)); + rate); hdr->duration_id = dur; return dest_data; @@ -1054,7 +1063,8 @@ static u8 *b43legacy_generate_probe_resp(struct b43legacy_wldev *dev, static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev, u16 ram_offset, - u16 shm_size_offset, u8 rate) + u16 shm_size_offset, + struct ieee80211_rate *rate) { u8 *probe_resp_data; u16 size; @@ -1069,19 +1079,19 @@ static void b43legacy_write_probe_resp_template(struct b43legacy_wldev *dev, * all possible basic rates */ b43legacy_write_probe_resp_plcp(dev, 0x31A, size, - B43legacy_CCK_RATE_1MB); + &b43legacy_b_ratetable[0]); b43legacy_write_probe_resp_plcp(dev, 0x32C, size, - B43legacy_CCK_RATE_2MB); + &b43legacy_b_ratetable[1]); b43legacy_write_probe_resp_plcp(dev, 0x33E, size, - B43legacy_CCK_RATE_5MB); + &b43legacy_b_ratetable[2]); b43legacy_write_probe_resp_plcp(dev, 0x350, size, - B43legacy_CCK_RATE_11MB); + &b43legacy_b_ratetable[3]); size = min((size_t)size, 0x200 - sizeof(struct b43legacy_plcp_hdr6)); b43legacy_write_template_common(dev, probe_resp_data, size, ram_offset, - shm_size_offset, rate); + shm_size_offset, rate->bitrate); kfree(probe_resp_data); } @@ -1106,7 +1116,7 @@ static void b43legacy_update_templates(struct b43legacy_wldev *dev) b43legacy_write_beacon_template(dev, 0x468, 0x1A, B43legacy_CCK_RATE_1MB); b43legacy_write_probe_resp_template(dev, 0x268, 0x4A, - B43legacy_CCK_RATE_11MB); + &b43legacy_b_ratetable[0]); status = b43legacy_read32(dev, B43legacy_MMIO_MACCMD); status |= 0x03; @@ -2550,14 +2560,16 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx); mutex_lock(&wl->mutex); + dev = wl->current_dev; + phy = &dev->phy; /* Switch the PHY mode (if necessary). */ - switch (conf->phymode) { - case MODE_IEEE80211B: - new_phymode = B43legacy_PHYMODE_B; - break; - case MODE_IEEE80211G: - new_phymode = B43legacy_PHYMODE_G; + switch (conf->channel->band) { + case IEEE80211_BAND_2GHZ: + if (phy->type == B43legacy_PHYTYPE_B) + new_phymode = B43legacy_PHYMODE_B; + else + new_phymode = B43legacy_PHYMODE_G; break; default: B43legacy_WARN_ON(1); @@ -2565,8 +2577,6 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, err = b43legacy_switch_phymode(wl, new_phymode); if (err) goto out_unlock_mutex; - dev = wl->current_dev; - phy = &dev->phy; /* Disable IRQs while reconfiguring the device. * This makes it possible to drop the spinlock throughout @@ -2582,8 +2592,8 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, /* Switch to the requested channel. * The firmware takes care of races with the TX handler. */ - if (conf->channel_val != phy->channel) - b43legacy_radio_selectchannel(dev, conf->channel_val, 0); + if (conf->channel->hw_value != phy->channel) + b43legacy_radio_selectchannel(dev, conf->channel->hw_value, 0); /* Enable/Disable ShortSlot timing. */ if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) @@ -3398,48 +3408,19 @@ static int b43legacy_setup_modes(struct b43legacy_wldev *dev, int have_gphy) { struct ieee80211_hw *hw = dev->wl->hw; - struct ieee80211_hw_mode *mode; struct b43legacy_phy *phy = &dev->phy; - int cnt = 0; - int err; phy->possible_phymodes = 0; - for (; 1; cnt++) { - if (have_bphy) { - B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES); - mode = &phy->hwmodes[cnt]; - - mode->mode = MODE_IEEE80211B; - mode->num_channels = b43legacy_bg_chantable_size; - mode->channels = b43legacy_bg_chantable; - mode->num_rates = b43legacy_b_ratetable_size; - mode->rates = b43legacy_b_ratetable; - err = ieee80211_register_hwmode(hw, mode); - if (err) - return err; - - phy->possible_phymodes |= B43legacy_PHYMODE_B; - have_bphy = 0; - continue; - } - if (have_gphy) { - B43legacy_WARN_ON(cnt >= B43legacy_MAX_PHYHWMODES); - mode = &phy->hwmodes[cnt]; - - mode->mode = MODE_IEEE80211G; - mode->num_channels = b43legacy_bg_chantable_size; - mode->channels = b43legacy_bg_chantable; - mode->num_rates = b43legacy_g_ratetable_size; - mode->rates = b43legacy_g_ratetable; - err = ieee80211_register_hwmode(hw, mode); - if (err) - return err; - - phy->possible_phymodes |= B43legacy_PHYMODE_G; - have_gphy = 0; - continue; - } - break; + if (have_bphy) { + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &b43legacy_band_2GHz_BPHY; + phy->possible_phymodes |= B43legacy_PHYMODE_B; + } + + if (have_gphy) { + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = + &b43legacy_band_2GHz_GPHY; + phy->possible_phymodes |= B43legacy_PHYMODE_G; } return 0; diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index d84408a82db9..47e130e9fdf2 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -37,45 +37,48 @@ /* Extract the bitrate out of a CCK PLCP header. */ -static u8 b43legacy_plcp_get_bitrate_cck(struct b43legacy_plcp_hdr6 *plcp) +static u8 b43legacy_plcp_get_bitrate_idx_cck(struct b43legacy_plcp_hdr6 *plcp) { switch (plcp->raw[0]) { case 0x0A: - return B43legacy_CCK_RATE_1MB; + return 0; case 0x14: - return B43legacy_CCK_RATE_2MB; + return 1; case 0x37: - return B43legacy_CCK_RATE_5MB; + return 2; case 0x6E: - return B43legacy_CCK_RATE_11MB; + return 3; } B43legacy_BUG_ON(1); - return 0; + return -1; } /* Extract the bitrate out of an OFDM PLCP header. */ -static u8 b43legacy_plcp_get_bitrate_ofdm(struct b43legacy_plcp_hdr6 *plcp) +static u8 b43legacy_plcp_get_bitrate_idx_ofdm(struct b43legacy_plcp_hdr6 *plcp, + bool aphy) { + int base = aphy ? 0 : 4; + switch (plcp->raw[0] & 0xF) { case 0xB: - return B43legacy_OFDM_RATE_6MB; + return base + 0; case 0xF: - return B43legacy_OFDM_RATE_9MB; + return base + 1; case 0xA: - return B43legacy_OFDM_RATE_12MB; + return base + 2; case 0xE: - return B43legacy_OFDM_RATE_18MB; + return base + 3; case 0x9: - return B43legacy_OFDM_RATE_24MB; + return base + 4; case 0xD: - return B43legacy_OFDM_RATE_36MB; + return base + 5; case 0x8: - return B43legacy_OFDM_RATE_48MB; + return base + 6; case 0xC: - return B43legacy_OFDM_RATE_54MB; + return base + 7; } B43legacy_BUG_ON(1); - return 0; + return -1; } u8 b43legacy_plcp_get_ratecode_cck(const u8 bitrate) @@ -192,7 +195,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, int use_encryption = (!(txctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)); u16 fctl; u8 rate; - u8 rate_fb; + struct ieee80211_rate *rate_fb; int rate_ofdm; int rate_fb_ofdm; unsigned int plcp_fragment_len; @@ -204,16 +207,16 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, memset(txhdr, 0, sizeof(*txhdr)); - rate = txctl->tx_rate; + rate = txctl->tx_rate->hw_value; rate_ofdm = b43legacy_is_ofdm_rate(rate); - rate_fb = (txctl->alt_retry_rate == -1) ? rate : txctl->alt_retry_rate; - rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb); + rate_fb = txctl->alt_retry_rate ? : txctl->tx_rate; + rate_fb_ofdm = b43legacy_is_ofdm_rate(rate_fb->hw_value); txhdr->mac_frame_ctl = wlhdr->frame_control; memcpy(txhdr->tx_receiver, wlhdr->addr1, 6); /* Calculate duration for fallback rate */ - if ((rate_fb == rate) || + if ((rate_fb->hw_value == rate) || (wlhdr->duration_id & cpu_to_le16(0x8000)) || (wlhdr->duration_id == cpu_to_le16(0))) { /* If the fallback rate equals the normal rate or the @@ -221,11 +224,10 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, * use the original dur_id field. */ txhdr->dur_fb = wlhdr->duration_id; } else { - int fbrate_base100kbps = B43legacy_RATE_TO_100KBPS(rate_fb); txhdr->dur_fb = ieee80211_generic_frame_duration(dev->wl->hw, txctl->vif, fragment_len, - fbrate_base100kbps); + rate_fb); } plcp_fragment_len = fragment_len + FCS_LEN; @@ -266,7 +268,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, rate); b43legacy_generate_plcp_hdr((struct b43legacy_plcp_hdr4 *) (&txhdr->plcp_fb), plcp_fragment_len, - rate_fb); + rate_fb->hw_value); /* PHY TX Control word */ if (rate_ofdm) @@ -310,7 +312,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, int rts_rate_ofdm; int rts_rate_fb_ofdm; - rts_rate = txctl->rts_cts_rate; + rts_rate = txctl->rts_cts_rate->hw_value; rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate); rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb); @@ -536,10 +538,11 @@ void b43legacy_rx(struct b43legacy_wldev *dev, (phystat3 & B43legacy_RX_PHYST3_TRSTATE)); status.noise = dev->stats.link_noise; status.signal = (jssi * 100) / B43legacy_RX_MAX_SSI; + /* change to support A PHY */ if (phystat0 & B43legacy_RX_PHYST0_OFDM) - status.rate = b43legacy_plcp_get_bitrate_ofdm(plcp); + status.rate_idx = b43legacy_plcp_get_bitrate_idx_ofdm(plcp, false); else - status.rate = b43legacy_plcp_get_bitrate_cck(plcp); + status.rate_idx = b43legacy_plcp_get_bitrate_idx_cck(plcp); status.antenna = !!(phystat0 & B43legacy_RX_PHYST0_ANT); /* @@ -564,14 +567,9 @@ void b43legacy_rx(struct b43legacy_wldev *dev, B43legacy_RX_CHAN_ID_SHIFT; switch (chanstat & B43legacy_RX_CHAN_PHYTYPE) { case B43legacy_PHYTYPE_B: - status.phymode = MODE_IEEE80211B; - status.freq = chanid + 2400; - status.channel = b43legacy_freq_to_channel_bg(chanid + 2400); - break; case B43legacy_PHYTYPE_G: - status.phymode = MODE_IEEE80211G; + status.band = IEEE80211_BAND_2GHZ; status.freq = chanid + 2400; - status.channel = b43legacy_freq_to_channel_bg(chanid + 2400); break; default: b43legacywarn(dev->wl, "Unexpected value for chanstat (0x%X)\n", diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 80d31ae51e77..f018ce464d97 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -100,14 +100,6 @@ static struct iwl3945_tpt_entry iwl3945_tpt_table_a[] = { {-89, IWL_RATE_6M_INDEX} }; -static struct iwl3945_tpt_entry iwl3945_tpt_table_b[] = { - {-86, IWL_RATE_11M_INDEX}, - {-88, IWL_RATE_5M_INDEX}, - {-90, IWL_RATE_2M_INDEX}, - {-92, IWL_RATE_1M_INDEX} - -}; - static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = { {-60, IWL_RATE_54M_INDEX}, {-64, IWL_RATE_48M_INDEX}, @@ -129,7 +121,7 @@ static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = { #define IWL_RATE_MIN_SUCCESS_TH 8 #define IWL_RATE_DECREASE_TH 1920 -static u8 iwl3945_get_rate_index_by_rssi(s32 rssi, u8 mode) +static u8 iwl3945_get_rate_index_by_rssi(s32 rssi, enum ieee80211_band band) { u32 index = 0; u32 table_size = 0; @@ -138,21 +130,19 @@ static u8 iwl3945_get_rate_index_by_rssi(s32 rssi, u8 mode) if ((rssi < IWL_MIN_RSSI_VAL) || (rssi > IWL_MAX_RSSI_VAL)) rssi = IWL_MIN_RSSI_VAL; - switch (mode) { - case MODE_IEEE80211G: + switch (band) { + case IEEE80211_BAND_2GHZ: tpt_table = iwl3945_tpt_table_g; table_size = ARRAY_SIZE(iwl3945_tpt_table_g); break; - case MODE_IEEE80211A: + case IEEE80211_BAND_5GHZ: tpt_table = iwl3945_tpt_table_a; table_size = ARRAY_SIZE(iwl3945_tpt_table_a); break; default: - case MODE_IEEE80211B: - tpt_table = iwl3945_tpt_table_b; - table_size = ARRAY_SIZE(iwl3945_tpt_table_b); + BUG(); break; } @@ -340,17 +330,17 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, * after assoc.. */ for (i = IWL_RATE_COUNT - 1; i >= 0; i--) { - if (sta->supp_rates & (1 << i)) { - sta->txrate = i; + if (sta->supp_rates[local->hw.conf.channel->band] & (1 << i)) { + sta->txrate_idx = i; break; } } - sta->last_txrate = sta->txrate; + sta->last_txrate_idx = sta->txrate_idx; - /* For MODE_IEEE80211A mode it start at IWL_FIRST_OFDM_RATE */ - if (local->hw.conf.phymode == MODE_IEEE80211A) - sta->last_txrate += IWL_FIRST_OFDM_RATE; + /* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */ + if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) + sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; IWL_DEBUG_RATE("leave\n"); } @@ -429,17 +419,19 @@ static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate) { int next_rate = iwl3945_get_prev_ieee_rate(rate); - switch (priv->phymode) { - case MODE_IEEE80211A: + switch (priv->band) { + case IEEE80211_BAND_5GHZ: if (rate == IWL_RATE_12M_INDEX) next_rate = IWL_RATE_9M_INDEX; else if (rate == IWL_RATE_6M_INDEX) next_rate = IWL_RATE_6M_INDEX; break; +/* XXX cannot be invoked in current mac80211 so not a regression case MODE_IEEE80211B: if (rate == IWL_RATE_11M_INDEX_TABLE) next_rate = IWL_RATE_5M_INDEX_TABLE; break; + */ default: break; } @@ -465,15 +457,17 @@ static void rs_tx_status(void *priv_rate, struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct iwl3945_rs_sta *rs_sta; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; IWL_DEBUG_RATE("enter\n"); retries = tx_resp->retry_count; - first_index = tx_resp->control.tx_rate; + first_index = &sband->bitrates[0] - tx_resp->control.tx_rate; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { - IWL_DEBUG_RATE("leave: Rate out of bounds: %0x for %d\n", - tx_resp->control.tx_rate, first_index); + IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); return; } @@ -561,14 +555,14 @@ static void rs_tx_status(void *priv_rate, } static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta, - u8 index, u16 rate_mask, int phymode) + u8 index, u16 rate_mask, enum ieee80211_band band) { u8 high = IWL_RATE_INVALID; u8 low = IWL_RATE_INVALID; /* 802.11A walks to the next literal adjacent rate in * the rate table */ - if (unlikely(phymode == MODE_IEEE80211A)) { + if (unlikely(band == IEEE80211_BAND_5GHZ)) { int i; u32 mask; @@ -639,7 +633,8 @@ static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta, * */ static void rs_get_rate(void *priv_rate, struct net_device *dev, - struct ieee80211_hw_mode *mode, struct sk_buff *skb, + struct ieee80211_supported_band *band, + struct sk_buff *skb, struct rate_selection *sel) { u8 low = IWL_RATE_INVALID; @@ -672,16 +667,16 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, is_multicast_ether_addr(hdr->addr1) || !sta || !sta->rate_ctrl_priv) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); - sel->rate = rate_lowest(local, local->oper_hw_mode, sta); + sel->rate = rate_lowest(local, band, sta); if (sta) sta_info_put(sta); return; } - rate_mask = sta->supp_rates; - index = min(sta->last_txrate & 0xffff, IWL_RATE_COUNT - 1); + rate_mask = sta->supp_rates[band->band]; + index = min(sta->last_txrate_idx & 0xffff, IWL_RATE_COUNT - 1); - if (priv->phymode == (u8) MODE_IEEE80211A) + if (priv->band == IEEE80211_BAND_5GHZ) rate_mask = rate_mask << IWL_FIRST_OFDM_RATE; rs_sta = (void *)sta->rate_ctrl_priv; @@ -732,7 +727,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, current_tpt = window->average_tpt; high_low = iwl3945_get_adjacent_rate(rs_sta, index, rate_mask, - local->hw.conf.phymode); + band->band); low = high_low & 0xff; high = (high_low >> 8) & 0xff; @@ -810,11 +805,11 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, out: - sta->last_txrate = index; - if (priv->phymode == (u8) MODE_IEEE80211A) - sta->txrate = sta->last_txrate - IWL_FIRST_OFDM_RATE; + sta->last_txrate_idx = index; + if (priv->band == IEEE80211_BAND_5GHZ) + sta->txrate_idx = sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; else - sta->txrate = sta->last_txrate; + sta->txrate_idx = sta->last_txrate_idx; sta_info_put(sta); @@ -945,8 +940,9 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) spin_lock_irqsave(&rs_sta->lock, flags); rs_sta->tgg = 0; - switch (priv->phymode) { - case MODE_IEEE80211G: + switch (priv->band) { + case IEEE80211_BAND_2GHZ: + /* TODO: this always does G, not a regression */ if (priv->active_rxon.flags & RXON_FLG_TGG_PROTECT_MSK) { rs_sta->tgg = 1; rs_sta->expected_tpt = iwl3945_expected_tpt_g_prot; @@ -954,14 +950,11 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) rs_sta->expected_tpt = iwl3945_expected_tpt_g; break; - case MODE_IEEE80211A: + case IEEE80211_BAND_5GHZ: rs_sta->expected_tpt = iwl3945_expected_tpt_a; break; - - default: - IWL_WARNING("Invalid phymode. Defaulting to 802.11b\n"); - case MODE_IEEE80211B: - rs_sta->expected_tpt = iwl3945_expected_tpt_b; + case IEEE80211_NUM_BANDS: + BUG(); break; } @@ -974,8 +967,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) IWL_DEBUG(IWL_DL_INFO | IWL_DL_RATE, "Network RSSI: %d\n", rssi); - rs_sta->start_rate = - iwl3945_get_rate_index_by_rssi(rssi, priv->phymode); + rs_sta->start_rate = iwl3945_get_rate_index_by_rssi(rssi, priv->band); IWL_DEBUG_RATE("leave: rssi %d assign rate index: " "%d (plcp 0x%x)\n", rssi, rs_sta->start_rate, diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 8d4d91d35fd2..50d927bb2170 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -247,7 +247,7 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv, * the information provided in the skb from the hardware */ s8 signal = stats->ssi; s8 noise = 0; - int rate = stats->rate; + int rate = stats->rate_idx; u64 tsf = stats->mactime; __le16 phy_flags_hw = rx_hdr->phy_flags; @@ -315,7 +315,6 @@ static void iwl3945_add_radiotap(struct iwl3945_priv *priv, IEEE80211_CHAN_2GHZ), &iwl3945_rt->rt_chbitmask); - rate = iwl3945_rate_index_from_plcp(rate); if (rate == -1) iwl3945_rt->rt_rate = 0; else @@ -387,11 +386,10 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, struct ieee80211_rx_status stats = { .mactime = le64_to_cpu(rx_end->timestamp), .freq = ieee80211chan2mhz(le16_to_cpu(rx_hdr->channel)), - .channel = le16_to_cpu(rx_hdr->channel), - .phymode = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? - MODE_IEEE80211G : MODE_IEEE80211A, + .band = (rx_hdr->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ, .antenna = 0, - .rate = rx_hdr->rate, + .rate_idx = iwl3945_rate_index_from_plcp(rx_hdr->rate), .flag = 0, }; u8 network_packet; @@ -450,8 +448,6 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, stats.ssi, stats.noise, stats.signal, rx_stats_sig_avg, rx_stats_noise_diff); - stats.freq = ieee80211chan2mhz(stats.channel); - /* can be covered by iwl3945_report_frame() in most cases */ /* IWL_DEBUG_RX("RX status: 0x%08X\n", rx_end->status); */ @@ -464,8 +460,9 @@ static void iwl3945_rx_reply_rx(struct iwl3945_priv *priv, IWL_DEBUG_STATS ("[%c] %d RSSI: %d Signal: %u, Noise: %u, Rate: %u\n", network_packet ? '*' : ' ', - stats.channel, stats.ssi, stats.ssi, - stats.ssi, stats.rate); + le16_to_cpu(rx_hdr->channel), + stats.ssi, stats.ssi, + stats.ssi, stats.rate_idx); if (iwl3945_debug_level & (IWL_DL_RX)) /* Set "1" to report good data frames in groups of 100 */ @@ -689,7 +686,7 @@ void iwl3945_hw_build_tx_cmd_rate(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr, int sta_id, int tx_id) { unsigned long flags; - u16 rate_index = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1); + u16 rate_index = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); u16 rate_mask; int rate; u8 rts_retry_limit; @@ -1552,14 +1549,14 @@ int iwl3945_hw_reg_send_txpower(struct iwl3945_priv *priv) .channel = priv->active_rxon.channel, }; - txpower.band = (priv->phymode == MODE_IEEE80211A) ? 0 : 1; + txpower.band = (priv->band == IEEE80211_BAND_5GHZ) ? 0 : 1; ch_info = iwl3945_get_channel_info(priv, - priv->phymode, + priv->band, le16_to_cpu(priv->active_rxon.channel)); if (!ch_info) { IWL_ERROR ("Failed to get channel info for channel %d [%d]\n", - le16_to_cpu(priv->active_rxon.channel), priv->phymode); + le16_to_cpu(priv->active_rxon.channel), priv->band); return -EINVAL; } @@ -2241,8 +2238,8 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) table[index].next_rate_index = iwl3945_rates[prev_index].table_rs_index; } - switch (priv->phymode) { - case MODE_IEEE80211A: + switch (priv->band) { + case IEEE80211_BAND_5GHZ: IWL_DEBUG_RATE("Select A mode rate scale\n"); /* If one of the following CCK rates is used, * have it fall back to the 6M OFDM rate */ @@ -2257,8 +2254,8 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index; break; - case MODE_IEEE80211B: - IWL_DEBUG_RATE("Select B mode rate scale\n"); + case IEEE80211_BAND_2GHZ: + IWL_DEBUG_RATE("Select B/G mode rate scale\n"); /* If an OFDM rate is used, have it fall back to the * 1M CCK rates */ for (i = IWL_RATE_6M_INDEX_TABLE; i <= IWL_RATE_54M_INDEX_TABLE; i++) @@ -2269,7 +2266,7 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) break; default: - IWL_DEBUG_RATE("Select G mode rate scale\n"); + WARN_ON(1); break; } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index 1da14f9bbe0f..1beb5b676797 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -195,7 +195,7 @@ struct iwl3945_channel_info { u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */ u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ - u8 phymode; /* MODE_IEEE80211{A,B,G} */ + enum ieee80211_band band; /* Radio/DSP gain settings for each "normal" data Tx rate. * These include, in addition to RF and DSP gain, a few fields for @@ -699,14 +699,14 @@ struct iwl3945_priv { struct list_head free_frames; int frames_count; - u8 phymode; + enum ieee80211_band band; int alloc_rxb_skb; bool add_radiotap; void (*rx_handlers[REPLY_MAX])(struct iwl3945_priv *priv, struct iwl3945_rx_mem_buffer *rxb); - const struct ieee80211_hw_mode *modes; + struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT /* spectrum measurement report caching */ @@ -937,13 +937,12 @@ static inline int is_channel_radar(const struct iwl3945_channel_info *ch_info) static inline u8 is_channel_a_band(const struct iwl3945_channel_info *ch_info) { - return ch_info->phymode == MODE_IEEE80211A; + return ch_info->band == IEEE80211_BAND_5GHZ; } static inline u8 is_channel_bg_band(const struct iwl3945_channel_info *ch_info) { - return ((ch_info->phymode == MODE_IEEE80211B) || - (ch_info->phymode == MODE_IEEE80211G)); + return ch_info->band == IEEE80211_BAND_2GHZ; } static inline int is_channel_passive(const struct iwl3945_channel_info *ch) @@ -967,7 +966,7 @@ static inline int iwl3945_rate_index_from_plcp(int plcp) } extern const struct iwl3945_channel_info *iwl3945_get_channel_info( - const struct iwl3945_priv *priv, int phymode, u16 channel); + const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel); /* Requires full declaration of iwl3945_priv before including */ #include "iwl-3945-io.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 660671f17a3b..48a6a85355ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -139,7 +139,7 @@ struct iwl4965_lq_sta { u8 valid_antenna; u8 is_green; u8 is_dup; - u8 phymode; + enum ieee80211_band band; u8 ibss_sta_added; /* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */ @@ -563,7 +563,8 @@ static void rs_mcs_from_tbl(struct iwl4965_rate *mcs_rate, * fill "search" or "active" tx mode table. */ static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, - int phymode, struct iwl4965_scale_tbl_info *tbl, + enum ieee80211_band band, + struct iwl4965_scale_tbl_info *tbl, int *rate_idx) { int index; @@ -588,7 +589,7 @@ static int rs_get_tbl_info_from_mcs(const struct iwl4965_rate *mcs_rate, tbl->lq_type = LQ_NONE; else { - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) tbl->lq_type = LQ_A; else tbl->lq_type = LQ_G; @@ -766,7 +767,7 @@ static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, if (!is_legacy(tbl->lq_type) && (!ht_possible || !scale_index)) { switch_to_legacy = 1; scale_index = rs_ht_to_legacy[scale_index]; - if (lq_sta->phymode == MODE_IEEE80211A) + if (lq_sta->band == IEEE80211_BAND_5GHZ) tbl->lq_type = LQ_A; else tbl->lq_type = LQ_G; @@ -784,7 +785,7 @@ static void rs_get_lower_rate(struct iwl4965_lq_sta *lq_sta, /* Mask with station rate restriction */ if (is_legacy(tbl->lq_type)) { /* supp_rates has no CCK bits in A mode */ - if (lq_sta->phymode == (u8) MODE_IEEE80211A) + if (lq_sta->band == IEEE80211_BAND_5GHZ) rate_mask = (u16)(rate_mask & (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); else @@ -883,9 +884,9 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, search_win = (struct iwl4965_rate_scale_data *) &(search_tbl->win[0]); - tx_mcs.rate_n_flags = tx_resp->control.tx_rate; + tx_mcs.rate_n_flags = tx_resp->control.tx_rate->hw_value; - rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, + rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index); if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n", @@ -918,7 +919,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, * Each tx attempt steps one entry deeper in the rate table. */ tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[index].rate_n_flags); - rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, + rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index); /* If type matches "search" table, @@ -959,12 +960,12 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, * else look up the rate that was, finally, successful. */ if (!tx_resp->retry_count) - tx_mcs.rate_n_flags = tx_resp->control.tx_rate; + tx_mcs.rate_n_flags = tx_resp->control.tx_rate->hw_value; else tx_mcs.rate_n_flags = le32_to_cpu(table->rs_table[index].rate_n_flags); - rs_get_tbl_info_from_mcs(&tx_mcs, priv->phymode, + rs_get_tbl_info_from_mcs(&tx_mcs, priv->band, &tbl_type, &rs_index); /* Update frame history window with "success" if Tx got ACKed ... */ @@ -1801,7 +1802,7 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, is_green = lq_sta->is_green; /* current tx rate */ - index = sta->last_txrate; + index = sta->last_txrate_idx; IWL_DEBUG_RATE("Rate scale index %d for type %d\n", index, tbl->lq_type); @@ -1814,7 +1815,7 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, /* mask with station rate restriction */ if (is_legacy(tbl->lq_type)) { - if (lq_sta->phymode == (u8) MODE_IEEE80211A) + if (lq_sta->band == IEEE80211_BAND_5GHZ) /* supp_rates has no CCK bits in A mode */ rate_scale_index_msk = (u16) (rate_mask & (lq_sta->supp_rates << IWL_FIRST_OFDM_RATE)); @@ -2134,15 +2135,15 @@ static void rs_rate_scale_perform(struct iwl4965_priv *priv, out: rs_mcs_from_tbl(&tbl->current_rate, tbl, index, is_green); i = index; - sta->last_txrate = i; + sta->last_txrate_idx = i; - /* sta->txrate is an index to A mode rates which start + /* sta->txrate_idx is an index to A mode rates which start * at IWL_FIRST_OFDM_RATE */ - if (lq_sta->phymode == (u8) MODE_IEEE80211A) - sta->txrate = i - IWL_FIRST_OFDM_RATE; + if (lq_sta->band == IEEE80211_BAND_5GHZ) + sta->txrate_idx = i - IWL_FIRST_OFDM_RATE; else - sta->txrate = i; + sta->txrate_idx = i; return; } @@ -2164,7 +2165,7 @@ static void rs_initialize_lq(struct iwl4965_priv *priv, goto out; lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; - i = sta->last_txrate; + i = sta->last_txrate_idx; if ((lq_sta->lq.sta_id == 0xff) && (priv->iw_mode == IEEE80211_IF_TYPE_IBSS)) @@ -2188,7 +2189,7 @@ static void rs_initialize_lq(struct iwl4965_priv *priv, mcs_rate.rate_n_flags |= RATE_MCS_CCK_MSK; tbl->antenna_type = ANT_AUX; - rs_get_tbl_info_from_mcs(&mcs_rate, priv->phymode, tbl, &rate_idx); + rs_get_tbl_info_from_mcs(&mcs_rate, priv->band, tbl, &rate_idx); if (!rs_is_ant_connected(priv->valid_antenna, tbl->antenna_type)) rs_toggle_antenna(&mcs_rate, tbl); @@ -2202,7 +2203,8 @@ static void rs_initialize_lq(struct iwl4965_priv *priv, } static void rs_get_rate(void *priv_rate, struct net_device *dev, - struct ieee80211_hw_mode *mode, struct sk_buff *skb, + struct ieee80211_supported_band *sband, + struct sk_buff *skb, struct rate_selection *sel) { @@ -2224,14 +2226,14 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, fc = le16_to_cpu(hdr->frame_control); if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || !sta || !sta->rate_ctrl_priv) { - sel->rate = rate_lowest(local, local->oper_hw_mode, sta); + sel->rate = rate_lowest(local, sband, sta); if (sta) sta_info_put(sta); return; } lq_sta = (struct iwl4965_lq_sta *)sta->rate_ctrl_priv; - i = sta->last_txrate; + i = sta->last_txrate_idx; if ((priv->iw_mode == IEEE80211_IF_TYPE_IBSS) && !lq_sta->ibss_sta_added) { @@ -2256,7 +2258,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, done: if ((i < 0) || (i > IWL_RATE_COUNT)) { - sel->rate = rate_lowest(local, local->oper_hw_mode, sta); + sel->rate = rate_lowest(local, sband, sta); return; } sta_info_put(sta); @@ -2291,13 +2293,15 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, { int i, j; struct ieee80211_conf *conf = &local->hw.conf; - struct ieee80211_hw_mode *mode = local->oper_hw_mode; + struct ieee80211_supported_band *sband; struct iwl4965_priv *priv = (struct iwl4965_priv *)priv_rate; struct iwl4965_lq_sta *lq_sta = priv_sta; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + lq_sta->flush_timer = 0; - lq_sta->supp_rates = sta->supp_rates; - sta->txrate = 3; + lq_sta->supp_rates = sta->supp_rates[sband->band]; + sta->txrate_idx = 3; for (j = 0; j < LQ_SIZE; j++) for (i = 0; i < IWL_RATE_COUNT; i++) rs_rate_scale_clear_window(&(lq_sta->lq_info[j].win[i])); @@ -2332,15 +2336,15 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, } /* Find highest tx rate supported by hardware and destination station */ - for (i = 0; i < mode->num_rates; i++) { - if ((sta->supp_rates & BIT(i)) && - (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) - sta->txrate = i; - } - sta->last_txrate = sta->txrate; + for (i = 0; i < sband->n_bitrates; i++) + if (sta->supp_rates[sband->band] & BIT(i)) + sta->txrate_idx = i; + + sta->last_txrate_idx = sta->txrate_idx; + /* WTF is with this bogus comment? A doesn't have cck rates */ /* For MODE_IEEE80211A, cck rates are at end of rate table */ - if (local->hw.conf.phymode == MODE_IEEE80211A) - sta->last_txrate += IWL_FIRST_OFDM_RATE; + if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ) + sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; lq_sta->is_dup = 0; lq_sta->valid_antenna = priv->valid_antenna; @@ -2349,7 +2353,7 @@ static void rs_rate_init(void *priv_rate, void *priv_sta, lq_sta->active_rate = priv->active_rate; lq_sta->active_rate &= ~(0x1000); lq_sta->active_rate_basic = priv->active_rate_basic; - lq_sta->phymode = priv->phymode; + lq_sta->band = priv->band; #ifdef CONFIG_IWL4965_HT /* * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), @@ -2401,7 +2405,7 @@ static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, rs_dbgfs_set_mcs(lq_sta, tx_mcs, index); /* Interpret rate_n_flags */ - rs_get_tbl_info_from_mcs(tx_mcs, lq_sta->phymode, + rs_get_tbl_info_from_mcs(tx_mcs, lq_sta->band, &tbl_type, &rate_idx); /* How many times should we repeat the initial rate? */ @@ -2455,7 +2459,7 @@ static void rs_fill_link_cmd(struct iwl4965_lq_sta *lq_sta, index++; } - rs_get_tbl_info_from_mcs(&new_rate, lq_sta->phymode, &tbl_type, + rs_get_tbl_info_from_mcs(&new_rate, lq_sta->band, &tbl_type, &rate_idx); /* Indicate to uCode which entries might be MIMO. @@ -2542,7 +2546,7 @@ static void rs_dbgfs_set_mcs(struct iwl4965_lq_sta *lq_sta, { u32 base_rate; - if (lq_sta->phymode == (u8) MODE_IEEE80211A) + if (lq_sta->band == IEEE80211_BAND_5GHZ) base_rate = 0x800D; else base_rate = 0x820A; @@ -2802,7 +2806,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) cnt += sprintf(&buf[cnt], "\nrate scale type %d antenna %d " "active_search %d rate index %d\n", lq_type, antenna, - lq_sta->search_better_tbl, sta->last_txrate); + lq_sta->search_better_tbl, sta->last_txrate_idx); sta_info_put(sta); return cnt; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 0bded8570275..a89439320498 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -339,14 +339,15 @@ static int iwl4965_kw_alloc(struct iwl4965_priv *priv) * * Does not set up a command, or touch hardware. */ -int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode, u16 channel, +int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, + enum ieee80211_band band, u16 channel, const struct iwl4965_eeprom_channel *eeprom_ch, u8 fat_extension_channel) { struct iwl4965_channel_info *ch_info; ch_info = (struct iwl4965_channel_info *) - iwl4965_get_channel_info(priv, phymode, channel); + iwl4965_get_channel_info(priv, band, channel); if (!is_channel_valid(ch_info)) return -1; @@ -1939,11 +1940,12 @@ static s32 iwl4965_get_voltage_compensation(s32 eeprom_voltage, } static const struct iwl4965_channel_info * -iwl4965_get_channel_txpower_info(struct iwl4965_priv *priv, u8 phymode, u16 channel) +iwl4965_get_channel_txpower_info(struct iwl4965_priv *priv, + enum ieee80211_band band, u16 channel) { const struct iwl4965_channel_info *ch_info; - ch_info = iwl4965_get_channel_info(priv, phymode, channel); + ch_info = iwl4965_get_channel_info(priv, band, channel); if (!is_channel_valid(ch_info)) return NULL; @@ -2392,7 +2394,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl4965_priv *priv, u8 band, u16 chan /* Get current (RXON) channel, band, width */ ch_info = - iwl4965_get_channel_txpower_info(priv, priv->phymode, channel); + iwl4965_get_channel_txpower_info(priv, priv->band, channel); IWL_DEBUG_TXPOWER("chan %d band %d is_fat %d\n", channel, band, is_fat); @@ -2619,8 +2621,7 @@ int iwl4965_hw_reg_send_txpower(struct iwl4965_priv *priv) return -EAGAIN; } - band = ((priv->phymode == MODE_IEEE80211B) || - (priv->phymode == MODE_IEEE80211G)); + band = priv->band == IEEE80211_BAND_2GHZ; is_fat = is_fat_channel(priv->active_rxon.flags); @@ -2650,10 +2651,9 @@ int iwl4965_hw_channel_switch(struct iwl4965_priv *priv, u16 channel) struct iwl4965_channel_switch_cmd cmd = { 0 }; const struct iwl4965_channel_info *ch_info; - band = ((priv->phymode == MODE_IEEE80211B) || - (priv->phymode == MODE_IEEE80211G)); + band = priv->band == IEEE80211_BAND_2GHZ; - ch_info = iwl4965_get_channel_info(priv, priv->phymode, channel); + ch_info = iwl4965_get_channel_info(priv, priv->band, channel); is_fat = is_fat_channel(priv->staging_rxon.flags); @@ -2698,7 +2698,7 @@ void iwl4965_hw_build_tx_cmd_rate(struct iwl4965_priv *priv, u16 fc = le16_to_cpu(hdr->frame_control); u8 rate_plcp; u16 rate_flags = 0; - int rate_idx = min(ctrl->tx_rate & 0xffff, IWL_RATE_COUNT - 1); + int rate_idx = min(ctrl->tx_rate->hw_value & 0xffff, IWL_RATE_COUNT - 1); rate_plcp = iwl4965_rates[rate_idx].plcp; @@ -3178,7 +3178,7 @@ static void iwl4965_add_radiotap(struct iwl4965_priv *priv, { s8 signal = stats->ssi; s8 noise = 0; - int rate = stats->rate; + int rate = stats->rate_idx; u64 tsf = stats->mactime; __le16 phy_flags_hw = rx_start->phy_flags; struct iwl4965_rt_rx_hdr { @@ -3246,7 +3246,6 @@ static void iwl4965_add_radiotap(struct iwl4965_priv *priv, IEEE80211_CHAN_2GHZ), &iwl4965_rt->rt_chbitmask); - rate = iwl4965_rate_index_from_plcp(rate); if (rate == -1) iwl4965_rt->rt_rate = 0; else @@ -3542,12 +3541,13 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, u16 fc; struct ieee80211_rx_status stats = { .mactime = le64_to_cpu(rx_start->timestamp), - .channel = le16_to_cpu(rx_start->channel), - .phymode = + .freq = ieee80211chan2mhz(le16_to_cpu(rx_start->channel)), + .band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? - MODE_IEEE80211G : MODE_IEEE80211A, + IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ, .antenna = 0, - .rate = iwl4965_hw_get_rate(rx_start->rate_n_flags), + .rate_idx = iwl4965_hw_get_rate( + le32_to_cpu(rx_start->rate_n_flags)), .flag = 0, }; u8 network_packet; @@ -3598,8 +3598,6 @@ static void iwl4965_rx_reply_rx(struct iwl4965_priv *priv, priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); - stats.freq = ieee80211chan2mhz(stats.channel); - /* Find max signal strength (dBm) among 3 antenna/receiver chains */ stats.ssi = iwl4965_calc_rssi(rx_start); @@ -4185,7 +4183,7 @@ void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap) * all the way down to 1M in IEEE order, and then spin on 1M */ if (is_ap) r = IWL_RATE_54M_INDEX; - else if (priv->phymode == MODE_IEEE80211A) + else if (priv->band == IEEE80211_BAND_5GHZ) r = IWL_RATE_6M_INDEX; else r = IWL_RATE_1M_INDEX; @@ -4218,12 +4216,13 @@ void iwl4965_add_station(struct iwl4965_priv *priv, const u8 *addr, int is_ap) #ifdef CONFIG_IWL4965_HT -static u8 iwl4965_is_channel_extension(struct iwl4965_priv *priv, int phymode, +static u8 iwl4965_is_channel_extension(struct iwl4965_priv *priv, + enum ieee80211_band band, u16 channel, u8 extension_chan_offset) { const struct iwl4965_channel_info *ch_info; - ch_info = iwl4965_get_channel_info(priv, phymode, channel); + ch_info = iwl4965_get_channel_info(priv, band, channel); if (!is_channel_valid(ch_info)) return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h index de5c1bf8fc42..cb8f7f2a8d48 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965.h @@ -206,7 +206,7 @@ struct iwl4965_channel_info { u8 group_index; /* 0-4, maps channel to group1/2/3/4/5 */ u8 band_index; /* 0-4, maps channel to band1/2/3/4/5 */ - u8 phymode; /* MODE_IEEE80211{A,B,G} */ + enum ieee80211_band band; /* Radio/DSP gain settings for each "normal" data Tx rate. * These include, in addition to RF and DSP gain, a few fields for @@ -764,7 +764,8 @@ extern void iwl4965_update_rate_scaling(struct iwl4965_priv *priv, u8 mode); extern void iwl4965_chain_noise_reset(struct iwl4965_priv *priv); extern void iwl4965_init_sensitivity(struct iwl4965_priv *priv, u8 flags, u8 force); -extern int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, int phymode, +extern int iwl4965_set_fat_chan_info(struct iwl4965_priv *priv, + enum ieee80211_band band, u16 channel, const struct iwl4965_eeprom_channel *eeprom_ch, u8 fat_extension_channel); @@ -977,14 +978,14 @@ struct iwl4965_priv { struct list_head free_frames; int frames_count; - u8 phymode; + enum ieee80211_band band; int alloc_rxb_skb; bool add_radiotap; void (*rx_handlers[REPLY_MAX])(struct iwl4965_priv *priv, struct iwl4965_rx_mem_buffer *rxb); - const struct ieee80211_hw_mode *modes; + struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT /* spectrum measurement report caching */ @@ -1243,13 +1244,12 @@ static inline int is_channel_radar(const struct iwl4965_channel_info *ch_info) static inline u8 is_channel_a_band(const struct iwl4965_channel_info *ch_info) { - return ch_info->phymode == MODE_IEEE80211A; + return ch_info->band == IEEE80211_BAND_5GHZ; } static inline u8 is_channel_bg_band(const struct iwl4965_channel_info *ch_info) { - return ((ch_info->phymode == MODE_IEEE80211B) || - (ch_info->phymode == MODE_IEEE80211G)); + return ch_info->band == IEEE80211_BAND_2GHZ; } static inline int is_channel_passive(const struct iwl4965_channel_info *ch) @@ -1263,7 +1263,7 @@ static inline int is_channel_ibss(const struct iwl4965_channel_info *ch) } extern const struct iwl4965_channel_info *iwl4965_get_channel_info( - const struct iwl4965_priv *priv, int phymode, u16 channel); + const struct iwl4965_priv *priv, enum ieee80211_band band, u16 channel); /* Requires full declaration of iwl4965_priv before including */ #include "iwl-4965-io.h" diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 40b71bc2c4a4..57a1d70f2abf 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -116,16 +116,10 @@ static __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) return NULL; } -static const struct ieee80211_hw_mode *iwl3945_get_hw_mode( - struct iwl3945_priv *priv, int mode) +static const struct ieee80211_supported_band *iwl3945_get_band( + struct iwl3945_priv *priv, enum ieee80211_band band) { - int i; - - for (i = 0; i < 3; i++) - if (priv->modes[i].mode == mode) - return &priv->modes[i]; - - return NULL; + return priv->hw->wiphy->bands[band]; } static int iwl3945_is_empty_essid(const char *essid, int essid_len) @@ -547,7 +541,7 @@ u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 station->sta.sta.sta_id = index; station->sta.station_flags = 0; - if (priv->phymode == MODE_IEEE80211A) + if (priv->band == IEEE80211_BAND_5GHZ) rate = IWL_RATE_6M_PLCP; else rate = IWL_RATE_1M_PLCP; @@ -894,35 +888,37 @@ int iwl3945_send_statistics_request(struct iwl3945_priv *priv) /** * iwl3945_set_rxon_channel - Set the phymode and channel values in staging RXON - * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz - * @channel: Any channel valid for the requested phymode + * @band: 2.4 or 5 GHz band + * @channel: Any channel valid for the requested band - * In addition to setting the staging RXON, priv->phymode is also set. + * In addition to setting the staging RXON, priv->band is also set. * * NOTE: Does not commit to the hardware; it sets appropriate bit fields - * in the staging RXON flag structure based on the phymode + * in the staging RXON flag structure based on the band */ -static int iwl3945_set_rxon_channel(struct iwl3945_priv *priv, u8 phymode, u16 channel) +static int iwl3945_set_rxon_channel(struct iwl3945_priv *priv, + enum ieee80211_band band, + u16 channel) { - if (!iwl3945_get_channel_info(priv, phymode, channel)) { + if (!iwl3945_get_channel_info(priv, band, channel)) { IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", - channel, phymode); + channel, band); return -EINVAL; } if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && - (priv->phymode == phymode)) + (priv->band == band)) return 0; priv->staging_rxon.channel = cpu_to_le16(channel); - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; else priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; - priv->phymode = phymode; + priv->band = band; - IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode); + IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, band); return 0; } @@ -1210,8 +1206,7 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv) return -EIO; } - /* Init the hardware's rate fallback order based on the - * phymode */ + /* Init the hardware's rate fallback order based on the band */ rc = iwl3945_init_hw_rate_table(priv); if (rc) { IWL_ERROR("Error setting HW rate table: %02X\n", rc); @@ -2461,9 +2456,10 @@ static int iwl3945_set_rxon_hwcrypto(struct iwl3945_priv *priv, int hw_decrypt) return 0; } -static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode) +static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, + enum ieee80211_band band) { - if (phymode == MODE_IEEE80211A) { + if (band == IEEE80211_BAND_5GHZ) { priv->staging_rxon.flags &= ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_CCK_MSK); @@ -2526,7 +2522,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; #endif - ch_info = iwl3945_get_channel_info(priv, priv->phymode, + ch_info = iwl3945_get_channel_info(priv, priv->band, le16_to_cpu(priv->staging_rxon.channel)); if (!ch_info) @@ -2542,11 +2538,11 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); if (is_channel_a_band(ch_info)) - priv->phymode = MODE_IEEE80211A; + priv->band = IEEE80211_BAND_5GHZ; else - priv->phymode = MODE_IEEE80211G; + priv->band = IEEE80211_BAND_2GHZ; - iwl3945_set_flags_for_phymode(priv, priv->phymode); + iwl3945_set_flags_for_phymode(priv, priv->band); priv->staging_rxon.ofdm_basic_rates = (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; @@ -2560,7 +2556,7 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) const struct iwl3945_channel_info *ch_info; ch_info = iwl3945_get_channel_info(priv, - priv->phymode, + priv->band, le16_to_cpu(priv->staging_rxon.channel)); if (!ch_info || !is_channel_ibss(ch_info)) { @@ -2792,7 +2788,7 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, goto drop_unlock; } - if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) { + if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } @@ -2992,12 +2988,12 @@ drop: static void iwl3945_set_rate(struct iwl3945_priv *priv) { - const struct ieee80211_hw_mode *hw = NULL; + const struct ieee80211_supported_band *sband = NULL; struct ieee80211_rate *rate; int i; - hw = iwl3945_get_hw_mode(priv, priv->phymode); - if (!hw) { + sband = iwl3945_get_band(priv, priv->band); + if (!sband) { IWL_ERROR("Failed to set rate: unable to get hw mode\n"); return; } @@ -3005,24 +3001,17 @@ static void iwl3945_set_rate(struct iwl3945_priv *priv) priv->active_rate = 0; priv->active_rate_basic = 0; - IWL_DEBUG_RATE("Setting rates for 802.11%c\n", - hw->mode == MODE_IEEE80211A ? - 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g')); - - for (i = 0; i < hw->num_rates; i++) { - rate = &(hw->rates[i]); - if ((rate->val < IWL_RATE_COUNT) && - (rate->flags & IEEE80211_RATE_SUPPORTED)) { - IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n", - rate->val, iwl3945_rates[rate->val].plcp, - (rate->flags & IEEE80211_RATE_BASIC) ? - "*" : ""); - priv->active_rate |= (1 << rate->val); - if (rate->flags & IEEE80211_RATE_BASIC) - priv->active_rate_basic |= (1 << rate->val); - } else - IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n", - rate->val, iwl3945_rates[rate->val].plcp); + IWL_DEBUG_RATE("Setting rates for %s GHz\n", + sband->band == IEEE80211_BAND_2GHZ ? "2.4" : "5"); + + for (i = 0; i < sband->n_bitrates; i++) { + rate = &sband->bitrates[i]; + if ((rate->hw_value < IWL_RATE_COUNT) && + !(rate->flags & IEEE80211_CHAN_DISABLED)) { + IWL_DEBUG_RATE("Adding rate index %d (plcp %d)\n", + rate->hw_value, iwl3945_rates[rate->hw_value].plcp); + priv->active_rate |= (1 << rate->hw_value); + } } IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", @@ -3436,8 +3425,6 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, tx_status->flags = iwl3945_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; - tx_status->control.tx_rate = iwl3945_rate_index_from_plcp(tx_resp->rate); - IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) plcp rate %d retries %d\n", txq_id, iwl3945_get_tx_fail_reason(status), status, tx_resp->rate, tx_resp->failure_frame); @@ -5026,24 +5013,24 @@ static void iwl3945_init_band_reference(const struct iwl3945_priv *priv, int ban * Based on band and channel number. */ const struct iwl3945_channel_info *iwl3945_get_channel_info(const struct iwl3945_priv *priv, - int phymode, u16 channel) + enum ieee80211_band band, u16 channel) { int i; - switch (phymode) { - case MODE_IEEE80211A: + switch (band) { + case IEEE80211_BAND_5GHZ: for (i = 14; i < priv->channel_count; i++) { if (priv->channel_info[i].channel == channel) return &priv->channel_info[i]; } break; - case MODE_IEEE80211B: - case MODE_IEEE80211G: + case IEEE80211_BAND_2GHZ: if (channel >= 1 && channel <= 14) return &priv->channel_info[channel - 1]; break; - + case IEEE80211_NUM_BANDS: + WARN_ON(1); } return NULL; @@ -5106,8 +5093,8 @@ static int iwl3945_init_channel_map(struct iwl3945_priv *priv) /* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) { ch_info->channel = eeprom_ch_index[ch]; - ch_info->phymode = (band == 1) ? MODE_IEEE80211B : - MODE_IEEE80211A; + ch_info->band = (band == 1) ? IEEE80211_BAND_2GHZ : + IEEE80211_BAND_5GHZ; /* permanently store EEPROM's channel regulatory flags * and max power in channel info database. */ @@ -5203,18 +5190,20 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv) #define IWL_PASSIVE_DWELL_BASE (100) #define IWL_CHANNEL_TUNE_TIME 5 -static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, int phymode) +static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, + enum ieee80211_band band) { - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) return IWL_ACTIVE_DWELL_TIME_52; else return IWL_ACTIVE_DWELL_TIME_24; } -static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, int phymode) +static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, + enum ieee80211_band band) { - u16 active = iwl3945_get_active_dwell_time(priv, phymode); - u16 passive = (phymode != MODE_IEEE80211A) ? + u16 active = iwl3945_get_active_dwell_time(priv, band); + u16 passive = (band == IEEE80211_BAND_2GHZ) ? IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; @@ -5234,28 +5223,29 @@ static u16 iwl3945_get_passive_dwell_time(struct iwl3945_priv *priv, int phymode return passive; } -static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, +static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, + enum ieee80211_band band, u8 is_active, u8 direct_mask, struct iwl3945_scan_channel *scan_ch) { const struct ieee80211_channel *channels = NULL; - const struct ieee80211_hw_mode *hw_mode; + const struct ieee80211_supported_band *sband; const struct iwl3945_channel_info *ch_info; u16 passive_dwell = 0; u16 active_dwell = 0; int added, i; - hw_mode = iwl3945_get_hw_mode(priv, phymode); - if (!hw_mode) + sband = iwl3945_get_band(priv, band); + if (!sband) return 0; - channels = hw_mode->channels; + channels = sband->channels; - active_dwell = iwl3945_get_active_dwell_time(priv, phymode); - passive_dwell = iwl3945_get_passive_dwell_time(priv, phymode); + active_dwell = iwl3945_get_active_dwell_time(priv, band); + passive_dwell = iwl3945_get_passive_dwell_time(priv, band); - for (i = 0, added = 0; i < hw_mode->num_channels; i++) { - if (channels[i].chan == + for (i = 0, added = 0; i < sband->n_channels; i++) { + if (channels[i].hw_value == le16_to_cpu(priv->active_rxon.channel)) { if (iwl3945_is_associated(priv)) { IWL_DEBUG_SCAN @@ -5266,9 +5256,9 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, } else if (priv->only_active_channel) continue; - scan_ch->channel = channels[i].chan; + scan_ch->channel = channels[i].hw_value; - ch_info = iwl3945_get_channel_info(priv, phymode, scan_ch->channel); + ch_info = iwl3945_get_channel_info(priv, band, scan_ch->channel); if (!is_channel_valid(ch_info)) { IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n", scan_ch->channel); @@ -5276,7 +5266,7 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, } if (!is_active || is_channel_passive(ch_info) || - !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN)) + (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) scan_ch->type = 0; /* passive */ else scan_ch->type = 1; /* active */ @@ -5295,7 +5285,7 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, /* scan_pwr_info->tpc.dsp_atten; */ /*scan_pwr_info->tpc.tx_gain; */ - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; else { scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); @@ -5319,41 +5309,23 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, int phymode, return added; } -static void iwl3945_reset_channel_flag(struct iwl3945_priv *priv) -{ - int i, j; - for (i = 0; i < 3; i++) { - struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i]; - for (j = 0; j < hw_mode->num_channels; j++) - hw_mode->channels[j].flag = hw_mode->channels[j].val; - } -} - static void iwl3945_init_hw_rates(struct iwl3945_priv *priv, struct ieee80211_rate *rates) { int i; for (i = 0; i < IWL_RATE_COUNT; i++) { - rates[i].rate = iwl3945_rates[i].ieee * 5; - rates[i].val = i; /* Rate scaling will work on indexes */ - rates[i].val2 = i; - rates[i].flags = IEEE80211_RATE_SUPPORTED; - /* Only OFDM have the bits-per-symbol set */ - if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE)) - rates[i].flags |= IEEE80211_RATE_OFDM; - else { + rates[i].bitrate = iwl3945_rates[i].ieee * 5; + rates[i].hw_value = i; /* Rate scaling will work on indexes */ + rates[i].hw_value_short = i; + rates[i].flags = 0; + if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) { /* - * If CCK 1M then set rate flag to CCK else CCK_2 - * which is CCK | PREAMBLE2 + * If CCK != 1M then set short preamble rate flag. */ rates[i].flags |= (iwl3945_rates[i].plcp == 10) ? - IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2; + 0 : IEEE80211_RATE_SHORT_PREAMBLE; } - - /* Set up which ones are basic rates... */ - if (IWL_BASIC_RATES_MASK & (1 << i)) - rates[i].flags |= IEEE80211_RATE_BASIC; } } @@ -5363,67 +5335,41 @@ static void iwl3945_init_hw_rates(struct iwl3945_priv *priv, static int iwl3945_init_geos(struct iwl3945_priv *priv) { struct iwl3945_channel_info *ch; - struct ieee80211_hw_mode *modes; + struct ieee80211_supported_band *band; struct ieee80211_channel *channels; struct ieee80211_channel *geo_ch; struct ieee80211_rate *rates; int i = 0; - enum { - A = 0, - B = 1, - G = 2, - }; - int mode_count = 3; - if (priv->modes) { + if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || + priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { IWL_DEBUG_INFO("Geography modes already initialized.\n"); set_bit(STATUS_GEO_CONFIGURED, &priv->status); return 0; } - modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count, - GFP_KERNEL); - if (!modes) - return -ENOMEM; - channels = kzalloc(sizeof(struct ieee80211_channel) * priv->channel_count, GFP_KERNEL); - if (!channels) { - kfree(modes); + if (!channels) return -ENOMEM; - } rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)), GFP_KERNEL); if (!rates) { - kfree(modes); kfree(channels); return -ENOMEM; } - /* 0 = 802.11a - * 1 = 802.11b - * 2 = 802.11g - */ - /* 5.2GHz channels start after the 2.4GHz channels */ - modes[A].mode = MODE_IEEE80211A; - modes[A].channels = &channels[ARRAY_SIZE(iwl3945_eeprom_band_1)]; - modes[A].rates = &rates[4]; - modes[A].num_rates = 8; /* just OFDM */ - modes[A].num_channels = 0; - - modes[B].mode = MODE_IEEE80211B; - modes[B].channels = channels; - modes[B].rates = rates; - modes[B].num_rates = 4; /* just CCK */ - modes[B].num_channels = 0; - - modes[G].mode = MODE_IEEE80211G; - modes[G].channels = channels; - modes[G].rates = rates; - modes[G].num_rates = 12; /* OFDM & CCK */ - modes[G].num_channels = 0; + band = &priv->bands[IEEE80211_BAND_5GHZ]; + band->channels = &channels[ARRAY_SIZE(iwl3945_eeprom_band_1)]; + band->bitrates = &rates[4]; + band->n_bitrates = 8; /* just OFDM */ + + band = &priv->bands[IEEE80211_BAND_2GHZ]; + band->channels = channels; + band->bitrates = rates; + band->n_bitrates = 12; /* OFDM & CCK */ priv->ieee_channels = channels; priv->ieee_rates = rates; @@ -5442,37 +5388,32 @@ static int iwl3945_init_geos(struct iwl3945_priv *priv) } if (is_channel_a_band(ch)) - geo_ch = &modes[A].channels[modes[A].num_channels++]; - else { - geo_ch = &modes[B].channels[modes[B].num_channels++]; - modes[G].num_channels++; - } + geo_ch = &priv->bands[IEEE80211_BAND_5GHZ].channels[priv->bands[IEEE80211_BAND_5GHZ].n_channels++]; + else + geo_ch = &priv->bands[IEEE80211_BAND_2GHZ].channels[priv->bands[IEEE80211_BAND_2GHZ].n_channels++]; - geo_ch->freq = ieee80211chan2mhz(ch->channel); - geo_ch->chan = ch->channel; - geo_ch->power_level = ch->max_power_avg; - geo_ch->antenna_max = 0xff; + geo_ch->center_freq = ieee80211chan2mhz(ch->channel); + geo_ch->max_power = ch->max_power_avg; + geo_ch->max_antenna_gain = 0xff; if (is_channel_valid(ch)) { - geo_ch->flag = IEEE80211_CHAN_W_SCAN; - if (ch->flags & EEPROM_CHANNEL_IBSS) - geo_ch->flag |= IEEE80211_CHAN_W_IBSS; + if (!(ch->flags & EEPROM_CHANNEL_IBSS)) + geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; - if (ch->flags & EEPROM_CHANNEL_ACTIVE) - geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN; + if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) + geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; if (ch->flags & EEPROM_CHANNEL_RADAR) - geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT; + geo_ch->flags |= IEEE80211_CHAN_RADAR; if (ch->max_power_avg > priv->max_channel_txpower_limit) priv->max_channel_txpower_limit = ch->max_power_avg; - } - - geo_ch->val = geo_ch->flag; + } else + geo_ch->flags |= IEEE80211_CHAN_DISABLED; } - if ((modes[A].num_channels == 0) && priv->is_abg) { + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && priv->is_abg) { printk(KERN_INFO DRV_NAME ": Incorrectly detected BG card as ABG. Please send " "your PCI ID 0x%04X:0x%04X to maintainer.\n", @@ -5482,24 +5423,12 @@ static int iwl3945_init_geos(struct iwl3945_priv *priv) printk(KERN_INFO DRV_NAME ": Tunable channels: %d 802.11bg, %d 802.11a channels\n", - modes[G].num_channels, modes[A].num_channels); + priv->bands[IEEE80211_BAND_2GHZ].n_channels, + priv->bands[IEEE80211_BAND_5GHZ].n_channels); - /* - * NOTE: We register these in preference of order -- the - * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick - * a phymode based on rates or AP capabilities but seems to - * configure it purely on if the channel being configured - * is supported by a mode -- and the first match is taken - */ - - if (modes[G].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[G]); - if (modes[B].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[B]); - if (modes[A].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[A]); + priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->bands[IEEE80211_BAND_2GHZ]; + priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->bands[IEEE80211_BAND_5GHZ]; - priv->modes = modes; set_bit(STATUS_GEO_CONFIGURED, &priv->status); return 0; @@ -5510,7 +5439,6 @@ static int iwl3945_init_geos(struct iwl3945_priv *priv) */ static void iwl3945_free_geos(struct iwl3945_priv *priv) { - kfree(priv->modes); kfree(priv->ieee_channels); kfree(priv->ieee_rates); clear_bit(STATUS_GEO_CONFIGURED, &priv->status); @@ -6519,7 +6447,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) struct iwl3945_scan_cmd *scan; struct ieee80211_conf *conf = NULL; u8 direct_mask; - int phymode; + enum ieee80211_band band; conf = ieee80211_get_hw_conf(priv->hw); @@ -6651,13 +6579,13 @@ static void iwl3945_bg_request_scan(struct work_struct *data) scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; scan->tx_cmd.rate = IWL_RATE_1M_PLCP; scan->good_CRC_th = 0; - phymode = MODE_IEEE80211G; + band = IEEE80211_BAND_2GHZ; break; case 1: scan->tx_cmd.rate = IWL_RATE_6M_PLCP; scan->good_CRC_th = IWL_GOOD_CRC_TH; - phymode = MODE_IEEE80211A; + band = IEEE80211_BAND_5GHZ; break; default: @@ -6680,7 +6608,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) scan->channel_count = iwl3945_get_channels_for_scan( - priv, phymode, 1, /* active */ + priv, band, 1, /* active */ direct_mask, (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); @@ -6825,7 +6753,7 @@ static void iwl3945_bg_post_associate(struct work_struct *data) iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0); iwl3945_add_station(priv, priv->bssid, 0, 0); iwl3945_sync_sta(priv, IWL_STA_ID, - (priv->phymode == MODE_IEEE80211A)? + (priv->band == IEEE80211_BAND_5GHZ) ? IWL_RATE_6M_PLCP : IWL_RATE_1M_PLCP, CMD_ASYNC); iwl3945_rate_scale_init(priv->hw, IWL_STA_ID); @@ -7020,7 +6948,7 @@ static int iwl3945_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ctl->tx_rate); + ctl->tx_rate->bitrate); if (iwl3945_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); @@ -7079,7 +7007,7 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co int ret = 0; mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel); + IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); @@ -7099,19 +7027,20 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co spin_lock_irqsave(&priv->lock, flags); - ch_info = iwl3945_get_channel_info(priv, conf->phymode, conf->channel); + ch_info = iwl3945_get_channel_info(priv, conf->channel->band, + conf->channel->hw_value); if (!is_channel_valid(ch_info)) { IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n", - conf->channel, conf->phymode); + conf->channel->hw_value, conf->channel->band); IWL_DEBUG_MAC80211("leave - invalid channel\n"); spin_unlock_irqrestore(&priv->lock, flags); ret = -EINVAL; goto out; } - iwl3945_set_rxon_channel(priv, conf->phymode, conf->channel); + iwl3945_set_rxon_channel(priv, conf->channel->band, conf->channel->hw_value); - iwl3945_set_flags_for_phymode(priv, conf->phymode); + iwl3945_set_flags_for_phymode(priv, conf->channel->band); /* The list of supported rates and rate mask can be different * for each phymode; since the phymode may have changed, reset @@ -7892,65 +7821,6 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); -static ssize_t show_tune(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; - - return sprintf(buf, "0x%04X\n", - (priv->phymode << 8) | - le16_to_cpu(priv->active_rxon.channel)); -} - -static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, u8 phymode); - -static ssize_t store_tune(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl3945_priv *priv = (struct iwl3945_priv *)d->driver_data; - char *p = (char *)buf; - u16 tune = simple_strtoul(p, &p, 0); - u8 phymode = (tune >> 8) & 0xff; - u16 channel = tune & 0xff; - - IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel); - - mutex_lock(&priv->mutex); - if ((le16_to_cpu(priv->staging_rxon.channel) != channel) || - (priv->phymode != phymode)) { - const struct iwl3945_channel_info *ch_info; - - ch_info = iwl3945_get_channel_info(priv, phymode, channel); - if (!ch_info) { - IWL_WARNING("Requested invalid phymode/channel " - "combination: %d %d\n", phymode, channel); - mutex_unlock(&priv->mutex); - return -EINVAL; - } - - /* Cancel any currently running scans... */ - if (iwl3945_scan_cancel_timeout(priv, 100)) - IWL_WARNING("Could not cancel scan.\n"); - else { - IWL_DEBUG_INFO("Committing phymode and " - "rxon.channel = %d %d\n", - phymode, channel); - - iwl3945_set_rxon_channel(priv, phymode, channel); - iwl3945_set_flags_for_phymode(priv, phymode); - - iwl3945_set_rate(priv); - iwl3945_commit_rxon(priv); - } - } - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune); - #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT static ssize_t show_measurement(struct device *d, @@ -8165,73 +8035,8 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, static ssize_t show_channels(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl3945_priv *priv = dev_get_drvdata(d); - int len = 0, i; - struct ieee80211_channel *channels = NULL; - const struct ieee80211_hw_mode *hw_mode = NULL; - int count = 0; - - if (!iwl3945_is_ready(priv)) - return -EAGAIN; - - hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211G); - if (!hw_mode) - hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211B); - if (hw_mode) { - channels = hw_mode->channels; - count = hw_mode->num_channels; - } - - len += - sprintf(&buf[len], - "Displaying %d channels in 2.4GHz band " - "(802.11bg):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - channels[i].chan, - channels[i].power_level, - channels[i]. - flag & IEEE80211_CHAN_W_RADAR_DETECT ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) - || (channels[i]. - flag & - IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : - ", IBSS", - channels[i]. - flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? - "active/passive" : "passive only"); - - hw_mode = iwl3945_get_hw_mode(priv, MODE_IEEE80211A); - if (hw_mode) { - channels = hw_mode->channels; - count = hw_mode->num_channels; - } else { - channels = NULL; - count = 0; - } - - len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " - "(802.11a):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - channels[i].chan, - channels[i].power_level, - channels[i]. - flag & IEEE80211_CHAN_W_RADAR_DETECT ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) - || (channels[i]. - flag & - IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : - ", IBSS", - channels[i]. - flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? - "active/passive" : "passive only"); - - return len; + /* all this shit doesn't belong into sysfs anyway */ + return 0; } static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); @@ -8411,7 +8216,6 @@ static struct attribute *iwl3945_sysfs_entries[] = { &dev_attr_statistics.attr, &dev_attr_status.attr, &dev_attr_temperature.attr, - &dev_attr_tune.attr, &dev_attr_tx_power.attr, NULL @@ -8532,7 +8336,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->data_retry_limit = -1; priv->ieee_channels = NULL; priv->ieee_rates = NULL; - priv->phymode = -1; + priv->band = IEEE80211_BAND_2GHZ; err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (!err) @@ -8614,7 +8418,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->qos_data.qos_cap.val = 0; #endif /* CONFIG_IWL3945_QOS */ - iwl3945_set_rxon_channel(priv, MODE_IEEE80211G, 6); + iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); iwl3945_setup_deferred_work(priv); iwl3945_setup_rx_handlers(priv); @@ -8665,7 +8469,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_ERROR("initializing geos failed: %d\n", err); goto out_free_channel_map; } - iwl3945_reset_channel_flag(priv); iwl3945_rate_control_register(priv->hw); err = ieee80211_register_hw(priv->hw); diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index 5f38fc585eda..6de969de4c84 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -115,16 +115,10 @@ __le16 *ieee80211_get_qos_ctrl(struct ieee80211_hdr *hdr) return NULL; } -static const struct ieee80211_hw_mode *iwl4965_get_hw_mode( - struct iwl4965_priv *priv, int mode) +static const struct ieee80211_supported_band *iwl4965_get_hw_mode( + struct iwl4965_priv *priv, enum ieee80211_band band) { - int i; - - for (i = 0; i < 3; i++) - if (priv->modes[i].mode == mode) - return &priv->modes[i]; - - return NULL; + return priv->hw->wiphy->bands[band]; } static int iwl4965_is_empty_essid(const char *essid, int essid_len) @@ -937,28 +931,29 @@ static int iwl4965_rxon_add_station(struct iwl4965_priv *priv, * NOTE: Does not commit to the hardware; it sets appropriate bit fields * in the staging RXON flag structure based on the phymode */ -static int iwl4965_set_rxon_channel(struct iwl4965_priv *priv, u8 phymode, +static int iwl4965_set_rxon_channel(struct iwl4965_priv *priv, + enum ieee80211_band band, u16 channel) { - if (!iwl4965_get_channel_info(priv, phymode, channel)) { + if (!iwl4965_get_channel_info(priv, band, channel)) { IWL_DEBUG_INFO("Could not set channel to %d [%d]\n", - channel, phymode); + channel, band); return -EINVAL; } if ((le16_to_cpu(priv->staging_rxon.channel) == channel) && - (priv->phymode == phymode)) + (priv->band == band)) return 0; priv->staging_rxon.channel = cpu_to_le16(channel); - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK; else priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK; - priv->phymode = phymode; + priv->band = band; - IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode); + IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, band); return 0; } @@ -2571,9 +2566,10 @@ static int iwl4965_set_rxon_hwcrypto(struct iwl4965_priv *priv, int hw_decrypt) return 0; } -static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, u8 phymode) +static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, + enum ieee80211_band band) { - if (phymode == MODE_IEEE80211A) { + if (band == IEEE80211_BAND_5GHZ) { priv->staging_rxon.flags &= ~(RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_CCK_MSK); @@ -2636,7 +2632,7 @@ static void iwl4965_connection_init_rx_config(struct iwl4965_priv *priv) priv->staging_rxon.flags |= RXON_FLG_SHORT_PREAMBLE_MSK; #endif - ch_info = iwl4965_get_channel_info(priv, priv->phymode, + ch_info = iwl4965_get_channel_info(priv, priv->band, le16_to_cpu(priv->staging_rxon.channel)); if (!ch_info) @@ -2651,12 +2647,9 @@ static void iwl4965_connection_init_rx_config(struct iwl4965_priv *priv) ch_info = &priv->channel_info[0]; priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); - if (is_channel_a_band(ch_info)) - priv->phymode = MODE_IEEE80211A; - else - priv->phymode = MODE_IEEE80211G; + priv->band = ch_info->band; - iwl4965_set_flags_for_phymode(priv, priv->phymode); + iwl4965_set_flags_for_phymode(priv, priv->band); priv->staging_rxon.ofdm_basic_rates = (IWL_OFDM_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; @@ -2678,7 +2671,7 @@ static int iwl4965_set_mode(struct iwl4965_priv *priv, int mode) const struct iwl4965_channel_info *ch_info; ch_info = iwl4965_get_channel_info(priv, - priv->phymode, + priv->band, le16_to_cpu(priv->staging_rxon.channel)); if (!ch_info || !is_channel_ibss(ch_info)) { @@ -2918,7 +2911,7 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, goto drop_unlock; } - if ((ctl->tx_rate & 0xFF) == IWL_INVALID_RATE) { + if ((ctl->tx_rate->hw_value & 0xFF) == IWL_INVALID_RATE) { IWL_ERROR("ERROR: No TX rate available.\n"); goto drop_unlock; } @@ -3125,11 +3118,11 @@ drop: static void iwl4965_set_rate(struct iwl4965_priv *priv) { - const struct ieee80211_hw_mode *hw = NULL; + const struct ieee80211_supported_band *hw = NULL; struct ieee80211_rate *rate; int i; - hw = iwl4965_get_hw_mode(priv, priv->phymode); + hw = iwl4965_get_hw_mode(priv, priv->band); if (!hw) { IWL_ERROR("Failed to set rate: unable to get hw mode\n"); return; @@ -3138,24 +3131,10 @@ static void iwl4965_set_rate(struct iwl4965_priv *priv) priv->active_rate = 0; priv->active_rate_basic = 0; - IWL_DEBUG_RATE("Setting rates for 802.11%c\n", - hw->mode == MODE_IEEE80211A ? - 'a' : ((hw->mode == MODE_IEEE80211B) ? 'b' : 'g')); - - for (i = 0; i < hw->num_rates; i++) { - rate = &(hw->rates[i]); - if ((rate->val < IWL_RATE_COUNT) && - (rate->flags & IEEE80211_RATE_SUPPORTED)) { - IWL_DEBUG_RATE("Adding rate index %d (plcp %d)%s\n", - rate->val, iwl4965_rates[rate->val].plcp, - (rate->flags & IEEE80211_RATE_BASIC) ? - "*" : ""); - priv->active_rate |= (1 << rate->val); - if (rate->flags & IEEE80211_RATE_BASIC) - priv->active_rate_basic |= (1 << rate->val); - } else - IWL_DEBUG_RATE("Not adding rate %d (plcp %d)\n", - rate->val, iwl4965_rates[rate->val].plcp); + for (i = 0; i < hw->n_bitrates; i++) { + rate = &(hw->bitrates[i]); + if (rate->hw_value < IWL_RATE_COUNT) + priv->active_rate |= (1 << rate->hw_value); } IWL_DEBUG_RATE("Set active_rate = %0x, active_rate_basic = %0x\n", @@ -3775,9 +3754,6 @@ static void iwl4965_rx_reply_tx(struct iwl4965_priv *priv, tx_status->flags = iwl4965_is_tx_success(status) ? IEEE80211_TX_STATUS_ACK : 0; - tx_status->control.tx_rate = - iwl4965_hw_get_rate_n_flags(tx_resp->rate_n_flags); - IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags 0x%x " "retries %d\n", txq_id, iwl4965_get_tx_fail_reason(status), status, le32_to_cpu(tx_resp->rate_n_flags), @@ -5419,24 +5395,23 @@ static void iwl4965_init_band_reference(const struct iwl4965_priv *priv, * Based on band and channel number. */ const struct iwl4965_channel_info *iwl4965_get_channel_info(const struct iwl4965_priv *priv, - int phymode, u16 channel) + enum ieee80211_band band, u16 channel) { int i; - switch (phymode) { - case MODE_IEEE80211A: + switch (band) { + case IEEE80211_BAND_5GHZ: for (i = 14; i < priv->channel_count; i++) { if (priv->channel_info[i].channel == channel) return &priv->channel_info[i]; } break; - - case MODE_IEEE80211B: - case MODE_IEEE80211G: + case IEEE80211_BAND_2GHZ: if (channel >= 1 && channel <= 14) return &priv->channel_info[channel - 1]; break; - + default: + BUG(); } return NULL; @@ -5499,8 +5474,8 @@ static int iwl4965_init_channel_map(struct iwl4965_priv *priv) /* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) { ch_info->channel = eeprom_ch_index[ch]; - ch_info->phymode = (band == 1) ? MODE_IEEE80211B : - MODE_IEEE80211A; + ch_info->band = (band == 1) ? IEEE80211_BAND_2GHZ : + IEEE80211_BAND_5GHZ; /* permanently store EEPROM's channel regulatory flags * and max power in channel info database. */ @@ -5559,14 +5534,14 @@ static int iwl4965_init_channel_map(struct iwl4965_priv *priv) /* Two additional EEPROM bands for 2.4 and 5 GHz FAT channels */ for (band = 6; band <= 7; band++) { - int phymode; + enum ieee80211_band ieeeband; u8 fat_extension_chan; iwl4965_init_band_reference(priv, band, &eeprom_ch_count, &eeprom_ch_info, &eeprom_ch_index); /* EEPROM band 6 is 2.4, band 7 is 5 GHz */ - phymode = (band == 6) ? MODE_IEEE80211B : MODE_IEEE80211A; + ieeeband = (band == 6) ? IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; /* Loop through each band adding each of the channels */ for (ch = 0; ch < eeprom_ch_count; ch++) { @@ -5580,13 +5555,13 @@ static int iwl4965_init_channel_map(struct iwl4965_priv *priv) fat_extension_chan = HT_IE_EXT_CHANNEL_ABOVE; /* Set up driver's info for lower half */ - iwl4965_set_fat_chan_info(priv, phymode, + iwl4965_set_fat_chan_info(priv, ieeeband, eeprom_ch_index[ch], &(eeprom_ch_info[ch]), fat_extension_chan); /* Set up driver's info for upper half */ - iwl4965_set_fat_chan_info(priv, phymode, + iwl4965_set_fat_chan_info(priv, ieeeband, (eeprom_ch_index[ch] + 4), &(eeprom_ch_info[ch]), HT_IE_EXT_CHANNEL_BELOW); @@ -5628,18 +5603,20 @@ static void iwl4965_free_channel_map(struct iwl4965_priv *priv) #define IWL_PASSIVE_DWELL_BASE (100) #define IWL_CHANNEL_TUNE_TIME 5 -static inline u16 iwl4965_get_active_dwell_time(struct iwl4965_priv *priv, int phymode) +static inline u16 iwl4965_get_active_dwell_time(struct iwl4965_priv *priv, + enum ieee80211_band band) { - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) return IWL_ACTIVE_DWELL_TIME_52; else return IWL_ACTIVE_DWELL_TIME_24; } -static u16 iwl4965_get_passive_dwell_time(struct iwl4965_priv *priv, int phymode) +static u16 iwl4965_get_passive_dwell_time(struct iwl4965_priv *priv, + enum ieee80211_band band) { - u16 active = iwl4965_get_active_dwell_time(priv, phymode); - u16 passive = (phymode != MODE_IEEE80211A) ? + u16 active = iwl4965_get_active_dwell_time(priv, band); + u16 passive = (band != IEEE80211_BAND_5GHZ) ? IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 : IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52; @@ -5659,28 +5636,29 @@ static u16 iwl4965_get_passive_dwell_time(struct iwl4965_priv *priv, int phymode return passive; } -static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode, +static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, + enum ieee80211_band band, u8 is_active, u8 direct_mask, struct iwl4965_scan_channel *scan_ch) { const struct ieee80211_channel *channels = NULL; - const struct ieee80211_hw_mode *hw_mode; + const struct ieee80211_supported_band *sband; const struct iwl4965_channel_info *ch_info; u16 passive_dwell = 0; u16 active_dwell = 0; int added, i; - hw_mode = iwl4965_get_hw_mode(priv, phymode); - if (!hw_mode) + sband = iwl4965_get_hw_mode(priv, band); + if (!sband) return 0; - channels = hw_mode->channels; + channels = sband->channels; - active_dwell = iwl4965_get_active_dwell_time(priv, phymode); - passive_dwell = iwl4965_get_passive_dwell_time(priv, phymode); + active_dwell = iwl4965_get_active_dwell_time(priv, band); + passive_dwell = iwl4965_get_passive_dwell_time(priv, band); - for (i = 0, added = 0; i < hw_mode->num_channels; i++) { - if (channels[i].chan == + for (i = 0, added = 0; i < sband->n_channels; i++) { + if (ieee80211_frequency_to_channel(channels[i].center_freq) == le16_to_cpu(priv->active_rxon.channel)) { if (iwl4965_is_associated(priv)) { IWL_DEBUG_SCAN @@ -5691,9 +5669,9 @@ static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode, } else if (priv->only_active_channel) continue; - scan_ch->channel = channels[i].chan; + scan_ch->channel = ieee80211_frequency_to_channel(channels[i].center_freq); - ch_info = iwl4965_get_channel_info(priv, phymode, + ch_info = iwl4965_get_channel_info(priv, band, scan_ch->channel); if (!is_channel_valid(ch_info)) { IWL_DEBUG_SCAN("Channel %d is INVALID for this SKU.\n", @@ -5702,7 +5680,7 @@ static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode, } if (!is_active || is_channel_passive(ch_info) || - !(channels[i].flag & IEEE80211_CHAN_W_ACTIVE_SCAN)) + (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) scan_ch->type = 0; /* passive */ else scan_ch->type = 1; /* active */ @@ -5721,7 +5699,7 @@ static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode, /* scan_pwr_info->tpc.dsp_atten; */ /*scan_pwr_info->tpc.tx_gain; */ - if (phymode == MODE_IEEE80211A) + if (band == IEEE80211_BAND_5GHZ) scan_ch->tpc.tx_gain = ((1 << 5) | (3 << 3)) | 3; else { scan_ch->tpc.tx_gain = ((1 << 5) | (5 << 3)); @@ -5745,41 +5723,23 @@ static int iwl4965_get_channels_for_scan(struct iwl4965_priv *priv, int phymode, return added; } -static void iwl4965_reset_channel_flag(struct iwl4965_priv *priv) -{ - int i, j; - for (i = 0; i < 3; i++) { - struct ieee80211_hw_mode *hw_mode = (void *)&priv->modes[i]; - for (j = 0; j < hw_mode->num_channels; j++) - hw_mode->channels[j].flag = hw_mode->channels[j].val; - } -} - static void iwl4965_init_hw_rates(struct iwl4965_priv *priv, struct ieee80211_rate *rates) { int i; for (i = 0; i < IWL_RATE_COUNT; i++) { - rates[i].rate = iwl4965_rates[i].ieee * 5; - rates[i].val = i; /* Rate scaling will work on indexes */ - rates[i].val2 = i; - rates[i].flags = IEEE80211_RATE_SUPPORTED; - /* Only OFDM have the bits-per-symbol set */ - if ((i <= IWL_LAST_OFDM_RATE) && (i >= IWL_FIRST_OFDM_RATE)) - rates[i].flags |= IEEE80211_RATE_OFDM; - else { + rates[i].bitrate = iwl4965_rates[i].ieee * 5; + rates[i].hw_value = i; /* Rate scaling will work on indexes */ + rates[i].hw_value_short = i; + rates[i].flags = 0; + if ((i > IWL_LAST_OFDM_RATE) || (i < IWL_FIRST_OFDM_RATE)) { /* - * If CCK 1M then set rate flag to CCK else CCK_2 - * which is CCK | PREAMBLE2 + * If CCK != 1M then set short preamble rate flag. */ rates[i].flags |= (iwl4965_rates[i].plcp == 10) ? - IEEE80211_RATE_CCK : IEEE80211_RATE_CCK_2; + 0 : IEEE80211_RATE_SHORT_PREAMBLE; } - - /* Set up which ones are basic rates... */ - if (IWL_BASIC_RATES_MASK & (1 << i)) - rates[i].flags |= IEEE80211_RATE_BASIC; } } @@ -5789,74 +5749,47 @@ static void iwl4965_init_hw_rates(struct iwl4965_priv *priv, static int iwl4965_init_geos(struct iwl4965_priv *priv) { struct iwl4965_channel_info *ch; - struct ieee80211_hw_mode *modes; + struct ieee80211_supported_band *band; struct ieee80211_channel *channels; struct ieee80211_channel *geo_ch; struct ieee80211_rate *rates; int i = 0; - enum { - A = 0, - B = 1, - G = 2, - }; - int mode_count = 3; - if (priv->modes) { + if (priv->bands[IEEE80211_BAND_2GHZ].n_bitrates || + priv->bands[IEEE80211_BAND_5GHZ].n_bitrates) { IWL_DEBUG_INFO("Geography modes already initialized.\n"); set_bit(STATUS_GEO_CONFIGURED, &priv->status); return 0; } - modes = kzalloc(sizeof(struct ieee80211_hw_mode) * mode_count, - GFP_KERNEL); - if (!modes) - return -ENOMEM; - channels = kzalloc(sizeof(struct ieee80211_channel) * priv->channel_count, GFP_KERNEL); - if (!channels) { - kfree(modes); + if (!channels) return -ENOMEM; - } rates = kzalloc((sizeof(struct ieee80211_rate) * (IWL_MAX_RATES + 1)), GFP_KERNEL); if (!rates) { - kfree(modes); kfree(channels); return -ENOMEM; } - /* 0 = 802.11a - * 1 = 802.11b - * 2 = 802.11g - */ - /* 5.2GHz channels start after the 2.4GHz channels */ - modes[A].mode = MODE_IEEE80211A; - modes[A].channels = &channels[ARRAY_SIZE(iwl4965_eeprom_band_1)]; - modes[A].rates = rates; - modes[A].num_rates = 8; /* just OFDM */ - modes[A].rates = &rates[4]; - modes[A].num_channels = 0; #ifdef CONFIG_IWL4965_HT iwl4965_init_ht_hw_capab(&modes[A].ht_info, MODE_IEEE80211A); #endif - - modes[B].mode = MODE_IEEE80211B; - modes[B].channels = channels; - modes[B].rates = rates; - modes[B].num_rates = 4; /* just CCK */ - modes[B].num_channels = 0; - - modes[G].mode = MODE_IEEE80211G; - modes[G].channels = channels; - modes[G].rates = rates; - modes[G].num_rates = 12; /* OFDM & CCK */ - modes[G].num_channels = 0; #ifdef CONFIG_IWL4965_HT iwl4965_init_ht_hw_capab(&modes[G].ht_info, MODE_IEEE80211G); #endif + band = &priv->bands[IEEE80211_BAND_5GHZ]; + band->channels = &channels[ARRAY_SIZE(iwl4965_eeprom_band_1)]; + band->bitrates = &rates[4]; + band->n_bitrates = 8; /* just OFDM */ + + band = &priv->bands[IEEE80211_BAND_2GHZ]; + band->channels = channels; + band->bitrates = rates; + band->n_bitrates = 12; /* OFDM & CCK */ priv->ieee_channels = channels; priv->ieee_rates = rates; @@ -5875,37 +5808,32 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv) } if (is_channel_a_band(ch)) { - geo_ch = &modes[A].channels[modes[A].num_channels++]; - } else { - geo_ch = &modes[B].channels[modes[B].num_channels++]; - modes[G].num_channels++; - } + geo_ch = &priv->bands[IEEE80211_BAND_5GHZ].channels[priv->bands[IEEE80211_BAND_5GHZ].n_channels++]; + } else + geo_ch = &priv->bands[IEEE80211_BAND_2GHZ].channels[priv->bands[IEEE80211_BAND_2GHZ].n_channels++]; - geo_ch->freq = ieee80211chan2mhz(ch->channel); - geo_ch->chan = ch->channel; - geo_ch->power_level = ch->max_power_avg; - geo_ch->antenna_max = 0xff; + geo_ch->center_freq = ieee80211chan2mhz(ch->channel); + geo_ch->max_power = ch->max_power_avg; + geo_ch->max_antenna_gain = 0xff; if (is_channel_valid(ch)) { - geo_ch->flag = IEEE80211_CHAN_W_SCAN; - if (ch->flags & EEPROM_CHANNEL_IBSS) - geo_ch->flag |= IEEE80211_CHAN_W_IBSS; + if (!(ch->flags & EEPROM_CHANNEL_IBSS)) + geo_ch->flags |= IEEE80211_CHAN_NO_IBSS; - if (ch->flags & EEPROM_CHANNEL_ACTIVE) - geo_ch->flag |= IEEE80211_CHAN_W_ACTIVE_SCAN; + if (!(ch->flags & EEPROM_CHANNEL_ACTIVE)) + geo_ch->flags |= IEEE80211_CHAN_PASSIVE_SCAN; if (ch->flags & EEPROM_CHANNEL_RADAR) - geo_ch->flag |= IEEE80211_CHAN_W_RADAR_DETECT; + geo_ch->flags |= IEEE80211_CHAN_RADAR; if (ch->max_power_avg > priv->max_channel_txpower_limit) priv->max_channel_txpower_limit = ch->max_power_avg; - } - - geo_ch->val = geo_ch->flag; + } else + geo_ch->flags |= IEEE80211_CHAN_DISABLED; } - if ((modes[A].num_channels == 0) && priv->is_abg) { + if ((priv->bands[IEEE80211_BAND_5GHZ].n_channels == 0) && priv->is_abg) { printk(KERN_INFO DRV_NAME ": Incorrectly detected BG card as ABG. Please send " "your PCI ID 0x%04X:0x%04X to maintainer.\n", @@ -5915,24 +5843,12 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv) printk(KERN_INFO DRV_NAME ": Tunable channels: %d 802.11bg, %d 802.11a channels\n", - modes[G].num_channels, modes[A].num_channels); - - /* - * NOTE: We register these in preference of order -- the - * stack doesn't currently (as of 7.0.6 / Apr 24 '07) pick - * a phymode based on rates or AP capabilities but seems to - * configure it purely on if the channel being configured - * is supported by a mode -- and the first match is taken - */ + priv->bands[IEEE80211_BAND_2GHZ].n_channels, + priv->bands[IEEE80211_BAND_5GHZ].n_channels); - if (modes[G].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[G]); - if (modes[B].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[B]); - if (modes[A].num_channels) - ieee80211_register_hwmode(priv->hw, &modes[A]); + priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->bands[IEEE80211_BAND_2GHZ]; + priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &priv->bands[IEEE80211_BAND_5GHZ]; - priv->modes = modes; set_bit(STATUS_GEO_CONFIGURED, &priv->status); return 0; @@ -5943,7 +5859,6 @@ static int iwl4965_init_geos(struct iwl4965_priv *priv) */ static void iwl4965_free_geos(struct iwl4965_priv *priv) { - kfree(priv->modes); kfree(priv->ieee_channels); kfree(priv->ieee_rates); clear_bit(STATUS_GEO_CONFIGURED, &priv->status); @@ -6945,7 +6860,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data) struct iwl4965_scan_cmd *scan; struct ieee80211_conf *conf = NULL; u8 direct_mask; - int phymode; + enum ieee80211_band band; conf = ieee80211_get_hw_conf(priv->hw); @@ -7075,7 +6990,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data) RATE_MCS_ANT_B_MSK|RATE_MCS_CCK_MSK); scan->good_CRC_th = 0; - phymode = MODE_IEEE80211G; + band = IEEE80211_BAND_2GHZ; break; case 1: @@ -7083,7 +6998,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data) iwl4965_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, RATE_MCS_ANT_B_MSK); scan->good_CRC_th = IWL_GOOD_CRC_TH; - phymode = MODE_IEEE80211A; + band = IEEE80211_BAND_5GHZ; break; default: @@ -7113,7 +7028,7 @@ static void iwl4965_bg_request_scan(struct work_struct *data) scan->channel_count = iwl4965_get_channels_for_scan( - priv, phymode, 1, /* active */ + priv, band, 1, /* active */ direct_mask, (void *)&scan->data[le16_to_cpu(scan->tx_cmd.len)]); @@ -7463,7 +7378,7 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb, } IWL_DEBUG_TX("dev->xmit(%d bytes) at rate 0x%02x\n", skb->len, - ctl->tx_rate); + ctl->tx_rate->bitrate); if (iwl4965_tx_skb(priv, skb, ctl)) dev_kfree_skb_any(skb); @@ -7522,7 +7437,7 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co int ret = 0; mutex_lock(&priv->mutex); - IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel); + IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); priv->add_radiotap = !!(conf->flags & IEEE80211_CONF_RADIOTAP); @@ -7542,10 +7457,9 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co spin_lock_irqsave(&priv->lock, flags); - ch_info = iwl4965_get_channel_info(priv, conf->phymode, conf->channel); + ch_info = iwl4965_get_channel_info(priv, conf->channel->band, + ieee80211_frequency_to_channel(conf->channel->center_freq)); if (!is_channel_valid(ch_info)) { - IWL_DEBUG_SCAN("Channel %d [%d] is INVALID for this SKU.\n", - conf->channel, conf->phymode); IWL_DEBUG_MAC80211("leave - invalid channel\n"); spin_unlock_irqrestore(&priv->lock, flags); ret = -EINVAL; @@ -7564,12 +7478,13 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co priv->staging_rxon.flags = 0; #endif /* CONFIG_IWL4965_HT */ - iwl4965_set_rxon_channel(priv, conf->phymode, conf->channel); + iwl4965_set_rxon_channel(priv, conf->channel->band, + ieee80211_frequency_to_channel(conf->channel->center_freq)); - iwl4965_set_flags_for_phymode(priv, conf->phymode); + iwl4965_set_flags_for_phymode(priv, conf->channel->band); /* The list of supported rates and rate mask can be different - * for each phymode; since the phymode may have changed, reset + * for each band; since the band may have changed, reset * the rate mask to what mac80211 lists */ iwl4965_set_rate(priv); @@ -7839,7 +7754,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, } if (changes & BSS_CHANGED_ERP_CTS_PROT) { - if (bss_conf->use_cts_prot && (priv->phymode != MODE_IEEE80211A)) + if (bss_conf->use_cts_prot && (priv->band != IEEE80211_BAND_5GHZ)) priv->staging_rxon.flags |= RXON_FLG_TGG_PROTECT_MSK; else priv->staging_rxon.flags &= ~RXON_FLG_TGG_PROTECT_MSK; @@ -8277,7 +8192,6 @@ static void iwl4965_set_ht_capab(struct ieee80211_hw *hw, u8 use_current_config) { struct ieee80211_conf *conf = &hw->conf; - struct ieee80211_hw_mode *mode = conf->mode; if (use_current_config) { ht_cap->cap_info = cpu_to_le16(conf->ht_conf.cap); @@ -8488,65 +8402,6 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); -static ssize_t show_tune(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; - - return sprintf(buf, "0x%04X\n", - (priv->phymode << 8) | - le16_to_cpu(priv->active_rxon.channel)); -} - -static void iwl4965_set_flags_for_phymode(struct iwl4965_priv *priv, u8 phymode); - -static ssize_t store_tune(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl4965_priv *priv = (struct iwl4965_priv *)d->driver_data; - char *p = (char *)buf; - u16 tune = simple_strtoul(p, &p, 0); - u8 phymode = (tune >> 8) & 0xff; - u16 channel = tune & 0xff; - - IWL_DEBUG_INFO("Tune request to:%d channel:%d\n", phymode, channel); - - mutex_lock(&priv->mutex); - if ((le16_to_cpu(priv->staging_rxon.channel) != channel) || - (priv->phymode != phymode)) { - const struct iwl4965_channel_info *ch_info; - - ch_info = iwl4965_get_channel_info(priv, phymode, channel); - if (!ch_info) { - IWL_WARNING("Requested invalid phymode/channel " - "combination: %d %d\n", phymode, channel); - mutex_unlock(&priv->mutex); - return -EINVAL; - } - - /* Cancel any currently running scans... */ - if (iwl4965_scan_cancel_timeout(priv, 100)) - IWL_WARNING("Could not cancel scan.\n"); - else { - IWL_DEBUG_INFO("Committing phymode and " - "rxon.channel = %d %d\n", - phymode, channel); - - iwl4965_set_rxon_channel(priv, phymode, channel); - iwl4965_set_flags_for_phymode(priv, phymode); - - iwl4965_set_rate(priv); - iwl4965_commit_rxon(priv); - } - } - mutex_unlock(&priv->mutex); - - return count; -} - -static DEVICE_ATTR(tune, S_IWUSR | S_IRUGO, show_tune, store_tune); - #ifdef CONFIG_IWL4965_SPECTRUM_MEASUREMENT static ssize_t show_measurement(struct device *d, @@ -8736,73 +8591,8 @@ static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, static ssize_t show_channels(struct device *d, struct device_attribute *attr, char *buf) { - struct iwl4965_priv *priv = dev_get_drvdata(d); - int len = 0, i; - struct ieee80211_channel *channels = NULL; - const struct ieee80211_hw_mode *hw_mode = NULL; - int count = 0; - - if (!iwl4965_is_ready(priv)) - return -EAGAIN; - - hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211G); - if (!hw_mode) - hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211B); - if (hw_mode) { - channels = hw_mode->channels; - count = hw_mode->num_channels; - } - - len += - sprintf(&buf[len], - "Displaying %d channels in 2.4GHz band " - "(802.11bg):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - channels[i].chan, - channels[i].power_level, - channels[i]. - flag & IEEE80211_CHAN_W_RADAR_DETECT ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) - || (channels[i]. - flag & - IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : - ", IBSS", - channels[i]. - flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? - "active/passive" : "passive only"); - - hw_mode = iwl4965_get_hw_mode(priv, MODE_IEEE80211A); - if (hw_mode) { - channels = hw_mode->channels; - count = hw_mode->num_channels; - } else { - channels = NULL; - count = 0; - } - - len += sprintf(&buf[len], "Displaying %d channels in 5.2GHz band " - "(802.11a):\n", count); - - for (i = 0; i < count; i++) - len += sprintf(&buf[len], "%d: %ddBm: BSS%s%s, %s.\n", - channels[i].chan, - channels[i].power_level, - channels[i]. - flag & IEEE80211_CHAN_W_RADAR_DETECT ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flag & IEEE80211_CHAN_W_IBSS) - || (channels[i]. - flag & - IEEE80211_CHAN_W_RADAR_DETECT)) ? "" : - ", IBSS", - channels[i]. - flag & IEEE80211_CHAN_W_ACTIVE_SCAN ? - "active/passive" : "passive only"); - - return len; + /* all this shit doesn't belong into sysfs anyway */ + return 0; } static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); @@ -8981,7 +8771,6 @@ static struct attribute *iwl4965_sysfs_entries[] = { &dev_attr_statistics.attr, &dev_attr_status.attr, &dev_attr_temperature.attr, - &dev_attr_tune.attr, &dev_attr_tx_power.attr, NULL @@ -9109,7 +8898,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->data_retry_limit = -1; priv->ieee_channels = NULL; priv->ieee_rates = NULL; - priv->phymode = -1; + priv->band = IEEE80211_BAND_2GHZ; err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (!err) @@ -9175,7 +8964,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e priv->qos_data.qos_cap.val = 0; #endif /* CONFIG_IWL4965_QOS */ - iwl4965_set_rxon_channel(priv, MODE_IEEE80211G, 6); + iwl4965_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); iwl4965_setup_deferred_work(priv); iwl4965_setup_rx_handlers(priv); @@ -9226,7 +9015,6 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e IWL_ERROR("initializing geos failed: %d\n", err); goto out_free_channel_map; } - iwl4965_reset_channel_flag(priv); iwl4965_rate_control_register(priv->hw); err = ieee80211_register_hw(priv->hw); diff --git a/drivers/net/wireless/p54.h b/drivers/net/wireless/p54.h index 744c866066c5..06d2c67f4c81 100644 --- a/drivers/net/wireless/p54.h +++ b/drivers/net/wireless/p54.h @@ -64,10 +64,6 @@ struct p54_common { unsigned int tx_hdr_len; void *cached_vdcf; unsigned int fw_var; - /* FIXME: this channels/modes/rates stuff sucks */ - struct ieee80211_channel channels[14]; - struct ieee80211_rate rates[12]; - struct ieee80211_hw_mode modes[2]; struct ieee80211_tx_queue_stats tx_stats; }; diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c index 5cda49aff3a8..218ff7770ef6 100644 --- a/drivers/net/wireless/p54common.c +++ b/drivers/net/wireless/p54common.c @@ -27,6 +27,46 @@ MODULE_DESCRIPTION("Softmac Prism54 common code"); MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54common"); +static struct ieee80211_rate p54_rates[] = { + { .bitrate = 10, .hw_value = 0, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 20, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static struct ieee80211_channel p54_channels[] = { + { .center_freq = 2412, .hw_value = 1, }, + { .center_freq = 2417, .hw_value = 2, }, + { .center_freq = 2422, .hw_value = 3, }, + { .center_freq = 2427, .hw_value = 4, }, + { .center_freq = 2432, .hw_value = 5, }, + { .center_freq = 2437, .hw_value = 6, }, + { .center_freq = 2442, .hw_value = 7, }, + { .center_freq = 2447, .hw_value = 8, }, + { .center_freq = 2452, .hw_value = 9, }, + { .center_freq = 2457, .hw_value = 10, }, + { .center_freq = 2462, .hw_value = 11, }, + { .center_freq = 2467, .hw_value = 12, }, + { .center_freq = 2472, .hw_value = 13, }, + { .center_freq = 2484, .hw_value = 14, }, +}; + +struct ieee80211_supported_band band_2GHz = { + .channels = p54_channels, + .n_channels = ARRAY_SIZE(p54_channels), + .bitrates = p54_rates, + .n_bitrates = ARRAY_SIZE(p54_rates), +}; + + void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) { struct p54_common *priv = dev->priv; @@ -308,10 +348,10 @@ static void p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) u16 freq = le16_to_cpu(hdr->freq); rx_status.ssi = hdr->rssi; - rx_status.rate = hdr->rate & 0x1f; /* report short preambles & CCK too */ - rx_status.channel = freq == 2484 ? 14 : (freq - 2407)/5; + /* XX correct? */ + rx_status.rate_idx = hdr->rate & 0xf; rx_status.freq = freq; - rx_status.phymode = MODE_IEEE80211G; + rx_status.band = IEEE80211_BAND_2GHZ; rx_status.antenna = hdr->antenna; rx_status.mactime = le64_to_cpu(hdr->timestamp); rx_status.flag |= RX_FLAG_TSFT; @@ -547,7 +587,9 @@ static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb, txhdr->padding2 = 0; /* TODO: add support for alternate retry TX rates */ - rate = control->tx_rate; + rate = control->tx_rate->hw_value; + if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + rate |= 0x10; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) rate |= 0x40; else if (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) @@ -849,7 +891,7 @@ static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { int ret; - ret = p54_set_freq(dev, cpu_to_le16(conf->freq)); + ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); p54_set_vdcf(dev); return ret; } @@ -944,7 +986,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) { struct ieee80211_hw *dev; struct p54_common *priv; - int i; dev = ieee80211_alloc_hw(priv_data_len, &p54_ops); if (!dev) @@ -953,18 +994,7 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) priv = dev->priv; priv->mode = IEEE80211_IF_TYPE_INVALID; skb_queue_head_init(&priv->tx_queue); - memcpy(priv->channels, p54_channels, sizeof(p54_channels)); - memcpy(priv->rates, p54_rates, sizeof(p54_rates)); - priv->modes[1].mode = MODE_IEEE80211B; - priv->modes[1].num_rates = 4; - priv->modes[1].rates = priv->rates; - priv->modes[1].num_channels = ARRAY_SIZE(p54_channels); - priv->modes[1].channels = priv->channels; - priv->modes[0].mode = MODE_IEEE80211G; - priv->modes[0].num_rates = ARRAY_SIZE(p54_rates); - priv->modes[0].rates = priv->rates; - priv->modes[0].num_channels = ARRAY_SIZE(p54_channels); - priv->modes[0].channels = priv->channels; + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ IEEE80211_HW_RX_INCLUDES_FCS; dev->channel_change_time = 1000; /* TODO: find actual value */ @@ -986,14 +1016,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) p54_init_vdcf(dev); - for (i = 0; i < 2; i++) { - if (ieee80211_register_hwmode(dev, &priv->modes[i])) { - kfree(priv->cached_vdcf); - ieee80211_free_hw(dev); - return NULL; - } - } - return dev; } EXPORT_SYMBOL_GPL(p54_init_common); diff --git a/drivers/net/wireless/p54common.h b/drivers/net/wireless/p54common.h index a721334e20d9..dc9f4cef585e 100644 --- a/drivers/net/wireless/p54common.h +++ b/drivers/net/wireless/p54common.h @@ -251,79 +251,4 @@ struct p54_tx_control_vdcf { __le16 frameburst; } __attribute__ ((packed)); -static const struct ieee80211_rate p54_rates[] = { - { .rate = 10, - .val = 0, - .val2 = 0x10, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 20, - .val = 1, - .val2 = 0x11, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 55, - .val = 2, - .val2 = 0x12, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 110, - .val = 3, - .val2 = 0x13, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 60, - .val = 4, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 90, - .val = 5, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 120, - .val = 6, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 180, - .val = 7, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 240, - .val = 8, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 360, - .val = 9, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 480, - .val = 10, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 540, - .val = 11, - .flags = IEEE80211_RATE_OFDM }, -}; - -// TODO: just generate this.. -static const struct ieee80211_channel p54_channels[] = { - { .chan = 1, - .freq = 2412}, - { .chan = 2, - .freq = 2417}, - { .chan = 3, - .freq = 2422}, - { .chan = 4, - .freq = 2427}, - { .chan = 5, - .freq = 2432}, - { .chan = 6, - .freq = 2437}, - { .chan = 7, - .freq = 2442}, - { .chan = 8, - .freq = 2447}, - { .chan = 9, - .freq = 2452}, - { .chan = 10, - .freq = 2457}, - { .chan = 11, - .freq = 2462}, - { .chan = 12, - .freq = 2467}, - { .chan = 13, - .freq = 2472}, - { .chan = 14, - .freq = 2484} -}; - #endif /* PRISM54COMMON_H */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index b0e4ea7c9dca..4fa762bdb734 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -390,6 +390,10 @@ static inline struct rt2x00_intf* vif_to_intf(struct ieee80211_vif *vif) return (struct rt2x00_intf *)vif->drv_priv; } +#define HWMODE_B 0 +#define HWMODE_G 1 +#define HWMODE_A 2 + /* * Details about the supported modes, rates and channels * of a particular chipset. This is used by rt2x00lib @@ -644,11 +648,8 @@ struct rt2x00_dev { * IEEE80211 control structure. */ struct ieee80211_hw *hw; - struct ieee80211_hw_mode *hwmodes; - unsigned int curr_hwmode; -#define HWMODE_B 0 -#define HWMODE_G 1 -#define HWMODE_A 2 + struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; + enum ieee80211_band curr_band; /* * rfkill structure for RF state switching support. diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 20231e0c53fa..9fba485a40ac 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -152,7 +152,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, const int force_config) { struct rt2x00lib_conf libconf; - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *band; struct ieee80211_rate *rate; struct antenna_setup *default_ant = &rt2x00dev->default_ant; struct antenna_setup *active_ant = &rt2x00dev->link.ant.active; @@ -172,9 +172,9 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, * Check which configuration options have been * updated and should be send to the device. */ - if (rt2x00dev->rx_status.phymode != conf->phymode) + if (rt2x00dev->rx_status.band != conf->channel->band) flags |= CONFIG_UPDATE_PHYMODE; - if (rt2x00dev->rx_status.channel != conf->channel) + if (rt2x00dev->rx_status.freq != conf->channel->center_freq) flags |= CONFIG_UPDATE_CHANNEL; if (rt2x00dev->tx_power != conf->power_level) flags |= CONFIG_UPDATE_TXPOWER; @@ -229,33 +229,31 @@ config: memset(&libconf, 0, sizeof(libconf)); if (flags & CONFIG_UPDATE_PHYMODE) { - switch (conf->phymode) { - case MODE_IEEE80211A: + switch (conf->channel->band) { + case IEEE80211_BAND_5GHZ: libconf.phymode = HWMODE_A; break; - case MODE_IEEE80211B: - libconf.phymode = HWMODE_B; - break; - case MODE_IEEE80211G: + case IEEE80211_BAND_2GHZ: + /* Uh oh. what about B? */ libconf.phymode = HWMODE_G; break; default: ERROR(rt2x00dev, "Attempt to configure unsupported mode (%d)" - "Defaulting to 802.11b", conf->phymode); + "Defaulting to 802.11b", conf->channel->band); libconf.phymode = HWMODE_B; } - mode = &rt2x00dev->hwmodes[libconf.phymode]; - rate = &mode->rates[mode->num_rates - 1]; + band = &rt2x00dev->bands[conf->channel->band]; + rate = &band->bitrates[band->n_bitrates - 1]; libconf.basic_rates = - DEVICE_GET_RATE_FIELD(rate->val, RATEMASK) & DEV_BASIC_RATEMASK; + DEVICE_GET_RATE_FIELD(rate->hw_value, RATEMASK) & DEV_BASIC_RATEMASK; } if (flags & CONFIG_UPDATE_CHANNEL) { memcpy(&libconf.rf, - &rt2x00dev->spec.channels[conf->channel_val], + &rt2x00dev->spec.channels[conf->channel->hw_value], sizeof(libconf.rf)); } @@ -301,12 +299,11 @@ config: rt2x00lib_reset_link_tuner(rt2x00dev); if (flags & CONFIG_UPDATE_PHYMODE) { - rt2x00dev->curr_hwmode = libconf.phymode; - rt2x00dev->rx_status.phymode = conf->phymode; + rt2x00dev->curr_band = conf->channel->band; + rt2x00dev->rx_status.band = conf->channel->band; } - rt2x00dev->rx_status.freq = conf->freq; - rt2x00dev->rx_status.channel = conf->channel; + rt2x00dev->rx_status.freq = conf->channel->center_freq; rt2x00dev->tx_power = conf->power_level; if (flags & CONFIG_UPDATE_ANTENNA) { diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 0df8062b1a8e..83a72ae36638 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -550,19 +550,19 @@ void rt2x00lib_rxdone(struct queue_entry *entry, { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct ieee80211_rx_status *rx_status = &rt2x00dev->rx_status; - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; struct ieee80211_rate *rate; struct ieee80211_hdr *hdr; unsigned int i; - int val = 0; + int val = 0, idx = -1; u16 fc; /* * Update RX statistics. */ - mode = &rt2x00dev->hwmodes[rt2x00dev->curr_hwmode]; - for (i = 0; i < mode->num_rates; i++) { - rate = &mode->rates[i]; + sband = &rt2x00dev->bands[rt2x00dev->curr_band]; + for (i = 0; i < sband->n_bitrates; i++) { + rate = &sband->bitrates[i]; /* * When frame was received with an OFDM bitrate, @@ -570,12 +570,12 @@ void rt2x00lib_rxdone(struct queue_entry *entry, * a CCK bitrate the signal is the rate in 0.5kbit/s. */ if (!rxdesc->ofdm) - val = DEVICE_GET_RATE_FIELD(rate->val, RATE); + val = DEVICE_GET_RATE_FIELD(rate->hw_value, RATE); else - val = DEVICE_GET_RATE_FIELD(rate->val, PLCP); + val = DEVICE_GET_RATE_FIELD(rate->hw_value, PLCP); if (val == rxdesc->signal) { - val = rate->val; + idx = i; break; } } @@ -590,7 +590,7 @@ void rt2x00lib_rxdone(struct queue_entry *entry, rt2x00dev->link.qual.rx_success++; - rx_status->rate = val; + rx_status->rate_idx = idx; rx_status->signal = rt2x00lib_calculate_link_signal(rt2x00dev, rxdesc->rssi); rx_status->ssi = rxdesc->rssi; @@ -639,7 +639,7 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, frame_control = le16_to_cpu(ieee80211hdr->frame_control); seq_ctrl = le16_to_cpu(ieee80211hdr->seq_ctrl); - tx_rate = control->tx_rate; + tx_rate = control->tx_rate->hw_value; /* * Check whether this frame is to be acked @@ -658,7 +658,7 @@ void rt2x00lib_write_tx_desc(struct rt2x00_dev *rt2x00dev, } else __clear_bit(ENTRY_TXD_ACK, &txdesc.flags); if (control->rts_cts_rate) - tx_rate = control->rts_cts_rate; + tx_rate = control->rts_cts_rate->hw_value; } /* @@ -760,54 +760,45 @@ static void rt2x00lib_channel(struct ieee80211_channel *entry, const int channel, const int tx_power, const int value) { - entry->chan = channel; if (channel <= 14) - entry->freq = 2407 + (5 * channel); + entry->center_freq = 2407 + (5 * channel); else - entry->freq = 5000 + (5 * channel); - entry->val = value; - entry->flag = - IEEE80211_CHAN_W_IBSS | - IEEE80211_CHAN_W_ACTIVE_SCAN | - IEEE80211_CHAN_W_SCAN; - entry->power_level = tx_power; - entry->antenna_max = 0xff; + entry->center_freq = 5000 + (5 * channel); + entry->hw_value = value; + entry->max_power = tx_power; + entry->max_antenna_gain = 0xff; } static void rt2x00lib_rate(struct ieee80211_rate *entry, const int rate, const int mask, const int plcp, const int flags) { - entry->rate = rate; - entry->val = + entry->bitrate = rate; + entry->hw_value = DEVICE_SET_RATE_FIELD(rate, RATE) | DEVICE_SET_RATE_FIELD(mask, RATEMASK) | DEVICE_SET_RATE_FIELD(plcp, PLCP); entry->flags = flags; - entry->val2 = entry->val; - if (entry->flags & IEEE80211_RATE_PREAMBLE2) - entry->val2 |= DEVICE_SET_RATE_FIELD(1, PREAMBLE); - entry->min_rssi_ack = 0; - entry->min_rssi_ack_delta = 0; + entry->hw_value_short = entry->hw_value; + if (entry->flags & IEEE80211_RATE_SHORT_PREAMBLE) + entry->hw_value_short |= DEVICE_SET_RATE_FIELD(1, PREAMBLE); } static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, struct hw_mode_spec *spec) { struct ieee80211_hw *hw = rt2x00dev->hw; - struct ieee80211_hw_mode *hwmodes; + struct ieee80211_supported_band *sbands; struct ieee80211_channel *channels; struct ieee80211_rate *rates; unsigned int i; unsigned char tx_power; - hwmodes = kzalloc(sizeof(*hwmodes) * spec->num_modes, GFP_KERNEL); - if (!hwmodes) - goto exit; + sbands = &rt2x00dev->bands[0]; channels = kzalloc(sizeof(*channels) * spec->num_channels, GFP_KERNEL); if (!channels) - goto exit_free_modes; + return -ENOMEM; rates = kzalloc(sizeof(*rates) * spec->num_rates, GFP_KERNEL); if (!rates) @@ -817,31 +808,31 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, * Initialize Rate list. */ rt2x00lib_rate(&rates[0], 10, DEV_RATEMASK_1MB, - 0x00, IEEE80211_RATE_CCK); + 0x00, 0); rt2x00lib_rate(&rates[1], 20, DEV_RATEMASK_2MB, - 0x01, IEEE80211_RATE_CCK_2); + 0x01, IEEE80211_RATE_SHORT_PREAMBLE); rt2x00lib_rate(&rates[2], 55, DEV_RATEMASK_5_5MB, - 0x02, IEEE80211_RATE_CCK_2); + 0x02, IEEE80211_RATE_SHORT_PREAMBLE); rt2x00lib_rate(&rates[3], 110, DEV_RATEMASK_11MB, - 0x03, IEEE80211_RATE_CCK_2); + 0x03, IEEE80211_RATE_SHORT_PREAMBLE); if (spec->num_rates > 4) { rt2x00lib_rate(&rates[4], 60, DEV_RATEMASK_6MB, - 0x0b, IEEE80211_RATE_OFDM); + 0x0b, 0); rt2x00lib_rate(&rates[5], 90, DEV_RATEMASK_9MB, - 0x0f, IEEE80211_RATE_OFDM); + 0x0f, 0); rt2x00lib_rate(&rates[6], 120, DEV_RATEMASK_12MB, - 0x0a, IEEE80211_RATE_OFDM); + 0x0a, 0); rt2x00lib_rate(&rates[7], 180, DEV_RATEMASK_18MB, - 0x0e, IEEE80211_RATE_OFDM); + 0x0e, 0); rt2x00lib_rate(&rates[8], 240, DEV_RATEMASK_24MB, - 0x09, IEEE80211_RATE_OFDM); + 0x09, 0); rt2x00lib_rate(&rates[9], 360, DEV_RATEMASK_36MB, - 0x0d, IEEE80211_RATE_OFDM); + 0x0d, 0); rt2x00lib_rate(&rates[10], 480, DEV_RATEMASK_48MB, - 0x08, IEEE80211_RATE_OFDM); + 0x08, 0); rt2x00lib_rate(&rates[11], 540, DEV_RATEMASK_54MB, - 0x0c, IEEE80211_RATE_OFDM); + 0x0c, 0); } /* @@ -862,27 +853,27 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, /* * Intitialize 802.11b * Rates: CCK. - * Channels: OFDM. + * Channels: 2.4 GHz */ if (spec->num_modes > HWMODE_B) { - hwmodes[HWMODE_B].mode = MODE_IEEE80211B; - hwmodes[HWMODE_B].num_channels = 14; - hwmodes[HWMODE_B].num_rates = 4; - hwmodes[HWMODE_B].channels = channels; - hwmodes[HWMODE_B].rates = rates; + sbands[IEEE80211_BAND_2GHZ].n_channels = 14; + sbands[IEEE80211_BAND_2GHZ].n_bitrates = 4; + sbands[IEEE80211_BAND_2GHZ].channels = channels; + sbands[IEEE80211_BAND_2GHZ].bitrates = rates; + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &rt2x00dev->bands[IEEE80211_BAND_2GHZ]; } /* * Intitialize 802.11g * Rates: CCK, OFDM. - * Channels: OFDM. + * Channels: 2.4 GHz */ if (spec->num_modes > HWMODE_G) { - hwmodes[HWMODE_G].mode = MODE_IEEE80211G; - hwmodes[HWMODE_G].num_channels = 14; - hwmodes[HWMODE_G].num_rates = spec->num_rates; - hwmodes[HWMODE_G].channels = channels; - hwmodes[HWMODE_G].rates = rates; + sbands[IEEE80211_BAND_2GHZ].n_channels = 14; + sbands[IEEE80211_BAND_2GHZ].n_bitrates = spec->num_rates; + sbands[IEEE80211_BAND_2GHZ].channels = channels; + sbands[IEEE80211_BAND_2GHZ].bitrates = rates; + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &rt2x00dev->bands[IEEE80211_BAND_2GHZ]; } /* @@ -891,39 +882,17 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, * Channels: OFDM, UNII, HiperLAN2. */ if (spec->num_modes > HWMODE_A) { - hwmodes[HWMODE_A].mode = MODE_IEEE80211A; - hwmodes[HWMODE_A].num_channels = spec->num_channels - 14; - hwmodes[HWMODE_A].num_rates = spec->num_rates - 4; - hwmodes[HWMODE_A].channels = &channels[14]; - hwmodes[HWMODE_A].rates = &rates[4]; + sbands[IEEE80211_BAND_5GHZ].n_channels = spec->num_channels - 14; + sbands[IEEE80211_BAND_5GHZ].n_bitrates = spec->num_rates - 4; + sbands[IEEE80211_BAND_5GHZ].channels = &channels[14]; + sbands[IEEE80211_BAND_5GHZ].bitrates = &rates[4]; + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &rt2x00dev->bands[IEEE80211_BAND_5GHZ]; } - if (spec->num_modes > HWMODE_G && - ieee80211_register_hwmode(hw, &hwmodes[HWMODE_G])) - goto exit_free_rates; - - if (spec->num_modes > HWMODE_B && - ieee80211_register_hwmode(hw, &hwmodes[HWMODE_B])) - goto exit_free_rates; - - if (spec->num_modes > HWMODE_A && - ieee80211_register_hwmode(hw, &hwmodes[HWMODE_A])) - goto exit_free_rates; - - rt2x00dev->hwmodes = hwmodes; - return 0; -exit_free_rates: - kfree(rates); - -exit_free_channels: + exit_free_channels: kfree(channels); - -exit_free_modes: - kfree(hwmodes); - -exit: ERROR(rt2x00dev, "Allocation ieee80211 modes failed.\n"); return -ENOMEM; } @@ -933,11 +902,11 @@ static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) if (test_bit(DEVICE_REGISTERED_HW, &rt2x00dev->flags)) ieee80211_unregister_hw(rt2x00dev->hw); - if (likely(rt2x00dev->hwmodes)) { - kfree(rt2x00dev->hwmodes->channels); - kfree(rt2x00dev->hwmodes->rates); - kfree(rt2x00dev->hwmodes); - rt2x00dev->hwmodes = NULL; + if (likely(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ])) { + kfree(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->channels); + kfree(rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ]->bitrates); + rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = NULL; + rt2x00dev->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; } } diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index 59e87a1d96a4..1dd30510ed1e 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -426,12 +426,12 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, case ANTENNA_HW_DIVERSITY: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, - (rt2x00dev->curr_hwmode != HWMODE_A)); + (rt2x00dev->curr_band != IEEE80211_BAND_5GHZ)); break; case ANTENNA_A: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); - if (rt2x00dev->curr_hwmode == HWMODE_A) + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); else rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); @@ -446,7 +446,7 @@ static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, case ANTENNA_B: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); - if (rt2x00dev->curr_hwmode == HWMODE_A) + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); else rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); @@ -602,7 +602,7 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, unsigned int i; u32 reg; - if (rt2x00dev->curr_hwmode == HWMODE_A) { + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { sel = antenna_sel_a; lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); } else { @@ -616,10 +616,9 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, PHY_CSR0, ®); rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, - (rt2x00dev->curr_hwmode == HWMODE_B || - rt2x00dev->curr_hwmode == HWMODE_G)); + rt2x00dev->curr_band == IEEE80211_BAND_2GHZ); rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, - (rt2x00dev->curr_hwmode == HWMODE_A)); + rt2x00dev->curr_band == IEEE80211_BAND_5GHZ); rt2x00pci_register_write(rt2x00dev, PHY_CSR0, reg); @@ -698,9 +697,9 @@ static void rt61pci_enable_led(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1); rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, - (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)); + rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ); rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, - (rt2x00dev->rx_status.phymode != MODE_IEEE80211A)); + rt2x00dev->rx_status.band != IEEE80211_BAND_5GHZ); arg0 = rt2x00dev->led_reg & 0xff; arg1 = (rt2x00dev->led_reg >> 8) & 0xff; @@ -798,7 +797,7 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev) /* * Determine r17 bounds. */ - if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (rt2x00dev->rx_status.band == IEEE80211_BAND_2GHZ) { low_bound = 0x28; up_bound = 0x48; if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { @@ -1544,8 +1543,10 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 5, &word); +/* XXX: removed for now rt2x00_set_field32(&word, TXD_W5_TX_POWER, TXPOWER_TO_DEV(control->power_level)); + */ rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); rt2x00_desc_write(txd, 5, word); @@ -1637,7 +1638,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return 0; } - if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) { if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) offset += 14; diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 4b5bde8b53de..9cbc879da037 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -439,13 +439,13 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, case ANTENNA_HW_DIVERSITY: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2); temp = !test_bit(CONFIG_FRAME_TYPE, &rt2x00dev->flags) - && (rt2x00dev->curr_hwmode != HWMODE_A); + && (rt2x00dev->curr_band != IEEE80211_BAND_5GHZ); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, temp); break; case ANTENNA_A: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); - if (rt2x00dev->curr_hwmode == HWMODE_A) + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); else rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); @@ -460,7 +460,7 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, case ANTENNA_B: rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 1); rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, 0); - if (rt2x00dev->curr_hwmode == HWMODE_A) + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 3); else rt2x00_set_field8(&r77, BBP_R77_RX_ANTENNA, 0); @@ -555,7 +555,7 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, unsigned int i; u32 reg; - if (rt2x00dev->curr_hwmode == HWMODE_A) { + if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) { sel = antenna_sel_a; lna = test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags); } else { @@ -569,10 +569,9 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, rt73usb_register_read(rt2x00dev, PHY_CSR0, ®); rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, - (rt2x00dev->curr_hwmode == HWMODE_B || - rt2x00dev->curr_hwmode == HWMODE_G)); + (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ)); rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, - (rt2x00dev->curr_hwmode == HWMODE_A)); + (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ)); rt73usb_register_write(rt2x00dev, PHY_CSR0, reg); @@ -644,9 +643,9 @@ static void rt73usb_enable_led(struct rt2x00_dev *rt2x00dev) rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_RADIO_STATUS, 1); rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_A_STATUS, - (rt2x00dev->rx_status.phymode == MODE_IEEE80211A)); + (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ)); rt2x00_set_field16(&rt2x00dev->led_reg, MCU_LEDCS_LINK_BG_STATUS, - (rt2x00dev->rx_status.phymode != MODE_IEEE80211A)); + (rt2x00dev->rx_status.band != IEEE80211_BAND_5GHZ)); rt2x00usb_vendor_request_sw(rt2x00dev, USB_LED_CONTROL, 0x0000, rt2x00dev->led_reg, REGISTER_TIMEOUT); @@ -736,7 +735,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev) /* * Determine r17 bounds. */ - if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) { low_bound = 0x28; up_bound = 0x48; @@ -1278,8 +1277,10 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); rt2x00_desc_read(txd, 5, &word); +/* XXX: removed for now rt2x00_set_field32(&word, TXD_W5_TX_POWER, TXPOWER_TO_DEV(control->power_level)); + */ rt2x00_set_field32(&word, TXD_W5_WAITING_DMA_DONE_INT, 1); rt2x00_desc_write(txd, 5, word); @@ -1370,7 +1371,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) return 0; } - if (rt2x00dev->rx_status.phymode == MODE_IEEE80211A) { + if (rt2x00dev->rx_status.band == IEEE80211_BAND_5GHZ) { if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) { if (lna == 3 || lna == 2) offset += 10; diff --git a/drivers/net/wireless/rtl8180.h b/drivers/net/wireless/rtl8180.h index 2cbfe3c8081f..082a11f93beb 100644 --- a/drivers/net/wireless/rtl8180.h +++ b/drivers/net/wireless/rtl8180.h @@ -102,7 +102,7 @@ struct rtl8180_priv { struct rtl8180_tx_ring tx_ring[4]; struct ieee80211_channel channels[14]; struct ieee80211_rate rates[12]; - struct ieee80211_hw_mode modes[2]; + struct ieee80211_supported_band band; struct pci_dev *pdev; u32 rx_conf; diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl8180_dev.c index 5e9a8ace0d81..d0928c91c21c 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl8180_dev.c @@ -49,6 +49,41 @@ static struct pci_device_id rtl8180_table[] __devinitdata = { MODULE_DEVICE_TABLE(pci, rtl8180_table); +static const struct ieee80211_rate rtl818x_rates[] = { + { .bitrate = 10, .hw_value = 0, }, + { .bitrate = 20, .hw_value = 1, }, + { .bitrate = 55, .hw_value = 2, }, + { .bitrate = 110, .hw_value = 3, }, + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static const struct ieee80211_channel rtl818x_channels[] = { + { .center_freq = 2412 }, + { .center_freq = 2417 }, + { .center_freq = 2422 }, + { .center_freq = 2427 }, + { .center_freq = 2432 }, + { .center_freq = 2437 }, + { .center_freq = 2442 }, + { .center_freq = 2447 }, + { .center_freq = 2452 }, + { .center_freq = 2457 }, + { .center_freq = 2462 }, + { .center_freq = 2467 }, + { .center_freq = 2472 }, + { .center_freq = 2484 }, +}; + + + + void rtl8180_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) { struct rtl8180_priv *priv = dev->priv; @@ -99,10 +134,10 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev) /* TODO: improve signal/rssi reporting */ rx_status.signal = flags2 & 0xFF; rx_status.ssi = (flags2 >> 8) & 0x7F; - rx_status.rate = (flags >> 20) & 0xF; - rx_status.freq = dev->conf.freq; - rx_status.channel = dev->conf.channel; - rx_status.phymode = dev->conf.phymode; + /* XXX: is this correct? */ + rx_status.rate_idx = (flags >> 20) & 0xF; + rx_status.freq = dev->conf.channel->center_freq; + rx_status.band = dev->conf.channel->band; rx_status.mactime = le64_to_cpu(entry->tsft); rx_status.flag |= RX_FLAG_TSFT; if (flags & RTL8180_RX_DESC_FLAG_CRC32_ERR) @@ -223,8 +258,9 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, skb->len, PCI_DMA_TODEVICE); tx_flags = RTL8180_TX_DESC_FLAG_OWN | RTL8180_TX_DESC_FLAG_FS | - RTL8180_TX_DESC_FLAG_LS | (control->tx_rate << 24) | - (control->rts_cts_rate << 19) | skb->len; + RTL8180_TX_DESC_FLAG_LS | + (control->tx_rate->hw_value << 24) | + (control->rts_cts_rate->hw_value << 19) | skb->len; if (priv->r8185) tx_flags |= RTL8180_TX_DESC_FLAG_DMA | @@ -246,9 +282,9 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, unsigned int remainder; plcp_len = DIV_ROUND_UP(16 * (skb->len + 4), - (control->rate->rate * 2) / 10); + (control->tx_rate->bitrate * 2) / 10); remainder = (16 * (skb->len + 4)) % - ((control->rate->rate * 2) / 10); + ((control->tx_rate->bitrate * 2) / 10); if (remainder > 0 && remainder <= 6) plcp_len |= 1 << 15; } @@ -261,8 +297,8 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb, entry->plcp_len = cpu_to_le16(plcp_len); entry->tx_buf = cpu_to_le32(mapping); entry->frame_len = cpu_to_le32(skb->len); - entry->flags2 = control->alt_retry_rate != -1 ? - control->alt_retry_rate << 4 : 0; + entry->flags2 = control->alt_retry_rate != NULL ? + control->alt_retry_rate->bitrate << 4 : 0; entry->retry_limit = control->retry_limit; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); @@ -838,19 +874,19 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, goto err_free_dev; } + BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels)); + BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates)); + memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); - priv->modes[0].mode = MODE_IEEE80211G; - priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates); - priv->modes[0].rates = priv->rates; - priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels); - priv->modes[0].channels = priv->channels; - priv->modes[1].mode = MODE_IEEE80211B; - priv->modes[1].num_rates = 4; - priv->modes[1].rates = priv->rates; - priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels); - priv->modes[1].channels = priv->channels; - priv->mode = IEEE80211_IF_TYPE_INVALID; + + priv->band.band = IEEE80211_BAND_2GHZ; + priv->band.channels = priv->channels; + priv->band.n_channels = ARRAY_SIZE(rtl818x_channels); + priv->band.bitrates = priv->rates; + priv->band.n_bitrates = 4; + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_RX_INCLUDES_FCS; dev->queues = 1; @@ -879,15 +915,10 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, priv->r8185 = reg & RTL818X_TX_CONF_R8185_ABC; if (priv->r8185) { - if ((err = ieee80211_register_hwmode(dev, &priv->modes[0]))) - goto err_iounmap; - + priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); pci_try_set_mwi(pdev); } - if ((err = ieee80211_register_hwmode(dev, &priv->modes[1]))) - goto err_iounmap; - eeprom.data = dev; eeprom.register_read = rtl8180_eeprom_register_read; eeprom.register_write = rtl8180_eeprom_register_write; @@ -950,8 +981,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, for (i = 0; i < 14; i += 2) { u16 txpwr; eeprom_93cx6_read(&eeprom, 0x10 + (i >> 1), &txpwr); - priv->channels[i].val = txpwr & 0xFF; - priv->channels[i + 1].val = txpwr >> 8; + priv->channels[i].hw_value = txpwr & 0xFF; + priv->channels[i + 1].hw_value = txpwr >> 8; } /* OFDM TX power */ @@ -959,8 +990,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, for (i = 0; i < 14; i += 2) { u16 txpwr; eeprom_93cx6_read(&eeprom, 0x20 + (i >> 1), &txpwr); - priv->channels[i].val |= (txpwr & 0xFF) << 8; - priv->channels[i + 1].val |= txpwr & 0xFF00; + priv->channels[i].hw_value |= (txpwr & 0xFF) << 8; + priv->channels[i + 1].hw_value |= txpwr & 0xFF00; } } diff --git a/drivers/net/wireless/rtl8180_grf5101.c b/drivers/net/wireless/rtl8180_grf5101.c index 8293e19c4c59..5d47935dbac3 100644 --- a/drivers/net/wireless/rtl8180_grf5101.c +++ b/drivers/net/wireless/rtl8180_grf5101.c @@ -73,8 +73,9 @@ static void grf5101_rf_set_channel(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct rtl8180_priv *priv = dev->priv; - u32 txpw = priv->channels[conf->channel - 1].val & 0xFF; - u32 chan = conf->channel - 1; + int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; + u32 chan = channel - 1; /* set TX power */ write_grf5101(dev, 0x15, 0x0); diff --git a/drivers/net/wireless/rtl8180_max2820.c b/drivers/net/wireless/rtl8180_max2820.c index 98fe9fd64968..a34dfd382b6d 100644 --- a/drivers/net/wireless/rtl8180_max2820.c +++ b/drivers/net/wireless/rtl8180_max2820.c @@ -78,8 +78,9 @@ static void max2820_rf_set_channel(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct rtl8180_priv *priv = dev->priv; - unsigned int chan_idx = conf ? conf->channel - 1 : 0; - u32 txpw = priv->channels[chan_idx].val & 0xFF; + int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + unsigned int chan_idx = channel - 1; + u32 txpw = priv->channels[chan_idx].hw_value & 0xFF; u32 chan = max2820_chan[chan_idx]; /* While philips SA2400 drive the PA bias from diff --git a/drivers/net/wireless/rtl8180_rtl8225.c b/drivers/net/wireless/rtl8180_rtl8225.c index ef3832bee85c..cd22781728a9 100644 --- a/drivers/net/wireless/rtl8180_rtl8225.c +++ b/drivers/net/wireless/rtl8180_rtl8225.c @@ -261,8 +261,8 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) u32 reg; int i; - cck_power = priv->channels[channel - 1].val & 0xFF; - ofdm_power = priv->channels[channel - 1].val >> 8; + cck_power = priv->channels[channel - 1].hw_value & 0xFF; + ofdm_power = priv->channels[channel - 1].hw_value >> 8; cck_power = min(cck_power, (u8)35); ofdm_power = min(ofdm_power, (u8)35); @@ -476,8 +476,8 @@ static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) const u8 *tmp; int i; - cck_power = priv->channels[channel - 1].val & 0xFF; - ofdm_power = priv->channels[channel - 1].val >> 8; + cck_power = priv->channels[channel - 1].hw_value & 0xFF; + ofdm_power = priv->channels[channel - 1].hw_value >> 8; if (channel == 14) tmp = rtl8225z2_tx_power_cck_ch14; @@ -716,13 +716,14 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct rtl8180_priv *priv = dev->priv; + int chan = ieee80211_frequency_to_channel(conf->channel->center_freq); if (priv->rf->init == rtl8225_rf_init) - rtl8225_rf_set_tx_power(dev, conf->channel); + rtl8225_rf_set_tx_power(dev, chan); else - rtl8225z2_rf_set_tx_power(dev, conf->channel); + rtl8225z2_rf_set_tx_power(dev, chan); - rtl8225_write(dev, 0x7, rtl8225_chan[conf->channel - 1]); + rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); msleep(10); if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { diff --git a/drivers/net/wireless/rtl8180_sa2400.c b/drivers/net/wireless/rtl8180_sa2400.c index e08ace7b1cb7..0311b4ea124c 100644 --- a/drivers/net/wireless/rtl8180_sa2400.c +++ b/drivers/net/wireless/rtl8180_sa2400.c @@ -80,8 +80,9 @@ static void sa2400_rf_set_channel(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct rtl8180_priv *priv = dev->priv; - u32 txpw = priv->channels[conf->channel - 1].val & 0xFF; - u32 chan = sa2400_chan[conf->channel - 1]; + int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); + u32 txpw = priv->channels[channel - 1].hw_value & 0xFF; + u32 chan = sa2400_chan[channel - 1]; write_sa2400(dev, 7, txpw); diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl8187.h index 8680a0b6433c..076d88b6db0e 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl8187.h @@ -71,7 +71,7 @@ struct rtl8187_priv { /* rtl8187 specific */ struct ieee80211_channel channels[14]; struct ieee80211_rate rates[12]; - struct ieee80211_hw_mode modes[2]; + struct ieee80211_supported_band band; struct usb_device *udev; u32 rx_conf; u16 txpwr_base; diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl8187_dev.c index f44505994a0e..6ef67990692d 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl8187_dev.c @@ -45,6 +45,38 @@ static struct usb_device_id rtl8187_table[] __devinitdata = { MODULE_DEVICE_TABLE(usb, rtl8187_table); +static const struct ieee80211_rate rtl818x_rates[] = { + { .bitrate = 10, .hw_value = 0, }, + { .bitrate = 20, .hw_value = 1, }, + { .bitrate = 55, .hw_value = 2, }, + { .bitrate = 110, .hw_value = 3, }, + { .bitrate = 60, .hw_value = 4, }, + { .bitrate = 90, .hw_value = 5, }, + { .bitrate = 120, .hw_value = 6, }, + { .bitrate = 180, .hw_value = 7, }, + { .bitrate = 240, .hw_value = 8, }, + { .bitrate = 360, .hw_value = 9, }, + { .bitrate = 480, .hw_value = 10, }, + { .bitrate = 540, .hw_value = 11, }, +}; + +static const struct ieee80211_channel rtl818x_channels[] = { + { .center_freq = 2412 }, + { .center_freq = 2417 }, + { .center_freq = 2422 }, + { .center_freq = 2427 }, + { .center_freq = 2432 }, + { .center_freq = 2437 }, + { .center_freq = 2442 }, + { .center_freq = 2447 }, + { .center_freq = 2452 }, + { .center_freq = 2457 }, + { .center_freq = 2462 }, + { .center_freq = 2467 }, + { .center_freq = 2472 }, + { .center_freq = 2484 }, +}; + static void rtl8187_iowrite_async_cb(struct urb *urb) { kfree(urb->context); @@ -146,8 +178,8 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb, flags = skb->len; flags |= RTL8187_TX_FLAG_NO_ENCRYPT; - flags |= control->rts_cts_rate << 19; - flags |= control->tx_rate << 24; + flags |= control->rts_cts_rate->hw_value << 19; + flags |= control->tx_rate->hw_value << 24; if (ieee80211_get_morefrag((struct ieee80211_hdr *)skb->data)) flags |= RTL8187_TX_FLAG_MORE_FRAG; if (control->flags & IEEE80211_TXCTL_USE_RTS_CTS) { @@ -225,10 +257,9 @@ static void rtl8187_rx_cb(struct urb *urb) rx_status.antenna = (hdr->signal >> 7) & 1; rx_status.signal = 64 - min(hdr->noise, (u8)64); rx_status.ssi = signal; - rx_status.rate = rate; - rx_status.freq = dev->conf.freq; - rx_status.channel = dev->conf.channel; - rx_status.phymode = dev->conf.phymode; + rx_status.rate_idx = rate; + rx_status.freq = dev->conf.channel->center_freq; + rx_status.band = dev->conf.channel->band; rx_status.mactime = le64_to_cpu(hdr->mac_time); rx_status.flag |= RX_FLAG_TSFT; if (flags & (1 << 13)) @@ -682,19 +713,22 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, usb_get_dev(udev); skb_queue_head_init(&priv->rx_queue); + + BUILD_BUG_ON(sizeof(priv->channels) != sizeof(rtl818x_channels)); + BUILD_BUG_ON(sizeof(priv->rates) != sizeof(rtl818x_rates)); + memcpy(priv->channels, rtl818x_channels, sizeof(rtl818x_channels)); memcpy(priv->rates, rtl818x_rates, sizeof(rtl818x_rates)); priv->map = (struct rtl818x_csr *)0xFF00; - priv->modes[0].mode = MODE_IEEE80211G; - priv->modes[0].num_rates = ARRAY_SIZE(rtl818x_rates); - priv->modes[0].rates = priv->rates; - priv->modes[0].num_channels = ARRAY_SIZE(rtl818x_channels); - priv->modes[0].channels = priv->channels; - priv->modes[1].mode = MODE_IEEE80211B; - priv->modes[1].num_rates = 4; - priv->modes[1].rates = priv->rates; - priv->modes[1].num_channels = ARRAY_SIZE(rtl818x_channels); - priv->modes[1].channels = priv->channels; + + priv->band.band = IEEE80211_BAND_2GHZ; + priv->band.channels = priv->channels; + priv->band.n_channels = ARRAY_SIZE(rtl818x_channels); + priv->band.bitrates = priv->rates; + priv->band.n_bitrates = ARRAY_SIZE(rtl818x_rates); + dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band; + + priv->mode = IEEE80211_IF_TYPE_MNTR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | IEEE80211_HW_RX_INCLUDES_FCS; @@ -703,10 +737,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, dev->max_rssi = 65; dev->max_signal = 64; - for (i = 0; i < 2; i++) - if ((err = ieee80211_register_hwmode(dev, &priv->modes[i]))) - goto err_free_dev; - eeprom.data = dev; eeprom.register_read = rtl8187_eeprom_register_read; eeprom.register_write = rtl8187_eeprom_register_write; @@ -730,20 +760,20 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, for (i = 0; i < 3; i++) { eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_1 + i, &txpwr); - (*channel++).val = txpwr & 0xFF; - (*channel++).val = txpwr >> 8; + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; } for (i = 0; i < 2; i++) { eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_4 + i, &txpwr); - (*channel++).val = txpwr & 0xFF; - (*channel++).val = txpwr >> 8; + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; } for (i = 0; i < 2; i++) { eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_CHAN_6 + i, &txpwr); - (*channel++).val = txpwr & 0xFF; - (*channel++).val = txpwr >> 8; + (*channel++).hw_value = txpwr & 0xFF; + (*channel++).hw_value = txpwr >> 8; } eeprom_93cx6_read(&eeprom, RTL8187_EEPROM_TXPWR_BASE, diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl8187_rtl8225.c index b713de17ba0a..9146387b4c5e 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl8187_rtl8225.c @@ -283,8 +283,8 @@ static void rtl8225_rf_set_tx_power(struct ieee80211_hw *dev, int channel) u32 reg; int i; - cck_power = priv->channels[channel - 1].val & 0xF; - ofdm_power = priv->channels[channel - 1].val >> 4; + cck_power = priv->channels[channel - 1].hw_value & 0xF; + ofdm_power = priv->channels[channel - 1].hw_value >> 4; cck_power = min(cck_power, (u8)11); ofdm_power = min(ofdm_power, (u8)35); @@ -500,8 +500,8 @@ static void rtl8225z2_rf_set_tx_power(struct ieee80211_hw *dev, int channel) u32 reg; int i; - cck_power = priv->channels[channel - 1].val & 0xF; - ofdm_power = priv->channels[channel - 1].val >> 4; + cck_power = priv->channels[channel - 1].hw_value & 0xF; + ofdm_power = priv->channels[channel - 1].hw_value >> 4; cck_power = min(cck_power, (u8)15); cck_power += priv->txpwr_base & 0xF; @@ -735,13 +735,14 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, struct ieee80211_conf *conf) { struct rtl8187_priv *priv = dev->priv; + int chan = ieee80211_frequency_to_channel(conf->channel->center_freq); if (priv->rf->init == rtl8225_rf_init) - rtl8225_rf_set_tx_power(dev, conf->channel); + rtl8225_rf_set_tx_power(dev, chan); else - rtl8225z2_rf_set_tx_power(dev, conf->channel); + rtl8225z2_rf_set_tx_power(dev, chan); - rtl8225_write(dev, 0x7, rtl8225_chan[conf->channel - 1]); + rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); msleep(10); } diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x.h index 1e7d6f8278d7..4f7d38f506eb 100644 --- a/drivers/net/wireless/rtl818x.h +++ b/drivers/net/wireless/rtl818x.h @@ -175,74 +175,4 @@ struct rtl818x_rf_ops { void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *); }; -static const struct ieee80211_rate rtl818x_rates[] = { - { .rate = 10, - .val = 0, - .flags = IEEE80211_RATE_CCK }, - { .rate = 20, - .val = 1, - .flags = IEEE80211_RATE_CCK }, - { .rate = 55, - .val = 2, - .flags = IEEE80211_RATE_CCK }, - { .rate = 110, - .val = 3, - .flags = IEEE80211_RATE_CCK }, - { .rate = 60, - .val = 4, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 90, - .val = 5, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 120, - .val = 6, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 180, - .val = 7, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 240, - .val = 8, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 360, - .val = 9, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 480, - .val = 10, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 540, - .val = 11, - .flags = IEEE80211_RATE_OFDM }, -}; - -static const struct ieee80211_channel rtl818x_channels[] = { - { .chan = 1, - .freq = 2412}, - { .chan = 2, - .freq = 2417}, - { .chan = 3, - .freq = 2422}, - { .chan = 4, - .freq = 2427}, - { .chan = 5, - .freq = 2432}, - { .chan = 6, - .freq = 2437}, - { .chan = 7, - .freq = 2442}, - { .chan = 8, - .freq = 2447}, - { .chan = 9, - .freq = 2452}, - { .chan = 10, - .freq = 2457}, - { .chan = 11, - .freq = 2462}, - { .chan = 12, - .freq = 2467}, - { .chan = 13, - .freq = 2472}, - { .chan = 14, - .freq = 2484} -}; - #endif /* RTL818X_H */ diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 99e5b03b3f51..e3fba6f09455 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -986,7 +986,7 @@ static int print_fw_version(struct zd_chip *chip) return 0; } -static int set_mandatory_rates(struct zd_chip *chip, int mode) +static int set_mandatory_rates(struct zd_chip *chip, int gmode) { u32 rates; ZD_ASSERT(mutex_is_locked(&chip->mutex)); @@ -994,17 +994,12 @@ static int set_mandatory_rates(struct zd_chip *chip, int mode) * that the device is supporting. Until further notice we should try * to support 802.11g also for full speed USB. */ - switch (mode) { - case MODE_IEEE80211B: + if (!gmode) rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M; - break; - case MODE_IEEE80211G: + else rates = CR_RATE_1M|CR_RATE_2M|CR_RATE_5_5M|CR_RATE_11M| CR_RATE_6M|CR_RATE_12M|CR_RATE_24M; - break; - default: - return -EINVAL; - } + return zd_iowrite32_locked(chip, rates, CR_MANDATORY_RATE_TBL); } @@ -1108,7 +1103,7 @@ int zd_chip_init_hw(struct zd_chip *chip) * It might be discussed, whether we should suppport pure b mode for * full speed USB. */ - r = set_mandatory_rates(chip, MODE_IEEE80211G); + r = set_mandatory_rates(chip, 1); if (r) goto out; /* Disabling interrupts is certainly a smart thing here. diff --git a/drivers/net/wireless/zd1211rw/zd_ieee80211.c b/drivers/net/wireless/zd1211rw/zd_ieee80211.c index 7c277ec43f79..d8dc41ec0e5d 100644 --- a/drivers/net/wireless/zd1211rw/zd_ieee80211.c +++ b/drivers/net/wireless/zd1211rw/zd_ieee80211.c @@ -65,16 +65,14 @@ static const struct channel_range *zd_channel_range(u8 regdomain) static void unmask_bg_channels(struct ieee80211_hw *hw, const struct channel_range *range, - struct ieee80211_hw_mode *mode) + struct ieee80211_supported_band *sband) { u8 channel; for (channel = range->start; channel < range->end; channel++) { struct ieee80211_channel *chan = - &mode->channels[CHAN_TO_IDX(channel)]; - chan->flag |= IEEE80211_CHAN_W_SCAN | - IEEE80211_CHAN_W_ACTIVE_SCAN | - IEEE80211_CHAN_W_IBSS; + &sband->channels[CHAN_TO_IDX(channel)]; + chan->flags = 0; } } @@ -97,7 +95,6 @@ void zd_geo_init(struct ieee80211_hw *hw, u8 regdomain) range = zd_channel_range(ZD_REGDOMAIN_FCC); } - unmask_bg_channels(hw, range, &mac->modes[0]); - unmask_bg_channels(hw, range, &mac->modes[1]); + unmask_bg_channels(hw, range, &mac->band); } diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 76ef2d83919d..21b653458831 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -34,76 +34,61 @@ /* This table contains the hardware specific values for the modulation rates. */ static const struct ieee80211_rate zd_rates[] = { - { .rate = 10, - .val = ZD_CCK_RATE_1M, - .flags = IEEE80211_RATE_CCK }, - { .rate = 20, - .val = ZD_CCK_RATE_2M, - .val2 = ZD_CCK_RATE_2M | ZD_CCK_PREA_SHORT, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 55, - .val = ZD_CCK_RATE_5_5M, - .val2 = ZD_CCK_RATE_5_5M | ZD_CCK_PREA_SHORT, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 110, - .val = ZD_CCK_RATE_11M, - .val2 = ZD_CCK_RATE_11M | ZD_CCK_PREA_SHORT, - .flags = IEEE80211_RATE_CCK_2 }, - { .rate = 60, - .val = ZD_OFDM_RATE_6M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 90, - .val = ZD_OFDM_RATE_9M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 120, - .val = ZD_OFDM_RATE_12M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 180, - .val = ZD_OFDM_RATE_18M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 240, - .val = ZD_OFDM_RATE_24M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 360, - .val = ZD_OFDM_RATE_36M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 480, - .val = ZD_OFDM_RATE_48M, - .flags = IEEE80211_RATE_OFDM }, - { .rate = 540, - .val = ZD_OFDM_RATE_54M, - .flags = IEEE80211_RATE_OFDM }, + { .bitrate = 10, + .hw_value = ZD_CCK_RATE_1M, }, + { .bitrate = 20, + .hw_value = ZD_CCK_RATE_2M, + .hw_value_short = ZD_CCK_RATE_2M | ZD_CCK_PREA_SHORT, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 55, + .hw_value = ZD_CCK_RATE_5_5M, + .hw_value_short = ZD_CCK_RATE_5_5M | ZD_CCK_PREA_SHORT, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 110, + .hw_value = ZD_CCK_RATE_11M, + .hw_value_short = ZD_CCK_RATE_11M | ZD_CCK_PREA_SHORT, + .flags = IEEE80211_RATE_SHORT_PREAMBLE }, + { .bitrate = 60, + .hw_value = ZD_OFDM_RATE_6M, + .flags = 0 }, + { .bitrate = 90, + .hw_value = ZD_OFDM_RATE_9M, + .flags = 0 }, + { .bitrate = 120, + .hw_value = ZD_OFDM_RATE_12M, + .flags = 0 }, + { .bitrate = 180, + .hw_value = ZD_OFDM_RATE_18M, + .flags = 0 }, + { .bitrate = 240, + .hw_value = ZD_OFDM_RATE_24M, + .flags = 0 }, + { .bitrate = 360, + .hw_value = ZD_OFDM_RATE_36M, + .flags = 0 }, + { .bitrate = 480, + .hw_value = ZD_OFDM_RATE_48M, + .flags = 0 }, + { .bitrate = 540, + .hw_value = ZD_OFDM_RATE_54M, + .flags = 0 }, }; static const struct ieee80211_channel zd_channels[] = { - { .chan = 1, - .freq = 2412}, - { .chan = 2, - .freq = 2417}, - { .chan = 3, - .freq = 2422}, - { .chan = 4, - .freq = 2427}, - { .chan = 5, - .freq = 2432}, - { .chan = 6, - .freq = 2437}, - { .chan = 7, - .freq = 2442}, - { .chan = 8, - .freq = 2447}, - { .chan = 9, - .freq = 2452}, - { .chan = 10, - .freq = 2457}, - { .chan = 11, - .freq = 2462}, - { .chan = 12, - .freq = 2467}, - { .chan = 13, - .freq = 2472}, - { .chan = 14, - .freq = 2484} + { .center_freq = 2412, .hw_value = 1 }, + { .center_freq = 2417, .hw_value = 2 }, + { .center_freq = 2422, .hw_value = 3 }, + { .center_freq = 2427, .hw_value = 4 }, + { .center_freq = 2432, .hw_value = 5 }, + { .center_freq = 2437, .hw_value = 6 }, + { .center_freq = 2442, .hw_value = 7 }, + { .center_freq = 2447, .hw_value = 8 }, + { .center_freq = 2452, .hw_value = 9 }, + { .center_freq = 2457, .hw_value = 10 }, + { .center_freq = 2462, .hw_value = 11 }, + { .center_freq = 2467, .hw_value = 12 }, + { .center_freq = 2472, .hw_value = 13 }, + { .center_freq = 2484, .hw_value = 14 }, }; static void housekeeping_init(struct zd_mac *mac); @@ -503,7 +488,9 @@ static int fill_ctrlset(struct zd_mac *mac, ZD_ASSERT(frag_len <= 0xffff); - cs->modulation = control->tx_rate; + cs->modulation = control->tx_rate->hw_value; + if (control->flags & IEEE80211_TXCTL_SHORT_PREAMBLE) + cs->modulation = control->tx_rate->hw_value_short; cs->tx_length = cpu_to_le16(frag_len); @@ -631,6 +618,8 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) int bad_frame = 0; u16 fc; bool is_qos, is_4addr, need_padding; + int i; + u8 rate; if (length < ZD_PLCP_HEADER_SIZE + 10 /* IEEE80211_1ADDR_LEN */ + FCS_LEN + sizeof(struct rx_status)) @@ -660,14 +649,19 @@ int zd_mac_rx(struct ieee80211_hw *hw, const u8 *buffer, unsigned int length) } } - stats.channel = _zd_chip_get_channel(&mac->chip); - stats.freq = zd_channels[stats.channel - 1].freq; - stats.phymode = MODE_IEEE80211G; + stats.freq = zd_channels[_zd_chip_get_channel(&mac->chip) - 1].center_freq; + stats.band = IEEE80211_BAND_2GHZ; stats.ssi = status->signal_strength; stats.signal = zd_rx_qual_percent(buffer, length - sizeof(struct rx_status), status); - stats.rate = zd_rx_rate(buffer, status); + + rate = zd_rx_rate(buffer, status); + + /* todo: return index in the big switches in zd_rx_rate instead */ + for (i = 0; i < mac->band.n_bitrates; i++) + if (rate == mac->band.bitrates[i].hw_value) + stats.rate_idx = i; length -= ZD_PLCP_HEADER_SIZE + sizeof(struct rx_status); buffer += ZD_PLCP_HEADER_SIZE; @@ -736,7 +730,7 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw, static int zd_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) { struct zd_mac *mac = zd_hw_mac(hw); - return zd_chip_set_channel(&mac->chip, conf->channel); + return zd_chip_set_channel(&mac->chip, conf->channel->hw_value); } static int zd_op_config_interface(struct ieee80211_hw *hw, @@ -894,7 +888,6 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) { struct zd_mac *mac; struct ieee80211_hw *hw; - int i; hw = ieee80211_alloc_hw(sizeof(struct zd_mac), &zd_ops); if (!hw) { @@ -912,19 +905,14 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) memcpy(mac->channels, zd_channels, sizeof(zd_channels)); memcpy(mac->rates, zd_rates, sizeof(zd_rates)); - mac->modes[0].mode = MODE_IEEE80211G; - mac->modes[0].num_rates = ARRAY_SIZE(zd_rates); - mac->modes[0].rates = mac->rates; - mac->modes[0].num_channels = ARRAY_SIZE(zd_channels); - mac->modes[0].channels = mac->channels; - mac->modes[1].mode = MODE_IEEE80211B; - mac->modes[1].num_rates = 4; - mac->modes[1].rates = mac->rates; - mac->modes[1].num_channels = ARRAY_SIZE(zd_channels); - mac->modes[1].channels = mac->channels; - - hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED; + mac->band.n_bitrates = ARRAY_SIZE(zd_rates); + mac->band.bitrates = mac->rates; + mac->band.n_channels = ARRAY_SIZE(zd_channels); + mac->band.channels = mac->channels; + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &mac->band; + + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS; hw->max_rssi = 100; hw->max_signal = 100; @@ -933,14 +921,6 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf) skb_queue_head_init(&mac->ack_wait_queue); - for (i = 0; i < 2; i++) { - if (ieee80211_register_hwmode(hw, &mac->modes[i])) { - dev_dbg_f(&intf->dev, "cannot register hwmode\n"); - ieee80211_free_hw(hw); - return NULL; - } - } - zd_chip_init(&mac->chip, hw, intf); housekeeping_init(mac); INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h index 2dde108df767..67dea9739c8f 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.h +++ b/drivers/net/wireless/zd1211rw/zd_mac.h @@ -185,7 +185,7 @@ struct zd_mac { struct sk_buff_head ack_wait_queue; struct ieee80211_channel channels[14]; struct ieee80211_rate rates[12]; - struct ieee80211_hw_mode modes[2]; + struct ieee80211_supported_band band; /* Short preamble (used for RTS/CTS) */ unsigned int short_preamble:1; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 277488176a44..460da54a0019 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -69,95 +69,6 @@ * not do so then mac80211 may add this under certain circumstances. */ -#define IEEE80211_CHAN_W_SCAN 0x00000001 -#define IEEE80211_CHAN_W_ACTIVE_SCAN 0x00000002 -#define IEEE80211_CHAN_W_IBSS 0x00000004 - -/* Channel information structure. Low-level driver is expected to fill in chan, - * freq, and val fields. Other fields will be filled in by 80211.o based on - * hostapd information and low-level driver does not need to use them. The - * limits for each channel will be provided in 'struct ieee80211_conf' when - * configuring the low-level driver with hw->config callback. If a device has - * a default regulatory domain, IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED - * can be set to let the driver configure all fields */ -struct ieee80211_channel { - short chan; /* channel number (IEEE 802.11) */ - short freq; /* frequency in MHz */ - int val; /* hw specific value for the channel */ - int flag; /* flag for hostapd use (IEEE80211_CHAN_*) */ - unsigned char power_level; - unsigned char antenna_max; -}; - -#define IEEE80211_RATE_ERP 0x00000001 -#define IEEE80211_RATE_BASIC 0x00000002 -#define IEEE80211_RATE_PREAMBLE2 0x00000004 -#define IEEE80211_RATE_SUPPORTED 0x00000010 -#define IEEE80211_RATE_OFDM 0x00000020 -#define IEEE80211_RATE_CCK 0x00000040 -#define IEEE80211_RATE_MANDATORY 0x00000100 - -#define IEEE80211_RATE_CCK_2 (IEEE80211_RATE_CCK | IEEE80211_RATE_PREAMBLE2) -#define IEEE80211_RATE_MODULATION(f) \ - (f & (IEEE80211_RATE_CCK | IEEE80211_RATE_OFDM)) - -/* Low-level driver should set PREAMBLE2, OFDM and CCK flags. - * BASIC, SUPPORTED, ERP, and MANDATORY flags are set in 80211.o based on the - * configuration. */ -struct ieee80211_rate { - int rate; /* rate in 100 kbps */ - int val; /* hw specific value for the rate */ - int flags; /* IEEE80211_RATE_ flags */ - int val2; /* hw specific value for the rate when using short preamble - * (only when IEEE80211_RATE_PREAMBLE2 flag is set, i.e., for - * 2, 5.5, and 11 Mbps) */ - signed char min_rssi_ack; - unsigned char min_rssi_ack_delta; - - /* following fields are set by 80211.o and need not be filled by the - * low-level driver */ - int rate_inv; /* inverse of the rate (LCM(all rates) / rate) for - * optimizing channel utilization estimates */ -}; - -/** - * enum ieee80211_phymode - PHY modes - * - * @MODE_IEEE80211A: 5GHz as defined by 802.11a/802.11h - * @MODE_IEEE80211B: 2.4 GHz as defined by 802.11b - * @MODE_IEEE80211G: 2.4 GHz as defined by 802.11g (with OFDM), - * backwards compatible with 11b mode - * @NUM_IEEE80211_MODES: internal - */ -enum ieee80211_phymode { - MODE_IEEE80211A, - MODE_IEEE80211B, - MODE_IEEE80211G, - - /* keep last */ - NUM_IEEE80211_MODES -}; - -/** - * struct ieee80211_ht_info - describing STA's HT capabilities - * - * This structure describes most essential parameters needed - * to describe 802.11n HT capabilities for an STA. - * - * @ht_supported: is HT supported by STA, 0: no, 1: yes - * @cap: HT capabilities map as described in 802.11n spec - * @ampdu_factor: Maximum A-MPDU length factor - * @ampdu_density: Minimum A-MPDU spacing - * @supp_mcs_set: Supported MCS set as described in 802.11n spec - */ -struct ieee80211_ht_info { - u8 ht_supported; - u16 cap; /* use IEEE80211_HT_CAP_ */ - u8 ampdu_factor; - u8 ampdu_density; - u8 supp_mcs_set[16]; -}; - /** * struct ieee80211_ht_bss_info - describing BSS's HT characteristics * @@ -174,30 +85,6 @@ struct ieee80211_ht_bss_info { u8 bss_op_mode; /* use IEEE80211_HT_IE_ */ }; -/** - * struct ieee80211_hw_mode - PHY mode definition - * - * This structure describes the capabilities supported by the device - * in a single PHY mode. - * - * @list: internal - * @channels: pointer to array of supported channels - * @rates: pointer to array of supported bitrates - * @mode: the PHY mode for this definition - * @num_channels: number of supported channels - * @num_rates: number of supported bitrates - * @ht_info: PHY's 802.11n HT abilities for this mode - */ -struct ieee80211_hw_mode { - struct list_head list; - struct ieee80211_channel *channels; - struct ieee80211_rate *rates; - enum ieee80211_phymode mode; - int num_channels; - int num_rates; - struct ieee80211_ht_info ht_info; -}; - /** * struct ieee80211_tx_queue_params - transmit queue configuration * @@ -320,11 +207,13 @@ struct ieee80211_bss_conf { struct ieee80211_tx_control { struct ieee80211_vif *vif; - int tx_rate; /* Transmit rate, given as the hw specific value for the - * rate (from struct ieee80211_rate) */ - int rts_cts_rate; /* Transmit rate for RTS/CTS frame, given as the hw - * specific value for the rate (from - * struct ieee80211_rate) */ + struct ieee80211_rate *tx_rate; + + /* Transmit rate for RTS/CTS frame */ + struct ieee80211_rate *rts_cts_rate; + + /* retry rate for the last retries */ + struct ieee80211_rate *alt_retry_rate; #define IEEE80211_TXCTL_REQ_TX_STATUS (1<<0)/* request TX status callback for * this frame */ @@ -343,6 +232,7 @@ struct ieee80211_tx_control { #define IEEE80211_TXCTL_REQUEUE (1<<7) #define IEEE80211_TXCTL_FIRST_FRAGMENT (1<<8) /* this is a first fragment of * the frame */ +#define IEEE80211_TXCTL_SHORT_PREAMBLE (1<<9) #define IEEE80211_TXCTL_LONG_RETRY_LIMIT (1<<10) /* this frame should be send * using the through * set_retry_limit configured @@ -359,20 +249,11 @@ struct ieee80211_tx_control { u8 retry_limit; /* 1 = only first attempt, 2 = one retry, .. * This could be used when set_retry_limit * is not implemented by the driver */ - u8 power_level; /* per-packet transmit power level, in dBm */ u8 antenna_sel_tx; /* 0 = default/diversity, 1 = Ant0, 2 = Ant1 */ u8 icv_len; /* length of the ICV/MIC field in octets */ u8 iv_len; /* length of the IV field in octets */ u8 queue; /* hardware queue to use for this frame; * 0 = highest, hw->queues-1 = lowest */ - struct ieee80211_rate *rate; /* internal 80211.o rate */ - struct ieee80211_rate *rts_rate; /* internal 80211.o rate - * for RTS/CTS */ - int alt_retry_rate; /* retry rate for the last retries, given as the - * hw specific value for the rate (from - * struct ieee80211_rate). To be used to limit - * packet dropping when probing higher rates, if hw - * supports multiple retry rates. -1 = not used */ int type; /* internal */ }; @@ -415,26 +296,24 @@ enum mac80211_rx_flags { * supported by hardware) to the 802.11 code with each received * frame. * @mactime: MAC timestamp as defined by 802.11 + * @band: the active band when this frame was received * @freq: frequency the radio was tuned to when receiving this frame, in MHz - * @channel: channel the radio was tuned to - * @phymode: active PHY mode * @ssi: signal strength when receiving this frame * @signal: used as 'qual' in statistics reporting * @noise: PHY noise when receiving this frame * @antenna: antenna used - * @rate: data rate + * @rate_idx: index of data rate into band's supported rates * @flag: %RX_FLAG_* */ struct ieee80211_rx_status { u64 mactime; + enum ieee80211_band band; int freq; - int channel; - enum ieee80211_phymode phymode; int ssi; int signal; int noise; int antenna; - int rate; + int rate_idx; int flag; }; @@ -509,41 +388,30 @@ enum ieee80211_conf_flags { * * @radio_enabled: when zero, driver is required to switch off the radio. * TODO make a flag - * @channel: IEEE 802.11 channel number - * @freq: frequency in MHz - * @channel_val: hardware specific channel value for the channel - * @phymode: PHY mode to activate (REMOVE) - * @chan: channel to switch to, pointer to the channel information - * @mode: pointer to mode definition - * @regulatory_domain: ?? * @beacon_int: beacon interval (TODO make interface config) * @flags: configuration flags defined above - * @power_level: transmit power limit for current regulatory domain in dBm - * @antenna_max: maximum antenna gain + * @power_level: requested transmit power (in dBm) + * @max_antenna_gain: maximum antenna gain (in dBi) * @antenna_sel_tx: transmit antenna selection, 0: default/diversity, * 1/2: antenna 0/1 * @antenna_sel_rx: receive antenna selection, like @antenna_sel_tx * @ht_conf: describes current self configuration of 802.11n HT capabilies * @ht_bss_conf: describes current BSS configuration of 802.11n HT parameters + * @channel: the channel to tune to */ struct ieee80211_conf { - int channel; /* IEEE 802.11 channel number */ - int freq; /* MHz */ - int channel_val; /* hw specific value for the channel */ - - enum ieee80211_phymode phymode; - struct ieee80211_channel *chan; - struct ieee80211_hw_mode *mode; unsigned int regulatory_domain; int radio_enabled; int beacon_int; u32 flags; - u8 power_level; - u8 antenna_max; + int power_level; + int max_antenna_gain; u8 antenna_sel_tx; u8 antenna_sel_rx; + struct ieee80211_channel *channel; + struct ieee80211_ht_info ht_conf; struct ieee80211_ht_bss_info ht_bss_conf; }; @@ -764,15 +632,19 @@ enum sta_notify_cmd { * %IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE is also not set because * otherwise the stack will not know when the DTIM beacon was sent. * - * @IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED: - * Channels are already configured to the default regulatory domain - * specified in the device's EEPROM + * @IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE: + * Hardware is not capable of short slot operation on the 2.4 GHz band. + * + * @IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE: + * Hardware is not capable of receiving frames with short preamble on + * the 2.4 GHz band. */ enum ieee80211_hw_flags { IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE = 1<<0, IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING = 1<<2, - IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED = 1<<3, + IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE = 1<<3, + IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE = 1<<4, }; /** @@ -784,7 +656,8 @@ enum ieee80211_hw_flags { * @wiphy: This points to the &struct wiphy allocated for this * 802.11 PHY. You must fill in the @perm_addr and @dev * members of this structure using SET_IEEE80211_DEV() - * and SET_IEEE80211_PERM_ADDR(). + * and SET_IEEE80211_PERM_ADDR(). Additionally, all supported + * bands (with channels, bitrates) are registered here. * * @conf: &struct ieee80211_conf, device configuration, don't use. * @@ -1062,7 +935,9 @@ enum ieee80211_ampdu_mlme_action { * given local_address is enabled. * * @hw_scan: Ask the hardware to service the scan request, no need to start - * the scan state machine in stack. + * the scan state machine in stack. The scan must honour the channel + * configuration done by the regulatory agent in the wiphy's registered + * bands. * * @get_stats: return low-level statistics * @@ -1284,10 +1159,6 @@ static inline char *ieee80211_get_radio_led_name(struct ieee80211_hw *hw) #endif } -/* Register a new hardware PHYMODE capability to the stack. */ -int ieee80211_register_hwmode(struct ieee80211_hw *hw, - struct ieee80211_hw_mode *mode); - /** * ieee80211_unregister_hw - Unregister a hardware device * @@ -1461,7 +1332,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from &struct ieee80211_if_init_conf. * @frame_len: the length of the frame. - * @rate: the rate (in 100kbps) at which the frame is going to be transmitted. + * @rate: the rate at which the frame is going to be transmitted. * * Calculate the duration field of some generic frame, given its * length and transmission rate (in 100kbps). @@ -1469,7 +1340,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, size_t frame_len, - int rate); + struct ieee80211_rate *rate); /** * ieee80211_get_buffered_bc - accessing buffered broadcast and multicast frames diff --git a/include/net/wireless.h b/include/net/wireless.h index d30c4ba8fd99..c7f805ee5545 100644 --- a/include/net/wireless.h +++ b/include/net/wireless.h @@ -12,6 +12,162 @@ #include #include +/** + * enum ieee80211_band - supported frequency bands + * + * The bands are assigned this way because the supported + * bitrates differ in these bands. + * + * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band + * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) + */ +enum ieee80211_band { + IEEE80211_BAND_2GHZ, + IEEE80211_BAND_5GHZ, + + /* keep last */ + IEEE80211_NUM_BANDS +}; + +/** + * enum ieee80211_channel_flags - channel flags + * + * Channel flags set by the regulatory control code. + * + * @IEEE80211_CHAN_DISABLED: This channel is disabled. + * @IEEE80211_CHAN_PASSIVE_SCAN: Only passive scanning is permitted + * on this channel. + * @IEEE80211_CHAN_NO_IBSS: IBSS is not allowed on this channel. + * @IEEE80211_CHAN_RADAR: Radar detection is required on this channel. + */ +enum ieee80211_channel_flags { + IEEE80211_CHAN_DISABLED = 1<<0, + IEEE80211_CHAN_PASSIVE_SCAN = 1<<1, + IEEE80211_CHAN_NO_IBSS = 1<<2, + IEEE80211_CHAN_RADAR = 1<<3, +}; + +/** + * struct ieee80211_channel - channel definition + * + * This structure describes a single channel for use + * with cfg80211. + * + * @center_freq: center frequency in MHz + * @hw_value: hardware-specific value for the channel + * @flags: channel flags from &enum ieee80211_channel_flags. + * @orig_flags: channel flags at registration time, used by regulatory + * code to support devices with additional restrictions + * @band: band this channel belongs to. + * @max_antenna_gain: maximum antenna gain in dBi + * @max_power: maximum transmission power (in dBm) + * @orig_mag: internal use + * @orig_mpwr: internal use + */ +struct ieee80211_channel { + enum ieee80211_band band; + u16 center_freq; + u16 hw_value; + u32 flags; + int max_antenna_gain; + int max_power; + u32 orig_flags; + int orig_mag, orig_mpwr; +}; + +/** + * enum ieee80211_rate_flags - rate flags + * + * Hardware/specification flags for rates. These are structured + * in a way that allows using the same bitrate structure for + * different bands/PHY modes. + * + * @IEEE80211_RATE_SHORT_PREAMBLE: Hardware can send with short + * preamble on this bitrate; only relevant in 2.4GHz band and + * with CCK rates. + * @IEEE80211_RATE_MANDATORY_A: This bitrate is a mandatory rate + * when used with 802.11a (on the 5 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_MANDATORY_B: This bitrate is a mandatory rate + * when used with 802.11b (on the 2.4 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_MANDATORY_G: This bitrate is a mandatory rate + * when used with 802.11g (on the 2.4 GHz band); filled by the + * core code when registering the wiphy. + * @IEEE80211_RATE_ERP_G: This is an ERP rate in 802.11g mode. + */ +enum ieee80211_rate_flags { + IEEE80211_RATE_SHORT_PREAMBLE = 1<<0, + IEEE80211_RATE_MANDATORY_A = 1<<1, + IEEE80211_RATE_MANDATORY_B = 1<<2, + IEEE80211_RATE_MANDATORY_G = 1<<3, + IEEE80211_RATE_ERP_G = 1<<4, +}; + +/** + * struct ieee80211_rate - bitrate definition + * + * This structure describes a bitrate that an 802.11 PHY can + * operate with. The two values @hw_value and @hw_value_short + * are only for driver use when pointers to this structure are + * passed around. + * + * @flags: rate-specific flags + * @bitrate: bitrate in units of 100 Kbps + * @hw_value: driver/hardware value for this rate + * @hw_value_short: driver/hardware value for this rate when + * short preamble is used + */ +struct ieee80211_rate { + u32 flags; + u16 bitrate; + u16 hw_value, hw_value_short; +}; + +/** + * struct ieee80211_ht_info - describing STA's HT capabilities + * + * This structure describes most essential parameters needed + * to describe 802.11n HT capabilities for an STA. + * + * @ht_supported: is HT supported by STA, 0: no, 1: yes + * @cap: HT capabilities map as described in 802.11n spec + * @ampdu_factor: Maximum A-MPDU length factor + * @ampdu_density: Minimum A-MPDU spacing + * @supp_mcs_set: Supported MCS set as described in 802.11n spec + */ +struct ieee80211_ht_info { + u16 cap; /* use IEEE80211_HT_CAP_ */ + u8 ht_supported; + u8 ampdu_factor; + u8 ampdu_density; + u8 supp_mcs_set[16]; +}; + +/** + * struct ieee80211_supported_band - frequency band definition + * + * This structure describes a frequency band a wiphy + * is able to operate in. + * + * @channels: Array of channels the hardware can operate in + * in this band. + * @band: the band this structure represents + * @n_channels: Number of channels in @channels + * @bitrates: Array of bitrates the hardware can operate with + * in this band. Must be sorted to give a valid "supported + * rates" IE, i.e. CCK rates first, then OFDM. + * @n_bitrates: Number of bitrates in @bitrates + */ +struct ieee80211_supported_band { + struct ieee80211_channel *channels; + struct ieee80211_rate *bitrates; + enum ieee80211_band band; + int n_channels; + int n_bitrates; + struct ieee80211_ht_info ht_info; +}; + /** * struct wiphy - wireless hardware description * @idx: the wiphy index assigned to this item @@ -30,6 +186,8 @@ struct wiphy { * help determine whether you own this wiphy or not. */ void *privid; + struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]; + /* fields below are read-only, assigned by cfg80211 */ /* the item in /sys/class/ieee80211/ points to this, @@ -136,4 +294,14 @@ extern void wiphy_unregister(struct wiphy *wiphy); */ extern void wiphy_free(struct wiphy *wiphy); +/** + * ieee80211_channel_to_frequency - convert channel number to frequency + */ +extern int ieee80211_channel_to_frequency(int chan); + +/** + * ieee80211_frequency_to_channel - convert frequency to channel number + */ +extern int ieee80211_frequency_to_channel(int freq); + #endif /* __NET_WIRELESS_H */ diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 54f46bc80cfe..9d7a19581a29 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -19,7 +19,6 @@ mac80211-y := \ ieee80211_iface.o \ ieee80211_rate.o \ michael.o \ - regdomain.o \ tkip.o \ aes_ccm.o \ cfg.o \ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 22c9619ba776..15b8cf94f510 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -498,7 +498,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, { u32 rates; int i, j; - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; if (params->station_flags & STATION_FLAG_CHANGED) { sta->flags &= ~WLAN_STA_AUTHORIZED; @@ -525,15 +525,16 @@ static void sta_apply_parameters(struct ieee80211_local *local, if (params->supported_rates) { rates = 0; - mode = local->oper_hw_mode; + sband = local->hw.wiphy->bands[local->oper_channel->band]; + for (i = 0; i < params->supported_rates_len; i++) { int rate = (params->supported_rates[i] & 0x7f) * 5; - for (j = 0; j < mode->num_rates; j++) { - if (mode->rates[j].rate == rate) + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) rates |= BIT(j); } } - sta->supp_rates = rates; + sta->supp_rates[local->oper_channel->band] = rates; } } diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 60514b2c97b9..4736c64937b4 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -19,41 +19,6 @@ int mac80211_open_file_generic(struct inode *inode, struct file *file) return 0; } -static const char *ieee80211_mode_str(int mode) -{ - switch (mode) { - case MODE_IEEE80211A: - return "IEEE 802.11a"; - case MODE_IEEE80211B: - return "IEEE 802.11b"; - case MODE_IEEE80211G: - return "IEEE 802.11g"; - default: - return "UNKNOWN"; - } -} - -static ssize_t modes_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct ieee80211_local *local = file->private_data; - struct ieee80211_hw_mode *mode; - char buf[150], *p = buf; - - /* FIXME: locking! */ - list_for_each_entry(mode, &local->modes_list, list) { - p += scnprintf(p, sizeof(buf)+buf-p, - "%s\n", ieee80211_mode_str(mode->mode)); - } - - return simple_read_from_buffer(userbuf, count, ppos, buf, p-buf); -} - -static const struct file_operations modes_ops = { - .read = modes_read, - .open = mac80211_open_file_generic, -}; - #define DEBUGFS_READONLY_FILE(name, buflen, fmt, value...) \ static ssize_t name## _read(struct file *file, char __user *userbuf, \ size_t count, loff_t *ppos) \ @@ -80,10 +45,8 @@ static const struct file_operations name## _ops = { \ local->debugfs.name = NULL; -DEBUGFS_READONLY_FILE(channel, 20, "%d", - local->hw.conf.channel); DEBUGFS_READONLY_FILE(frequency, 20, "%d", - local->hw.conf.freq); + local->hw.conf.channel->center_freq); DEBUGFS_READONLY_FILE(antenna_sel_tx, 20, "%d", local->hw.conf.antenna_sel_tx); DEBUGFS_READONLY_FILE(antenna_sel_rx, 20, "%d", @@ -100,8 +63,6 @@ DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", local->long_retry_limit); DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", local->total_ps_buffered); -DEBUGFS_READONLY_FILE(mode, 20, "%s", - ieee80211_mode_str(local->hw.conf.phymode)); DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x", local->wep_iv & 0xffffff); DEBUGFS_READONLY_FILE(rate_ctrl_alg, 100, "%s", @@ -294,7 +255,6 @@ void debugfs_hw_add(struct ieee80211_local *local) local->debugfs.stations = debugfs_create_dir("stations", phyd); local->debugfs.keys = debugfs_create_dir("keys", phyd); - DEBUGFS_ADD(channel); DEBUGFS_ADD(frequency); DEBUGFS_ADD(antenna_sel_tx); DEBUGFS_ADD(antenna_sel_rx); @@ -304,9 +264,7 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_ADD(short_retry_limit); DEBUGFS_ADD(long_retry_limit); DEBUGFS_ADD(total_ps_buffered); - DEBUGFS_ADD(mode); DEBUGFS_ADD(wep_iv); - DEBUGFS_ADD(modes); statsd = debugfs_create_dir("statistics", phyd); local->debugfs.statistics = statsd; @@ -356,7 +314,6 @@ void debugfs_hw_add(struct ieee80211_local *local) void debugfs_hw_del(struct ieee80211_local *local) { - DEBUGFS_DEL(channel); DEBUGFS_DEL(frequency); DEBUGFS_DEL(antenna_sel_tx); DEBUGFS_DEL(antenna_sel_rx); @@ -366,9 +323,7 @@ void debugfs_hw_del(struct ieee80211_local *local) DEBUGFS_DEL(short_retry_limit); DEBUGFS_DEL(long_retry_limit); DEBUGFS_DEL(total_ps_buffered); - DEBUGFS_DEL(mode); DEBUGFS_DEL(wep_iv); - DEBUGFS_DEL(modes); DEBUGFS_STATS_DEL(transmitted_fragment_count); DEBUGFS_STATS_DEL(multicast_transmitted_frame_count); diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index df25abf63137..49660f4e845d 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -33,22 +33,6 @@ static ssize_t sta_ ##name## _read(struct file *file, \ #define STA_READ_LU(name, field) STA_READ(name, 20, field, "%lu\n") #define STA_READ_S(name, field) STA_READ(name, 20, field, "%s\n") -#define STA_READ_RATE(name, field) \ -static ssize_t sta_##name##_read(struct file *file, \ - char __user *userbuf, \ - size_t count, loff_t *ppos) \ -{ \ - struct sta_info *sta = file->private_data; \ - struct ieee80211_local *local = wdev_priv(sta->dev->ieee80211_ptr);\ - struct ieee80211_hw_mode *mode = local->oper_hw_mode; \ - char buf[20]; \ - int res = scnprintf(buf, sizeof(buf), "%d\n", \ - (sta->field >= 0 && \ - sta->field < mode->num_rates) ? \ - mode->rates[sta->field].rate : -1); \ - return simple_read_from_buffer(userbuf, count, ppos, buf, res); \ -} - #define STA_OPS(name) \ static const struct file_operations sta_ ##name## _ops = { \ .read = sta_##name##_read, \ @@ -77,8 +61,6 @@ STA_FILE(rx_fragments, rx_fragments, LU); STA_FILE(rx_dropped, rx_dropped, LU); STA_FILE(tx_fragments, tx_fragments, LU); STA_FILE(tx_filtered, tx_filtered_count, LU); -STA_FILE(txrate, txrate, RATE); -STA_FILE(last_txrate, last_txrate, RATE); STA_FILE(tx_retry_failed, tx_retry_failed, LU); STA_FILE(tx_retry_count, tx_retry_count, LU); STA_FILE(last_rssi, last_rssi, D); diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 3961d4c4320c..de894b61a23c 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -876,37 +876,28 @@ int ieee80211_if_config_beacon(struct net_device *dev) int ieee80211_hw_config(struct ieee80211_local *local) { - struct ieee80211_hw_mode *mode; struct ieee80211_channel *chan; int ret = 0; - if (local->sta_sw_scanning) { + if (local->sta_sw_scanning) chan = local->scan_channel; - mode = local->scan_hw_mode; - } else { + else chan = local->oper_channel; - mode = local->oper_hw_mode; - } - local->hw.conf.channel = chan->chan; - local->hw.conf.channel_val = chan->val; - if (!local->hw.conf.power_level) { - local->hw.conf.power_level = chan->power_level; - } else { - local->hw.conf.power_level = min(chan->power_level, - local->hw.conf.power_level); - } - local->hw.conf.freq = chan->freq; - local->hw.conf.phymode = mode->mode; - local->hw.conf.antenna_max = chan->antenna_max; - local->hw.conf.chan = chan; - local->hw.conf.mode = mode; + local->hw.conf.channel = chan; + + if (!local->hw.conf.power_level) + local->hw.conf.power_level = chan->max_power; + else + local->hw.conf.power_level = min(chan->max_power, + local->hw.conf.power_level); + + local->hw.conf.max_antenna_gain = chan->max_antenna_gain; #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "HW CONFIG: channel=%d freq=%d " - "phymode=%d\n", local->hw.conf.channel, local->hw.conf.freq, - local->hw.conf.phymode); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n", + wiphy_name(local->hw.wiphy), chan->center_freq); +#endif if (local->open_count) ret = local->ops->config(local_to_hw(local), &local->hw.conf); @@ -924,11 +915,13 @@ int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, struct ieee80211_ht_bss_info *req_bss_cap) { struct ieee80211_conf *conf = &local->hw.conf; - struct ieee80211_hw_mode *mode = conf->mode; + struct ieee80211_supported_band *sband; int i; + sband = local->hw.wiphy->bands[conf->channel->band]; + /* HT is not supported */ - if (!mode->ht_info.ht_supported) { + if (!sband->ht_info.ht_supported) { conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; return -EOPNOTSUPP; } @@ -938,17 +931,17 @@ int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; } else { conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; - conf->ht_conf.cap = req_ht_cap->cap & mode->ht_info.cap; + conf->ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; conf->ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); conf->ht_conf.cap |= - mode->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; + sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; conf->ht_bss_conf.primary_channel = req_bss_cap->primary_channel; conf->ht_bss_conf.bss_cap = req_bss_cap->bss_cap; conf->ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; for (i = 0; i < SUPP_MCS_SET_LEN; i++) conf->ht_conf.supp_mcs_set[i] = - mode->ht_info.supp_mcs_set[i] & + sband->ht_info.supp_mcs_set[i] & req_ht_cap->supp_mcs_set[i]; /* In STA mode, this gives us indication @@ -1418,10 +1411,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->long_retry_limit = 4; local->hw.conf.radio_enabled = 1; - local->enabled_modes = ~0; - - INIT_LIST_HEAD(&local->modes_list); - INIT_LIST_HEAD(&local->interfaces); INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); @@ -1466,6 +1455,25 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) struct ieee80211_local *local = hw_to_local(hw); const char *name; int result; + enum ieee80211_band band; + + /* + * generic code guarantees at least one band, + * set this very early because much code assumes + * that hw.conf.channel is assigned + */ + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[band]; + if (sband) { + /* init channel we're on */ + local->hw.conf.channel = + local->oper_channel = + local->scan_channel = &sband->channels[0]; + break; + } + } result = wiphy_register(local->hw.wiphy); if (result < 0) @@ -1567,44 +1575,10 @@ fail_workqueue: } EXPORT_SYMBOL(ieee80211_register_hw); -int ieee80211_register_hwmode(struct ieee80211_hw *hw, - struct ieee80211_hw_mode *mode) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_rate *rate; - int i; - - INIT_LIST_HEAD(&mode->list); - list_add_tail(&mode->list, &local->modes_list); - - local->hw_modes |= (1 << mode->mode); - for (i = 0; i < mode->num_rates; i++) { - rate = &(mode->rates[i]); - rate->rate_inv = CHAN_UTIL_RATE_LCM / rate->rate; - } - ieee80211_prepare_rates(local, mode); - - if (!local->oper_hw_mode) { - /* Default to this mode */ - local->hw.conf.phymode = mode->mode; - local->oper_hw_mode = local->scan_hw_mode = mode; - local->oper_channel = local->scan_channel = &mode->channels[0]; - local->hw.conf.mode = local->oper_hw_mode; - local->hw.conf.chan = local->oper_channel; - } - - if (!(hw->flags & IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED)) - ieee80211_set_default_regdomain(mode); - - return 0; -} -EXPORT_SYMBOL(ieee80211_register_hwmode); - void ieee80211_unregister_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata, *tmp; - int i; tasklet_kill(&local->tx_pending_tasklet); tasklet_kill(&local->tasklet); @@ -1645,11 +1619,6 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) rate_control_deinitialize(local); debugfs_hw_del(local); - for (i = 0; i < NUM_IEEE80211_MODES; i++) { - kfree(local->supp_rates[i]); - kfree(local->basic_rates[i]); - } - if (skb_queue_len(&local->skb_queue) || skb_queue_len(&local->skb_queue_unreliable)) printk(KERN_WARNING "%s: skb_queue not empty\n", @@ -1696,7 +1665,6 @@ static int __init ieee80211_init(void) } ieee80211_debugfs_netdev_init(); - ieee80211_regdomain_init(); return 0; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 9d09ba8cc02b..54eea5f24474 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -79,8 +79,7 @@ struct ieee80211_sta_bss { u8 ssid[IEEE80211_MAX_SSID_LEN]; size_t ssid_len; u16 capability; /* host byte order */ - int hw_mode; - int channel; + enum ieee80211_band band; int freq; int rssi, signal, noise; u8 *wpa_ie; @@ -136,13 +135,12 @@ struct ieee80211_txrx_data { union { struct { struct ieee80211_tx_control *control; - struct ieee80211_hw_mode *mode; + struct ieee80211_channel *channel; struct ieee80211_rate *rate; /* use this rate (if set) for last fragment; rate can * be set to lower rate for the first fragments, e.g., * when using CTS protection with IEEE 802.11g. */ struct ieee80211_rate *last_frag_rate; - int last_frag_hwrate; /* Extra fragments (in addition to the first fragment * in skb) */ @@ -151,6 +149,7 @@ struct ieee80211_txrx_data { } tx; struct { struct ieee80211_rx_status *status; + struct ieee80211_rate *rate; int sent_ps_buffered; int queue; int load; @@ -179,8 +178,6 @@ struct ieee80211_tx_stored_packet { struct sk_buff *skb; int num_extra_frag; struct sk_buff **extra_frag; - int last_frag_rateidx; - int last_frag_hwrate; struct ieee80211_rate *last_frag_rate; unsigned int last_frag_rate_ctrl_probe; }; @@ -283,7 +280,7 @@ struct ieee80211_if_sta { unsigned long ibss_join_req; struct sk_buff *probe_resp; /* ProbeResp template for IBSS */ - u32 supp_rates_bits; + u32 supp_rates_bits[IEEE80211_NUM_BANDS]; int wmm_last_param_set; }; @@ -293,6 +290,7 @@ struct ieee80211_if_sta { #define IEEE80211_SDATA_ALLMULTI BIT(0) #define IEEE80211_SDATA_PROMISC BIT(1) #define IEEE80211_SDATA_USERSPACE_MLME BIT(2) +#define IEEE80211_SDATA_OPERATING_GMODE BIT(3) struct ieee80211_sub_if_data { struct list_head list; @@ -313,6 +311,11 @@ struct ieee80211_sub_if_data { */ int ieee802_1x_pac; + /* + * basic rates of this AP or the AP we're associated to + */ + u64 basic_rates; + u16 sequence; /* Fragment table for host-based reassembly */ @@ -420,9 +423,6 @@ struct ieee80211_local { const struct ieee80211_ops *ops; - /* List of registered struct ieee80211_hw_mode */ - struct list_head modes_list; - struct net_device *mdev; /* wmaster# - "master" 802.11 device */ int open_count; int monitors; @@ -462,11 +462,6 @@ struct ieee80211_local { struct rate_control_ref *rate_ctrl; - /* Supported and basic rate filters for different modes. These are - * pointers to -1 terminated lists and rates in 100 kbps units. */ - int *supp_rates[NUM_IEEE80211_MODES]; - int *basic_rates[NUM_IEEE80211_MODES]; - int rts_threshold; int fragmentation_threshold; int short_retry_limit; /* dot11ShortRetryLimit */ @@ -488,12 +483,13 @@ struct ieee80211_local { bool sta_sw_scanning; bool sta_hw_scanning; int scan_channel_idx; + enum ieee80211_band scan_band; + enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state; unsigned long last_scan_completed; struct delayed_work scan_work; struct net_device *scan_dev; struct ieee80211_channel *oper_channel, *scan_channel; - struct ieee80211_hw_mode *oper_hw_mode, *scan_hw_mode; u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; size_t scan_ssid_len; struct list_head sta_bss_list; @@ -562,14 +558,8 @@ struct ieee80211_local { int wifi_wme_noack_test; unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ - unsigned int enabled_modes; /* bitfield of allowed modes; - * (1 << MODE_*) */ - unsigned int hw_modes; /* bitfield of supported hardware modes; - * (1 << MODE_*) */ - #ifdef CONFIG_MAC80211_DEBUGFS struct local_debugfsdentries { - struct dentry *channel; struct dentry *frequency; struct dentry *antenna_sel_tx; struct dentry *antenna_sel_rx; @@ -579,9 +569,7 @@ struct ieee80211_local { struct dentry *short_retry_limit; struct dentry *long_retry_limit; struct dentry *total_ps_buffered; - struct dentry *mode; struct dentry *wep_iv; - struct dentry *modes; struct dentry *statistics; struct local_debugfsdentries_statsdentries { struct dentry *transmitted_fragment_count; @@ -692,23 +680,6 @@ static inline void bss_tim_clear(struct ieee80211_local *local, read_unlock_bh(&local->sta_lock); } -/** - * ieee80211_is_erp_rate - Check if a rate is an ERP rate - * @phymode: The PHY-mode for this rate (MODE_IEEE80211...) - * @rate: Transmission rate to check, in 100 kbps - * - * Check if a given rate is an Extended Rate PHY (ERP) rate. - */ -static inline int ieee80211_is_erp_rate(int phymode, int rate) -{ - if (phymode == MODE_IEEE80211G) { - if (rate != 10 && rate != 20 && - rate != 55 && rate != 110) - return 1; - } - return 0; -} - static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) { return compare_ether_addr(raddr, addr) == 0 || @@ -720,13 +691,9 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) int ieee80211_hw_config(struct ieee80211_local *local); int ieee80211_if_config(struct net_device *dev); int ieee80211_if_config_beacon(struct net_device *dev); -void ieee80211_prepare_rates(struct ieee80211_local *local, - struct ieee80211_hw_mode *mode); void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); void ieee80211_if_setup(struct net_device *dev); -struct ieee80211_rate *ieee80211_get_rate(struct ieee80211_local *local, - int phymode, int hwrate); int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, struct ieee80211_ht_info *req_ht_cap, struct ieee80211_ht_bss_info *req_bss_cap); @@ -757,7 +724,7 @@ extern const struct iw_handler_def ieee80211_iw_handler_def; /* ieee80211_ioctl.c */ int ieee80211_set_compression(struct ieee80211_local *local, struct net_device *dev, struct sta_info *sta); -int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq); +int ieee80211_set_freq(struct ieee80211_local *local, int freq); /* ieee80211_sta.c */ void ieee80211_sta_timer(unsigned long data); void ieee80211_sta_work(struct work_struct *work); @@ -810,10 +777,6 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id); void ieee80211_if_free(struct net_device *dev); void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata); -/* regdomain.c */ -void ieee80211_regdomain_init(void); -void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode); - /* rx handling */ extern ieee80211_rx_handler ieee80211_rx_handlers[]; diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 92f1eb2da311..27cee580f9f1 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -118,6 +118,8 @@ void ieee80211_if_set_type(struct net_device *dev, int type) sdata->bss = NULL; sdata->vif.type = type; + sdata->basic_rates = 0; + switch (type) { case IEEE80211_IF_TYPE_WDS: /* nothing special */ diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 5024d3733834..54ad07aafe2d 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -129,22 +129,7 @@ static int ieee80211_ioctl_giwname(struct net_device *dev, struct iw_request_info *info, char *name, char *extra) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - switch (local->hw.conf.phymode) { - case MODE_IEEE80211A: - strcpy(name, "IEEE 802.11a"); - break; - case MODE_IEEE80211B: - strcpy(name, "IEEE 802.11b"); - break; - case MODE_IEEE80211G: - strcpy(name, "IEEE 802.11g"); - break; - default: - strcpy(name, "IEEE 802.11"); - break; - } + strcpy(name, "IEEE 802.11"); return 0; } @@ -156,7 +141,7 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct iw_range *range = (struct iw_range *) extra; - struct ieee80211_hw_mode *mode = NULL; + enum ieee80211_band band; int c = 0; data->length = sizeof(struct iw_range); @@ -191,24 +176,27 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - list_for_each_entry(mode, &local->modes_list, list) { - int i = 0; - if (!(local->enabled_modes & (1 << mode->mode)) || - (local->hw_modes & local->enabled_modes & - (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B)) + for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { + int i; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[band]; + + if (!sband) continue; - while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) { - struct ieee80211_channel *chan = &mode->channels[i]; + for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { + struct ieee80211_channel *chan = &sband->channels[i]; - if (chan->flag & IEEE80211_CHAN_W_SCAN) { - range->freq[c].i = chan->chan; - range->freq[c].m = chan->freq * 100000; - range->freq[c].e = 1; + if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { + range->freq[c].i = + ieee80211_frequency_to_channel( + chan->center_freq); + range->freq[c].m = chan->center_freq; + range->freq[c].e = 6; c++; } - i++; } } range->num_channels = c; @@ -294,22 +282,29 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev, return 0; } -int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq) +int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz) { - struct ieee80211_hw_mode *mode; - int c, set = 0; + int set = 0; int ret = -EINVAL; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + int i; + + for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { + sband = local->hw.wiphy->bands[band]; - list_for_each_entry(mode, &local->modes_list, list) { - if (!(local->enabled_modes & (1 << mode->mode))) + if (!sband) continue; - for (c = 0; c < mode->num_channels; c++) { - struct ieee80211_channel *chan = &mode->channels[c]; - if (chan->flag & IEEE80211_CHAN_W_SCAN && - ((chan->chan == channel) || (chan->freq == freq))) { - local->oper_channel = chan; - local->oper_hw_mode = mode; + + for (i = 0; i < sband->n_channels; i++) { + struct ieee80211_channel *chan = &sband->channels[i]; + + if (chan->flags & IEEE80211_CHAN_DISABLED) + continue; + + if (chan->center_freq == freqMHz) { set = 1; + local->oper_channel = chan; break; } } @@ -347,13 +342,14 @@ static int ieee80211_ioctl_siwfreq(struct net_device *dev, IEEE80211_STA_AUTO_CHANNEL_SEL; return 0; } else - return ieee80211_set_channel(local, freq->m, -1); + return ieee80211_set_freq(local, + ieee80211_channel_to_frequency(freq->m)); } else { int i, div = 1000000; for (i = 0; i < freq->e; i++) div /= 10; if (div > 0) - return ieee80211_set_channel(local, -1, freq->m / div); + return ieee80211_set_freq(local, freq->m / div); else return -EINVAL; } @@ -366,10 +362,7 @@ static int ieee80211_ioctl_giwfreq(struct net_device *dev, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - /* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level - * driver for the current channel with firmware-based management */ - - freq->m = local->hw.conf.freq; + freq->m = local->hw.conf.channel->center_freq; freq->e = 6; return 0; @@ -566,15 +559,17 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, struct iw_param *rate, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw_mode *mode; - int i; + int i, err = -EINVAL; u32 target_rate = rate->value / 100000; struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (!sdata->bss) return -ENODEV; - mode = local->oper_hw_mode; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates * target_rate = X, rate->fixed = 1 means only rate X * target_rate = X, rate->fixed = 0 means all rates <= X */ @@ -582,18 +577,20 @@ static int ieee80211_ioctl_siwrate(struct net_device *dev, sdata->bss->force_unicast_rateidx = -1; if (rate->value < 0) return 0; - for (i=0; i < mode->num_rates; i++) { - struct ieee80211_rate *rates = &mode->rates[i]; - int this_rate = rates->rate; + + for (i=0; i< sband->n_bitrates; i++) { + struct ieee80211_rate *brate = &sband->bitrates[i]; + int this_rate = brate->bitrate; if (target_rate == this_rate) { sdata->bss->max_ratectrl_rateidx = i; if (rate->fixed) sdata->bss->force_unicast_rateidx = i; - return 0; + err = 0; + break; } } - return -EINVAL; + return err; } static int ieee80211_ioctl_giwrate(struct net_device *dev, @@ -603,18 +600,24 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type == IEEE80211_IF_TYPE_STA) sta = sta_info_get(local, sdata->u.sta.bssid); else return -EOPNOTSUPP; if (!sta) return -ENODEV; - if (sta->txrate < local->oper_hw_mode->num_rates) - rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + if (sta->txrate_idx < sband->n_bitrates) + rate->value = sband->bitrates[sta->txrate_idx].bitrate; else rate->value = 0; + rate->value *= 100000; sta_info_put(sta); return 0; } @@ -625,7 +628,7 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); bool need_reconfig = 0; - u8 new_power_level; + int new_power_level; if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) return -EINVAL; @@ -635,13 +638,15 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, if (data->txpower.fixed) { new_power_level = data->txpower.value; } else { - /* Automatic power level. Get the px power from the current - * channel. */ - struct ieee80211_channel* chan = local->oper_channel; + /* + * Automatic power level. Use maximum power for the current + * channel. Should be part of rate control. + */ + struct ieee80211_channel* chan = local->hw.conf.channel; if (!chan) return -EINVAL; - new_power_level = chan->power_level; + new_power_level = chan->max_power; } if (local->hw.conf.power_level != new_power_level) { diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c index b957e67c5fba..ebe29b716b27 100644 --- a/net/mac80211/ieee80211_rate.c +++ b/net/mac80211/ieee80211_rate.c @@ -163,7 +163,8 @@ static void rate_control_release(struct kref *kref) } void rate_control_get_rate(struct net_device *dev, - struct ieee80211_hw_mode *mode, struct sk_buff *skb, + struct ieee80211_supported_band *sband, + struct sk_buff *skb, struct rate_selection *sel) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -174,17 +175,17 @@ void rate_control_get_rate(struct net_device *dev, memset(sel, 0, sizeof(struct rate_selection)); - ref->ops->get_rate(ref->priv, dev, mode, skb, sel); + ref->ops->get_rate(ref->priv, dev, sband, skb, sel); /* Select a non-ERP backup rate. */ if (!sel->nonerp) { - for (i = 0; i < mode->num_rates - 1; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - if (sel->rate->rate < rate->rate) + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *rate = &sband->bitrates[i]; + if (sel->rate->bitrate < rate->bitrate) break; - if (rate_supported(sta, mode, i) && - !(rate->flags & IEEE80211_RATE_ERP)) + if (rate_supported(sta, sband->band, i) && + !(rate->flags & IEEE80211_RATE_ERP_G)) sel->nonerp = rate; } } diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h index 73f19e8aa51c..5f9a2ca49a57 100644 --- a/net/mac80211/ieee80211_rate.h +++ b/net/mac80211/ieee80211_rate.h @@ -18,6 +18,7 @@ #include "ieee80211_i.h" #include "sta_info.h" +/* TODO: kdoc */ struct rate_selection { /* Selected transmission rate */ struct ieee80211_rate *rate; @@ -34,7 +35,8 @@ struct rate_control_ops { struct sk_buff *skb, struct ieee80211_tx_status *status); void (*get_rate)(void *priv, struct net_device *dev, - struct ieee80211_hw_mode *mode, struct sk_buff *skb, + struct ieee80211_supported_band *band, + struct sk_buff *skb, struct rate_selection *sel); void (*rate_init)(void *priv, void *priv_sta, struct ieee80211_local *local, struct sta_info *sta); @@ -66,7 +68,8 @@ void ieee80211_rate_control_unregister(struct rate_control_ops *ops); struct rate_control_ref *rate_control_alloc(const char *name, struct ieee80211_local *local); void rate_control_get_rate(struct net_device *dev, - struct ieee80211_hw_mode *mode, struct sk_buff *skb, + struct ieee80211_supported_band *sband, + struct sk_buff *skb, struct rate_selection *sel); struct rate_control_ref *rate_control_get(struct rate_control_ref *ref); void rate_control_put(struct rate_control_ref *ref); @@ -127,23 +130,23 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) #endif } -static inline int -rate_supported(struct sta_info *sta, struct ieee80211_hw_mode *mode, int index) +static inline int rate_supported(struct sta_info *sta, + enum ieee80211_band band, + int index) { - return (sta == NULL || sta->supp_rates & BIT(index)) && - (mode->rates[index].flags & IEEE80211_RATE_SUPPORTED); + return (sta == NULL || sta->supp_rates[band] & BIT(index)); } static inline int -rate_lowest_index(struct ieee80211_local *local, struct ieee80211_hw_mode *mode, +rate_lowest_index(struct ieee80211_local *local, + struct ieee80211_supported_band *sband, struct sta_info *sta) { int i; - for (i = 0; i < mode->num_rates; i++) { - if (rate_supported(sta, mode, i)) + for (i = 0; i < sband->n_bitrates; i++) + if (rate_supported(sta, sband->band, i)) return i; - } /* warn when we cannot find a rate. */ WARN_ON(1); @@ -152,10 +155,11 @@ rate_lowest_index(struct ieee80211_local *local, struct ieee80211_hw_mode *mode, } static inline struct ieee80211_rate * -rate_lowest(struct ieee80211_local *local, struct ieee80211_hw_mode *mode, +rate_lowest(struct ieee80211_local *local, + struct ieee80211_supported_band *sband, struct sta_info *sta) { - return &mode->rates[rate_lowest_index(local, mode, sta)]; + return &sband->bitrates[rate_lowest_index(local, sband, sta)]; } diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index d0273ccbdbae..2628222a5085 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -74,7 +74,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, u8 *ssid, size_t ssid_len); static struct ieee80211_sta_bss * -ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel, +ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, u8 *ssid, u8 ssid_len); static void ieee80211_rx_bss_put(struct net_device *dev, struct ieee80211_sta_bss *bss); @@ -466,7 +466,7 @@ static void ieee80211_set_associated(struct net_device *dev, return; bss = ieee80211_rx_bss_get(dev, ifsta->bssid, - local->hw.conf.channel, + local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (bss) { if (bss->has_erp_value) @@ -593,7 +593,6 @@ static void ieee80211_send_assoc(struct net_device *dev, struct ieee80211_if_sta *ifsta) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw_mode *mode; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos, *ies; @@ -601,6 +600,7 @@ static void ieee80211_send_assoc(struct net_device *dev, u16 capab; struct ieee80211_sta_bss *bss; int wmm = 0; + struct ieee80211_supported_band *sband; skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + ifsta->extra_ie_len + @@ -612,13 +612,19 @@ static void ieee80211_send_assoc(struct net_device *dev, } skb_reserve(skb, local->hw.extra_tx_headroom); - mode = local->oper_hw_mode; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + capab = ifsta->capab; - if (mode->mode == MODE_IEEE80211G) { - capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME | - WLAN_CAPABILITY_SHORT_PREAMBLE; + + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; } - bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel, + + bss = ieee80211_rx_bss_get(dev, ifsta->bssid, + local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (bss) { if (bss->capability & WLAN_CAPABILITY_PRIVACY) @@ -657,23 +663,23 @@ static void ieee80211_send_assoc(struct net_device *dev, *pos++ = ifsta->ssid_len; memcpy(pos, ifsta->ssid, ifsta->ssid_len); - len = mode->num_rates; + len = sband->n_bitrates; if (len > 8) len = 8; pos = skb_put(skb, len + 2); *pos++ = WLAN_EID_SUPP_RATES; *pos++ = len; for (i = 0; i < len; i++) { - int rate = mode->rates[i].rate; + int rate = sband->bitrates[i].bitrate; *pos++ = (u8) (rate / 5); } - if (mode->num_rates > len) { - pos = skb_put(skb, mode->num_rates - len + 2); + if (sband->n_bitrates > len) { + pos = skb_put(skb, sband->n_bitrates - len + 2); *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = mode->num_rates - len; - for (i = len; i < mode->num_rates; i++) { - int rate = mode->rates[i].rate; + *pos++ = sband->n_bitrates - len; + for (i = len; i < sband->n_bitrates; i++) { + int rate = sband->bitrates[i].bitrate; *pos++ = (u8) (rate / 5); } } @@ -696,17 +702,18 @@ static void ieee80211_send_assoc(struct net_device *dev, *pos++ = 0; } /* wmm support is a must to HT */ - if (wmm && mode->ht_info.ht_supported) { - __le16 tmp = cpu_to_le16(mode->ht_info.cap); + if (wmm && sband->ht_info.ht_supported) { + __le16 tmp = cpu_to_le16(sband->ht_info.cap); pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); *pos++ = WLAN_EID_HT_CAPABILITY; *pos++ = sizeof(struct ieee80211_ht_cap); memset(pos, 0, sizeof(struct ieee80211_ht_cap)); memcpy(pos, &tmp, sizeof(u16)); pos += sizeof(u16); - *pos++ = (mode->ht_info.ampdu_factor | - (mode->ht_info.ampdu_density << 2)); - memcpy(pos, mode->ht_info.supp_mcs_set, 16); + /* TODO: needs a define here for << 2 */ + *pos++ = sband->ht_info.ampdu_factor | + (sband->ht_info.ampdu_density << 2); + memcpy(pos, sband->ht_info.supp_mcs_set, 16); } kfree(ifsta->assocreq_ies); @@ -789,7 +796,8 @@ static int ieee80211_privacy_mismatch(struct net_device *dev, if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL)) return 0; - bss = ieee80211_rx_bss_get(dev, ifsta->bssid, local->hw.conf.channel, + bss = ieee80211_rx_bss_get(dev, ifsta->bssid, + local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (!bss) return 0; @@ -899,7 +907,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, u8 *ssid, size_t ssid_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos, *supp_rates, *esupp_rates = NULL; @@ -933,11 +941,10 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, supp_rates = skb_put(skb, 2); supp_rates[0] = WLAN_EID_SUPP_RATES; supp_rates[1] = 0; - mode = local->oper_hw_mode; - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - if (!(rate->flags & IEEE80211_RATE_SUPPORTED)) - continue; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *rate = &sband->bitrates[i]; if (esupp_rates) { pos = skb_put(skb, 1); esupp_rates[1]++; @@ -950,7 +957,7 @@ static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, pos = skb_put(skb, 1); supp_rates[1]++; } - *pos = rate->rate / 5; + *pos = rate->bitrate / 5; } ieee80211_sta_tx(dev, skb, 0); @@ -1146,9 +1153,11 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, } /* determine default buffer size */ if (buf_size == 0) { - struct ieee80211_hw_mode *mode = conf->mode; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[conf->channel->band]; buf_size = IEEE80211_MIN_AMPDU_BUF; - buf_size = buf_size << mode->ht_info.ampdu_factor; + buf_size = buf_size << sband->ht_info.ampdu_factor; } tid_agg_rx = &sta->ampdu_mlme.tid_rx[tid]; @@ -1718,15 +1727,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct net_device *dev = sdata->dev; - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; struct sta_info *sta; - u32 rates; + u64 rates, basic_rates; u16 capab_info, status_code, aid; struct ieee802_11_elems elems; struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; u8 *pos; int i, j; DECLARE_MAC_BUF(mac); + bool have_higher_than_11mbit = false; /* AssocResp and ReassocResp have identical structure, so process both * of them in this function. */ @@ -1796,10 +1806,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (ifsta->assocresp_ies) memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); - /* set AID, ieee80211_set_associated() will tell the driver */ - bss_conf->aid = aid; - ieee80211_set_associated(dev, ifsta, 1); - /* Add STA entry for the AP */ sta = sta_info_get(local, ifsta->bssid); if (!sta) { @@ -1811,7 +1817,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, return; } bss = ieee80211_rx_bss_get(dev, ifsta->bssid, - local->hw.conf.channel, + local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (bss) { sta->last_rssi = bss->rssi; @@ -1825,20 +1831,46 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP; rates = 0; - mode = local->oper_hw_mode; + basic_rates = 0; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + for (i = 0; i < elems.supp_rates_len; i++) { int rate = (elems.supp_rates[i] & 0x7f) * 5; - for (j = 0; j < mode->num_rates; j++) - if (mode->rates[j].rate == rate) + + if (rate > 110) + have_higher_than_11mbit = true; + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) rates |= BIT(j); + if (elems.supp_rates[i] & 0x80) + basic_rates |= BIT(j); + } } + for (i = 0; i < elems.ext_supp_rates_len; i++) { int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; - for (j = 0; j < mode->num_rates; j++) - if (mode->rates[j].rate == rate) + + if (rate > 110) + have_higher_than_11mbit = true; + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) rates |= BIT(j); + if (elems.ext_supp_rates[i] & 0x80) + basic_rates |= BIT(j); + } } - sta->supp_rates = rates; + + sta->supp_rates[local->hw.conf.channel->band] = rates; + sdata->basic_rates = basic_rates; + + /* cf. IEEE 802.11 9.2.12 */ + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + have_higher_than_11mbit) + sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; + else + sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && local->ops->conf_ht) { @@ -1861,6 +1893,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, elems.wmm_param_len); } + /* set AID, ieee80211_set_associated() will tell the driver */ + bss_conf->aid = aid; + ieee80211_set_associated(dev, ifsta, 1); sta_info_put(sta); @@ -1901,7 +1936,7 @@ static void __ieee80211_rx_bss_hash_del(struct net_device *dev, static struct ieee80211_sta_bss * -ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel, +ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int freq, u8 *ssid, u8 ssid_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -1913,7 +1948,7 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel, atomic_inc(&bss->users); atomic_inc(&bss->users); memcpy(bss->bssid, bssid, ETH_ALEN); - bss->channel = channel; + bss->freq = freq; if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) { memcpy(bss->ssid, ssid, ssid_len); bss->ssid_len = ssid_len; @@ -1929,7 +1964,7 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel, static struct ieee80211_sta_bss * -ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel, +ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, u8 *ssid, u8 ssid_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -1939,7 +1974,7 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel, bss = local->sta_bss_hash[STA_HASH(bssid)]; while (bss) { if (!memcmp(bss->bssid, bssid, ETH_ALEN) && - bss->channel == channel && + bss->freq == freq && bss->ssid_len == ssid_len && (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { atomic_inc(&bss->users); @@ -2004,7 +2039,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee802_11_elems elems; size_t baselen; - int channel, clen; + int freq, clen; struct ieee80211_sta_bss *bss; struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -2055,26 +2090,22 @@ static void ieee80211_rx_bss_info(struct net_device *dev, if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && (sta = sta_info_get(local, mgmt->sa))) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rates; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *bitrates; size_t num_rates; - u32 supp_rates, prev_rates; + u64 supp_rates, prev_rates; int i, j; - mode = local->sta_sw_scanning ? - local->scan_hw_mode : local->oper_hw_mode; - - if (local->sta_hw_scanning) { - /* search for the correct mode matches the beacon */ - list_for_each_entry(mode, &local->modes_list, list) - if (mode->mode == rx_status->phymode) - break; + sband = local->hw.wiphy->bands[rx_status->band]; - if (mode == NULL) - mode = local->oper_hw_mode; + if (!sband) { + WARN_ON(1); + sband = local->hw.wiphy->bands[ + local->hw.conf.channel->band]; } - rates = mode->rates; - num_rates = mode->num_rates; + + bitrates = sband->bitrates; + num_rates = sband->n_bitrates; supp_rates = 0; for (i = 0; i < elems.supp_rates_len + @@ -2088,24 +2119,27 @@ static void ieee80211_rx_bss_info(struct net_device *dev, [i - elems.supp_rates_len]; own_rate = 5 * (rate & 0x7f); for (j = 0; j < num_rates; j++) - if (rates[j].rate == own_rate) + if (bitrates[j].bitrate == own_rate) supp_rates |= BIT(j); } - prev_rates = sta->supp_rates; - sta->supp_rates &= supp_rates; - if (sta->supp_rates == 0) { + prev_rates = sta->supp_rates[rx_status->band]; + sta->supp_rates[rx_status->band] &= supp_rates; + if (sta->supp_rates[rx_status->band] == 0) { /* No matching rates - this should not really happen. * Make sure that at least one rate is marked * supported to avoid issues with TX rate ctrl. */ - sta->supp_rates = sdata->u.sta.supp_rates_bits; + sta->supp_rates[rx_status->band] = + sdata->u.sta.supp_rates_bits[rx_status->band]; } - if (sta->supp_rates != prev_rates) { + if (sta->supp_rates[rx_status->band] != prev_rates) { printk(KERN_DEBUG "%s: updated supp_rates set for " - "%s based on beacon info (0x%x & 0x%x -> " - "0x%x)\n", - dev->name, print_mac(mac, sta->addr), prev_rates, - supp_rates, sta->supp_rates); + "%s based on beacon info (0x%llx & 0x%llx -> " + "0x%llx)\n", + dev->name, print_mac(mac, sta->addr), + (unsigned long long) prev_rates, + (unsigned long long) supp_rates, + (unsigned long long) sta->supp_rates[rx_status->band]); } sta_info_put(sta); } @@ -2114,14 +2148,14 @@ static void ieee80211_rx_bss_info(struct net_device *dev, return; if (elems.ds_params && elems.ds_params_len == 1) - channel = elems.ds_params[0]; + freq = ieee80211_channel_to_frequency(elems.ds_params[0]); else - channel = rx_status->channel; + freq = rx_status->freq; - bss = ieee80211_rx_bss_get(dev, mgmt->bssid, channel, + bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq, elems.ssid, elems.ssid_len); if (!bss) { - bss = ieee80211_rx_bss_add(dev, mgmt->bssid, channel, + bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, elems.ssid, elems.ssid_len); if (!bss) return; @@ -2134,6 +2168,8 @@ static void ieee80211_rx_bss_info(struct net_device *dev, #endif } + bss->band = rx_status->band; + if (bss->probe_resp && beacon) { /* Do not allow beacon to override data from Probe Response. */ ieee80211_rx_bss_put(dev, bss); @@ -2232,20 +2268,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->ht_ie_len = 0; } - bss->hw_mode = rx_status->phymode; - bss->freq = rx_status->freq; - if (channel != rx_status->channel && - (bss->hw_mode == MODE_IEEE80211G || - bss->hw_mode == MODE_IEEE80211B) && - channel >= 1 && channel <= 14) { - static const int freq_list[] = { - 2412, 2417, 2422, 2427, 2432, 2437, 2442, - 2447, 2452, 2457, 2462, 2467, 2472, 2484 - }; - /* IEEE 802.11g/b mode can receive packets from neighboring - * channels, so map the channel into frequency. */ - bss->freq = freq_list[channel - 1]; - } bss->timestamp = timestamp; bss->last_update = jiffies; bss->rssi = rx_status->ssi; @@ -2817,7 +2839,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, } spin_lock_bh(&local->sta_bss_lock); - freq = local->oper_channel->freq; + freq = local->oper_channel->center_freq; list_for_each_entry(bss, &local->sta_bss_list, list) { if (!(bss->capability & WLAN_CAPABILITY_ESS)) continue; @@ -2848,7 +2870,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, spin_unlock_bh(&local->sta_bss_lock); if (selected) { - ieee80211_set_channel(local, -1, selected->freq); + ieee80211_set_freq(local, selected->freq); if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) ieee80211_sta_set_ssid(dev, selected->ssid, selected->ssid_len); @@ -2881,10 +2903,12 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, struct sk_buff *skb; struct ieee80211_mgmt *mgmt; struct ieee80211_tx_control control; - struct ieee80211_hw_mode *mode; struct rate_selection ratesel; u8 *pos; struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; /* Remove possible STA entries from other IBSS networks. */ sta_info_flush(local, NULL); @@ -2904,12 +2928,11 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, sdata->drop_unencrypted = bss->capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; - res = ieee80211_set_channel(local, -1, bss->freq); + res = ieee80211_set_freq(local, bss->freq); - if (!(local->oper_channel->flag & IEEE80211_CHAN_W_IBSS)) { - printk(KERN_DEBUG "%s: IBSS not allowed on channel %d " - "(%d MHz)\n", dev->name, local->hw.conf.channel, - local->hw.conf.freq); + if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) { + printk(KERN_DEBUG "%s: IBSS not allowed on frequency " + "%d MHz\n", dev->name, local->oper_channel->center_freq); return -1; } @@ -2946,10 +2969,12 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, *pos++ = rates; memcpy(pos, bss->supp_rates, rates); - pos = skb_put(skb, 2 + 1); - *pos++ = WLAN_EID_DS_PARAMS; - *pos++ = 1; - *pos++ = bss->channel; + if (bss->band == IEEE80211_BAND_2GHZ) { + pos = skb_put(skb, 2 + 1); + *pos++ = WLAN_EID_DS_PARAMS; + *pos++ = 1; + *pos++ = ieee80211_frequency_to_channel(bss->freq); + } pos = skb_put(skb, 2 + 2); *pos++ = WLAN_EID_IBSS_PARAMS; @@ -2967,19 +2992,18 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, } memset(&control, 0, sizeof(control)); - rate_control_get_rate(dev, local->oper_hw_mode, skb, &ratesel); + rate_control_get_rate(dev, sband, skb, &ratesel); if (!ratesel.rate) { printk(KERN_DEBUG "%s: Failed to determine TX rate " "for IBSS beacon\n", dev->name); break; } control.vif = &sdata->vif; - control.tx_rate = - (sdata->bss_conf.use_short_preamble && - (ratesel.rate->flags & IEEE80211_RATE_PREAMBLE2)) ? - ratesel.rate->val2 : ratesel.rate->val; + control.tx_rate = ratesel.rate; + if (sdata->bss_conf.use_short_preamble && + ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control.power_level = local->hw.conf.power_level; control.flags |= IEEE80211_TXCTL_NO_ACK; control.retry_limit = 1; @@ -3004,14 +3028,14 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, } rates = 0; - mode = local->oper_hw_mode; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; for (i = 0; i < bss->supp_rates_len; i++) { int bitrate = (bss->supp_rates[i] & 0x7f) * 5; - for (j = 0; j < mode->num_rates; j++) - if (mode->rates[j].rate == bitrate) + for (j = 0; j < sband->n_bitrates; j++) + if (sband->bitrates[j].bitrate == bitrate) rates |= BIT(j); } - ifsta->supp_rates_bits = rates; + ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; } while (0); if (skb) { @@ -3035,7 +3059,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sta_bss *bss; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; u8 bssid[ETH_ALEN], *pos; int i; DECLARE_MAC_BUF(mac); @@ -3057,28 +3081,28 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", dev->name, print_mac(mac, bssid)); - bss = ieee80211_rx_bss_add(dev, bssid, local->hw.conf.channel, + bss = ieee80211_rx_bss_add(dev, bssid, + local->hw.conf.channel->center_freq, sdata->u.sta.ssid, sdata->u.sta.ssid_len); if (!bss) return -ENOMEM; - mode = local->oper_hw_mode; + bss->band = local->hw.conf.channel->band; + sband = local->hw.wiphy->bands[bss->band]; if (local->hw.conf.beacon_int == 0) local->hw.conf.beacon_int = 100; bss->beacon_int = local->hw.conf.beacon_int; - bss->hw_mode = local->hw.conf.phymode; - bss->freq = local->hw.conf.freq; bss->last_update = jiffies; bss->capability = WLAN_CAPABILITY_IBSS; if (sdata->default_key) { bss->capability |= WLAN_CAPABILITY_PRIVACY; } else sdata->drop_unencrypted = 0; - bss->supp_rates_len = mode->num_rates; + bss->supp_rates_len = sband->n_bitrates; pos = bss->supp_rates; - for (i = 0; i < mode->num_rates; i++) { - int rate = mode->rates[i].rate; + for (i = 0; i < sband->n_bitrates; i++) { + int rate = sband->bitrates[i].bitrate; *pos++ = (u8) (rate / 5); } @@ -3127,7 +3151,8 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid)); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && - (bss = ieee80211_rx_bss_get(dev, bssid, local->hw.conf.channel, + (bss = ieee80211_rx_bss_get(dev, bssid, + local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len))) { printk(KERN_DEBUG "%s: Selected IBSS BSSID %s" " based on configured SSID\n", @@ -3155,13 +3180,13 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, if (time_after(jiffies, ifsta->ibss_join_req + IEEE80211_IBSS_JOIN_TIMEOUT)) { if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) && - local->oper_channel->flag & IEEE80211_CHAN_W_IBSS) + (!(local->oper_channel->flags & + IEEE80211_CHAN_NO_IBSS))) return ieee80211_sta_create_ibss(dev, ifsta); if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) { - printk(KERN_DEBUG "%s: IBSS not allowed on the" - " configured channel %d (%d MHz)\n", - dev->name, local->hw.conf.channel, - local->hw.conf.freq); + printk(KERN_DEBUG "%s: IBSS not allowed on" + " %d MHz\n", dev->name, + local->hw.conf.channel->center_freq); } /* No IBSS found - decrease scan interval and continue @@ -3180,7 +3205,7 @@ static int ieee80211_sta_find_ibss(struct net_device *dev, int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) { - struct ieee80211_sub_if_data *sdata; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *ifsta; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -3194,18 +3219,23 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) int i; memset(&qparam, 0, sizeof(qparam)); - /* TODO: are these ok defaults for all hw_modes? */ + qparam.aifs = 2; - qparam.cw_min = - local->hw.conf.phymode == MODE_IEEE80211B ? 31 : 15; + + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) + qparam.cw_min = 31; + else + qparam.cw_min = 15; + qparam.cw_max = 1023; qparam.burst_time = 0; + for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) - { local->ops->conf_tx(local_to_hw(local), i + IEEE80211_TX_QUEUE_DATA0, &qparam); - } + /* IBSS uses different parameters for Beacon sending */ qparam.cw_min++; qparam.cw_min *= 2; @@ -3214,7 +3244,6 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) IEEE80211_TX_QUEUE_BEACON, &qparam); } - sdata = IEEE80211_DEV_TO_SUB_IF(dev); ifsta = &sdata->u.sta; if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) @@ -3373,7 +3402,7 @@ void ieee80211_sta_scan_work(struct work_struct *work) container_of(work, struct ieee80211_local, scan_work.work); struct net_device *dev = local->scan_dev; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; int skip; unsigned long next_delay = 0; @@ -3383,44 +3412,47 @@ void ieee80211_sta_scan_work(struct work_struct *work) switch (local->scan_state) { case SCAN_SET_CHANNEL: - mode = local->scan_hw_mode; - if (local->scan_hw_mode->list.next == &local->modes_list && - local->scan_channel_idx >= mode->num_channels) { + /* get current scan band */ + if (local->scan_band < IEEE80211_NUM_BANDS) + sband = local->hw.wiphy->bands[local->scan_band]; + else + sband = NULL; + + /* if we started at an unsupported one, advance */ + while (!sband && local->scan_band < IEEE80211_NUM_BANDS) { + local->scan_band++; + sband = local->hw.wiphy->bands[local->scan_band]; + local->scan_channel_idx = 0; + } + + if (!sband || + (local->scan_channel_idx >= sband->n_channels && + local->scan_band >= IEEE80211_NUM_BANDS)) { ieee80211_scan_completed(local_to_hw(local)); return; } - skip = !(local->enabled_modes & (1 << mode->mode)); - chan = &mode->channels[local->scan_channel_idx]; - if (!(chan->flag & IEEE80211_CHAN_W_SCAN) || + skip = 0; + chan = &sband->channels[local->scan_channel_idx]; + + if (chan->flags & IEEE80211_CHAN_DISABLED || (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && - !(chan->flag & IEEE80211_CHAN_W_IBSS)) || - (local->hw_modes & local->enabled_modes & - (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B)) + chan->flags & IEEE80211_CHAN_NO_IBSS)) skip = 1; if (!skip) { -#if 0 - printk(KERN_DEBUG "%s: scan channel %d (%d MHz)\n", - dev->name, chan->chan, chan->freq); -#endif - local->scan_channel = chan; if (ieee80211_hw_config(local)) { - printk(KERN_DEBUG "%s: failed to set channel " - "%d (%d MHz) for scan\n", dev->name, - chan->chan, chan->freq); + printk(KERN_DEBUG "%s: failed to set freq to " + "%d MHz for scan\n", dev->name, + chan->center_freq); skip = 1; } } local->scan_channel_idx++; - if (local->scan_channel_idx >= local->scan_hw_mode->num_channels) { - if (local->scan_hw_mode->list.next != &local->modes_list) { - local->scan_hw_mode = list_entry(local->scan_hw_mode->list.next, - struct ieee80211_hw_mode, - list); - local->scan_channel_idx = 0; - } + if (local->scan_channel_idx >= sband->n_channels) { + local->scan_band++; + local->scan_channel_idx = 0; } if (skip) @@ -3431,13 +3463,14 @@ void ieee80211_sta_scan_work(struct work_struct *work) local->scan_state = SCAN_SEND_PROBE; break; case SCAN_SEND_PROBE: - if (local->scan_channel->flag & IEEE80211_CHAN_W_ACTIVE_SCAN) { - ieee80211_send_probe_req(dev, NULL, local->scan_ssid, - local->scan_ssid_len); - next_delay = IEEE80211_CHANNEL_TIME; - } else - next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; local->scan_state = SCAN_SET_CHANNEL; + + if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN) + break; + ieee80211_send_probe_req(dev, NULL, local->scan_ssid, + local->scan_ssid_len); + next_delay = IEEE80211_CHANNEL_TIME; break; } @@ -3512,10 +3545,8 @@ static int ieee80211_sta_start_scan(struct net_device *dev, } else local->scan_ssid_len = 0; local->scan_state = SCAN_SET_CHANNEL; - local->scan_hw_mode = list_entry(local->modes_list.next, - struct ieee80211_hw_mode, - list); local->scan_channel_idx = 0; + local->scan_band = IEEE80211_BAND_2GHZ; local->scan_dev = dev; netif_tx_lock_bh(local->mdev); @@ -3570,9 +3601,6 @@ ieee80211_sta_scan_result(struct net_device *dev, bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE)) return current_ev; - if (!(local->enabled_modes & (1 << bss->hw_mode))) - return current_ev; - memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; @@ -3600,12 +3628,15 @@ ieee80211_sta_scan_result(struct net_device *dev, memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = bss->channel; - iwe.u.freq.e = 0; + iwe.u.freq.m = bss->freq; + iwe.u.freq.e = 6; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); - iwe.u.freq.m = bss->freq * 100000; - iwe.u.freq.e = 1; + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); + iwe.u.freq.e = 0; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); @@ -3748,7 +3779,8 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, if (!sta) return NULL; - sta->supp_rates = sdata->u.sta.supp_rates_bits; + sta->supp_rates[local->hw.conf.channel->band] = + sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band]; rate_control_rate_init(sta, local); diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index c339571632b2..c5a607ca8440 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -102,23 +102,23 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local, struct rc_pid_rateinfo *rinfo) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; int newidx; int maxrate; int back = (adj > 0) ? 1 : -1; sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); - mode = local->oper_hw_mode; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1; - newidx = rate_control_pid_shift_adjust(rinfo, adj, sta->txrate, - mode->num_rates); + newidx = rate_control_pid_shift_adjust(rinfo, adj, sta->txrate_idx, + sband->n_bitrates); - while (newidx != sta->txrate) { - if (rate_supported(sta, mode, newidx) && + while (newidx != sta->txrate_idx) { + if (rate_supported(sta, sband->band, newidx) && (maxrate < 0 || newidx <= maxrate)) { - sta->txrate = newidx; + sta->txrate_idx = newidx; break; } @@ -128,7 +128,7 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local, #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_rate_change( &((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events, - newidx, mode->rates[newidx].rate); + newidx, sband->bitrates[newidx].bitrate); #endif } @@ -155,7 +155,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, { struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; struct rc_pid_rateinfo *rinfo = pinfo->rinfo; - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; u32 pf; s32 err_avg; u32 err_prop; @@ -164,7 +164,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, int adj, i, j, tmp; unsigned long period; - mode = local->oper_hw_mode; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; spinfo = sta->rate_ctrl_priv; /* In case nothing happened during the previous control interval, turn @@ -190,18 +190,18 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, spinfo->tx_num_failed = 0; /* If we just switched rate, update the rate behaviour info. */ - if (pinfo->oldrate != sta->txrate) { + if (pinfo->oldrate != sta->txrate_idx) { i = rinfo[pinfo->oldrate].rev_index; - j = rinfo[sta->txrate].rev_index; + j = rinfo[sta->txrate_idx].rev_index; tmp = (pf - spinfo->last_pf); tmp = RC_PID_DO_ARITH_RIGHT_SHIFT(tmp, RC_PID_ARITH_SHIFT); rinfo[j].diff = rinfo[i].diff + tmp; - pinfo->oldrate = sta->txrate; + pinfo->oldrate = sta->txrate_idx; } - rate_control_pid_normalize(pinfo, mode->num_rates); + rate_control_pid_normalize(pinfo, sband->n_bitrates); /* Compute the proportional, integral and derivative errors. */ err_prop = (pinfo->target << RC_PID_ARITH_SHIFT) - pf; @@ -242,8 +242,10 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, struct sta_info *sta; struct rc_pid_sta_info *spinfo; unsigned long period; + struct ieee80211_supported_band *sband; sta = sta_info_get(local, hdr->addr1); + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; if (!sta) return; @@ -251,13 +253,13 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, /* Don't update the state if we're not controlling the rate. */ sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { - sta->txrate = sdata->bss->max_ratectrl_rateidx; + sta->txrate_idx = sdata->bss->max_ratectrl_rateidx; return; } /* Ignore all frames that were sent with a different rate than the rate * we currently advise mac80211 to use. */ - if (status->control.rate != &local->oper_hw_mode->rates[sta->txrate]) + if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) goto ignore; spinfo = sta->rate_ctrl_priv; @@ -304,7 +306,7 @@ ignore: } static void rate_control_pid_get_rate(void *priv, struct net_device *dev, - struct ieee80211_hw_mode *mode, + struct ieee80211_supported_band *sband, struct sk_buff *skb, struct rate_selection *sel) { @@ -322,7 +324,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1) || !sta) { - sel->rate = rate_lowest(local, mode, sta); + sel->rate = rate_lowest(local, sband, sta); if (sta) sta_info_put(sta); return; @@ -331,23 +333,23 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, /* If a forced rate is in effect, select it. */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) - sta->txrate = sdata->bss->force_unicast_rateidx; + sta->txrate_idx = sdata->bss->force_unicast_rateidx; - rateidx = sta->txrate; + rateidx = sta->txrate_idx; - if (rateidx >= mode->num_rates) - rateidx = mode->num_rates - 1; + if (rateidx >= sband->n_bitrates) + rateidx = sband->n_bitrates - 1; - sta->last_txrate = rateidx; + sta->last_txrate_idx = rateidx; sta_info_put(sta); - sel->rate = &mode->rates[rateidx]; + sel->rate = &sband->bitrates[rateidx]; #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_tx_rate( &((struct rc_pid_sta_info *) sta->rate_ctrl_priv)->events, - rateidx, mode->rates[rateidx].rate); + rateidx, sband->bitrates[rateidx].bitrate); #endif } @@ -359,28 +361,32 @@ static void rate_control_pid_rate_init(void *priv, void *priv_sta, * as we need to have IEEE 802.1X auth succeed immediately after assoc.. * Until that method is implemented, we will use the lowest supported * rate as a workaround. */ - sta->txrate = rate_lowest_index(local, local->oper_hw_mode, sta); + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sta->txrate_idx = rate_lowest_index(local, sband, sta); } static void *rate_control_pid_alloc(struct ieee80211_local *local) { struct rc_pid_info *pinfo; struct rc_pid_rateinfo *rinfo; - struct ieee80211_hw_mode *mode; + struct ieee80211_supported_band *sband; int i, j, tmp; bool s; #ifdef CONFIG_MAC80211_DEBUGFS struct rc_pid_debugfs_entries *de; #endif + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + pinfo = kmalloc(sizeof(*pinfo), GFP_ATOMIC); if (!pinfo) return NULL; - /* We can safely assume that oper_hw_mode won't change unless we get + /* We can safely assume that sband won't change unless we get * reinitialized. */ - mode = local->oper_hw_mode; - rinfo = kmalloc(sizeof(*rinfo) * mode->num_rates, GFP_ATOMIC); + rinfo = kmalloc(sizeof(*rinfo) * sband->n_bitrates, GFP_ATOMIC); if (!rinfo) { kfree(pinfo); return NULL; @@ -389,7 +395,7 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local) /* Sort the rates. This is optimized for the most common case (i.e. * almost-sorted CCK+OFDM rates). Kind of bubble-sort with reversed * mapping too. */ - for (i = 0; i < mode->num_rates; i++) { + for (i = 0; i < sband->n_bitrates; i++) { rinfo[i].index = i; rinfo[i].rev_index = i; if (pinfo->fast_start) @@ -397,11 +403,11 @@ static void *rate_control_pid_alloc(struct ieee80211_local *local) else rinfo[i].diff = i * pinfo->norm_offset; } - for (i = 1; i < mode->num_rates; i++) { + for (i = 1; i < sband->n_bitrates; i++) { s = 0; - for (j = 0; j < mode->num_rates - i; j++) - if (unlikely(mode->rates[rinfo[j].index].rate > - mode->rates[rinfo[j + 1].index].rate)) { + for (j = 0; j < sband->n_bitrates - i; j++) + if (unlikely(sband->bitrates[rinfo[j].index].bitrate > + sband->bitrates[rinfo[j + 1].index].bitrate)) { tmp = rinfo[j].index; rinfo[j].index = rinfo[j + 1].index; rinfo[j + 1].index = tmp; diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index 9a78b116acff..c4678905a142 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c @@ -35,8 +35,8 @@ static void rate_control_rate_inc(struct ieee80211_local *local, struct sta_info *sta) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_hw_mode *mode; - int i = sta->txrate; + struct ieee80211_supported_band *sband; + int i = sta->txrate_idx; int maxrate; sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); @@ -45,18 +45,17 @@ static void rate_control_rate_inc(struct ieee80211_local *local, return; } - mode = local->oper_hw_mode; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1; - if (i > mode->num_rates) - i = mode->num_rates - 2; + if (i > sband->n_bitrates) + i = sband->n_bitrates - 2; - while (i + 1 < mode->num_rates) { + while (i + 1 < sband->n_bitrates) { i++; - if (sta->supp_rates & BIT(i) && - mode->rates[i].flags & IEEE80211_RATE_SUPPORTED && + if (rate_supported(sta, sband->band, i) && (maxrate < 0 || i <= maxrate)) { - sta->txrate = i; + sta->txrate_idx = i; break; } } @@ -67,8 +66,8 @@ static void rate_control_rate_dec(struct ieee80211_local *local, struct sta_info *sta) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_hw_mode *mode; - int i = sta->txrate; + struct ieee80211_supported_band *sband; + int i = sta->txrate_idx; sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { @@ -76,15 +75,14 @@ static void rate_control_rate_dec(struct ieee80211_local *local, return; } - mode = local->oper_hw_mode; - if (i > mode->num_rates) - i = mode->num_rates; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + if (i > sband->n_bitrates) + i = sband->n_bitrates; while (i > 0) { i--; - if (sta->supp_rates & BIT(i) && - mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) { - sta->txrate = i; + if (rate_supported(sta, sband->band, i)) { + sta->txrate_idx = i; break; } } @@ -168,7 +166,7 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, } else if (per_failed < RATE_CONTROL_NUM_UP) { rate_control_rate_inc(local, sta); } - srctrl->tx_avg_rate_sum += status->control.rate->rate; + srctrl->tx_avg_rate_sum += status->control.tx_rate->bitrate; srctrl->tx_avg_rate_num++; srctrl->tx_num_failures = 0; srctrl->tx_num_xmit = 0; @@ -201,7 +199,7 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, static void rate_control_simple_get_rate(void *priv, struct net_device *dev, - struct ieee80211_hw_mode *mode, + struct ieee80211_supported_band *sband, struct sk_buff *skb, struct rate_selection *sel) { @@ -219,7 +217,7 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev, fc = le16_to_cpu(hdr->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1) || !sta) { - sel->rate = rate_lowest(local, mode, sta); + sel->rate = rate_lowest(local, sband, sta); if (sta) sta_info_put(sta); return; @@ -228,18 +226,18 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev, /* If a forced rate is in effect, select it. */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) - sta->txrate = sdata->bss->force_unicast_rateidx; + sta->txrate_idx = sdata->bss->force_unicast_rateidx; - rateidx = sta->txrate; + rateidx = sta->txrate_idx; - if (rateidx >= mode->num_rates) - rateidx = mode->num_rates - 1; + if (rateidx >= sband->n_bitrates) + rateidx = sband->n_bitrates - 1; - sta->last_txrate = rateidx; + sta->last_txrate_idx = rateidx; sta_info_put(sta); - sel->rate = &mode->rates[rateidx]; + sel->rate = &sband->bitrates[rateidx]; } @@ -247,21 +245,15 @@ static void rate_control_simple_rate_init(void *priv, void *priv_sta, struct ieee80211_local *local, struct sta_info *sta) { - struct ieee80211_hw_mode *mode; - int i; - sta->txrate = 0; - mode = local->oper_hw_mode; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + /* TODO: This routine should consider using RSSI from previous packets * as we need to have IEEE 802.1X auth succeed immediately after assoc.. * Until that method is implemented, we will use the lowest supported rate * as a workaround, */ - for (i = 0; i < mode->num_rates; i++) { - if ((sta->supp_rates & BIT(i)) && - (mode->rates[i].flags & IEEE80211_RATE_SUPPORTED)) { - sta->txrate = i; - break; - } - } + sta->txrate_idx = rate_lowest_index(local, sband, sta); } diff --git a/net/mac80211/regdomain.c b/net/mac80211/regdomain.c deleted file mode 100644 index f42678fa62d1..000000000000 --- a/net/mac80211/regdomain.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright 2002-2005, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * This regulatory domain control implementation is known to be incomplete - * and confusing. mac80211 regulatory domain control will be significantly - * reworked in the not-too-distant future. - * - * For now, drivers wishing to control which channels are and aren't available - * are advised as follows: - * - set the IEEE80211_HW_DEFAULT_REG_DOMAIN_CONFIGURED flag - * - continue to include *ALL* possible channels in the modes registered - * through ieee80211_register_hwmode() - * - for each allowable ieee80211_channel structure registered in the above - * call, set the flag member to some meaningful value such as - * IEEE80211_CHAN_W_SCAN | IEEE80211_CHAN_W_ACTIVE_SCAN | - * IEEE80211_CHAN_W_IBSS. - * - leave flag as 0 for non-allowable channels - * - * The usual implementation is for a driver to read a device EEPROM to - * determine which regulatory domain it should be operating under, then - * looking up the allowable channels in a driver-local table, then performing - * the above. - */ - -#include -#include -#include -#include "ieee80211_i.h" - -static int ieee80211_regdom = 0x10; /* FCC */ -module_param(ieee80211_regdom, int, 0444); -MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain; 64=MKK"); - -/* - * If firmware is upgraded by the vendor, additional channels can be used based - * on the new Japanese regulatory rules. This is indicated by setting - * ieee80211_japan_5ghz module parameter to one when loading the 80211 kernel - * module. - */ -static int ieee80211_japan_5ghz /* = 0 */; -module_param(ieee80211_japan_5ghz, int, 0444); -MODULE_PARM_DESC(ieee80211_japan_5ghz, "Vendor-updated firmware for 5 GHz"); - - -struct ieee80211_channel_range { - short start_freq; - short end_freq; - unsigned char power_level; - unsigned char antenna_max; -}; - -static const struct ieee80211_channel_range ieee80211_fcc_channels[] = { - { 2412, 2462, 27, 6 } /* IEEE 802.11b/g, channels 1..11 */, - { 5180, 5240, 17, 6 } /* IEEE 802.11a, channels 36..48 */, - { 5260, 5320, 23, 6 } /* IEEE 802.11a, channels 52..64 */, - { 5745, 5825, 30, 6 } /* IEEE 802.11a, channels 149..165, outdoor */, - { 0 } -}; - -static const struct ieee80211_channel_range ieee80211_mkk_channels[] = { - { 2412, 2472, 20, 6 } /* IEEE 802.11b/g, channels 1..13 */, - { 5170, 5240, 20, 6 } /* IEEE 802.11a, channels 34..48 */, - { 5260, 5320, 20, 6 } /* IEEE 802.11a, channels 52..64 */, - { 0 } -}; - - -static const struct ieee80211_channel_range *channel_range = - ieee80211_fcc_channels; - - -static void ieee80211_unmask_channel(int mode, struct ieee80211_channel *chan) -{ - int i; - - chan->flag = 0; - - for (i = 0; channel_range[i].start_freq; i++) { - const struct ieee80211_channel_range *r = &channel_range[i]; - if (r->start_freq <= chan->freq && r->end_freq >= chan->freq) { - if (ieee80211_regdom == 64 && !ieee80211_japan_5ghz && - chan->freq >= 5260 && chan->freq <= 5320) { - /* - * Skip new channels in Japan since the - * firmware was not marked having been upgraded - * by the vendor. - */ - continue; - } - - if (ieee80211_regdom == 0x10 && - (chan->freq == 5190 || chan->freq == 5210 || - chan->freq == 5230)) { - /* Skip MKK channels when in FCC domain. */ - continue; - } - - chan->flag |= IEEE80211_CHAN_W_SCAN | - IEEE80211_CHAN_W_ACTIVE_SCAN | - IEEE80211_CHAN_W_IBSS; - chan->power_level = r->power_level; - chan->antenna_max = r->antenna_max; - - if (ieee80211_regdom == 64 && - (chan->freq == 5170 || chan->freq == 5190 || - chan->freq == 5210 || chan->freq == 5230)) { - /* - * New regulatory rules in Japan have backwards - * compatibility with old channels in 5.15-5.25 - * GHz band, but the station is not allowed to - * use active scan on these old channels. - */ - chan->flag &= ~IEEE80211_CHAN_W_ACTIVE_SCAN; - } - - if (ieee80211_regdom == 64 && - (chan->freq == 5260 || chan->freq == 5280 || - chan->freq == 5300 || chan->freq == 5320)) { - /* - * IBSS is not allowed on 5.25-5.35 GHz band - * due to radar detection requirements. - */ - chan->flag &= ~IEEE80211_CHAN_W_IBSS; - } - - break; - } - } -} - - -void ieee80211_set_default_regdomain(struct ieee80211_hw_mode *mode) -{ - int c; - for (c = 0; c < mode->num_channels; c++) - ieee80211_unmask_channel(mode->mode, &mode->channels[c]); -} - - -void ieee80211_regdomain_init(void) -{ - if (ieee80211_regdom == 0x40) - channel_range = ieee80211_mkk_channels; -} - diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3aae8e9e4e0a..c9ff98a93211 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -82,10 +82,10 @@ static inline int should_drop_frame(struct ieee80211_rx_status *status, */ static struct sk_buff * ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, - struct ieee80211_rx_status *status) + struct ieee80211_rx_status *status, + struct ieee80211_rate *rate) { struct ieee80211_sub_if_data *sdata; - struct ieee80211_rate *rate; int needed_headroom = 0; struct ieee80211_radiotap_header *rthdr; __le64 *rttsft = NULL; @@ -194,14 +194,11 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, rtfixed->rx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_RX_BADFCS); - rate = ieee80211_get_rate(local, status->phymode, - status->rate); - if (rate) - rtfixed->rate = rate->rate / 5; + rtfixed->rate = rate->bitrate / 5; rtfixed->chan_freq = cpu_to_le16(status->freq); - if (status->phymode == MODE_IEEE80211A) + if (status->band == IEEE80211_BAND_5GHZ) rtfixed->chan_flags = cpu_to_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ); @@ -320,34 +317,21 @@ static void ieee80211_verify_ip_alignment(struct ieee80211_txrx_data *rx) static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_rx_status *status) + struct sk_buff *skb, + struct ieee80211_rx_status *status, + struct ieee80211_rate *rate) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u32 load = 0, hdrtime; - struct ieee80211_rate *rate; - struct ieee80211_hw_mode *mode = local->hw.conf.mode; - int i; /* Estimate total channel use caused by this frame */ - if (unlikely(mode->num_rates < 0)) - return TXRX_CONTINUE; - - rate = &mode->rates[0]; - for (i = 0; i < mode->num_rates; i++) { - if (mode->rates[i].val == status->rate) { - rate = &mode->rates[i]; - break; - } - } - /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - if (mode->mode == MODE_IEEE80211A || - (mode->mode == MODE_IEEE80211G && - rate->flags & IEEE80211_RATE_ERP)) + if (status->band == IEEE80211_BAND_5GHZ || + (status->band == IEEE80211_BAND_5GHZ && + rate->flags & IEEE80211_RATE_ERP_G)) hdrtime = CHAN_UTIL_HDR_SHORT; else hdrtime = CHAN_UTIL_HDR_LONG; @@ -356,7 +340,8 @@ static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, if (!is_multicast_ether_addr(hdr->addr1)) load += hdrtime; - load += skb->len * rate->rate_inv; + /* TODO: optimise again */ + load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; /* Divide channel_use by 8 to avoid wrapping around the counter */ load >>= CHAN_UTIL_SHIFT; @@ -1685,7 +1670,8 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_rx_status *status, - u32 load) + u32 load, + struct ieee80211_rate *rate) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; @@ -1705,6 +1691,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, rx.u.rx.status = status; rx.u.rx.load = load; + rx.u.rx.rate = rate; rx.fc = le16_to_cpu(hdr->frame_control); type = rx.fc & IEEE80211_FCTL_FTYPE; @@ -1837,6 +1824,8 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, u16 head_seq_num, buf_size; int index; u32 pkt_load; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate; buf_size = tid_agg_rx->buf_size; head_seq_num = tid_agg_rx->head_seq_num; @@ -1867,12 +1856,14 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, sizeof(status)); + sband = local->hw.wiphy->bands[status.band]; + rate = &sband->bitrates[status.rate_idx]; pkt_load = ieee80211_rx_load_stats(local, tid_agg_rx->reorder_buf[index], - &status); + &status, rate); __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], - &status, pkt_load); + &status, pkt_load, rate); tid_agg_rx->stored_mpdu_num--; tid_agg_rx->reorder_buf[index] = NULL; } @@ -1912,11 +1903,13 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, /* release the reordered frame back to stack */ memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, sizeof(status)); + sband = local->hw.wiphy->bands[status.band]; + rate = &sband->bitrates[status.rate_idx]; pkt_load = ieee80211_rx_load_stats(local, tid_agg_rx->reorder_buf[index], - &status); + &status, rate); __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], - &status, pkt_load); + &status, pkt_load, rate); tid_agg_rx->stored_mpdu_num--; tid_agg_rx->reorder_buf[index] = NULL; tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); @@ -1997,6 +1990,25 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, { struct ieee80211_local *local = hw_to_local(hw); u32 pkt_load; + struct ieee80211_rate *rate = NULL; + struct ieee80211_supported_band *sband; + + if (status->band < 0 || + status->band > IEEE80211_NUM_BANDS) { + WARN_ON(1); + return; + } + + sband = local->hw.wiphy->bands[status->band]; + + if (!sband || + status->rate_idx < 0 || + status->rate_idx >= sband->n_bitrates) { + WARN_ON(1); + return; + } + + rate = &sband->bitrates[status->rate_idx]; /* * key references and virtual interfaces are protected using RCU @@ -2011,17 +2023,17 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, * if it was previously present. * Also, frames with less than 16 bytes are dropped. */ - skb = ieee80211_rx_monitor(local, skb, status); + skb = ieee80211_rx_monitor(local, skb, status, rate); if (!skb) { rcu_read_unlock(); return; } - pkt_load = ieee80211_rx_load_stats(local, skb, status); + pkt_load = ieee80211_rx_load_stats(local, skb, status, rate); local->channel_use_raw += pkt_load; if (!ieee80211_rx_reorder_ampdu(local, skb)) - __ieee80211_rx_handle_packet(hw, skb, status, pkt_load); + __ieee80211_rx_handle_packet(hw, skb, status, pkt_load, rate); rcu_read_unlock(); } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ddc1f47194dd..746bbdea6b4c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -74,30 +74,6 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) } EXPORT_SYMBOL(sta_info_get); -int sta_info_min_txrate_get(struct ieee80211_local *local) -{ - struct sta_info *sta; - struct ieee80211_hw_mode *mode; - int min_txrate = 9999999; - int i; - - read_lock_bh(&local->sta_lock); - mode = local->oper_hw_mode; - for (i = 0; i < STA_HASH_SIZE; i++) { - sta = local->sta_hash[i]; - while (sta) { - if (sta->txrate < min_txrate) - min_txrate = sta->txrate; - sta = sta->hnext; - } - } - read_unlock_bh(&local->sta_lock); - if (min_txrate == 9999999) - min_txrate = 0; - - return mode->rates[min_txrate].rate; -} - static void sta_info_release(struct kref *kref) { diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 75573dc79d7a..3573743dfa59 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -133,10 +133,11 @@ struct sta_info { unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */ unsigned long last_rx; - u32 supp_rates; /* bitmap of supported rates in local->curr_rates */ - int txrate; /* index in local->curr_rates */ - int last_txrate; /* last rate used to send a frame to this STA */ - int last_nonerp_idx; + /* bitmap of supported rates per band */ + u64 supp_rates[IEEE80211_NUM_BANDS]; + int txrate_idx; + /* last rates used to send a frame to this STA */ + int last_txrate_idx, last_nonerp_txrate_idx; struct net_device *dev; /* which net device is this station associated * to */ @@ -222,7 +223,6 @@ static inline void __sta_info_get(struct sta_info *sta) } struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); -int sta_info_min_txrate_get(struct ieee80211_local *local); void sta_info_put(struct sta_info *sta); struct sta_info * sta_info_add(struct ieee80211_local *local, struct net_device *dev, u8 *addr, gfp_t gfp); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 38e1b2bd8245..9e5359991985 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -92,9 +92,13 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, int rate, mrate, erp, dur, i; struct ieee80211_rate *txrate = tx->u.tx.rate; struct ieee80211_local *local = tx->local; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; + struct ieee80211_supported_band *sband; - erp = txrate->flags & IEEE80211_RATE_ERP; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + erp = 0; + if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + erp = txrate->flags & IEEE80211_RATE_ERP_G; /* * data and mgmt (except PS Poll): @@ -150,20 +154,36 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, * Mandatory rates for IEEE 802.11g PHY: 1, 2, 5.5, 11, 6, 12, 24 Mbps */ rate = -1; - mrate = 10; /* use 1 Mbps if everything fails */ - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *r = &mode->rates[i]; - if (r->rate > txrate->rate) - break; + /* use lowest available if everything fails */ + mrate = sband->bitrates[0].bitrate; + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *r = &sband->bitrates[i]; - if (IEEE80211_RATE_MODULATION(txrate->flags) != - IEEE80211_RATE_MODULATION(r->flags)) - continue; + if (r->bitrate > txrate->bitrate) + break; - if (r->flags & IEEE80211_RATE_BASIC) - rate = r->rate; - else if (r->flags & IEEE80211_RATE_MANDATORY) - mrate = r->rate; + if (tx->sdata->basic_rates & BIT(i)) + rate = r->bitrate; + + switch (sband->band) { + case IEEE80211_BAND_2GHZ: { + u32 flag; + if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + flag = IEEE80211_RATE_MANDATORY_G; + else + flag = IEEE80211_RATE_MANDATORY_B; + if (r->flags & flag) + mrate = r->bitrate; + break; + } + case IEEE80211_BAND_5GHZ: + if (r->flags & IEEE80211_RATE_MANDATORY_A) + mrate = r->bitrate; + break; + case IEEE80211_NUM_BANDS: + WARN_ON(1); + break; + } } if (rate == -1) { /* No matching basic rate found; use highest suitable mandatory @@ -184,7 +204,7 @@ static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, dur *= 2; /* ACK + SIFS */ /* next fragment */ dur += ieee80211_frame_duration(local, next_frag_len, - txrate->rate, erp, + txrate->bitrate, erp, tx->sdata->bss_conf.use_short_preamble); } @@ -585,26 +605,28 @@ static ieee80211_txrx_result ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) { struct rate_selection rsel; + struct ieee80211_supported_band *sband; + + sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; if (likely(!tx->u.tx.rate)) { - rate_control_get_rate(tx->dev, tx->u.tx.mode, tx->skb, &rsel); + rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); tx->u.tx.rate = rsel.rate; - if (unlikely(rsel.probe != NULL)) { + if (unlikely(rsel.probe)) { tx->u.tx.control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; - tx->u.tx.control->alt_retry_rate = tx->u.tx.rate->val; + tx->u.tx.control->alt_retry_rate = tx->u.tx.rate; tx->u.tx.rate = rsel.probe; } else - tx->u.tx.control->alt_retry_rate = -1; + tx->u.tx.control->alt_retry_rate = NULL; if (!tx->u.tx.rate) return TXRX_DROP; } else - tx->u.tx.control->alt_retry_rate = -1; + tx->u.tx.control->alt_retry_rate = NULL; - if (tx->u.tx.mode->mode == MODE_IEEE80211G && - tx->sdata->bss_conf.use_cts_prot && + if (tx->sdata->bss_conf.use_cts_prot && (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && rsel.nonerp) { tx->u.tx.last_frag_rate = tx->u.tx.rate; if (rsel.probe) @@ -612,13 +634,13 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) else tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; tx->u.tx.rate = rsel.nonerp; - tx->u.tx.control->rate = rsel.nonerp; + tx->u.tx.control->tx_rate = rsel.nonerp; tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; } else { tx->u.tx.last_frag_rate = tx->u.tx.rate; - tx->u.tx.control->rate = tx->u.tx.rate; + tx->u.tx.control->tx_rate = tx->u.tx.rate; } - tx->u.tx.control->tx_rate = tx->u.tx.rate->val; + tx->u.tx.control->tx_rate = tx->u.tx.rate; return TXRX_CONTINUE; } @@ -630,7 +652,6 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) u16 fc = le16_to_cpu(hdr->frame_control); u16 dur; struct ieee80211_tx_control *control = tx->u.tx.control; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; if (!control->retry_limit) { if (!is_multicast_ether_addr(hdr->addr1)) { @@ -657,14 +678,14 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) * frames. * TODO: The last fragment could still use multiple retry * rates. */ - control->alt_retry_rate = -1; + control->alt_retry_rate = NULL; } /* Use CTS protection for unicast frames sent using extended rates if * there are associated non-ERP stations and RTS/CTS is not configured * for the frame. */ - if (mode->mode == MODE_IEEE80211G && - (tx->u.tx.rate->flags & IEEE80211_RATE_ERP) && + if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && + (tx->u.tx.rate->flags & IEEE80211_RATE_ERP_G) && (tx->flags & IEEE80211_TXRXD_TXUNICAST) && tx->sdata->bss_conf.use_cts_prot && !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) @@ -674,10 +695,10 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) * short preambles at the selected rate and short preambles are * available on the network at the current point in time. */ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (tx->u.tx.rate->flags & IEEE80211_RATE_PREAMBLE2) && + (tx->u.tx.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && tx->sdata->bss_conf.use_short_preamble && (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { - tx->u.tx.control->tx_rate = tx->u.tx.rate->val2; + tx->u.tx.control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; } /* Setup duration field for the first fragment of the frame. Duration @@ -690,19 +711,33 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || (control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) { - struct ieee80211_rate *rate; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate, *baserate; + int idx; + + sband = tx->local->hw.wiphy->bands[ + tx->local->hw.conf.channel->band]; /* Do not use multiple retry rates when using RTS/CTS */ - control->alt_retry_rate = -1; + control->alt_retry_rate = NULL; /* Use min(data rate, max base rate) as CTS/RTS rate */ rate = tx->u.tx.rate; - while (rate > mode->rates && - !(rate->flags & IEEE80211_RATE_BASIC)) - rate--; + baserate = NULL; + + for (idx = 0; idx < sband->n_bitrates; idx++) { + if (sband->bitrates[idx].bitrate > rate->bitrate) + continue; + if (tx->sdata->basic_rates & BIT(idx) && + (!baserate || + (baserate->bitrate < sband->bitrates[idx].bitrate))) + baserate = &sband->bitrates[idx]; + } - control->rts_cts_rate = rate->val; - control->rts_rate = rate; + if (baserate) + control->rts_cts_rate = baserate; + else + control->rts_cts_rate = &sband->bitrates[0]; } if (tx->sta) { @@ -726,10 +761,10 @@ static ieee80211_txrx_result ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) { struct ieee80211_local *local = tx->local; - struct ieee80211_hw_mode *mode = tx->u.tx.mode; struct sk_buff *skb = tx->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u32 load = 0, hdrtime; + struct ieee80211_rate *rate = tx->u.tx.rate; /* TODO: this could be part of tx_status handling, so that the number * of retries would be known; TX rate should in that case be stored @@ -740,9 +775,9 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - if (mode->mode == MODE_IEEE80211A || - (mode->mode == MODE_IEEE80211G && - tx->u.tx.rate->flags & IEEE80211_RATE_ERP)) + if (tx->u.tx.channel->band == IEEE80211_BAND_5GHZ || + (tx->u.tx.channel->band == IEEE80211_BAND_2GHZ && + rate->flags & IEEE80211_RATE_ERP_G)) hdrtime = CHAN_UTIL_HDR_SHORT; else hdrtime = CHAN_UTIL_HDR_LONG; @@ -756,14 +791,15 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) load += hdrtime; - load += skb->len * tx->u.tx.rate->rate_inv; + /* TODO: optimise again */ + load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; if (tx->u.tx.extra_frag) { int i; for (i = 0; i < tx->u.tx.num_extra_frag; i++) { load += 2 * hdrtime; load += tx->u.tx.extra_frag[i]->len * - tx->u.tx.rate->rate; + tx->u.tx.rate->bitrate; } } @@ -816,10 +852,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, struct ieee80211_radiotap_iterator iterator; struct ieee80211_radiotap_header *rthdr = (struct ieee80211_radiotap_header *) skb->data; - struct ieee80211_hw_mode *mode = tx->local->hw.conf.mode; + struct ieee80211_supported_band *sband; int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); struct ieee80211_tx_control *control = tx->u.tx.control; + sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; + control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; tx->flags |= IEEE80211_TXRXD_TX_INJECTED; tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; @@ -852,10 +890,12 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps */ target_rate = (*iterator.this_arg) * 5; - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *r = &mode->rates[i]; + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *r; - if (r->rate == target_rate) { + r = &sband->bitrates[i]; + + if (r->bitrate == target_rate) { tx->u.tx.rate = r; break; } @@ -870,9 +910,11 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, control->antenna_sel_tx = (*iterator.this_arg) + 1; break; +#if 0 case IEEE80211_RADIOTAP_DBM_TX_POWER: control->power_level = *iterator.this_arg; break; +#endif case IEEE80211_RADIOTAP_FLAGS: if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS) { @@ -1054,8 +1096,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, if (__ieee80211_queue_stopped(local, control->queue)) return IEEE80211_TX_FRAG_AGAIN; if (i == tx->u.tx.num_extra_frag) { - control->tx_rate = tx->u.tx.last_frag_hwrate; - control->rate = tx->u.tx.last_frag_rate; + control->tx_rate = tx->u.tx.last_frag_rate; + if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG) control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; @@ -1114,7 +1156,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, rcu_read_lock(); sta = tx.sta; - tx.u.tx.mode = local->hw.conf.mode; + tx.u.tx.channel = local->hw.conf.channel; for (handler = local->tx_handlers; *handler != NULL; handler++) { @@ -1151,7 +1193,6 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, } else { next_len = 0; tx.u.tx.rate = tx.u.tx.last_frag_rate; - tx.u.tx.last_frag_hwrate = tx.u.tx.rate->val; } dur = ieee80211_duration(&tx, 0, next_len); hdr->duration_id = cpu_to_le16(dur); @@ -1188,7 +1229,6 @@ retry: store->skb = skb; store->extra_frag = tx.u.tx.extra_frag; store->num_extra_frag = tx.u.tx.num_extra_frag; - store->last_frag_hwrate = tx.u.tx.last_frag_hwrate; store->last_frag_rate = tx.u.tx.last_frag_rate; store->last_frag_rate_ctrl_probe = !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG); @@ -1609,7 +1649,6 @@ void ieee80211_tx_pending(unsigned long data) tx.u.tx.control = &store->control; tx.u.tx.extra_frag = store->extra_frag; tx.u.tx.num_extra_frag = store->num_extra_frag; - tx.u.tx.last_frag_hwrate = store->last_frag_hwrate; tx.u.tx.last_frag_rate = store->last_frag_rate; tx.flags = 0; if (store->last_frag_rate_ctrl_probe) @@ -1712,6 +1751,9 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_if_ap *ap = NULL; struct rate_selection rsel; struct beacon_data *beacon; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; rcu_read_lock(); @@ -1750,8 +1792,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, beacon->tail_len); if (control) { - rate_control_get_rate(local->mdev, local->oper_hw_mode, skb, - &rsel); + rate_control_get_rate(local->mdev, sband, skb, &rsel); if (!rsel.rate) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: ieee80211_beacon_get: " @@ -1764,12 +1805,11 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, } control->vif = vif; - control->tx_rate = - (sdata->bss_conf.use_short_preamble && - (rsel.rate->flags & IEEE80211_RATE_PREAMBLE2)) ? - rsel.rate->val2 : rsel.rate->val; + control->tx_rate = rsel.rate; + if (sdata->bss_conf.use_short_preamble && + rsel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control->power_level = local->hw.conf.power_level; control->flags |= IEEE80211_TXCTL_NO_ACK; control->retry_limit = 1; control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; @@ -1874,7 +1914,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, } sta = tx.sta; tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED; - tx.u.tx.mode = local->hw.conf.mode; + tx.u.tx.channel = local->hw.conf.channel; for (handler = local->tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5e631ce98d7e..f64804fed0a9 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -41,92 +41,6 @@ const unsigned char bridge_tunnel_header[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 }; -static int rate_list_match(const int *rate_list, int rate) -{ - int i; - - if (!rate_list) - return 0; - - for (i = 0; rate_list[i] >= 0; i++) - if (rate_list[i] == rate) - return 1; - - return 0; -} - -void ieee80211_prepare_rates(struct ieee80211_local *local, - struct ieee80211_hw_mode *mode) -{ - int i; - - for (i = 0; i < mode->num_rates; i++) { - struct ieee80211_rate *rate = &mode->rates[i]; - - rate->flags &= ~(IEEE80211_RATE_SUPPORTED | - IEEE80211_RATE_BASIC); - - if (local->supp_rates[mode->mode]) { - if (!rate_list_match(local->supp_rates[mode->mode], - rate->rate)) - continue; - } - - rate->flags |= IEEE80211_RATE_SUPPORTED; - - /* Use configured basic rate set if it is available. If not, - * use defaults that are sane for most cases. */ - if (local->basic_rates[mode->mode]) { - if (rate_list_match(local->basic_rates[mode->mode], - rate->rate)) - rate->flags |= IEEE80211_RATE_BASIC; - } else switch (mode->mode) { - case MODE_IEEE80211A: - if (rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_IEEE80211B: - if (rate->rate == 10 || rate->rate == 20) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case MODE_IEEE80211G: - if (rate->rate == 10 || rate->rate == 20 || - rate->rate == 55 || rate->rate == 110) - rate->flags |= IEEE80211_RATE_BASIC; - break; - case NUM_IEEE80211_MODES: - /* not useful */ - break; - } - - /* Set ERP and MANDATORY flags based on phymode */ - switch (mode->mode) { - case MODE_IEEE80211A: - if (rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case MODE_IEEE80211B: - if (rate->rate == 10) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case MODE_IEEE80211G: - if (rate->rate == 10 || rate->rate == 20 || - rate->rate == 55 || rate->rate == 110 || - rate->rate == 60 || rate->rate == 120 || - rate->rate == 240) - rate->flags |= IEEE80211_RATE_MANDATORY; - break; - case NUM_IEEE80211_MODES: - /* not useful */ - break; - } - if (ieee80211_is_erp_rate(mode->mode, rate->rate)) - rate->flags |= IEEE80211_RATE_ERP; - } -} - u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, enum ieee80211_if_types type) { @@ -262,7 +176,7 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, * DIV_ROUND_UP() operations. */ - if (local->hw.conf.phymode == MODE_IEEE80211A || erp) { + if (local->hw.conf.channel->band == IEEE80211_BAND_5GHZ || erp) { /* * OFDM: * @@ -304,15 +218,19 @@ int ieee80211_frame_duration(struct ieee80211_local *local, size_t len, /* Exported duration function for driver use */ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - size_t frame_len, int rate) + size_t frame_len, + struct ieee80211_rate *rate) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); u16 dur; int erp; - erp = ieee80211_is_erp_rate(hw->conf.phymode, rate); - dur = ieee80211_frame_duration(local, frame_len, rate, erp, + erp = 0; + if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + erp = rate->flags & IEEE80211_RATE_ERP_G; + + dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, sdata->bss_conf.use_short_preamble); return cpu_to_le16(dur); @@ -332,17 +250,20 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, short_preamble = sdata->bss_conf.use_short_preamble; - rate = frame_txctl->rts_rate; - erp = !!(rate->flags & IEEE80211_RATE_ERP); + rate = frame_txctl->rts_cts_rate; + + erp = 0; + if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + erp = rate->flags & IEEE80211_RATE_ERP_G; /* CTS duration */ - dur = ieee80211_frame_duration(local, 10, rate->rate, + dur = ieee80211_frame_duration(local, 10, rate->bitrate, erp, short_preamble); /* Data frame duration */ - dur += ieee80211_frame_duration(local, frame_len, rate->rate, + dur += ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, short_preamble); /* ACK duration */ - dur += ieee80211_frame_duration(local, 10, rate->rate, + dur += ieee80211_frame_duration(local, 10, rate->bitrate, erp, short_preamble); return cpu_to_le16(dur); @@ -363,15 +284,17 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, short_preamble = sdata->bss_conf.use_short_preamble; - rate = frame_txctl->rts_rate; - erp = !!(rate->flags & IEEE80211_RATE_ERP); + rate = frame_txctl->rts_cts_rate; + erp = 0; + if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) + erp = rate->flags & IEEE80211_RATE_ERP_G; /* Data frame duration */ - dur = ieee80211_frame_duration(local, frame_len, rate->rate, + dur = ieee80211_frame_duration(local, frame_len, rate->bitrate, erp, short_preamble); if (!(frame_txctl->flags & IEEE80211_TXCTL_NO_ACK)) { /* ACK duration */ - dur += ieee80211_frame_duration(local, 10, rate->rate, + dur += ieee80211_frame_duration(local, 10, rate->bitrate, erp, short_preamble); } @@ -379,27 +302,6 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_ctstoself_duration); -struct ieee80211_rate * -ieee80211_get_rate(struct ieee80211_local *local, int phymode, int hw_rate) -{ - struct ieee80211_hw_mode *mode; - int r; - - list_for_each_entry(mode, &local->modes_list, list) { - if (mode->mode != phymode) - continue; - for (r = 0; r < mode->num_rates; r++) { - struct ieee80211_rate *rate = &mode->rates[r]; - if (rate->val == hw_rate || - (rate->flags & IEEE80211_RATE_PREAMBLE2 && - rate->val2 == hw_rate)) - return rate; - } - } - - return NULL; -} - void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) { struct ieee80211_local *local = hw_to_local(hw); diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 65710a42e5a7..b9f943c45f3b 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_WIRELESS_EXT) += wext.o obj-$(CONFIG_CFG80211) += cfg80211.o -cfg80211-y += core.o sysfs.o radiotap.o +cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o cfg80211-$(CONFIG_NL80211) += nl80211.o diff --git a/net/wireless/core.c b/net/wireless/core.c index cfc5fc5f9e75..80afacdae46c 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -232,6 +232,47 @@ int wiphy_register(struct wiphy *wiphy) { struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy); int res; + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + bool have_band = false; + int i; + + /* sanity check supported bands/channels */ + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + if (!sband) + continue; + + sband->band = band; + + if (!sband->n_channels || !sband->n_bitrates) { + WARN_ON(1); + return -EINVAL; + } + + for (i = 0; i < sband->n_channels; i++) { + sband->channels[i].orig_flags = + sband->channels[i].flags; + sband->channels[i].orig_mag = + sband->channels[i].max_antenna_gain; + sband->channels[i].orig_mpwr = + sband->channels[i].max_power; + sband->channels[i].band = band; + } + + have_band = true; + } + + if (!have_band) { + WARN_ON(1); + return -EINVAL; + } + + /* check and set up bitrates */ + ieee80211_set_bitrate_flags(wiphy); + + /* set up regulatory info */ + wiphy_update_regulatory(wiphy); mutex_lock(&cfg80211_drv_mutex); diff --git a/net/wireless/core.h b/net/wireless/core.h index eb0f846b40df..7a02c356d63d 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -78,4 +78,7 @@ extern void cfg80211_dev_free(struct cfg80211_registered_device *drv); extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv, char *newname); +void ieee80211_set_bitrate_flags(struct wiphy *wiphy); +void wiphy_update_regulatory(struct wiphy *wiphy); + #endif /* __NET_WIRELESS_CORE_H */ diff --git a/net/wireless/reg.c b/net/wireless/reg.c new file mode 100644 index 000000000000..2b63c96dcf19 --- /dev/null +++ b/net/wireless/reg.c @@ -0,0 +1,153 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2007 Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This regulatory domain control implementation is highly incomplete, it + * only exists for the purpose of not regressing mac80211. + * + * For now, drivers can restrict the set of allowed channels by either + * not registering those channels or setting the IEEE80211_CHAN_DISABLED + * flag; that flag will only be *set* by this code, never *cleared. + * + * The usual implementation is for a driver to read a device EEPROM to + * determine which regulatory domain it should be operating under, then + * looking up the allowable channels in a driver-local table and finally + * registering those channels in the wiphy structure. + * + * Alternatively, drivers that trust the regulatory domain control here + * will register a complete set of capabilities and the control code + * will restrict the set by setting the IEEE80211_CHAN_* flags. + */ +#include +#include +#include "core.h" + +static char *ieee80211_regdom = "US"; +module_param(ieee80211_regdom, charp, 0444); +MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); + +struct ieee80211_channel_range { + short start_freq; + short end_freq; + int max_power; + int max_antenna_gain; + u32 flags; +}; + +struct ieee80211_regdomain { + const char *code; + const struct ieee80211_channel_range *ranges; + int n_ranges; +}; + +#define RANGE_PWR(_start, _end, _pwr, _ag, _flags) \ + { _start, _end, _pwr, _ag, _flags } + + +/* + * Ideally, in the future, these definitions will be loaded from a + * userspace table via some daemon. + */ +static const struct ieee80211_channel_range ieee80211_US_channels[] = { + /* IEEE 802.11b/g, channels 1..11 */ + RANGE_PWR(2412, 2462, 27, 6, 0), + /* IEEE 802.11a, channels 52..64 */ + RANGE_PWR(5260, 5320, 23, 6, 0), + /* IEEE 802.11a, channels 149..165, outdoor */ + RANGE_PWR(5745, 5825, 30, 6, 0), +}; + +static const struct ieee80211_channel_range ieee80211_JP_channels[] = { + /* IEEE 802.11b/g, channels 1..14 */ + RANGE_PWR(2412, 2484, 20, 6, 0), + /* IEEE 802.11a, channels 34..48 */ + RANGE_PWR(5170, 5240, 20, 6, IEEE80211_CHAN_PASSIVE_SCAN), + /* IEEE 802.11a, channels 52..64 */ + RANGE_PWR(5260, 5320, 20, 6, IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_RADAR), +}; + +#define REGDOM(_code) \ + { \ + .code = __stringify(_code), \ + .ranges = ieee80211_ ##_code## _channels, \ + .n_ranges = ARRAY_SIZE(ieee80211_ ##_code## _channels), \ + } + +static const struct ieee80211_regdomain ieee80211_regdoms[] = { + REGDOM(US), + REGDOM(JP), +}; + + +static const struct ieee80211_regdomain *get_regdom(void) +{ + static const struct ieee80211_channel_range + ieee80211_world_channels[] = { + /* IEEE 802.11b/g, channels 1..11 */ + RANGE_PWR(2412, 2462, 27, 6, 0), + }; + static const struct ieee80211_regdomain regdom_world = REGDOM(world); + int i; + + for (i = 0; i < ARRAY_SIZE(ieee80211_regdoms); i++) + if (strcmp(ieee80211_regdom, ieee80211_regdoms[i].code) == 0) + return &ieee80211_regdoms[i]; + + return ®dom_world; +} + + +static void handle_channel(struct ieee80211_channel *chan, + const struct ieee80211_regdomain *rd) +{ + int i; + u32 flags = chan->orig_flags; + const struct ieee80211_channel_range *rg = NULL; + + for (i = 0; i < rd->n_ranges; i++) { + if (rd->ranges[i].start_freq <= chan->center_freq && + chan->center_freq <= rd->ranges[i].end_freq) { + rg = &rd->ranges[i]; + break; + } + } + + if (!rg) { + /* not found */ + flags |= IEEE80211_CHAN_DISABLED; + chan->flags = flags; + return; + } + + chan->flags = flags; + chan->max_antenna_gain = min(chan->orig_mag, + rg->max_antenna_gain); + chan->max_power = min(chan->orig_mpwr, rg->max_power); +} + +static void handle_band(struct ieee80211_supported_band *sband, + const struct ieee80211_regdomain *rd) +{ + int i; + + for (i = 0; i < sband->n_channels; i++) + handle_channel(&sband->channels[i], rd); +} + +void wiphy_update_regulatory(struct wiphy *wiphy) +{ + enum ieee80211_band band; + const struct ieee80211_regdomain *rd = get_regdom(); + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) + if (wiphy->bands[band]) + handle_band(wiphy->bands[band], rd); +} diff --git a/net/wireless/util.c b/net/wireless/util.c new file mode 100644 index 000000000000..0dcccbf3eb57 --- /dev/null +++ b/net/wireless/util.c @@ -0,0 +1,98 @@ +/* + * Wireless utility functions + * + * Copyright 2007 Johannes Berg + */ +#include +#include +#include "core.h" + +int ieee80211_channel_to_frequency(int chan) +{ + if (chan < 14) + return 2407 + chan * 5; + + if (chan == 14) + return 2484; + + /* FIXME: 802.11j 17.3.8.3.2 */ + return (chan + 1000) * 5; +} +EXPORT_SYMBOL(ieee80211_channel_to_frequency); + +int ieee80211_frequency_to_channel(int freq) +{ + if (freq == 2484) + return 14; + + if (freq < 2484) + return (freq - 2407) / 5; + + /* FIXME: 802.11j 17.3.8.3.2 */ + return freq/5 - 1000; +} +EXPORT_SYMBOL(ieee80211_frequency_to_channel); + +static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, + enum ieee80211_band band) +{ + int i, want; + + switch (band) { + case IEEE80211_BAND_5GHZ: + want = 3; + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == 60 || + sband->bitrates[i].bitrate == 120 || + sband->bitrates[i].bitrate == 240) { + sband->bitrates[i].flags |= + IEEE80211_RATE_MANDATORY_A; + want--; + } + } + WARN_ON(want); + break; + case IEEE80211_BAND_2GHZ: + want = 7; + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == 10) { + sband->bitrates[i].flags |= + IEEE80211_RATE_MANDATORY_B | + IEEE80211_RATE_MANDATORY_G; + want--; + } + + if (sband->bitrates[i].bitrate == 20 || + sband->bitrates[i].bitrate == 55 || + sband->bitrates[i].bitrate == 110 || + sband->bitrates[i].bitrate == 60 || + sband->bitrates[i].bitrate == 120 || + sband->bitrates[i].bitrate == 240) { + sband->bitrates[i].flags |= + IEEE80211_RATE_MANDATORY_G; + want--; + } + + if (sband->bitrates[i].bitrate == 10 || + sband->bitrates[i].bitrate == 20 || + sband->bitrates[i].bitrate == 55 || + sband->bitrates[i].bitrate == 110) + sband->bitrates[i].flags |= + IEEE80211_RATE_ERP_G; + } + WARN_ON(want != 0 && want != 6); + break; + case IEEE80211_NUM_BANDS: + WARN_ON(1); + break; + } +} + +void ieee80211_set_bitrate_flags(struct wiphy *wiphy) +{ + enum ieee80211_band band; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) + if (wiphy->bands[band]) + set_mandatory_flags_band(wiphy->bands[band], band); +} -- cgit v1.2.3-59-g8ed1b From ee688b000d35f413f33561ec9c7d3355be561e2f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 24 Jan 2008 19:38:39 +0100 Subject: nl80211: export hardware bitrate/channel capabilities This makes nl80211 export the hardware bitrate/channel capabilities as registered in a wiphy. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 64 ++++++++++++++++++++++++++++++++++++++++++ net/wireless/nl80211.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 9fecf902419c..63695060db9f 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -161,6 +161,9 @@ enum nl80211_commands { * given for %NL80211_CMD_GET_STATION, nested attribute containing * info as possible, see &enum nl80211_sta_stats. * + * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, + * consisting of a nested array. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -195,6 +198,8 @@ enum nl80211_attrs { NL80211_ATTR_STA_VLAN, NL80211_ATTR_STA_STATS, + NL80211_ATTR_WIPHY_BANDS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -280,4 +285,63 @@ enum nl80211_sta_stats { NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1 }; +/** + * enum nl80211_band_attr - band attributes + * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved + * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band, + * an array of nested frequency attributes + * @NL80211_BAND_ATTR_RATES: supported bitrates in this band, + * an array of nested bitrate attributes + */ +enum nl80211_band_attr { + __NL80211_BAND_ATTR_INVALID, + NL80211_BAND_ATTR_FREQS, + NL80211_BAND_ATTR_RATES, + + /* keep last */ + __NL80211_BAND_ATTR_AFTER_LAST, + NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_frequency_attr - frequency attributes + * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz + * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current + * regulatory domain. + * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is + * permitted on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory + * on this channel in current regulatory domain. + */ +enum nl80211_frequency_attr { + __NL80211_FREQUENCY_ATTR_INVALID, + NL80211_FREQUENCY_ATTR_FREQ, + NL80211_FREQUENCY_ATTR_DISABLED, + NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, + NL80211_FREQUENCY_ATTR_NO_IBSS, + NL80211_FREQUENCY_ATTR_RADAR, + + /* keep last */ + __NL80211_FREQUENCY_ATTR_AFTER_LAST, + NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_bitrate_attr - bitrate attributes + * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps + * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported + * in 2.4 GHz band. + */ +enum nl80211_bitrate_attr { + __NL80211_BITRATE_ATTR_INVALID, + NL80211_BITRATE_ATTR_RATE, + NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE, + + /* keep last */ + __NL80211_BITRATE_ATTR_AFTER_LAST, + NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index e3a214f63f91..b123f58d3909 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -98,6 +98,13 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct cfg80211_registered_device *dev) { void *hdr; + struct nlattr *nl_bands, *nl_band; + struct nlattr *nl_freqs, *nl_freq; + struct nlattr *nl_rates, *nl_rate; + enum ieee80211_band band; + struct ieee80211_channel *chan; + struct ieee80211_rate *rate; + int i; hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_WIPHY); if (!hdr) @@ -105,6 +112,73 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx); NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy)); + + nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS); + if (!nl_bands) + goto nla_put_failure; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!dev->wiphy.bands[band]) + continue; + + nl_band = nla_nest_start(msg, band); + if (!nl_band) + goto nla_put_failure; + + /* add frequencies */ + nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); + if (!nl_freqs) + goto nla_put_failure; + + for (i = 0; i < dev->wiphy.bands[band]->n_channels; i++) { + nl_freq = nla_nest_start(msg, i); + if (!nl_freq) + goto nla_put_failure; + + chan = &dev->wiphy.bands[band]->channels[i]; + NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_FREQ, + chan->center_freq); + + if (chan->flags & IEEE80211_CHAN_DISABLED) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_DISABLED); + if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_PASSIVE_SCAN); + if (chan->flags & IEEE80211_CHAN_NO_IBSS) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_NO_IBSS); + if (chan->flags & IEEE80211_CHAN_RADAR) + NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); + + nla_nest_end(msg, nl_freq); + } + + nla_nest_end(msg, nl_freqs); + + /* add bitrates */ + nl_rates = nla_nest_start(msg, NL80211_BAND_ATTR_RATES); + if (!nl_rates) + goto nla_put_failure; + + for (i = 0; i < dev->wiphy.bands[band]->n_bitrates; i++) { + nl_rate = nla_nest_start(msg, i); + if (!nl_rate) + goto nla_put_failure; + + rate = &dev->wiphy.bands[band]->bitrates[i]; + NLA_PUT_U32(msg, NL80211_BITRATE_ATTR_RATE, + rate->bitrate); + if (rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + NLA_PUT_FLAG(msg, + NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE); + + nla_nest_end(msg, nl_rate); + } + + nla_nest_end(msg, nl_rates); + + nla_nest_end(msg, nl_band); + } + nla_nest_end(msg, nl_bands); + return genlmsg_end(msg, hdr); nla_put_failure: -- cgit v1.2.3-59-g8ed1b From 69d464d5938ca0f4fb3447b3e32872e0ca79efc1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 28 Jan 2008 17:08:56 +0100 Subject: mac80211: fix scan band off-by-one error When checking for the next band to advance to, there was an off-by-one error that could lead to an access to an invalid array index. Additionally, the later check for scan_band >= IEEE80211_NUM_BANDS is not required since that will never be true. This also improves the comments related to that code. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 2628222a5085..0d5e3fee8e53 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -3412,22 +3412,28 @@ void ieee80211_sta_scan_work(struct work_struct *work) switch (local->scan_state) { case SCAN_SET_CHANNEL: - /* get current scan band */ + /* + * Get current scan band. scan_band may be IEEE80211_NUM_BANDS + * after we successfully scanned the last channel of the last + * band (and the last band is supported by the hw) + */ if (local->scan_band < IEEE80211_NUM_BANDS) sband = local->hw.wiphy->bands[local->scan_band]; else sband = NULL; - /* if we started at an unsupported one, advance */ - while (!sband && local->scan_band < IEEE80211_NUM_BANDS) { + /* + * If we are at an unsupported band and have more bands + * left to scan, advance to the next supported one. + */ + while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) { local->scan_band++; sband = local->hw.wiphy->bands[local->scan_band]; local->scan_channel_idx = 0; } - if (!sband || - (local->scan_channel_idx >= sband->n_channels && - local->scan_band >= IEEE80211_NUM_BANDS)) { + /* if no more bands/channels left, complete scan */ + if (!sband || local->scan_channel_idx >= sband->n_channels) { ieee80211_scan_completed(local_to_hw(local)); return; } @@ -3449,8 +3455,14 @@ void ieee80211_sta_scan_work(struct work_struct *work) } } + /* advance state machine to next channel/band */ local->scan_channel_idx++; if (local->scan_channel_idx >= sband->n_channels) { + /* + * scan_band may end up == IEEE80211_NUM_BANDS, but + * we'll catch that case above and complete the scan + * if that is the case. + */ local->scan_band++; local->scan_channel_idx = 0; } -- cgit v1.2.3-59-g8ed1b From 238814fd9a9624e3076c47ef0c003101927c7818 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 28 Jan 2008 17:19:37 +0100 Subject: mac80211: remove port control enable switch, clean up sta flags This patch removes the 802.1X port acess control enable flag since it is not required. Instead, set the authorized flag for each station that we normally communicate with (WDS peers, IBSS peers and APs we're associated to) and require hostapd to set the authorized flag for all stations when port control is not enabled. Also, since I was working in that area, this documents station flags and removes the unused "permanent" one. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_netdev.c | 9 --------- net/mac80211/debugfs_sta.c | 3 +-- net/mac80211/ieee80211.c | 3 +++ net/mac80211/ieee80211_i.h | 9 --------- net/mac80211/ieee80211_sta.c | 5 ++++- net/mac80211/rx.c | 8 ++++---- net/mac80211/sta_info.h | 44 ++++++++++++++++++++++++++++--------------- net/mac80211/tx.c | 8 +++----- 8 files changed, 44 insertions(+), 45 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 829872a3ae81..29f7b98ba1fb 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -91,7 +91,6 @@ static const struct file_operations name##_ops = { \ /* common attributes */ IEEE80211_IF_FILE(channel_use, channel_use, DEC); IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); -IEEE80211_IF_FILE(ieee802_1x_pac, ieee802_1x_pac, DEC); /* STA/IBSS attributes */ IEEE80211_IF_FILE(state, u.sta.state, DEC); @@ -148,7 +147,6 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(channel_use, sta); DEBUGFS_ADD(drop_unencrypted, sta); - DEBUGFS_ADD(ieee802_1x_pac, sta); DEBUGFS_ADD(state, sta); DEBUGFS_ADD(bssid, sta); DEBUGFS_ADD(prev_bssid, sta); @@ -169,7 +167,6 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(channel_use, ap); DEBUGFS_ADD(drop_unencrypted, ap); - DEBUGFS_ADD(ieee802_1x_pac, ap); DEBUGFS_ADD(num_sta_ps, ap); DEBUGFS_ADD(dtim_count, ap); DEBUGFS_ADD(num_beacons, ap); @@ -182,7 +179,6 @@ static void add_wds_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(channel_use, wds); DEBUGFS_ADD(drop_unencrypted, wds); - DEBUGFS_ADD(ieee802_1x_pac, wds); DEBUGFS_ADD(peer, wds); } @@ -190,7 +186,6 @@ static void add_vlan_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_ADD(channel_use, vlan); DEBUGFS_ADD(drop_unencrypted, vlan); - DEBUGFS_ADD(ieee802_1x_pac, vlan); } static void add_monitor_files(struct ieee80211_sub_if_data *sdata) @@ -234,7 +229,6 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(channel_use, sta); DEBUGFS_DEL(drop_unencrypted, sta); - DEBUGFS_DEL(ieee802_1x_pac, sta); DEBUGFS_DEL(state, sta); DEBUGFS_DEL(bssid, sta); DEBUGFS_DEL(prev_bssid, sta); @@ -255,7 +249,6 @@ static void del_ap_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(channel_use, ap); DEBUGFS_DEL(drop_unencrypted, ap); - DEBUGFS_DEL(ieee802_1x_pac, ap); DEBUGFS_DEL(num_sta_ps, ap); DEBUGFS_DEL(dtim_count, ap); DEBUGFS_DEL(num_beacons, ap); @@ -268,7 +261,6 @@ static void del_wds_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(channel_use, wds); DEBUGFS_DEL(drop_unencrypted, wds); - DEBUGFS_DEL(ieee802_1x_pac, wds); DEBUGFS_DEL(peer, wds); } @@ -276,7 +268,6 @@ static void del_vlan_files(struct ieee80211_sub_if_data *sdata) { DEBUGFS_DEL(channel_use, vlan); DEBUGFS_DEL(drop_unencrypted, vlan); - DEBUGFS_DEL(ieee802_1x_pac, vlan); } static void del_monitor_files(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 49660f4e845d..ac61353ae7ce 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -74,12 +74,11 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, { char buf[100]; struct sta_info *sta = file->private_data; - int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s%s", + int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s", sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "", sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "", sta->flags & WLAN_STA_PS ? "PS\n" : "", sta->flags & WLAN_STA_TIM ? "TIM\n" : "", - sta->flags & WLAN_STA_PERM ? "PERM\n" : "", sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", sta->flags & WLAN_STA_WME ? "WME\n" : "", diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index de894b61a23c..cb09931af86a 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -804,6 +804,9 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); if (!sta) return -ENOMEM; + + sta->flags |= WLAN_STA_AUTHORIZED; + sta_info_put(sta); /* Remove STA entry for the old peer */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 54eea5f24474..ac802feb7655 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -305,11 +305,6 @@ struct ieee80211_sub_if_data { unsigned int flags; int drop_unencrypted; - /* - * IEEE 802.1X Port access control in effect, - * drop packets to/from unauthorized port - */ - int ieee802_1x_pac; /* * basic rates of this AP or the AP we're associated to @@ -352,7 +347,6 @@ struct ieee80211_sub_if_data { struct { struct dentry *channel_use; struct dentry *drop_unencrypted; - struct dentry *ieee802_1x_pac; struct dentry *state; struct dentry *bssid; struct dentry *prev_bssid; @@ -371,7 +365,6 @@ struct ieee80211_sub_if_data { struct { struct dentry *channel_use; struct dentry *drop_unencrypted; - struct dentry *ieee802_1x_pac; struct dentry *num_sta_ps; struct dentry *dtim_count; struct dentry *num_beacons; @@ -382,13 +375,11 @@ struct ieee80211_sub_if_data { struct { struct dentry *channel_use; struct dentry *drop_unencrypted; - struct dentry *ieee802_1x_pac; struct dentry *peer; } wds; struct { struct dentry *channel_use; struct dentry *drop_unencrypted; - struct dentry *ieee802_1x_pac; } vlan; struct { struct dentry *mode; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 0d5e3fee8e53..dac02d001ef0 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1828,7 +1828,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, } sta->dev = dev; - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP; + sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | + WLAN_STA_AUTHORIZED; rates = 0; basic_rates = 0; @@ -3791,6 +3792,8 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, if (!sta) return NULL; + sta->flags |= WLAN_STA_AUTHORIZED; + sta->supp_rates[local->hw.conf.channel->band] = sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band]; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c9ff98a93211..0989c212b7c2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -987,11 +987,11 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) static int ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx) { - if (unlikely(rx->sdata->ieee802_1x_pac && - (!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED)))) { + if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) { #ifdef CONFIG_MAC80211_DEBUG - printk(KERN_DEBUG "%s: dropped frame " - "(unauthorized port)\n", rx->dev->name); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: dropped frame " + "(unauthorized port)\n", rx->dev->name); #endif /* CONFIG_MAC80211_DEBUG */ return -EACCES; } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 3573743dfa59..19f3fb412940 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -15,21 +15,35 @@ #include #include "ieee80211_key.h" -/* Stations flags (struct sta_info::flags) */ -#define WLAN_STA_AUTH BIT(0) -#define WLAN_STA_ASSOC BIT(1) -#define WLAN_STA_PS BIT(2) -#define WLAN_STA_TIM BIT(3) /* TIM bit is on for PS stations */ -#define WLAN_STA_PERM BIT(4) /* permanent; do not remove entry on expiration */ -#define WLAN_STA_AUTHORIZED BIT(5) /* If 802.1X is used, this flag is - * controlling whether STA is authorized to - * send and receive non-IEEE 802.1X frames - */ -#define WLAN_STA_SHORT_PREAMBLE BIT(7) -/* whether this is an AP that we are associated with as a client */ -#define WLAN_STA_ASSOC_AP BIT(8) -#define WLAN_STA_WME BIT(9) -#define WLAN_STA_WDS BIT(27) +/** + * enum ieee80211_sta_info_flags - Stations flags + * + * These flags are used with &struct sta_info's @flags member. + * + * @WLAN_STA_AUTH: Station is authenticated. + * @WLAN_STA_ASSOC: Station is associated. + * @WLAN_STA_PS: Station is in power-save mode + * @WLAN_STA_TIM: TIM bit is on for this PS station (traffic buffered) + * @WLAN_STA_AUTHORIZED: Station is authorized to send/receive traffic. + * This bit is always checked so needs to be enabled for all stations + * when virtual port control is not in use. + * @WLAN_STA_SHORT_PREAMBLE: Station is capable of receiving short-preamble + * frames. + * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP. + * @WLAN_STA_WME: Station is a QoS-STA. + * @WLAN_STA_WDS: Station is one of our WDS peers. + */ +enum ieee80211_sta_info_flags { + WLAN_STA_AUTH = 1<<0, + WLAN_STA_ASSOC = 1<<1, + WLAN_STA_PS = 1<<2, + WLAN_STA_TIM = 1<<3, + WLAN_STA_AUTHORIZED = 1<<4, + WLAN_STA_SHORT_PREAMBLE = 1<<5, + WLAN_STA_ASSOC_AP = 1<<6, + WLAN_STA_WME = 1<<7, + WLAN_STA_WDS = 1<<8, +}; #define STA_TID_NUM 16 #define ADDBA_RESP_INTERVAL HZ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 9e5359991985..2b4746441232 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1471,12 +1471,10 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, } /* - * If port access control is enabled, drop unicast frames to - * unauthorised stations unless they are EAPOL frames from the - * local station. + * Drop unicast frames to unauthorised stations unless they are + * EAPOL frames from the local station. */ - if (unlikely(sdata->ieee802_1x_pac && - !is_multicast_ether_addr(hdr.addr1) && + if (unlikely(!is_multicast_ether_addr(hdr.addr1) && !(sta_flags & WLAN_STA_AUTHORIZED) && !(ethertype == ETH_P_PAE && compare_ether_addr(dev->dev_addr, -- cgit v1.2.3-59-g8ed1b From b7c50de92e1b54fa4a9a2ee436b16ead3ee31767 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Tue, 29 Jan 2008 20:29:16 +0100 Subject: rc80211-pid: fix rate adjustment Merge rate_control_pid_shift_adjust() to rate_control_pid_adjust_rate() in order to make the learning algorithm aware of constraints on rates. Also add some comments and rename variables. This fixes a bug which prevented 802.11b/g non-AP STAs from working with 802.11b only AP STAs. Signed-off-by: Stefano Brivio Signed-off-by: John W. Linville --- net/mac80211/rc80211_pid_algo.c | 93 +++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 49 deletions(-) (limited to 'net') diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index c5a607ca8440..da8462bbd5f4 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -2,7 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005, Devicescape Software, Inc. * Copyright 2007, Mattias Nissler - * Copyright 2007, Stefano Brivio + * Copyright 2007-2008, Stefano Brivio * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -64,71 +64,66 @@ */ -/* Shift the adjustment so that we won't switch to a lower rate if it exhibited - * a worse failed frames behaviour and we'll choose the highest rate whose - * failed frames behaviour is not worse than the one of the original rate - * target. While at it, check that the adjustment is within the ranges. Then, - * provide the new rate index. */ -static int rate_control_pid_shift_adjust(struct rc_pid_rateinfo *r, - int adj, int cur, int l) -{ - int i, j, k, tmp; - - j = r[cur].rev_index; - i = j + adj; - - if (i < 0) - return r[0].index; - if (i >= l - 1) - return r[l - 1].index; - - tmp = i; - - if (adj < 0) { - for (k = j; k >= i; k--) - if (r[k].diff <= r[j].diff) - tmp = k; - } else { - for (k = i + 1; k + i < l; k++) - if (r[k].diff <= r[i].diff) - tmp = k; - } - - return r[tmp].index; -} - +/* Adjust the rate while ensuring that we won't switch to a lower rate if it + * exhibited a worse failed frames behaviour and we'll choose the highest rate + * whose failed frames behaviour is not worse than the one of the original rate + * target. While at it, check that the new rate is valid. */ static void rate_control_pid_adjust_rate(struct ieee80211_local *local, struct sta_info *sta, int adj, struct rc_pid_rateinfo *rinfo) { struct ieee80211_sub_if_data *sdata; struct ieee80211_supported_band *sband; - int newidx; - int maxrate; - int back = (adj > 0) ? 1 : -1; + int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; + int cur = sta->txrate_idx; sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1; + band = sband->band; + n_bitrates = sband->n_bitrates; - newidx = rate_control_pid_shift_adjust(rinfo, adj, sta->txrate_idx, - sband->n_bitrates); + /* Map passed arguments to sorted values. */ + cur_sorted = rinfo[cur].rev_index; + new_sorted = cur_sorted + adj; - while (newidx != sta->txrate_idx) { - if (rate_supported(sta, sband->band, newidx) && - (maxrate < 0 || newidx <= maxrate)) { - sta->txrate_idx = newidx; - break; - } + /* Check limits. */ + if (new_sorted < 0) + new_sorted = rinfo[0].rev_index; + else if (new_sorted >= n_bitrates) + new_sorted = rinfo[n_bitrates - 1].rev_index; - newidx += back; + tmp = new_sorted; + + if (adj < 0) { + /* Ensure that the rate decrease isn't disadvantageous. */ + for (probe = cur_sorted; probe >= new_sorted; probe--) + if (rinfo[probe].diff <= rinfo[cur_sorted].diff && + rate_supported(sta, band, rinfo[probe].index)) + tmp = probe; + } else { + /* Look for rate increase with zero (or below) cost. */ + for (probe = new_sorted + 1; probe < n_bitrates; probe++) + if (rinfo[probe].diff <= rinfo[new_sorted].diff && + rate_supported(sta, band, rinfo[probe].index)) + tmp = probe; } + /* Fit the rate found to the nearest supported rate. */ + do { + if (rate_supported(sta, band, rinfo[tmp].index)) { + sta->txrate_idx = rinfo[tmp].index; + break; + } + if (adj < 0) + tmp--; + else + tmp++; + } while (tmp < n_bitrates && tmp >= 0); + #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_rate_change( &((struct rc_pid_sta_info *)sta->rate_ctrl_priv)->events, - newidx, sband->bitrates[newidx].bitrate); + sta->txrate_idx, sband->bitrates[sta->txrate_idx].bitrate); #endif } -- cgit v1.2.3-59-g8ed1b From aac09fbf827b467995b00a1ea0213843a9e605b8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 30 Jan 2008 17:36:10 +0100 Subject: wireless: fix ERP rate flags In the rate API patch I accidentally reverted the test for ERP rates, this fixes it. All rates except 1, 2, 5.5 and 11 MBit are ERP rates, not those. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/wireless/util.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/wireless/util.c b/net/wireless/util.c index 0dcccbf3eb57..e6046901055a 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -73,10 +73,10 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, want--; } - if (sband->bitrates[i].bitrate == 10 || - sband->bitrates[i].bitrate == 20 || - sband->bitrates[i].bitrate == 55 || - sband->bitrates[i].bitrate == 110) + if (sband->bitrates[i].bitrate != 10 && + sband->bitrates[i].bitrate != 20 && + sband->bitrates[i].bitrate != 55 && + sband->bitrates[i].bitrate != 110) sband->bitrates[i].flags |= IEEE80211_RATE_ERP_G; } -- cgit v1.2.3-59-g8ed1b From 406f2388cc1f6e6c176305bd325cef230ce1afdd Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Sat, 2 Feb 2008 23:53:10 +0100 Subject: wireless: Fix WARN_ON() with ieee802.11b When the driver registers a IEEE80211_BAND_2GHZ band, it can either be 802.11b or 802.11g. But when 802.11b rates are registered "want" will be 3 (since 4 rates are being registered, and each of those 4 rates will decrease "want"). Since this is a correct situation, there is no need to trigger a WARN_ON() for this. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- net/wireless/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/wireless/util.c b/net/wireless/util.c index e6046901055a..77336c22fcf2 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -80,7 +80,7 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, sband->bitrates[i].flags |= IEEE80211_RATE_ERP_G; } - WARN_ON(want != 0 && want != 6); + WARN_ON(want != 0 && want != 3 && want != 6); break; case IEEE80211_NUM_BANDS: WARN_ON(1); -- cgit v1.2.3-59-g8ed1b From 9ae54c8463691b64ca6e6d8680787a6527810984 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 31 Jan 2008 19:48:20 +0100 Subject: mac80211: split ieee80211_txrx_result The _DROP result will need to be split in the RX path but not in the TX path, so for preparation split up the type into two types, one for RX and one for TX. Also make sure (via sparse) that they cannot be confused. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 23 ++++--- net/mac80211/ieee80211_sta.c | 14 ++-- net/mac80211/rx.c | 150 +++++++++++++++++++++---------------------- net/mac80211/tx.c | 110 +++++++++++++++---------------- net/mac80211/wep.c | 16 ++--- net/mac80211/wep.h | 4 +- net/mac80211/wpa.c | 72 ++++++++++----------- net/mac80211/wpa.h | 12 ++-- 8 files changed, 204 insertions(+), 197 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ac802feb7655..36ea4fbdf950 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -108,9 +108,16 @@ struct ieee80211_sta_bss { }; -typedef enum { - TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED -} ieee80211_txrx_result; +typedef unsigned __bitwise__ ieee80211_tx_result; +#define TX_CONTINUE ((__force ieee80211_tx_result) 0u) +#define TX_DROP ((__force ieee80211_tx_result) 1u) +#define TX_QUEUED ((__force ieee80211_tx_result) 2u) + +typedef unsigned __bitwise__ ieee80211_rx_result; +#define RX_CONTINUE ((__force ieee80211_rx_result) 0u) +#define RX_DROP ((__force ieee80211_rx_result) 1u) +#define RX_QUEUED ((__force ieee80211_rx_result) 2u) + /* flags used in struct ieee80211_txrx_data.flags */ /* whether the MSDU was fragmented */ @@ -182,10 +189,10 @@ struct ieee80211_tx_stored_packet { unsigned int last_frag_rate_ctrl_probe; }; -typedef ieee80211_txrx_result (*ieee80211_tx_handler) +typedef ieee80211_tx_result (*ieee80211_tx_handler) (struct ieee80211_txrx_data *tx); -typedef ieee80211_txrx_result (*ieee80211_rx_handler) +typedef ieee80211_rx_result (*ieee80211_rx_handler) (struct ieee80211_txrx_data *rx); struct beacon_data { @@ -729,9 +736,9 @@ int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len); void ieee80211_sta_req_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta); int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len); -ieee80211_txrx_result ieee80211_sta_rx_scan(struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_rx_status *rx_status); +ieee80211_rx_result ieee80211_sta_rx_scan( + struct net_device *dev, struct sk_buff *skb, + struct ieee80211_rx_status *rx_status); void ieee80211_rx_bss_list_init(struct net_device *dev); void ieee80211_rx_bss_list_deinit(struct net_device *dev); int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len); diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index dac02d001ef0..991689371bdc 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2559,7 +2559,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev, } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, struct ieee80211_rx_status *rx_status) { @@ -2567,31 +2567,31 @@ ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, u16 fc; if (skb->len < 2) - return TXRX_DROP; + return RX_DROP; mgmt = (struct ieee80211_mgmt *) skb->data; fc = le16_to_cpu(mgmt->frame_control); if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) - return TXRX_CONTINUE; + return RX_CONTINUE; if (skb->len < 24) - return TXRX_DROP; + return RX_DROP; if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) { ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status); dev_kfree_skb(skb); - return TXRX_QUEUED; + return RX_QUEUED; } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) { ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status); dev_kfree_skb(skb); - return TXRX_QUEUED; + return RX_QUEUED; } } - return TXRX_CONTINUE; + return RX_CONTINUE; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0989c212b7c2..ffd68d9a0013 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -351,16 +351,16 @@ static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, /* rx handlers */ -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) { if (rx->sta) rx->sta->channel_use_raw += rx->u.rx.load; rx->sdata->channel_use_raw += rx->u.rx.load; - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) { struct ieee80211_local *local = rx->local; @@ -372,21 +372,21 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) if (unlikely(local->sta_sw_scanning)) { /* drop all the other packets during a software scan anyway */ if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status) - != TXRX_QUEUED) + != RX_QUEUED) dev_kfree_skb(skb); - return TXRX_QUEUED; + return RX_QUEUED; } if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) { /* scanning finished during invoking of handlers */ I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); - return TXRX_DROP; + return RX_DROP; } - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr; @@ -401,14 +401,14 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) rx->local->dot11FrameDuplicateCount++; rx->sta->num_duplicates++; } - return TXRX_DROP; + return RX_DROP; } else rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl; } if (unlikely(rx->skb->len < 16)) { I802_DEBUG_INC(rx->local->rx_handlers_drop_short); - return TXRX_DROP; + return RX_DROP; } /* Drop disallowed frame classes based on STA auth/assoc state; @@ -430,23 +430,23 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { /* Drop IBSS frames and frames for other hosts * silently. */ - return TXRX_DROP; + return RX_DROP; } - return TXRX_DROP; + return RX_DROP; } - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; int keyidx; int hdrlen; - ieee80211_txrx_result result = TXRX_DROP; + ieee80211_rx_result result = RX_DROP; struct ieee80211_key *stakey = NULL; /* @@ -476,14 +476,14 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) */ if (!(rx->fc & IEEE80211_FCTL_PROTECTED)) - return TXRX_CONTINUE; + return RX_CONTINUE; /* * No point in finding a key and decrypting if the frame is neither * addressed to us nor a multicast frame. */ if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_CONTINUE; + return RX_CONTINUE; if (rx->sta) stakey = rcu_dereference(rx->sta->key); @@ -502,12 +502,12 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) */ if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) - return TXRX_CONTINUE; + return RX_CONTINUE; hdrlen = ieee80211_get_hdrlen(rx->fc); if (rx->skb->len < 8 + hdrlen) - return TXRX_DROP; /* TODO: count this? */ + return RX_DROP; /* TODO: count this? */ /* * no need to call ieee80211_wep_get_keyidx, @@ -536,7 +536,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) printk(KERN_DEBUG "%s: RX protected frame," " but have no key\n", rx->dev->name); #endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; + return RX_DROP; } /* Check for weak IVs if possible */ @@ -629,7 +629,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) return sent; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) { struct sta_info *sta = rx->sta; @@ -637,7 +637,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; if (!sta) - return TXRX_CONTINUE; + return RX_CONTINUE; /* Update last_rx only for IBSS packets which are for the current * BSSID to avoid keeping the current IBSS network alive in cases where @@ -658,7 +658,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) } if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_CONTINUE; + return RX_CONTINUE; sta->rx_fragments++; sta->rx_bytes += rx->skb->len; @@ -685,10 +685,10 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) * as a dropped packed. */ sta->rx_packets++; dev_kfree_skb(rx->skb); - return TXRX_QUEUED; + return RX_QUEUED; } - return TXRX_CONTINUE; + return RX_CONTINUE; } /* ieee80211_rx_h_sta_process */ static inline struct ieee80211_fragment_entry * @@ -774,7 +774,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, return NULL; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr; @@ -811,7 +811,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) rx->key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN); } - return TXRX_QUEUED; + return RX_QUEUED; } /* This is a fragment for a frame that should already be pending in @@ -821,7 +821,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) rx->u.rx.queue, hdr); if (!entry) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); - return TXRX_DROP; + return RX_DROP; } /* Verify that MPDUs within one MSDU have sequential PN values. @@ -830,7 +830,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) int i; u8 pn[CCMP_PN_LEN], *rpn; if (!rx->key || rx->key->conf.alg != ALG_CCMP) - return TXRX_DROP; + return RX_DROP; memcpy(pn, entry->last_pn, CCMP_PN_LEN); for (i = CCMP_PN_LEN - 1; i >= 0; i--) { pn[i]++; @@ -848,7 +848,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], rpn[5], pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); - return TXRX_DROP; + return RX_DROP; } memcpy(entry->last_pn, pn, CCMP_PN_LEN); } @@ -859,7 +859,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) entry->extra_len += rx->skb->len; if (rx->fc & IEEE80211_FCTL_MOREFRAGS) { rx->skb = NULL; - return TXRX_QUEUED; + return RX_QUEUED; } rx->skb = __skb_dequeue(&entry->skb_list); @@ -869,7 +869,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) GFP_ATOMIC))) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); __skb_queue_purge(&entry->skb_list); - return TXRX_DROP; + return RX_DROP; } } while ((skb = __skb_dequeue(&entry->skb_list))) { @@ -887,10 +887,10 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) rx->local->dot11MulticastReceivedFrameCount++; else ieee80211_led_rx(rx->local); - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); @@ -902,11 +902,11 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL || (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))) - return TXRX_CONTINUE; + return RX_CONTINUE; if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) && (sdata->vif.type != IEEE80211_IF_TYPE_VLAN)) - return TXRX_DROP; + return RX_DROP; skb = skb_dequeue(&rx->sta->tx_filtered); if (!skb) { @@ -957,14 +957,14 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) } - /* Free PS Poll skb here instead of returning TXRX_DROP that would + /* Free PS Poll skb here instead of returning RX_DROP that would * count as an dropped frame. */ dev_kfree_skb(rx->skb); - return TXRX_QUEUED; + return RX_QUEUED; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) { u16 fc = rx->fc; @@ -972,7 +972,7 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) data; if (!WLAN_FC_IS_QOS_DATA(fc)) - return TXRX_CONTINUE; + return RX_CONTINUE; /* remove the qos control field, update frame type and meta-data */ memmove(data + 2, data, ieee80211_get_hdrlen(fc) - 2); @@ -981,7 +981,7 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) rx->fc = fc &= ~IEEE80211_STYPE_QOS_DATA; hdr->frame_control = cpu_to_le16(fc); - return TXRX_CONTINUE; + return RX_CONTINUE; } static int @@ -1238,7 +1238,7 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) } } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) { struct net_device *dev = rx->dev; @@ -1254,17 +1254,17 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) fc = rx->fc; if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) - return TXRX_CONTINUE; + return RX_CONTINUE; if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return TXRX_DROP; + return RX_DROP; if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU)) - return TXRX_CONTINUE; + return RX_CONTINUE; err = ieee80211_data_to_8023(rx); if (unlikely(err)) - return TXRX_DROP; + return RX_DROP; skb->dev = dev; @@ -1274,7 +1274,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) /* skip the wrapping header */ eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); if (!eth) - return TXRX_DROP; + return RX_DROP; while (skb != frame) { u8 padding; @@ -1289,7 +1289,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) /* the last MSDU has no padding */ if (subframe_len > remaining) { printk(KERN_DEBUG "%s: wrong buffer size", dev->name); - return TXRX_DROP; + return RX_DROP; } skb_pull(skb, sizeof(struct ethhdr)); @@ -1301,7 +1301,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) subframe_len); if (frame == NULL) - return TXRX_DROP; + return RX_DROP; skb_reserve(frame, local->hw.extra_tx_headroom + sizeof(struct ethhdr)); @@ -1314,7 +1314,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) printk(KERN_DEBUG "%s: wrong buffer size ", dev->name); dev_kfree_skb(frame); - return TXRX_DROP; + return RX_DROP; } } @@ -1344,7 +1344,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) if (!ieee80211_frame_allowed(rx)) { if (skb == frame) /* last frame */ - return TXRX_DROP; + return RX_DROP; dev_kfree_skb(frame); continue; } @@ -1352,10 +1352,10 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) ieee80211_deliver_skb(rx); } - return TXRX_QUEUED; + return RX_QUEUED; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) { struct net_device *dev = rx->dev; @@ -1364,17 +1364,17 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) fc = rx->fc; if (unlikely((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA)) - return TXRX_CONTINUE; + return RX_CONTINUE; if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return TXRX_DROP; + return RX_DROP; err = ieee80211_data_to_8023(rx); if (unlikely(err)) - return TXRX_DROP; + return RX_DROP; if (!ieee80211_frame_allowed(rx)) - return TXRX_DROP; + return RX_DROP; rx->skb->dev = dev; @@ -1383,10 +1383,10 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) ieee80211_deliver_skb(rx); - return TXRX_QUEUED; + return RX_QUEUED; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx) { struct ieee80211_local *local = rx->local; @@ -1398,15 +1398,15 @@ ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx) u16 tid; if (likely((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL)) - return TXRX_CONTINUE; + return RX_CONTINUE; if ((rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BACK_REQ) { if (!rx->sta) - return TXRX_CONTINUE; + return RX_CONTINUE; tid = le16_to_cpu(bar->control) >> 12; tid_agg_rx = &(rx->sta->ampdu_mlme.tid_rx[tid]); if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL) - return TXRX_CONTINUE; + return RX_CONTINUE; start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4; @@ -1423,19 +1423,19 @@ ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx) ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, start_seq_num, 1); rcu_read_unlock(); - return TXRX_DROP; + return RX_DROP; } - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_rx_result ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) { struct ieee80211_sub_if_data *sdata; if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_DROP; + return RX_DROP; sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || @@ -1443,39 +1443,39 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); else - return TXRX_DROP; + return RX_DROP; - return TXRX_QUEUED; + return RX_QUEUED; } -static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers( +static inline ieee80211_rx_result __ieee80211_invoke_rx_handlers( struct ieee80211_local *local, ieee80211_rx_handler *handlers, struct ieee80211_txrx_data *rx, struct sta_info *sta) { ieee80211_rx_handler *handler; - ieee80211_txrx_result res = TXRX_DROP; + ieee80211_rx_result res = RX_DROP; for (handler = handlers; *handler != NULL; handler++) { res = (*handler)(rx); switch (res) { - case TXRX_CONTINUE: + case RX_CONTINUE: continue; - case TXRX_DROP: + case RX_DROP: I802_DEBUG_INC(local->rx_handlers_drop); if (sta) sta->rx_dropped++; break; - case TXRX_QUEUED: + case RX_QUEUED: I802_DEBUG_INC(local->rx_handlers_queued); break; } break; } - if (res == TXRX_DROP) + if (res == RX_DROP) dev_kfree_skb(rx->skb); return res; } @@ -1486,7 +1486,7 @@ static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, struct sta_info *sta) { if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) == - TXRX_CONTINUE) + RX_CONTINUE) dev_kfree_skb(rx->skb); } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 2b4746441232..0cba4a214876 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -232,7 +232,7 @@ static int inline is_ieee80211_device(struct net_device *dev, /* tx handlers */ -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG @@ -242,15 +242,15 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) u32 sta_flags; if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) - return TXRX_CONTINUE; + return TX_CONTINUE; if (unlikely(tx->local->sta_sw_scanning) && ((tx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) - return TXRX_DROP; + return TX_DROP; if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED) - return TXRX_CONTINUE; + return TX_CONTINUE; sta_flags = tx->sta ? tx->sta->flags : 0; @@ -265,7 +265,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) tx->dev->name, print_mac(mac, hdr->addr1)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); - return TXRX_DROP; + return TX_DROP; } } else { if (unlikely((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && @@ -275,15 +275,15 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) * No associated STAs - no need to send multicast * frames. */ - return TXRX_DROP; + return TX_DROP; } - return TXRX_CONTINUE; + return TX_CONTINUE; } - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; @@ -291,7 +291,7 @@ ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx) if (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)) >= 24) ieee80211_include_sequence(tx->sdata, hdr); - return TXRX_CONTINUE; + return TX_CONTINUE; } /* This function is called whenever the AP is about to exceed the maximum limit @@ -341,7 +341,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) wiphy_name(local->hw.wiphy), purged); } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) { /* @@ -354,11 +354,11 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) /* not AP/IBSS or ordered frame */ if (!tx->sdata->bss || (tx->fc & IEEE80211_FCTL_ORDER)) - return TXRX_CONTINUE; + return TX_CONTINUE; /* no stations in PS mode */ if (!atomic_read(&tx->sdata->bss->num_sta_ps)) - return TXRX_CONTINUE; + return TX_CONTINUE; /* buffered in mac80211 */ if (tx->local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING) { @@ -375,16 +375,16 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) } else tx->local->total_ps_buffered++; skb_queue_tail(&tx->sdata->bss->ps_bc_buf, tx->skb); - return TXRX_QUEUED; + return TX_QUEUED; } /* buffered in hardware */ tx->u.tx.control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM; - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) { struct sta_info *sta = tx->sta; @@ -393,7 +393,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) if (unlikely(!sta || ((tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP))) - return TXRX_CONTINUE; + return TX_CONTINUE; if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) { struct ieee80211_tx_packet_data *pkt_data; @@ -427,7 +427,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb; pkt_data->jiffies = jiffies; skb_queue_tail(&sta->ps_tx_buf, tx->skb); - return TXRX_QUEUED; + return TX_QUEUED; } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG else if (unlikely(sta->flags & WLAN_STA_PS)) { @@ -438,14 +438,14 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ sta->pspoll = 0; - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) { if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)) - return TXRX_CONTINUE; + return TX_CONTINUE; if (tx->flags & IEEE80211_TXRXD_TXUNICAST) return ieee80211_tx_h_unicast_ps_buf(tx); @@ -453,7 +453,7 @@ ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) return ieee80211_tx_h_multicast_ps_buf(tx); } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) { struct ieee80211_key *key; @@ -469,7 +469,7 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) !(tx->u.tx.control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && !(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); - return TXRX_DROP; + return TX_DROP; } else tx->key = NULL; @@ -498,10 +498,10 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; @@ -513,7 +513,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) int frag_threshold = tx->local->fragmentation_threshold; if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED)) - return TXRX_CONTINUE; + return TX_CONTINUE; first = tx->skb; @@ -567,7 +567,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) tx->u.tx.num_extra_frag = num_fragm - 1; tx->u.tx.extra_frag = frags; - return TXRX_CONTINUE; + return TX_CONTINUE; fail: printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); @@ -578,14 +578,14 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) kfree(frags); } I802_DEBUG_INC(tx->local->tx_handlers_drop_fragment); - return TXRX_DROP; + return TX_DROP; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) { if (!tx->key) - return TXRX_CONTINUE; + return TX_CONTINUE; switch (tx->key->conf.alg) { case ALG_WEP: @@ -598,10 +598,10 @@ ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) /* not reached */ WARN_ON(1); - return TXRX_DROP; + return TX_DROP; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) { struct rate_selection rsel; @@ -622,7 +622,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) tx->u.tx.control->alt_retry_rate = NULL; if (!tx->u.tx.rate) - return TXRX_DROP; + return TX_DROP; } else tx->u.tx.control->alt_retry_rate = NULL; @@ -642,10 +642,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) } tx->u.tx.control->tx_rate = tx->u.tx.rate; - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; @@ -754,10 +754,10 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) } } - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result +static ieee80211_tx_result ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) { struct ieee80211_local *local = tx->local; @@ -810,7 +810,7 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) tx->sta->channel_use_raw += load; tx->sdata->channel_use_raw += load; - return TXRX_CONTINUE; + return TX_CONTINUE; } /* TODO: implement register/unregister functions for adding TX/RX handlers @@ -837,7 +837,7 @@ ieee80211_tx_handler ieee80211_tx_handlers[] = * deal with packet injection down monitor interface * with Radiotap Header -- only called for monitor mode interface */ -static ieee80211_txrx_result +static ieee80211_tx_result __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, struct sk_buff *skb) { @@ -926,7 +926,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, * on transmission */ if (skb->len < (iterator.max_length + FCS_LEN)) - return TXRX_DROP; + return TX_DROP; skb_trim(skb, skb->len - FCS_LEN); } @@ -949,7 +949,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, } if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ - return TXRX_DROP; + return TX_DROP; /* * remove the radiotap header @@ -958,13 +958,13 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, */ skb_pull(skb, iterator.max_length); - return TXRX_CONTINUE; + return TX_CONTINUE; } /* * initialises @tx */ -static ieee80211_txrx_result +static ieee80211_tx_result __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, struct sk_buff *skb, struct net_device *dev, @@ -991,8 +991,8 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, /* process and remove the injection radiotap header */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (unlikely(sdata->vif.type == IEEE80211_IF_TYPE_MNTR)) { - if (__ieee80211_parse_tx_radiotap(tx, skb) == TXRX_DROP) - return TXRX_DROP; + if (__ieee80211_parse_tx_radiotap(tx, skb) == TX_DROP) + return TX_DROP; /* * __ieee80211_parse_tx_radiotap has now removed @@ -1037,7 +1037,7 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, } control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; - return TXRX_CONTINUE; + return TX_CONTINUE; } /* @@ -1131,7 +1131,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, struct sta_info *sta; ieee80211_tx_handler *handler; struct ieee80211_txrx_data tx; - ieee80211_txrx_result res = TXRX_DROP, res_prepare; + ieee80211_tx_result res = TX_DROP, res_prepare; int ret, i; WARN_ON(__ieee80211_queue_pending(local, control->queue)); @@ -1144,7 +1144,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, /* initialises tx */ res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); - if (res_prepare == TXRX_DROP) { + if (res_prepare == TX_DROP) { dev_kfree_skb(skb); return 0; } @@ -1161,7 +1161,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, for (handler = local->tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); - if (res != TXRX_CONTINUE) + if (res != TX_CONTINUE) break; } @@ -1170,12 +1170,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, if (sta) sta_info_put(sta); - if (unlikely(res == TXRX_DROP)) { + if (unlikely(res == TX_DROP)) { I802_DEBUG_INC(local->tx_handlers_drop); goto drop; } - if (unlikely(res == TXRX_QUEUED)) { + if (unlikely(res == TX_QUEUED)) { I802_DEBUG_INC(local->tx_handlers_queued); rcu_read_unlock(); return 0; @@ -1864,7 +1864,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct sta_info *sta; ieee80211_tx_handler *handler; struct ieee80211_txrx_data tx; - ieee80211_txrx_result res = TXRX_DROP; + ieee80211_tx_result res = TX_DROP; struct net_device *bdev; struct ieee80211_sub_if_data *sdata; struct ieee80211_if_ap *bss = NULL; @@ -1916,16 +1916,16 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, for (handler = local->tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); - if (res == TXRX_DROP || res == TXRX_QUEUED) + if (res == TX_DROP || res == TX_QUEUED) break; } skb = tx.skb; /* handlers are allowed to change skb */ - if (res == TXRX_DROP) { + if (res == TX_DROP) { I802_DEBUG_INC(local->tx_handlers_drop); dev_kfree_skb(skb); skb = NULL; - } else if (res == TXRX_QUEUED) { + } else if (res == TX_QUEUED) { I802_DEBUG_INC(local->tx_handlers_queued); skb = NULL; } diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index a0cff72a580b..8b0015302645 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -305,13 +305,13 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) return NULL; } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) { if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) - return TXRX_CONTINUE; + return RX_CONTINUE; if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { @@ -320,7 +320,7 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) printk(KERN_DEBUG "%s: RX WEP frame, decrypt " "failed\n", rx->dev->name); #endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; + return RX_DROP; } } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) { ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); @@ -328,7 +328,7 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) skb_trim(rx->skb, rx->skb->len - 4); } - return TXRX_CONTINUE; + return RX_CONTINUE; } static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) @@ -346,7 +346,7 @@ static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) return 0; } -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx) { tx->u.tx.control->iv_len = WEP_IV_LEN; @@ -355,7 +355,7 @@ ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx) if (wep_encrypt_skb(tx, tx->skb) < 0) { I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); - return TXRX_DROP; + return TX_DROP; } if (tx->u.tx.extra_frag) { @@ -364,10 +364,10 @@ ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx) if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) { I802_DEBUG_INC(tx->local-> tx_handlers_drop_wep); - return TXRX_DROP; + return TX_DROP; } } } - return TXRX_CONTINUE; + return TX_CONTINUE; } diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index 785fbb4e0dd7..43aef50cd0d6 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -28,9 +28,9 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key); u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx); -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx); #endif /* WEP_H */ diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 6f04311cf0a0..c628fa93f574 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -70,7 +70,7 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da, } -ieee80211_txrx_result +ieee80211_tx_result ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) { u8 *data, *sa, *da, *key, *mic, qos_tid; @@ -84,10 +84,10 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) if (!tx->key || tx->key->conf.alg != ALG_TKIP || skb->len < 24 || !WLAN_FC_DATA_PRESENT(fc)) - return TXRX_CONTINUE; + return TX_CONTINUE; if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len)) - return TXRX_DROP; + return TX_DROP; if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) && @@ -95,7 +95,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) !wpa_test) { /* hwaccel - with no need for preallocated room for Michael MIC */ - return TXRX_CONTINUE; + return TX_CONTINUE; } if (skb_tailroom(skb) < MICHAEL_MIC_LEN) { @@ -105,7 +105,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) GFP_ATOMIC))) { printk(KERN_DEBUG "%s: failed to allocate more memory " "for Michael MIC\n", tx->dev->name); - return TXRX_DROP; + return TX_DROP; } } @@ -119,11 +119,11 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) mic = skb_put(skb, MICHAEL_MIC_LEN); michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); - return TXRX_CONTINUE; + return TX_CONTINUE; } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) { u8 *data, *sa, *da, *key = NULL, qos_tid; @@ -140,15 +140,15 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) * No way to verify the MIC if the hardware stripped it */ if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED) - return TXRX_CONTINUE; + return RX_CONTINUE; if (!rx->key || rx->key->conf.alg != ALG_TKIP || !(rx->fc & IEEE80211_FCTL_PROTECTED) || !WLAN_FC_DATA_PRESENT(fc)) - return TXRX_CONTINUE; + return RX_CONTINUE; if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len) || data_len < MICHAEL_MIC_LEN) - return TXRX_DROP; + return RX_DROP; data_len -= MICHAEL_MIC_LEN; @@ -162,14 +162,14 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_DROP; + return RX_DROP; printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " "%s\n", rx->dev->name, print_mac(mac, sa)); mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx, (void *) skb->data); - return TXRX_DROP; + return RX_DROP; } /* remove Michael MIC from payload */ @@ -179,7 +179,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) rx->key->u.tkip.iv32_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv32; rx->key->u.tkip.iv16_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv16; - return TXRX_CONTINUE; + return RX_CONTINUE; } @@ -242,7 +242,7 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, } -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx) { struct sk_buff *skb = tx->skb; @@ -257,26 +257,26 @@ ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx) !wpa_test) { /* hwaccel - with no need for preallocated room for IV/ICV */ tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; - return TXRX_CONTINUE; + return TX_CONTINUE; } if (tkip_encrypt_skb(tx, skb, test) < 0) - return TXRX_DROP; + return TX_DROP; if (tx->u.tx.extra_frag) { int i; for (i = 0; i < tx->u.tx.num_extra_frag; i++) { if (tkip_encrypt_skb(tx, tx->u.tx.extra_frag[i], test) < 0) - return TXRX_DROP; + return TX_DROP; } } - return TXRX_CONTINUE; + return TX_CONTINUE; } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; @@ -290,10 +290,10 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) hdrlen = ieee80211_get_hdrlen(fc); if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) - return TXRX_CONTINUE; + return RX_CONTINUE; if (!rx->sta || skb->len - hdrlen < 12) - return TXRX_DROP; + return RX_DROP; if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) { if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) { @@ -302,7 +302,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) * replay protection, and stripped the ICV/IV so * we cannot do any checks here. */ - return TXRX_CONTINUE; + return RX_CONTINUE; } /* let TKIP code verify IV, but skip decryption */ @@ -322,7 +322,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) "frame from %s (res=%d)\n", rx->dev->name, print_mac(mac, rx->sta->addr), res); #endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; + return RX_DROP; } /* Trim ICV */ @@ -332,7 +332,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) memmove(skb->data + TKIP_IV_LEN, skb->data, hdrlen); skb_pull(skb, TKIP_IV_LEN); - return TXRX_CONTINUE; + return RX_CONTINUE; } @@ -491,7 +491,7 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, } -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx) { struct sk_buff *skb = tx->skb; @@ -506,26 +506,26 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx) /* hwaccel - with no need for preallocated room for CCMP " * header or MIC fields */ tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; - return TXRX_CONTINUE; + return TX_CONTINUE; } if (ccmp_encrypt_skb(tx, skb, test) < 0) - return TXRX_DROP; + return TX_DROP; if (tx->u.tx.extra_frag) { int i; for (i = 0; i < tx->u.tx.num_extra_frag; i++) { if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test) < 0) - return TXRX_DROP; + return TX_DROP; } } - return TXRX_CONTINUE; + return TX_CONTINUE; } -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; @@ -541,15 +541,15 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) hdrlen = ieee80211_get_hdrlen(fc); if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) - return TXRX_CONTINUE; + return RX_CONTINUE; data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN; if (!rx->sta || data_len < 0) - return TXRX_DROP; + return RX_DROP; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) - return TXRX_CONTINUE; + return RX_CONTINUE; (void) ccmp_hdr2pn(pn, skb->data + hdrlen); @@ -565,7 +565,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]); #endif /* CONFIG_MAC80211_DEBUG */ key->u.ccmp.replays++; - return TXRX_DROP; + return RX_DROP; } if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { @@ -589,7 +589,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) "for RX frame from %s\n", rx->dev->name, print_mac(mac, rx->sta->addr)); #endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; + return RX_DROP; } } @@ -600,5 +600,5 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) memmove(skb->data + CCMP_HDR_LEN, skb->data, hdrlen); skb_pull(skb, CCMP_HDR_LEN); - return TXRX_CONTINUE; + return RX_CONTINUE; } diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index 49d80cf0cd75..16e4dba4aa70 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h @@ -13,19 +13,19 @@ #include #include "ieee80211_i.h" -ieee80211_txrx_result +ieee80211_tx_result ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx); -ieee80211_txrx_result +ieee80211_rx_result ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx); -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx); -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx); -ieee80211_txrx_result +ieee80211_tx_result ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx); -ieee80211_txrx_result +ieee80211_rx_result ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx); #endif /* WPA_H */ -- cgit v1.2.3-59-g8ed1b From e4c26add8893e40e6e809b8c1ebc81e37762af2b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 31 Jan 2008 19:48:21 +0100 Subject: mac80211: split RX_DROP Some instances of RX_DROP mean that the frame was useless, others mean that the frame should be visible in userspace on "cooked" monitor interfaces. This patch splits up RX_DROP and changes each instance appropriately. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 7 +++--- net/mac80211/ieee80211_sta.c | 4 +-- net/mac80211/rx.c | 59 ++++++++++++++++++++++---------------------- net/mac80211/wep.c | 2 +- net/mac80211/wpa.c | 16 ++++++------ 5 files changed, 45 insertions(+), 43 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 36ea4fbdf950..31fc64c5652c 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -114,9 +114,10 @@ typedef unsigned __bitwise__ ieee80211_tx_result; #define TX_QUEUED ((__force ieee80211_tx_result) 2u) typedef unsigned __bitwise__ ieee80211_rx_result; -#define RX_CONTINUE ((__force ieee80211_rx_result) 0u) -#define RX_DROP ((__force ieee80211_rx_result) 1u) -#define RX_QUEUED ((__force ieee80211_rx_result) 2u) +#define RX_CONTINUE ((__force ieee80211_rx_result) 0u) +#define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u) +#define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u) +#define RX_QUEUED ((__force ieee80211_rx_result) 3u) /* flags used in struct ieee80211_txrx_data.flags */ diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 991689371bdc..a8251a23917b 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2567,7 +2567,7 @@ ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, u16 fc; if (skb->len < 2) - return RX_DROP; + return RX_DROP_UNUSABLE; mgmt = (struct ieee80211_mgmt *) skb->data; fc = le16_to_cpu(mgmt->frame_control); @@ -2576,7 +2576,7 @@ ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, return RX_CONTINUE; if (skb->len < 24) - return RX_DROP; + return RX_DROP_MONITOR; if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) { diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index ffd68d9a0013..860c488984d8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -380,7 +380,7 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) { /* scanning finished during invoking of handlers */ I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); - return RX_DROP; + return RX_DROP_UNUSABLE; } return RX_CONTINUE; @@ -401,14 +401,14 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) rx->local->dot11FrameDuplicateCount++; rx->sta->num_duplicates++; } - return RX_DROP; + return RX_DROP_MONITOR; } else rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl; } if (unlikely(rx->skb->len < 16)) { I802_DEBUG_INC(rx->local->rx_handlers_drop_short); - return RX_DROP; + return RX_DROP_MONITOR; } /* Drop disallowed frame classes based on STA auth/assoc state; @@ -430,10 +430,10 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { /* Drop IBSS frames and frames for other hosts * silently. */ - return RX_DROP; + return RX_DROP_MONITOR; } - return RX_DROP; + return RX_DROP_MONITOR; } return RX_CONTINUE; @@ -446,7 +446,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; int keyidx; int hdrlen; - ieee80211_rx_result result = RX_DROP; + ieee80211_rx_result result = RX_DROP_UNUSABLE; struct ieee80211_key *stakey = NULL; /* @@ -507,7 +507,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) hdrlen = ieee80211_get_hdrlen(rx->fc); if (rx->skb->len < 8 + hdrlen) - return RX_DROP; /* TODO: count this? */ + return RX_DROP_UNUSABLE; /* TODO: count this? */ /* * no need to call ieee80211_wep_get_keyidx, @@ -536,7 +536,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) printk(KERN_DEBUG "%s: RX protected frame," " but have no key\n", rx->dev->name); #endif /* CONFIG_MAC80211_DEBUG */ - return RX_DROP; + return RX_DROP_MONITOR; } /* Check for weak IVs if possible */ @@ -821,7 +821,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) rx->u.rx.queue, hdr); if (!entry) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); - return RX_DROP; + return RX_DROP_MONITOR; } /* Verify that MPDUs within one MSDU have sequential PN values. @@ -830,7 +830,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) int i; u8 pn[CCMP_PN_LEN], *rpn; if (!rx->key || rx->key->conf.alg != ALG_CCMP) - return RX_DROP; + return RX_DROP_UNUSABLE; memcpy(pn, entry->last_pn, CCMP_PN_LEN); for (i = CCMP_PN_LEN - 1; i >= 0; i--) { pn[i]++; @@ -848,7 +848,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) rpn[0], rpn[1], rpn[2], rpn[3], rpn[4], rpn[5], pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); - return RX_DROP; + return RX_DROP_UNUSABLE; } memcpy(entry->last_pn, pn, CCMP_PN_LEN); } @@ -869,7 +869,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) GFP_ATOMIC))) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); __skb_queue_purge(&entry->skb_list); - return RX_DROP; + return RX_DROP_UNUSABLE; } } while ((skb = __skb_dequeue(&entry->skb_list))) { @@ -906,7 +906,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) && (sdata->vif.type != IEEE80211_IF_TYPE_VLAN)) - return RX_DROP; + return RX_DROP_UNUSABLE; skb = skb_dequeue(&rx->sta->tx_filtered); if (!skb) { @@ -1257,14 +1257,14 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) return RX_CONTINUE; if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return RX_DROP; + return RX_DROP_MONITOR; if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU)) return RX_CONTINUE; err = ieee80211_data_to_8023(rx); if (unlikely(err)) - return RX_DROP; + return RX_DROP_UNUSABLE; skb->dev = dev; @@ -1274,7 +1274,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) /* skip the wrapping header */ eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); if (!eth) - return RX_DROP; + return RX_DROP_UNUSABLE; while (skb != frame) { u8 padding; @@ -1289,7 +1289,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) /* the last MSDU has no padding */ if (subframe_len > remaining) { printk(KERN_DEBUG "%s: wrong buffer size", dev->name); - return RX_DROP; + return RX_DROP_UNUSABLE; } skb_pull(skb, sizeof(struct ethhdr)); @@ -1301,7 +1301,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) subframe_len); if (frame == NULL) - return RX_DROP; + return RX_DROP_UNUSABLE; skb_reserve(frame, local->hw.extra_tx_headroom + sizeof(struct ethhdr)); @@ -1314,7 +1314,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) printk(KERN_DEBUG "%s: wrong buffer size ", dev->name); dev_kfree_skb(frame); - return RX_DROP; + return RX_DROP_UNUSABLE; } } @@ -1344,7 +1344,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) if (!ieee80211_frame_allowed(rx)) { if (skb == frame) /* last frame */ - return RX_DROP; + return RX_DROP_UNUSABLE; dev_kfree_skb(frame); continue; } @@ -1367,14 +1367,14 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) return RX_CONTINUE; if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) - return RX_DROP; + return RX_DROP_MONITOR; err = ieee80211_data_to_8023(rx); if (unlikely(err)) - return RX_DROP; + return RX_DROP_UNUSABLE; if (!ieee80211_frame_allowed(rx)) - return RX_DROP; + return RX_DROP_MONITOR; rx->skb->dev = dev; @@ -1423,7 +1423,7 @@ ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx) ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, NULL, start_seq_num, 1); rcu_read_unlock(); - return RX_DROP; + return RX_DROP_UNUSABLE; } return RX_CONTINUE; @@ -1435,7 +1435,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) struct ieee80211_sub_if_data *sdata; if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return RX_DROP; + return RX_DROP_MONITOR; sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || @@ -1443,7 +1443,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); else - return RX_DROP; + return RX_DROP_MONITOR; return RX_QUEUED; } @@ -1455,7 +1455,7 @@ static inline ieee80211_rx_result __ieee80211_invoke_rx_handlers( struct sta_info *sta) { ieee80211_rx_handler *handler; - ieee80211_rx_result res = RX_DROP; + ieee80211_rx_result res = RX_DROP_MONITOR; for (handler = handlers; *handler != NULL; handler++) { res = (*handler)(rx); @@ -1463,7 +1463,8 @@ static inline ieee80211_rx_result __ieee80211_invoke_rx_handlers( switch (res) { case RX_CONTINUE: continue; - case RX_DROP: + case RX_DROP_UNUSABLE: + case RX_DROP_MONITOR: I802_DEBUG_INC(local->rx_handlers_drop); if (sta) sta->rx_dropped++; @@ -1475,7 +1476,7 @@ static inline ieee80211_rx_result __ieee80211_invoke_rx_handlers( break; } - if (res == RX_DROP) + if (res == RX_DROP_UNUSABLE || res == RX_DROP_MONITOR) dev_kfree_skb(rx->skb); return res; } diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 8b0015302645..a33ef5cfa9ad 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -320,7 +320,7 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) printk(KERN_DEBUG "%s: RX WEP frame, decrypt " "failed\n", rx->dev->name); #endif /* CONFIG_MAC80211_DEBUG */ - return RX_DROP; + return RX_DROP_UNUSABLE; } } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) { ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index c628fa93f574..b35e51c6ce0c 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -148,7 +148,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) if (ieee80211_get_hdr_info(skb, &sa, &da, &qos_tid, &data, &data_len) || data_len < MICHAEL_MIC_LEN) - return RX_DROP; + return RX_DROP_UNUSABLE; data_len -= MICHAEL_MIC_LEN; @@ -162,14 +162,14 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return RX_DROP; + return RX_DROP_UNUSABLE; printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " "%s\n", rx->dev->name, print_mac(mac, sa)); mac80211_ev_michael_mic_failure(rx->dev, rx->key->conf.keyidx, (void *) skb->data); - return RX_DROP; + return RX_DROP_UNUSABLE; } /* remove Michael MIC from payload */ @@ -293,7 +293,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) return RX_CONTINUE; if (!rx->sta || skb->len - hdrlen < 12) - return RX_DROP; + return RX_DROP_UNUSABLE; if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) { if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) { @@ -322,7 +322,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) "frame from %s (res=%d)\n", rx->dev->name, print_mac(mac, rx->sta->addr), res); #endif /* CONFIG_MAC80211_DEBUG */ - return RX_DROP; + return RX_DROP_UNUSABLE; } /* Trim ICV */ @@ -545,7 +545,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) data_len = skb->len - hdrlen - CCMP_HDR_LEN - CCMP_MIC_LEN; if (!rx->sta || data_len < 0) - return RX_DROP; + return RX_DROP_UNUSABLE; if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) @@ -565,7 +565,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) ppn[0], ppn[1], ppn[2], ppn[3], ppn[4], ppn[5]); #endif /* CONFIG_MAC80211_DEBUG */ key->u.ccmp.replays++; - return RX_DROP; + return RX_DROP_UNUSABLE; } if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { @@ -589,7 +589,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) "for RX frame from %s\n", rx->dev->name, print_mac(mac, rx->sta->addr)); #endif /* CONFIG_MAC80211_DEBUG */ - return RX_DROP; + return RX_DROP_UNUSABLE; } } -- cgit v1.2.3-59-g8ed1b From 66f7ac50ed7cc5c19a62bc97e8f6e7891004a03a Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Thu, 31 Jan 2008 19:48:22 +0100 Subject: nl80211: Add monitor interface configuration flags This allows precise control over what a monitor interface shows. Signed-off-by: Michael Wu Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 35 +++++++++++++++++++++++++++++++++++ include/net/cfg80211.h | 24 ++++++++++++++++++++++-- net/mac80211/cfg.c | 4 ++-- net/wireless/nl80211.c | 44 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 101 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 63695060db9f..a9f0b93324a2 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -164,6 +164,9 @@ enum nl80211_commands { * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, * consisting of a nested array. * + * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of + * &enum nl80211_mntr_flags. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -200,6 +203,8 @@ enum nl80211_attrs { NL80211_ATTR_WIPHY_BANDS, + NL80211_ATTR_MNTR_FLAGS, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -344,4 +349,34 @@ enum nl80211_bitrate_attr { NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1 }; +/** + * enum nl80211_mntr_flags - monitor configuration flags + * + * Monitor configuration flags. + * + * @__NL80211_MNTR_FLAG_INVALID: reserved + * + * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS + * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP + * @NL80211_MNTR_FLAG_CONTROL: pass control frames + * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering + * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing. + * overrides all other flags. + * + * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use + * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag + */ +enum nl80211_mntr_flags { + __NL80211_MNTR_FLAG_INVALID, + NL80211_MNTR_FLAG_FCSFAIL, + NL80211_MNTR_FLAG_PLCPFAIL, + NL80211_MNTR_FLAG_CONTROL, + NL80211_MNTR_FLAG_OTHER_BSS, + NL80211_MNTR_FLAG_COOK_FRAMES, + + /* keep last */ + __NL80211_MNTR_FLAG_AFTER_LAST, + NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1 +}; + #endif /* __LINUX_NL80211_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index bcc480b8892a..ab4caf63954f 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -163,6 +163,26 @@ struct station_stats { u32 tx_bytes; }; +/** + * enum monitor_flags - monitor flags + * + * Monitor interface configuration flags. Note that these must be the bits + * according to the nl80211 flags. + * + * @MONITOR_FLAG_FCSFAIL: pass frames with bad FCS + * @MONITOR_FLAG_PLCPFAIL: pass frames with bad PLCP + * @MONITOR_FLAG_CONTROL: pass control frames + * @MONITOR_FLAG_OTHER_BSS: disable BSSID filtering + * @MONITOR_FLAG_COOK_FRAMES: report frames after processing + */ +enum monitor_flags { + MONITOR_FLAG_FCSFAIL = 1<attrs[NL80211_ATTR_IFTYPE]) { type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); @@ -362,7 +393,11 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) } rtnl_lock(); - err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, type); + err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? + info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, + &flags); + err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, + type, err ? NULL : &flags); rtnl_unlock(); unlock: @@ -375,6 +410,7 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) struct cfg80211_registered_device *drv; int err; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; + u32 flags; if (!info->attrs[NL80211_ATTR_IFNAME]) return -EINVAL; @@ -395,8 +431,12 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) } rtnl_lock(); + err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? + info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, + &flags); err = drv->ops->add_virtual_intf(&drv->wiphy, - nla_data(info->attrs[NL80211_ATTR_IFNAME]), type); + nla_data(info->attrs[NL80211_ATTR_IFNAME]), + type, err ? NULL : &flags); rtnl_unlock(); unlock: -- cgit v1.2.3-59-g8ed1b From 8cc9a73914b07b5908d8a59320f4557fc9639f2e Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Thu, 31 Jan 2008 19:48:23 +0100 Subject: mac80211: Use monitor configuration flags Take advantage of the monitor configuration flags now provided by cfg80211. Signed-off-by: Michael Wu Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 15 ++++++++++- net/mac80211/ieee80211.c | 56 +++++++++++++++++++++++++++++++----------- net/mac80211/ieee80211_i.h | 3 +++ net/mac80211/ieee80211_iface.c | 2 ++ 4 files changed, 60 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 706418d477c2..a083cc78855e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -38,6 +38,9 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, { struct ieee80211_local *local = wiphy_priv(wiphy); enum ieee80211_if_types itype; + struct net_device *dev; + struct ieee80211_sub_if_data *sdata; + int err; if (unlikely(local->reg_state != IEEE80211_DEV_REGISTERED)) return -ENODEV; @@ -46,7 +49,13 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, if (itype == IEEE80211_IF_TYPE_INVALID) return -EINVAL; - return ieee80211_if_add(local->mdev, name, NULL, itype); + err = ieee80211_if_add(local->mdev, name, &dev, itype); + if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags) + return err; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sdata->u.mntr_flags = *flags; + return 0; } static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) @@ -99,6 +108,10 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, ieee80211_if_reinit(dev); ieee80211_if_set_type(dev, itype); + if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags) + return 0; + + sdata->u.mntr_flags = *flags; return 0; } diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index cb09931af86a..83694fb49734 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -67,9 +67,19 @@ static void ieee80211_configure_filter(struct ieee80211_local *local) new_flags |= FIF_ALLMULTI; if (local->monitors) - new_flags |= FIF_CONTROL | - FIF_OTHER_BSS | - FIF_BCN_PRBRESP_PROMISC; + new_flags |= FIF_BCN_PRBRESP_PROMISC; + + if (local->fif_fcsfail) + new_flags |= FIF_FCSFAIL; + + if (local->fif_plcpfail) + new_flags |= FIF_PLCPFAIL; + + if (local->fif_control) + new_flags |= FIF_CONTROL; + + if (local->fif_other_bss) + new_flags |= FIF_OTHER_BSS; changed_flags = local->filter_flags ^ new_flags; @@ -231,13 +241,21 @@ static int ieee80211_open(struct net_device *dev) case IEEE80211_IF_TYPE_MNTR: /* must be before the call to ieee80211_configure_filter */ local->monitors++; - if (local->monitors == 1) { - netif_tx_lock_bh(local->mdev); - ieee80211_configure_filter(local); - netif_tx_unlock_bh(local->mdev); - + if (local->monitors == 1) local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - } + + if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) + local->fif_fcsfail++; + if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) + local->fif_plcpfail++; + if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) + local->fif_control++; + if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) + local->fif_other_bss++; + + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: @@ -353,13 +371,21 @@ static int ieee80211_stop(struct net_device *dev) break; case IEEE80211_IF_TYPE_MNTR: local->monitors--; - if (local->monitors == 0) { - netif_tx_lock_bh(local->mdev); - ieee80211_configure_filter(local); - netif_tx_unlock_bh(local->mdev); - + if (local->monitors == 0) local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - } + + if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) + local->fif_fcsfail--; + if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) + local->fif_plcpfail--; + if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) + local->fif_control--; + if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) + local->fif_other_bss--; + + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); break; case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 31fc64c5652c..21d54b27ccc1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -345,6 +345,7 @@ struct ieee80211_sub_if_data { struct ieee80211_if_wds wds; struct ieee80211_if_vlan vlan; struct ieee80211_if_sta sta; + u32 mntr_flags; } u; int channel_use; int channel_use_raw; @@ -425,6 +426,8 @@ struct ieee80211_local { struct net_device *mdev; /* wmaster# - "master" 802.11 device */ int open_count; int monitors; + /* number of interfaces with corresponding FIF_ flags */ + int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; u8 wstats_flags; diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 27cee580f9f1..f66f1ddc3fda 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -160,6 +160,8 @@ void ieee80211_if_set_type(struct net_device *dev, int type) case IEEE80211_IF_TYPE_MNTR: dev->type = ARPHRD_IEEE80211_RADIOTAP; dev->hard_start_xmit = ieee80211_monitor_start_xmit; + sdata->u.mntr_flags = MONITOR_FLAG_CONTROL | + MONITOR_FLAG_OTHER_BSS; break; default: printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x", -- cgit v1.2.3-59-g8ed1b From 2c9745e5684ad75d02020bcaa31ab6d4b498e1e1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 31 Jan 2008 19:48:24 +0100 Subject: mac80211: clean up some things in the RX path Uninline ieee80211_invoke_rx_handlers to save .text space, make the code more readable in some places and remove the "optimisation" that is hit only very few times and unclear to start with. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 37 ++++++++++--------------------------- 1 file changed, 10 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 860c488984d8..794917fccd9b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1448,11 +1448,10 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) return RX_QUEUED; } -static inline ieee80211_rx_result __ieee80211_invoke_rx_handlers( - struct ieee80211_local *local, - ieee80211_rx_handler *handlers, - struct ieee80211_txrx_data *rx, - struct sta_info *sta) +static void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, + ieee80211_rx_handler *handlers, + struct ieee80211_txrx_data *rx, + struct sta_info *sta) { ieee80211_rx_handler *handler; ieee80211_rx_result res = RX_DROP_MONITOR; @@ -1476,19 +1475,13 @@ static inline ieee80211_rx_result __ieee80211_invoke_rx_handlers( break; } - if (res == RX_DROP_UNUSABLE || res == RX_DROP_MONITOR) - dev_kfree_skb(rx->skb); - return res; -} - -static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, - ieee80211_rx_handler *handlers, - struct ieee80211_txrx_data *rx, - struct sta_info *sta) -{ - if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) == - RX_CONTINUE) + switch (res) { + case RX_DROP_MONITOR: + case RX_DROP_UNUSABLE: + case RX_CONTINUE: dev_kfree_skb(rx->skb); + break; + } } static void ieee80211_rx_michael_mic_report(struct net_device *dev, @@ -1718,16 +1711,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, skb = rx.skb; - if (sta && !(sta->flags & (WLAN_STA_WDS | WLAN_STA_ASSOC_AP)) && - !atomic_read(&local->iff_promiscs) && - !is_multicast_ether_addr(hdr->addr1)) { - rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, - rx.sta); - sta_info_put(sta); - return; - } - list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (!netif_running(sdata->dev)) continue; -- cgit v1.2.3-59-g8ed1b From 589052904a60f00dd2cbc1d3488ee3f520a7de21 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 31 Jan 2008 19:48:25 +0100 Subject: mac80211: remove "dynamic" RX/TX handlers It doesn't really make sense to have extra pointers to the RX/TX handler arrays instead of just using the arrays directly, that also allows us to make them static. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 2 -- net/mac80211/ieee80211_i.h | 13 -------- net/mac80211/rx.c | 80 ++++++++++++++++++++++------------------------ net/mac80211/tx.c | 9 +++--- 4 files changed, 43 insertions(+), 61 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 83694fb49734..78fd91895c80 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -1429,8 +1429,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.queues = 1; /* default */ local->mdev = mdev; - local->rx_handlers = ieee80211_rx_handlers; - local->tx_handlers = ieee80211_tx_handlers; local->bridge_packets = 1; diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 21d54b27ccc1..1129a4299de7 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -190,12 +190,6 @@ struct ieee80211_tx_stored_packet { unsigned int last_frag_rate_ctrl_probe; }; -typedef ieee80211_tx_result (*ieee80211_tx_handler) -(struct ieee80211_txrx_data *tx); - -typedef ieee80211_rx_result (*ieee80211_rx_handler) -(struct ieee80211_txrx_data *rx); - struct beacon_data { u8 *head, *tail; int head_len, tail_len; @@ -477,9 +471,6 @@ struct ieee80211_local { * deliver multicast frames both back to wireless * media and to the local net stack */ - ieee80211_rx_handler *rx_handlers; - ieee80211_tx_handler *tx_handlers; - struct list_head interfaces; bool sta_sw_scanning; @@ -779,11 +770,7 @@ int ieee80211_if_remove(struct net_device *dev, const char *name, int id); void ieee80211_if_free(struct net_device *dev); void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata); -/* rx handling */ -extern ieee80211_rx_handler ieee80211_rx_handlers[]; - /* tx handling */ -extern ieee80211_tx_handler ieee80211_tx_handlers[]; void ieee80211_clear_tx_pending(struct ieee80211_local *local); void ieee80211_tx_pending(unsigned long data); int ieee80211_master_start_xmit(struct sk_buff *skb, struct net_device *dev); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 794917fccd9b..0ab9fef8ea8b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1448,42 +1448,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) return RX_QUEUED; } -static void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, - ieee80211_rx_handler *handlers, - struct ieee80211_txrx_data *rx, - struct sta_info *sta) -{ - ieee80211_rx_handler *handler; - ieee80211_rx_result res = RX_DROP_MONITOR; - - for (handler = handlers; *handler != NULL; handler++) { - res = (*handler)(rx); - - switch (res) { - case RX_CONTINUE: - continue; - case RX_DROP_UNUSABLE: - case RX_DROP_MONITOR: - I802_DEBUG_INC(local->rx_handlers_drop); - if (sta) - sta->rx_dropped++; - break; - case RX_QUEUED: - I802_DEBUG_INC(local->rx_handlers_queued); - break; - } - break; - } - - switch (res) { - case RX_DROP_MONITOR: - case RX_DROP_UNUSABLE: - case RX_CONTINUE: - dev_kfree_skb(rx->skb); - break; - } -} - static void ieee80211_rx_michael_mic_report(struct net_device *dev, struct ieee80211_hdr *hdr, struct sta_info *sta, @@ -1557,7 +1521,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, rx->skb = NULL; } -ieee80211_rx_handler ieee80211_rx_handlers[] = +typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *); +static ieee80211_rx_handler ieee80211_rx_handlers[] = { ieee80211_rx_h_if_stats, ieee80211_rx_h_passive_scan, @@ -1579,6 +1544,41 @@ ieee80211_rx_handler ieee80211_rx_handlers[] = NULL }; +static void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, + struct ieee80211_txrx_data *rx, + struct sta_info *sta) +{ + ieee80211_rx_handler *handler; + ieee80211_rx_result res = RX_DROP_MONITOR; + + for (handler = ieee80211_rx_handlers; *handler != NULL; handler++) { + res = (*handler)(rx); + + switch (res) { + case RX_CONTINUE: + continue; + case RX_DROP_UNUSABLE: + case RX_DROP_MONITOR: + I802_DEBUG_INC(local->rx_handlers_drop); + if (sta) + sta->rx_dropped++; + break; + case RX_QUEUED: + I802_DEBUG_INC(local->rx_handlers_queued); + break; + } + break; + } + + switch (res) { + case RX_DROP_MONITOR: + case RX_DROP_UNUSABLE: + case RX_CONTINUE: + dev_kfree_skb(rx->skb); + break; + } +} + /* main receive path */ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, @@ -1756,8 +1756,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, rx.skb = skb_new; rx.dev = prev->dev; rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, - &rx, sta); + ieee80211_invoke_rx_handlers(local, &rx, sta); prev = sdata; } if (prev) { @@ -1765,8 +1764,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, rx.skb = skb; rx.dev = prev->dev; rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, local->rx_handlers, - &rx, sta); + ieee80211_invoke_rx_handlers(local, &rx, sta); } else dev_kfree_skb(skb); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 0cba4a214876..181d97015f61 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -813,10 +813,9 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) return TX_CONTINUE; } -/* TODO: implement register/unregister functions for adding TX/RX handlers - * into ordered list */ -ieee80211_tx_handler ieee80211_tx_handlers[] = +typedef ieee80211_tx_result (*ieee80211_tx_handler)(struct ieee80211_txrx_data *); +static ieee80211_tx_handler ieee80211_tx_handlers[] = { ieee80211_tx_h_check_assoc, ieee80211_tx_h_sequence, @@ -1158,7 +1157,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, sta = tx.sta; tx.u.tx.channel = local->hw.conf.channel; - for (handler = local->tx_handlers; *handler != NULL; + for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); if (res != TX_CONTINUE) @@ -1914,7 +1913,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED; tx.u.tx.channel = local->hw.conf.channel; - for (handler = local->tx_handlers; *handler != NULL; handler++) { + for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); if (res == TX_DROP || res == TX_QUEUED) break; -- cgit v1.2.3-59-g8ed1b From 8944b79fe9b1fe249c599e7e51f1bfad539aab6d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 31 Jan 2008 19:48:26 +0100 Subject: mac80211: move some code into ieee80211_invoke_rx_handlers There is some duplicated code that sits in front of each function call to ieee80211_invoke_rx_handlers() that can very well be part of that function if it gets slightly different arguments. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 42 ++++++++++++++++++------------------------ 1 file changed, 18 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0ab9fef8ea8b..3a3112f17832 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1450,7 +1450,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) static void ieee80211_rx_michael_mic_report(struct net_device *dev, struct ieee80211_hdr *hdr, - struct sta_info *sta, struct ieee80211_txrx_data *rx) { int keyidx, hdrlen; @@ -1469,7 +1468,7 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, dev->name, print_mac(mac, hdr->addr2), print_mac(mac2, hdr->addr1), keyidx); - if (!sta) { + if (!rx->sta) { /* * Some hardware seem to generate incorrect Michael MIC * reports; ignore them to avoid triggering countermeasures. @@ -1544,13 +1543,17 @@ static ieee80211_rx_handler ieee80211_rx_handlers[] = NULL }; -static void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, +static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, struct ieee80211_txrx_data *rx, - struct sta_info *sta) + struct sk_buff *skb) { ieee80211_rx_handler *handler; ieee80211_rx_result res = RX_DROP_MONITOR; + rx->skb = skb; + rx->sdata = sdata; + rx->dev = sdata->dev; + for (handler = ieee80211_rx_handlers; *handler != NULL; handler++) { res = (*handler)(rx); @@ -1559,12 +1562,12 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_local *local, continue; case RX_DROP_UNUSABLE: case RX_DROP_MONITOR: - I802_DEBUG_INC(local->rx_handlers_drop); - if (sta) - sta->rx_dropped++; + I802_DEBUG_INC(sdata->local->rx_handlers_drop); + if (rx->sta) + rx->sta->rx_dropped++; break; case RX_QUEUED: - I802_DEBUG_INC(local->rx_handlers_queued); + I802_DEBUG_INC(sdata->local->rx_handlers_queued); break; } break; @@ -1669,7 +1672,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; - struct sta_info *sta; struct ieee80211_hdr *hdr; struct ieee80211_txrx_data rx; u16 type; @@ -1692,14 +1694,14 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) local->dot11ReceivedFragmentCount++; - sta = rx.sta = sta_info_get(local, hdr->addr2); - if (sta) { + rx.sta = sta_info_get(local, hdr->addr2); + if (rx.sta) { rx.dev = rx.sta->dev; rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); } if ((status->flag & RX_FLAG_MMIC_ERROR)) { - ieee80211_rx_michael_mic_report(local->mdev, hdr, sta, &rx); + ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx); goto end; } @@ -1721,8 +1723,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; prepares = prepare_for_handlers(sdata, bssid, &rx, hdr); - /* prepare_for_handlers can change sta */ - sta = rx.sta; if (!prepares) continue; @@ -1753,24 +1753,18 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, continue; } rx.fc = le16_to_cpu(hdr->frame_control); - rx.skb = skb_new; - rx.dev = prev->dev; - rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, &rx, sta); + ieee80211_invoke_rx_handlers(prev, &rx, skb_new); prev = sdata; } if (prev) { rx.fc = le16_to_cpu(hdr->frame_control); - rx.skb = skb; - rx.dev = prev->dev; - rx.sdata = prev; - ieee80211_invoke_rx_handlers(local, &rx, sta); + ieee80211_invoke_rx_handlers(prev, &rx, skb); } else dev_kfree_skb(skb); end: - if (sta) - sta_info_put(sta); + if (rx.sta) + sta_info_put(rx.sta); } #define SEQ_MODULO 0x1000 -- cgit v1.2.3-59-g8ed1b From 3d30d949cf3f9763393f3457721bca3ac2426e42 Mon Sep 17 00:00:00 2001 From: Michael Wu Date: Thu, 31 Jan 2008 19:48:27 +0100 Subject: mac80211: Add cooked monitor mode support This adds "cooked" monitor mode to mac80211. A monitor interface in "cooked" mode will see all frames that mac80211 has not used internally. Signed-off-by: Michael Wu Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 67 +++++++++++++++++++---------------- net/mac80211/ieee80211_i.h | 3 +- net/mac80211/rx.c | 87 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 126 insertions(+), 31 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 78fd91895c80..91f06c3f4a7c 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -239,6 +239,11 @@ static int ieee80211_open(struct net_device *dev) /* no need to tell driver */ break; case IEEE80211_IF_TYPE_MNTR: + if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { + local->cooked_mntrs++; + break; + } + /* must be before the call to ieee80211_configure_filter */ local->monitors++; if (local->monitors == 1) @@ -370,6 +375,11 @@ static int ieee80211_stop(struct net_device *dev) /* no need to tell driver */ break; case IEEE80211_IF_TYPE_MNTR: + if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { + local->cooked_mntrs--; + break; + } + local->monitors--; if (local->monitors == 0) local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; @@ -1177,7 +1187,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, u16 frag, type; struct ieee80211_tx_status_rtap_hdr *rthdr; struct ieee80211_sub_if_data *sdata; - int monitors; + struct net_device *prev_dev = NULL; if (!status) { printk(KERN_ERR @@ -1290,7 +1300,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, /* this was a transmitted frame, but now we want to reuse it */ skb_orphan(skb); - if (!local->monitors) { + /* + * This is a bit racy but we can avoid a lot of work + * with this test... + */ + if (!local->monitors && !local->cooked_mntrs) { dev_kfree_skb(skb); return; } @@ -1324,42 +1338,37 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, rthdr->data_retries = status->retry_count; + /* XXX: is this sufficient for BPF? */ + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + rcu_read_lock(); - monitors = local->monitors; list_for_each_entry_rcu(sdata, &local->interfaces, list) { - /* - * Using the monitors counter is possibly racy, but - * if the value is wrong we simply either clone the skb - * once too much or forget sending it to one monitor iface - * The latter case isn't nice but fixing the race is much - * more complicated. - */ - if (!monitors || !skb) - goto out; - if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) { if (!netif_running(sdata->dev)) continue; - monitors--; - if (monitors) + + if (prev_dev) { skb2 = skb_clone(skb, GFP_ATOMIC); - else - skb2 = NULL; - skb->dev = sdata->dev; - /* XXX: is this sufficient for BPF? */ - skb_set_mac_header(skb, 0); - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - netif_rx(skb); - skb = skb2; + if (skb2) { + skb2->dev = prev_dev; + netif_rx(skb2); + } + } + + prev_dev = sdata->dev; } } - out: + if (prev_dev) { + skb->dev = prev_dev; + netif_rx(skb); + skb = NULL; + } rcu_read_unlock(); - if (skb) - dev_kfree_skb(skb); + dev_kfree_skb(skb); } EXPORT_SYMBOL(ieee80211_tx_status); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1129a4299de7..1b4a4497030d 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -131,6 +131,7 @@ typedef unsigned __bitwise__ ieee80211_rx_result; #define IEEE80211_TXRXD_RXRA_MATCH BIT(5) #define IEEE80211_TXRXD_TX_INJECTED BIT(6) #define IEEE80211_TXRXD_RX_AMSDU BIT(7) +#define IEEE80211_TXRXD_RX_CMNTR_REPORTED BIT(8) struct ieee80211_txrx_data { struct sk_buff *skb; struct net_device *dev; @@ -419,7 +420,7 @@ struct ieee80211_local { struct net_device *mdev; /* wmaster# - "master" 802.11 device */ int open_count; - int monitors; + int monitors, cooked_mntrs; /* number of interfaces with corresponding FIF_ flags */ int fif_fcsfail, fif_plcpfail, fif_control, fif_other_bss; unsigned int filter_flags; /* FIF_* */ diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3a3112f17832..b1fc112152c9 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -223,6 +223,9 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR) continue; + if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) + continue; + if (prev_dev) { skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2) { @@ -1520,6 +1523,86 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, rx->skb = NULL; } +static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_local *local = rx->local; + struct ieee80211_rtap_hdr { + struct ieee80211_radiotap_header hdr; + u8 flags; + u8 rate; + __le16 chan_freq; + __le16 chan_flags; + } __attribute__ ((packed)) *rthdr; + struct sk_buff *skb = rx->skb, *skb2; + struct net_device *prev_dev = NULL; + struct ieee80211_rx_status *status = rx->u.rx.status; + + if (rx->flags & IEEE80211_TXRXD_RX_CMNTR_REPORTED) + goto out_free_skb; + + if (skb_headroom(skb) < sizeof(*rthdr) && + pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC)) + goto out_free_skb; + + rthdr = (void *)skb_push(skb, sizeof(*rthdr)); + memset(rthdr, 0, sizeof(*rthdr)); + rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); + rthdr->hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | + (1 << IEEE80211_RADIOTAP_RATE) | + (1 << IEEE80211_RADIOTAP_CHANNEL)); + + rthdr->rate = rx->u.rx.rate->bitrate / 5; + rthdr->chan_freq = cpu_to_le16(status->freq); + + if (status->band == IEEE80211_BAND_5GHZ) + rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_OFDM | + IEEE80211_CHAN_5GHZ); + else + rthdr->chan_flags = cpu_to_le16(IEEE80211_CHAN_DYN | + IEEE80211_CHAN_2GHZ); + + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (!netif_running(sdata->dev)) + continue; + + if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || + !(sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES)) + continue; + + if (prev_dev) { + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) { + skb2->dev = prev_dev; + netif_rx(skb2); + } + } + + prev_dev = sdata->dev; + sdata->dev->stats.rx_packets++; + sdata->dev->stats.rx_bytes += skb->len; + } + + if (prev_dev) { + skb->dev = prev_dev; + netif_rx(skb); + skb = NULL; + } else + goto out_free_skb; + + rx->flags |= IEEE80211_TXRXD_RX_CMNTR_REPORTED; + return; + + out_free_skb: + dev_kfree_skb(skb); +} + typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *); static ieee80211_rx_handler ieee80211_rx_handlers[] = { @@ -1574,9 +1657,11 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, } switch (res) { + case RX_CONTINUE: case RX_DROP_MONITOR: + ieee80211_rx_cooked_monitor(rx); + break; case RX_DROP_UNUSABLE: - case RX_CONTINUE: dev_kfree_skb(rx->skb); break; } -- cgit v1.2.3-59-g8ed1b From a9af2013ca791b40e38a33f94724b87826f17460 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Wed, 30 Jan 2008 12:58:45 +0200 Subject: mac80211: adjustable number of bits for qdisc pool This fix allows to control the number of bits that qdiscs book keeping can be done for with respect to the qdisc pool Signed-off-by: Ron Rindjunsky Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/wme.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 425aa8588ea0..8cc036decc82 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -25,7 +25,7 @@ const int ieee802_1d_to_ac[8] = { 2, 3, 3, 2, 1, 1, 0, 0 }; struct ieee80211_sched_data { - unsigned long qdisc_pool; + unsigned long qdisc_pool[BITS_TO_LONGS(TC_80211_MAX_QUEUES)]; struct tcf_proto *filter_list; struct Qdisc *queues[TC_80211_MAX_QUEUES]; struct sk_buff_head requeued[TC_80211_MAX_QUEUES]; @@ -158,7 +158,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) if (sta) { int ampdu_queue = sta->tid_to_tx_q[tid]; if ((ampdu_queue < local->hw.queues) && - test_bit(ampdu_queue, &q->qdisc_pool)) { + test_bit(ampdu_queue, q->qdisc_pool)) { queue = ampdu_queue; pkt_data->flags |= IEEE80211_TXPD_AMPDU; } else { @@ -191,7 +191,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) if (sta) { int ampdu_queue = sta->tid_to_tx_q[tid]; if ((ampdu_queue < local->hw.queues) && - test_bit(ampdu_queue, &q->qdisc_pool)) { + test_bit(ampdu_queue, q->qdisc_pool)) { queue = ampdu_queue; pkt_data->flags |= IEEE80211_TXPD_AMPDU; } else { @@ -272,7 +272,7 @@ static struct sk_buff *wme_qdiscop_dequeue(struct Qdisc* qd) &local->state[queue])) || (test_bit(IEEE80211_LINK_STATE_PENDING, &local->state[queue])) || - (!test_bit(queue, &q->qdisc_pool))) + (!test_bit(queue, q->qdisc_pool))) continue; /* there is space - try and get a frame */ @@ -396,7 +396,7 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) /* reserve all legacy QoS queues */ for (i = 0; i < min(IEEE80211_TX_QUEUE_DATA4, queues); i++) - set_bit(i, &q->qdisc_pool); + set_bit(i, q->qdisc_pool); return err; } @@ -657,7 +657,7 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, /* try to get a Qdisc from the pool */ for (i = IEEE80211_TX_QUEUE_BEACON; i < local->hw.queues; i++) - if (!test_and_set_bit(i, &q->qdisc_pool)) { + if (!test_and_set_bit(i, q->qdisc_pool)) { ieee80211_stop_queue(local_to_hw(local), i); sta->tid_to_tx_q[tid] = i; @@ -668,9 +668,9 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "allocated aggregation queue" - " %d tid %d addr %s pool=0x%lX\n", + " %d tid %d addr %s pool=0x%lX", i, tid, print_mac(mac, sta->addr), - q->qdisc_pool); + q->qdisc_pool[0]); #endif /* CONFIG_MAC80211_HT_DEBUG */ return 0; } @@ -690,7 +690,7 @@ void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local, int agg_queue = sta->tid_to_tx_q[tid]; /* return the qdisc to the pool */ - clear_bit(agg_queue, &q->qdisc_pool); + clear_bit(agg_queue, q->qdisc_pool); sta->tid_to_tx_q[tid] = local->hw.queues; if (requeue) -- cgit v1.2.3-59-g8ed1b From 96d510566e4908f77f03ff1436c78ae7162a17d0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 8 Feb 2008 09:48:13 +0100 Subject: mac80211: defer master netdev allocation to ieee80211_register_hw When we want to go multiqueue, we will need to know the number of queues the hardware has for registering the master netdev. This number is only available in ieee80211_register_hw() rather than ieee80211_alloc_hw(), so defer allocation of the master device to ieee80211_register_hw(). Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 72 +++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 34 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 91f06c3f4a7c..7df14799e38b 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -1375,9 +1375,7 @@ EXPORT_SYMBOL(ieee80211_tx_status); struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops) { - struct net_device *mdev; struct ieee80211_local *local; - struct ieee80211_sub_if_data *sdata; int priv_size; struct wiphy *wiphy; @@ -1423,22 +1421,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, BUG_ON(!ops->configure_filter); local->ops = ops; - /* for now, mdev needs sub_if_data :/ */ - mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), - "wmaster%d", ether_setup); - if (!mdev) { - wiphy_free(wiphy); - return NULL; - } - - sdata = IEEE80211_DEV_TO_SUB_IF(mdev); - mdev->ieee80211_ptr = &sdata->wdev; - sdata->wdev.wiphy = wiphy; - local->hw.queues = 1; /* default */ - local->mdev = mdev; - local->bridge_packets = 1; local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; @@ -1450,26 +1434,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_LIST_HEAD(&local->interfaces); INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); - ieee80211_rx_bss_list_init(mdev); sta_info_init(local); - mdev->hard_start_xmit = ieee80211_master_start_xmit; - mdev->open = ieee80211_master_open; - mdev->stop = ieee80211_master_stop; - mdev->type = ARPHRD_IEEE80211; - mdev->header_ops = &ieee80211_header_ops; - mdev->set_multicast_list = ieee80211_master_set_multicast_list; - - sdata->vif.type = IEEE80211_IF_TYPE_AP; - sdata->dev = mdev; - sdata->local = local; - sdata->u.ap.force_unicast_rateidx = -1; - sdata->u.ap.max_ratectrl_rateidx = -1; - ieee80211_if_sdata_init(sdata); - /* no RCU needed since we're still during init phase */ - list_add_tail(&sdata->list, &local->interfaces); - tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, (unsigned long)local); tasklet_disable(&local->tx_pending_tasklet); @@ -1492,6 +1459,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) const char *name; int result; enum ieee80211_band band; + struct net_device *mdev; + struct ieee80211_sub_if_data *sdata; /* * generic code guarantees at least one band, @@ -1515,6 +1484,37 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (result < 0) return result; + /* for now, mdev needs sub_if_data :/ */ + mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), + "wmaster%d", ether_setup); + if (!mdev) + goto fail_mdev_alloc; + + sdata = IEEE80211_DEV_TO_SUB_IF(mdev); + mdev->ieee80211_ptr = &sdata->wdev; + sdata->wdev.wiphy = local->hw.wiphy; + + local->mdev = mdev; + + ieee80211_rx_bss_list_init(mdev); + + mdev->hard_start_xmit = ieee80211_master_start_xmit; + mdev->open = ieee80211_master_open; + mdev->stop = ieee80211_master_stop; + mdev->type = ARPHRD_IEEE80211; + mdev->header_ops = &ieee80211_header_ops; + mdev->set_multicast_list = ieee80211_master_set_multicast_list; + + sdata->vif.type = IEEE80211_IF_TYPE_AP; + sdata->dev = mdev; + sdata->local = local; + sdata->u.ap.force_unicast_rateidx = -1; + sdata->u.ap.max_ratectrl_rateidx = -1; + ieee80211_if_sdata_init(sdata); + + /* no RCU needed since we're still during init phase */ + list_add_tail(&sdata->list, &local->interfaces); + name = wiphy_dev(local->hw.wiphy)->driver->name; local->hw.workqueue = create_singlethread_workqueue(name); if (!local->hw.workqueue) { @@ -1606,6 +1606,9 @@ fail_sta_info: debugfs_hw_del(local); destroy_workqueue(local->hw.workqueue); fail_workqueue: + ieee80211_if_free(local->mdev); + local->mdev = NULL; +fail_mdev_alloc: wiphy_unregister(local->hw.wiphy); return result; } @@ -1666,6 +1669,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) wiphy_unregister(local->hw.wiphy); ieee80211_wep_free(local); ieee80211_led_exit(local); + ieee80211_if_free(local->mdev); + local->mdev = NULL; } EXPORT_SYMBOL(ieee80211_unregister_hw); @@ -1673,7 +1678,6 @@ void ieee80211_free_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); - ieee80211_if_free(local->mdev); wiphy_free(local->hw.wiphy); } EXPORT_SYMBOL(ieee80211_free_hw); -- cgit v1.2.3-59-g8ed1b From 3330d7be7008fa8e213648750fc13613eecc54bb Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 10 Feb 2008 16:49:38 +0100 Subject: mac80211: give burst time in txop rather than 0.1msec units This changes mac80211 to pass the burst time to conf_tx in txop units rather than 0.1msec units. 0.1msec units are only required by atheros hardware (according to current driver support), all other drivers do other calculations or require the txop value. Therefore, it results in fewer calculations and more precision if we just pass the txop value through to the driver. Signed-off-by: Johannes Berg Acked-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 2 +- drivers/net/wireless/iwlwifi/iwl4965-base.c | 2 +- drivers/net/wireless/p54common.c | 21 +++++++++++++-------- include/net/mac80211.h | 12 ++++++------ net/mac80211/ieee80211_sta.c | 11 ++++++----- 5 files changed, 27 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4ad26f7613c5..bb3a5f633227 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -7442,7 +7442,7 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, int queue, priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; priv->qos_data.def_qos_parm.ac[q].edca_txop = - cpu_to_le16((params->burst_time * 100)); + cpu_to_le16((params->txop * 32)); priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; priv->qos_data.qos_active = 1; diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index f8931993ab70..fb4c84e31932 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -7916,7 +7916,7 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, int queue, priv->qos_data.def_qos_parm.ac[q].cw_max = cpu_to_le16(params->cw_max); priv->qos_data.def_qos_parm.ac[q].aifsn = params->aifs; priv->qos_data.def_qos_parm.ac[q].edca_txop = - cpu_to_le16((params->burst_time * 100)); + cpu_to_le16((params->txop * 32)); priv->qos_data.def_qos_parm.ac[q].reserved1 = 0; priv->qos_data.qos_active = 1; diff --git a/drivers/net/wireless/p54common.c b/drivers/net/wireless/p54common.c index 218ff7770ef6..0e9f887178ce 100644 --- a/drivers/net/wireless/p54common.c +++ b/drivers/net/wireless/p54common.c @@ -759,13 +759,12 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) return 0; } -#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, burst) \ +#define P54_SET_QUEUE(queue, ai_fs, cw_min, cw_max, _txop) \ do { \ queue.aifs = cpu_to_le16(ai_fs); \ queue.cwmin = cpu_to_le16(cw_min); \ queue.cwmax = cpu_to_le16(cw_max); \ - queue.txop = (burst == 0) ? \ - 0 : cpu_to_le16((burst * 100) / 32 + 1); \ + queue.txop = cpu_to_le16(_txop); \ } while(0) static void p54_init_vdcf(struct ieee80211_hw *dev) @@ -783,10 +782,16 @@ static void p54_init_vdcf(struct ieee80211_hw *dev) vdcf = (struct p54_tx_control_vdcf *) hdr->data; - P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 0x000f); - P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 0x001e); - P54_SET_QUEUE(vdcf->queue[2], 0x0002, 0x000f, 0x03ff, 0x0014); - P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0x0000); + /* + * FIXME: The default values in the spec (IEEE 802.11 + * 7.3.2.19 Table 37) are 47, 94, 0, 0, why use + * 47, 94, 63, 0 here? Also, the default AIFS + * values (second parameter) are 2, 2, 3, 7... + */ + P54_SET_QUEUE(vdcf->queue[0], 0x0002, 0x0003, 0x0007, 47); + P54_SET_QUEUE(vdcf->queue[1], 0x0002, 0x0007, 0x000f, 94); + P54_SET_QUEUE(vdcf->queue[2], 0x0002, 0x000f, 0x03ff, 63); + P54_SET_QUEUE(vdcf->queue[3], 0x0007, 0x000f, 0x03ff, 0); } static void p54_set_vdcf(struct ieee80211_hw *dev) @@ -939,7 +944,7 @@ static int p54_conf_tx(struct ieee80211_hw *dev, int queue, if ((params) && !((queue < 0) || (queue > 4))) { P54_SET_QUEUE(vdcf->queue[queue], params->aifs, - params->cw_min, params->cw_max, params->burst_time); + params->cw_min, params->cw_max, params->txop); } else return -EINVAL; diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 460da54a0019..5ecf3cc8d977 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -89,19 +89,19 @@ struct ieee80211_ht_bss_info { * struct ieee80211_tx_queue_params - transmit queue configuration * * The information provided in this structure is required for QoS - * transmit queue configuration. + * transmit queue configuration. Cf. IEEE 802.11 7.3.2.29. * * @aifs: arbitration interface space [0..255, -1: use default] * @cw_min: minimum contention window [will be a value of the form * 2^n-1 in the range 1..1023; 0: use default] * @cw_max: maximum contention window [like @cw_min] - * @burst_time: maximum burst time in units of 0.1ms, 0 meaning disabled + * @txop: maximum burst time in units of 32 usecs, 0 meaning disabled */ struct ieee80211_tx_queue_params { - int aifs; - int cw_min; - int cw_max; - int burst_time; + s16 aifs; + u16 cw_min; + u16 cw_max; + u16 txop; }; /** diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index a8251a23917b..11f2ee6b2269 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -297,12 +297,13 @@ static void ieee80211_sta_wmm_params(struct net_device *dev, params.aifs = pos[0] & 0x0f; params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); params.cw_min = ecw2cw(pos[1] & 0x0f); - /* TXOP is in units of 32 usec; burst_time in 0.1 ms */ - params.burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100; + params.txop = pos[2] | (pos[3] << 8); +#ifdef CONFIG_MAC80211_DEBUG printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " - "cWmin=%d cWmax=%d burst=%d\n", + "cWmin=%d cWmax=%d txop=%d\n", dev->name, queue, aci, acm, params.aifs, params.cw_min, - params.cw_max, params.burst_time); + params.cw_max, params.txop); +#endif /* TODO: handle ACM (block TX, fallback to next lowest allowed * AC for now) */ if (local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) { @@ -3230,7 +3231,7 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) qparam.cw_min = 15; qparam.cw_max = 1023; - qparam.burst_time = 0; + qparam.txop = 0; for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) local->ops->conf_tx(local_to_hw(local), -- cgit v1.2.3-59-g8ed1b From ac2bf3242e1a329543be50b5c9df4f0119ee188c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 14 Feb 2008 00:30:35 +0100 Subject: mac80211: fix ecw2cw brain-damage This brain-damaged code just bothers me, fix it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 11f2ee6b2269..a465e38c7252 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -227,12 +227,7 @@ static void ieee802_11_parse_elems(u8 *start, size_t len, static int ecw2cw(int ecw) { - int cw = 1; - while (ecw > 0) { - cw <<= 1; - ecw--; - } - return cw - 1; + return (1 << ecw) - 1; } static void ieee80211_sta_wmm_params(struct net_device *dev, -- cgit v1.2.3-59-g8ed1b From ab46623ec1f4ea022b861333ce959f0b8f9eb70e Mon Sep 17 00:00:00 2001 From: "S.Çağlar Onur" Date: Thu, 14 Feb 2008 17:36:47 +0200 Subject: net/mac80211/: Use time_* macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The functions time_before, time_before_eq, time_after, and time_after_eq are more robust for comparing jiffies against other values. So following patch implements usage of the time_after() macro, defined at linux/jiffies.h, which deals with wrapping correctly Cc: linux-wireless@vger.kernel.org Signed-off-by: S.Çağlar Onur Signed-off-by: John W. Linville --- net/mac80211/rc80211_simple.c | 3 ++- net/mac80211/rx.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index c4678905a142..a669bcb8739f 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c @@ -7,6 +7,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -175,7 +176,7 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, rate_control_rate_dec(local, sta); } - if (srctrl->avg_rate_update + 60 * HZ < jiffies) { + if (time_after(jiffies, srctrl->avg_rate_update + 60 * HZ)) { srctrl->avg_rate_update = jiffies; if (srctrl->tx_avg_rate_num > 0) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b1fc112152c9..472b19fc9143 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -767,7 +768,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, compare_ether_addr(hdr->addr2, f_hdr->addr2) != 0) continue; - if (entry->first_frag_time + 2 * HZ < jiffies) { + if (time_after(jiffies, entry->first_frag_time + 2 * HZ)) { __skb_queue_purge(&entry->skb_list); continue; } -- cgit v1.2.3-59-g8ed1b From a607268a0d5532d6ae3777ddd0339ff7d8b037a0 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Mon, 18 Feb 2008 11:21:15 +0900 Subject: mac80211: move function ieee80211_sta_join_ibss() this moves ieee80211_sta_join_ibss() up for the next patch (ibss merge). Signed-off-by: Bruno Randolf Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 317 ++++++++++++++++++++++--------------------- 1 file changed, 159 insertions(+), 158 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index a465e38c7252..a84ead49b1e6 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2027,6 +2027,165 @@ void ieee80211_rx_bss_list_deinit(struct net_device *dev) } +static int ieee80211_sta_join_ibss(struct net_device *dev, + struct ieee80211_if_sta *ifsta, + struct ieee80211_sta_bss *bss) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + int res, rates, i, j; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + struct ieee80211_tx_control control; + struct rate_selection ratesel; + u8 *pos; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + /* Remove possible STA entries from other IBSS networks. */ + sta_info_flush(local, NULL); + + if (local->ops->reset_tsf) { + /* Reset own TSF to allow time synchronization work. */ + local->ops->reset_tsf(local_to_hw(local)); + } + memcpy(ifsta->bssid, bss->bssid, ETH_ALEN); + res = ieee80211_if_config(dev); + if (res) + return res; + + local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sdata->drop_unencrypted = bss->capability & + WLAN_CAPABILITY_PRIVACY ? 1 : 0; + + res = ieee80211_set_freq(local, bss->freq); + + if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) { + printk(KERN_DEBUG "%s: IBSS not allowed on frequency " + "%d MHz\n", dev->name, local->oper_channel->center_freq); + return -1; + } + + /* Set beacon template */ + skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); + do { + if (!skb) + break; + + skb_reserve(skb, local->hw.extra_tx_headroom); + + mgmt = (struct ieee80211_mgmt *) + skb_put(skb, 24 + sizeof(mgmt->u.beacon)); + memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_BEACON); + memset(mgmt->da, 0xff, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + mgmt->u.beacon.beacon_int = + cpu_to_le16(local->hw.conf.beacon_int); + mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability); + + pos = skb_put(skb, 2 + ifsta->ssid_len); + *pos++ = WLAN_EID_SSID; + *pos++ = ifsta->ssid_len; + memcpy(pos, ifsta->ssid, ifsta->ssid_len); + + rates = bss->supp_rates_len; + if (rates > 8) + rates = 8; + pos = skb_put(skb, 2 + rates); + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = rates; + memcpy(pos, bss->supp_rates, rates); + + if (bss->band == IEEE80211_BAND_2GHZ) { + pos = skb_put(skb, 2 + 1); + *pos++ = WLAN_EID_DS_PARAMS; + *pos++ = 1; + *pos++ = ieee80211_frequency_to_channel(bss->freq); + } + + pos = skb_put(skb, 2 + 2); + *pos++ = WLAN_EID_IBSS_PARAMS; + *pos++ = 2; + /* FIX: set ATIM window based on scan results */ + *pos++ = 0; + *pos++ = 0; + + if (bss->supp_rates_len > 8) { + rates = bss->supp_rates_len - 8; + pos = skb_put(skb, 2 + rates); + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos++ = rates; + memcpy(pos, &bss->supp_rates[8], rates); + } + + memset(&control, 0, sizeof(control)); + rate_control_get_rate(dev, sband, skb, &ratesel); + if (!ratesel.rate) { + printk(KERN_DEBUG "%s: Failed to determine TX rate " + "for IBSS beacon\n", dev->name); + break; + } + control.vif = &sdata->vif; + control.tx_rate = ratesel.rate; + if (sdata->bss_conf.use_short_preamble && + ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; + control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; + control.flags |= IEEE80211_TXCTL_NO_ACK; + control.retry_limit = 1; + + ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC); + if (ifsta->probe_resp) { + mgmt = (struct ieee80211_mgmt *) + ifsta->probe_resp->data; + mgmt->frame_control = + IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_PROBE_RESP); + } else { + printk(KERN_DEBUG "%s: Could not allocate ProbeResp " + "template for IBSS\n", dev->name); + } + + if (local->ops->beacon_update && + local->ops->beacon_update(local_to_hw(local), + skb, &control) == 0) { + printk(KERN_DEBUG "%s: Configured IBSS beacon " + "template\n", dev->name); + skb = NULL; + } + + rates = 0; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + for (i = 0; i < bss->supp_rates_len; i++) { + int bitrate = (bss->supp_rates[i] & 0x7f) * 5; + for (j = 0; j < sband->n_bitrates; j++) + if (sband->bitrates[j].bitrate == bitrate) + rates |= BIT(j); + } + ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; + } while (0); + + if (skb) { + printk(KERN_DEBUG "%s: Failed to configure IBSS beacon " + "template\n", dev->name); + dev_kfree_skb(skb); + } + + ifsta->state = IEEE80211_IBSS_JOINED; + mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); + + ieee80211_rx_bss_put(dev, bss); + + return res; +} + + static void ieee80211_rx_bss_info(struct net_device *dev, struct ieee80211_mgmt *mgmt, size_t len, @@ -2891,164 +3050,6 @@ static int ieee80211_sta_config_auth(struct net_device *dev, return -1; } -static int ieee80211_sta_join_ibss(struct net_device *dev, - struct ieee80211_if_sta *ifsta, - struct ieee80211_sta_bss *bss) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int res, rates, i, j; - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - struct ieee80211_tx_control control; - struct rate_selection ratesel; - u8 *pos; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_supported_band *sband; - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - /* Remove possible STA entries from other IBSS networks. */ - sta_info_flush(local, NULL); - - if (local->ops->reset_tsf) { - /* Reset own TSF to allow time synchronization work. */ - local->ops->reset_tsf(local_to_hw(local)); - } - memcpy(ifsta->bssid, bss->bssid, ETH_ALEN); - res = ieee80211_if_config(dev); - if (res) - return res; - - local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - sdata->drop_unencrypted = bss->capability & - WLAN_CAPABILITY_PRIVACY ? 1 : 0; - - res = ieee80211_set_freq(local, bss->freq); - - if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) { - printk(KERN_DEBUG "%s: IBSS not allowed on frequency " - "%d MHz\n", dev->name, local->oper_channel->center_freq); - return -1; - } - - /* Set beacon template based on scan results */ - skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); - do { - if (!skb) - break; - - skb_reserve(skb, local->hw.extra_tx_headroom); - - mgmt = (struct ieee80211_mgmt *) - skb_put(skb, 24 + sizeof(mgmt->u.beacon)); - memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_BEACON); - memset(mgmt->da, 0xff, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); - mgmt->u.beacon.beacon_int = - cpu_to_le16(local->hw.conf.beacon_int); - mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability); - - pos = skb_put(skb, 2 + ifsta->ssid_len); - *pos++ = WLAN_EID_SSID; - *pos++ = ifsta->ssid_len; - memcpy(pos, ifsta->ssid, ifsta->ssid_len); - - rates = bss->supp_rates_len; - if (rates > 8) - rates = 8; - pos = skb_put(skb, 2 + rates); - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = rates; - memcpy(pos, bss->supp_rates, rates); - - if (bss->band == IEEE80211_BAND_2GHZ) { - pos = skb_put(skb, 2 + 1); - *pos++ = WLAN_EID_DS_PARAMS; - *pos++ = 1; - *pos++ = ieee80211_frequency_to_channel(bss->freq); - } - - pos = skb_put(skb, 2 + 2); - *pos++ = WLAN_EID_IBSS_PARAMS; - *pos++ = 2; - /* FIX: set ATIM window based on scan results */ - *pos++ = 0; - *pos++ = 0; - - if (bss->supp_rates_len > 8) { - rates = bss->supp_rates_len - 8; - pos = skb_put(skb, 2 + rates); - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = rates; - memcpy(pos, &bss->supp_rates[8], rates); - } - - memset(&control, 0, sizeof(control)); - rate_control_get_rate(dev, sband, skb, &ratesel); - if (!ratesel.rate) { - printk(KERN_DEBUG "%s: Failed to determine TX rate " - "for IBSS beacon\n", dev->name); - break; - } - control.vif = &sdata->vif; - control.tx_rate = ratesel.rate; - if (sdata->bss_conf.use_short_preamble && - ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) - control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; - control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control.flags |= IEEE80211_TXCTL_NO_ACK; - control.retry_limit = 1; - - ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC); - if (ifsta->probe_resp) { - mgmt = (struct ieee80211_mgmt *) - ifsta->probe_resp->data; - mgmt->frame_control = - IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_PROBE_RESP); - } else { - printk(KERN_DEBUG "%s: Could not allocate ProbeResp " - "template for IBSS\n", dev->name); - } - - if (local->ops->beacon_update && - local->ops->beacon_update(local_to_hw(local), - skb, &control) == 0) { - printk(KERN_DEBUG "%s: Configured IBSS beacon " - "template based on scan results\n", dev->name); - skb = NULL; - } - - rates = 0; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - for (i = 0; i < bss->supp_rates_len; i++) { - int bitrate = (bss->supp_rates[i] & 0x7f) * 5; - for (j = 0; j < sband->n_bitrates; j++) - if (sband->bitrates[j].bitrate == bitrate) - rates |= BIT(j); - } - ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; - } while (0); - - if (skb) { - printk(KERN_DEBUG "%s: Failed to configure IBSS beacon " - "template\n", dev->name); - dev_kfree_skb(skb); - } - - ifsta->state = IEEE80211_IBSS_JOINED; - mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); - - ieee80211_rx_bss_put(dev, bss); - - return res; -} - static int ieee80211_sta_create_ibss(struct net_device *dev, struct ieee80211_if_sta *ifsta) -- cgit v1.2.3-59-g8ed1b From 9d9bf77d16ba527f6f63846ca18cf20ae6e8d697 Mon Sep 17 00:00:00 2001 From: Bruno Randolf Date: Mon, 18 Feb 2008 11:21:36 +0900 Subject: mac80211: enable IBSS merging enable IBSS cell merging. if an IBSS beacon with the same channel, same ESSID and a TSF higher than the local TSF (mactime) is received, we have to join its BSSID. while this might not be immediately apparent from reading the 802.11 standard it is compliant and necessary to make IBSS mode functional in many cases. most drivers have a similar behaviour. * move the relevant code section (previously only containing debug code) down to the end of the function, so we can reuse the bss structure. * we have to compare the mactime (TSF at the time of packet receive) rather than the current TSF. since mactime is defined as the time the first data symbol arrived we add the time until byte 24 where the timestamp resides, since this is how the beacon timestamp is defined. as some some drivers are not able to give a reliable mactime we fall back to use the current TSF, which will be enough to catch most (but not all) cases where an IBSS merge is necessary. * in IBSS mode we want to allow beacons to override probe response info so we can correctly do merges. * we don't only configure beacons based on scan results, so change that message. * to enable this we have to let all beacons thru in IBSS mode, even if they have a different BSSID. Signed-off-by: Bruno Randolf Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 3 +- net/mac80211/ieee80211_sta.c | 90 ++++++++++++++++++++++++++++++-------------- net/mac80211/rx.c | 5 ++- 3 files changed, 67 insertions(+), 31 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 1a1d0d8203aa..784ab769b00b 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -276,7 +276,8 @@ struct ieee80211_tx_control { * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on * the frame. * @RX_FLAG_TSFT: The timestamp passed in the RX status (@mactime field) - * is valid. + * is valid. This is useful in monitor mode and necessary for beacon frames + * to enable IBSS merging. */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = 1<<0, diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index a84ead49b1e6..6e5b57dccc50 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2199,7 +2199,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev, struct ieee80211_sta_bss *bss; struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - u64 timestamp; + u64 beacon_timestamp, rx_timestamp; DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac2); @@ -2216,31 +2216,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev, if (baselen > len) return; - timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); - - if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && - memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) { -#ifdef CONFIG_MAC80211_IBSS_DEBUG - static unsigned long last_tsf_debug = 0; - u64 tsf; - if (local->ops->get_tsf) - tsf = local->ops->get_tsf(local_to_hw(local)); - else - tsf = -1LLU; - if (time_after(jiffies, last_tsf_debug + 5 * HZ)) { - printk(KERN_DEBUG "RX beacon SA=%s BSSID=" - "%s TSF=0x%llx BCN=0x%llx diff=%lld " - "@%lu\n", - print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->bssid), - (unsigned long long)tsf, - (unsigned long long)timestamp, - (unsigned long long)(tsf - timestamp), - jiffies); - last_tsf_debug = jiffies; - } -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ - } - + beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && @@ -2326,8 +2302,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->band = rx_status->band; - if (bss->probe_resp && beacon) { - /* Do not allow beacon to override data from Probe Response. */ + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && + bss->probe_resp && beacon) { + /* STA mode: + * Do not allow beacon to override data from Probe Response. */ ieee80211_rx_bss_put(dev, bss); return; } @@ -2424,13 +2402,67 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->ht_ie_len = 0; } - bss->timestamp = timestamp; + bss->timestamp = beacon_timestamp; bss->last_update = jiffies; bss->rssi = rx_status->ssi; bss->signal = rx_status->signal; bss->noise = rx_status->noise; if (!beacon) bss->probe_resp++; + + /* check if we need to merge IBSS */ + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && + !local->sta_sw_scanning && !local->sta_hw_scanning && + mgmt->u.beacon.capab_info & WLAN_CAPABILITY_IBSS && + bss->freq == local->oper_channel->center_freq && + elems.ssid_len == sdata->u.sta.ssid_len && + memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) { + if (rx_status->flag & RX_FLAG_TSFT) { + /* in order for correct IBSS merging we need mactime + * + * since mactime is defined as the time the first data + * symbol of the frame hits the PHY, and the timestamp + * of the beacon is defined as "the time that the data + * symbol containing the first bit of the timestamp is + * transmitted to the PHY plus the transmitting STA’s + * delays through its local PHY from the MAC-PHY + * interface to its interface with the WM" + * (802.11 11.1.2) - equals the time this bit arrives at + * the receiver - we have to take into account the + * offset between the two. + * e.g: at 1 MBit that means mactime is 192 usec earlier + * (=24 bytes * 8 usecs/byte) than the beacon timestamp. + */ + int rate = local->hw.wiphy->bands[rx_status->band]-> + bitrates[rx_status->rate_idx].bitrate; + rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); + } else if (local && local->ops && local->ops->get_tsf) + /* second best option: get current TSF */ + rx_timestamp = local->ops->get_tsf(local_to_hw(local)); + else + /* can't merge without knowing the TSF */ + rx_timestamp = -1LLU; +#ifdef CONFIG_MAC80211_IBSS_DEBUG + printk(KERN_DEBUG "RX beacon SA=%s BSSID=" + "%s TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", + print_mac(mac, mgmt->sa), + print_mac(mac2, mgmt->bssid), + (unsigned long long)rx_timestamp, + (unsigned long long)beacon_timestamp, + (unsigned long long)(rx_timestamp - beacon_timestamp), + jiffies); +#endif /* CONFIG_MAC80211_IBSS_DEBUG */ + if (beacon_timestamp > rx_timestamp) { + if (CONFIG_MAC80211_IBSS_DEBUG || net_ratelimit()) + printk(KERN_DEBUG "%s: beacon TSF higher than " + "local TSF - IBSS merge with BSSID %s\n", + dev->name, print_mac(mac, mgmt->bssid)); + ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); + ieee80211_ibss_add_sta(dev, NULL, + mgmt->bssid, mgmt->sa); + } + } + ieee80211_rx_bss_put(dev, bss); } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 472b19fc9143..279ee493520d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1695,7 +1695,10 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, case IEEE80211_IF_TYPE_IBSS: if (!bssid) return 0; - if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { + if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT && + (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) + return 1; + else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) return 0; rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; -- cgit v1.2.3-59-g8ed1b From 4a9a66e9a87a8346129d557c7ec2303173318012 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 19 Feb 2008 11:31:14 +0100 Subject: mac80211: convert sta_info.pspoll to a flag This doesn't really need to be a full int variable since it's just a flag to indicate a PS-poll is in progress. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 13 +++++++------ net/mac80211/sta_info.h | 3 ++- net/mac80211/tx.c | 5 +++-- 3 files changed, 12 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 279ee493520d..c4b7cc07315d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -579,7 +579,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) if (sdata->bss) atomic_inc(&sdata->bss->num_sta_ps); sta->flags |= WLAN_STA_PS; - sta->pspoll = 0; + sta->flags &= ~WLAN_STA_PSPOLL; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", dev->name, print_mac(mac, sta->addr), sta->aid); @@ -598,8 +598,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss) atomic_dec(&sdata->bss->num_sta_ps); - sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM); - sta->pspoll = 0; + sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM | WLAN_STA_PSPOLL); if (!skb_queue_empty(&sta->ps_tx_buf)) { if (local->ops->set_tim) local->ops->set_tim(local_to_hw(local), sta->aid, 0); @@ -925,9 +924,11 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - /* tell TX path to send one frame even though the STA may - * still remain is PS mode after this frame exchange */ - rx->sta->pspoll = 1; + /* + * Tell TX path to send one frame even though the STA may + * still remain is PS mode after this frame exchange. + */ + rx->sta->flags |= WLAN_STA_PSPOLL; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n", diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 19f3fb412940..ca51d29b7008 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -32,6 +32,7 @@ * @WLAN_STA_ASSOC_AP: We're associated to that station, it is an AP. * @WLAN_STA_WME: Station is a QoS-STA. * @WLAN_STA_WDS: Station is one of our WDS peers. + * @WLAN_STA_PSPOLL: Station has just PS-polled us. */ enum ieee80211_sta_info_flags { WLAN_STA_AUTH = 1<<0, @@ -43,6 +44,7 @@ enum ieee80211_sta_info_flags { WLAN_STA_ASSOC_AP = 1<<6, WLAN_STA_WME = 1<<7, WLAN_STA_WDS = 1<<8, + WLAN_STA_PSPOLL = 1<<9, }; #define STA_TID_NUM 16 @@ -133,7 +135,6 @@ struct sta_info { struct sk_buff_head ps_tx_buf; /* buffer of TX frames for station in * power saving state */ - int pspoll; /* whether STA has send a PS Poll frame */ struct sk_buff_head tx_filtered; /* buffer of TX frames that were * already given to low-level driver, * but were filtered */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 181d97015f61..4f951e78df15 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -395,7 +395,8 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) (tx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP))) return TX_CONTINUE; - if (unlikely((sta->flags & WLAN_STA_PS) && !sta->pspoll)) { + if (unlikely((sta->flags & WLAN_STA_PS) && + !(sta->flags & WLAN_STA_PSPOLL))) { struct ieee80211_tx_packet_data *pkt_data; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries " @@ -436,7 +437,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) print_mac(mac, sta->addr)); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - sta->pspoll = 0; + sta->flags &= ~WLAN_STA_PSPOLL; return TX_CONTINUE; } -- cgit v1.2.3-59-g8ed1b From b46b4ee034645dc87a34b29a7989a2540a8ee8ea Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Wed, 13 Feb 2008 20:58:34 +0200 Subject: wireless: update US regulatory domain This patch adds channels to US regulatory domain Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- net/wireless/reg.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 2b63c96dcf19..8cc6037eb2ae 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -58,8 +58,14 @@ struct ieee80211_regdomain { static const struct ieee80211_channel_range ieee80211_US_channels[] = { /* IEEE 802.11b/g, channels 1..11 */ RANGE_PWR(2412, 2462, 27, 6, 0), - /* IEEE 802.11a, channels 52..64 */ - RANGE_PWR(5260, 5320, 23, 6, 0), + /* IEEE 802.11a, channel 36*/ + RANGE_PWR(5180, 5180, 23, 6, 0), + /* IEEE 802.11a, channel 40*/ + RANGE_PWR(5200, 5200, 23, 6, 0), + /* IEEE 802.11a, channel 44*/ + RANGE_PWR(5220, 5220, 23, 6, 0), + /* IEEE 802.11a, channels 48..64 */ + RANGE_PWR(5240, 5320, 23, 6, 0), /* IEEE 802.11a, channels 149..165, outdoor */ RANGE_PWR(5745, 5825, 30, 6, 0), }; -- cgit v1.2.3-59-g8ed1b From d2259243a19894eee06c16e278adfea81dc42bd9 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 20 Feb 2008 01:36:16 +0100 Subject: mac80211: invoke set_tim() callback after setting own TIM info Drivers should be allowed to simply get a complete new beacon when set_tim() is invoked (and set_tim() is required for drivers that just want a beacon template!), so we need to update our own TIM bitmap before calling set_tim() so that getting the beacon will now get an already updated beacon. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 8 ++++---- net/mac80211/sta_info.c | 4 ++-- net/mac80211/tx.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index c4b7cc07315d..af606f715016 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -600,10 +600,10 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) atomic_dec(&sdata->bss->num_sta_ps); sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM | WLAN_STA_PSPOLL); if (!skb_queue_empty(&sta->ps_tx_buf)) { - if (local->ops->set_tim) - local->ops->set_tim(local_to_hw(local), sta->aid, 0); if (sdata->bss) bss_tim_clear(local, sdata->bss, sta->aid); + if (local->ops->set_tim) + local->ops->set_tim(local_to_hw(local), sta->aid, 0); } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n", @@ -947,11 +947,11 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) dev_queue_xmit(skb); if (no_pending_pkts) { + if (rx->sdata->bss) + bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid); if (rx->local->ops->set_tim) rx->local->ops->set_tim(local_to_hw(rx->local), rx->sta->aid, 0); - if (rx->sdata->bss) - bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid); } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG } else if (!rx->u.rx.sent_ps_buffered) { diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 746bbdea6b4c..cbe00979e444 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -396,11 +396,11 @@ void sta_info_remove_aid_ptr(struct sta_info *sta) sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + if (sdata->bss) + __bss_tim_clear(sdata->bss, sta->aid); if (sdata->local->ops->set_tim) sdata->local->ops->set_tim(local_to_hw(sdata->local), sta->aid, 0); - if (sdata->bss) - __bss_tim_clear(sdata->bss, sta->aid); } diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 4f951e78df15..82474a8f251b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -419,11 +419,11 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) tx->local->total_ps_buffered++; /* Queue frame to be sent after STA sends an PS Poll frame */ if (skb_queue_empty(&sta->ps_tx_buf)) { + if (tx->sdata->bss) + bss_tim_set(tx->local, tx->sdata->bss, sta->aid); if (tx->local->ops->set_tim) tx->local->ops->set_tim(local_to_hw(tx->local), sta->aid, 1); - if (tx->sdata->bss) - bss_tim_set(tx->local, tx->sdata->bss, sta->aid); } pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb; pkt_data->jiffies = jiffies; -- cgit v1.2.3-59-g8ed1b From 836341a70471ba77657b0b420dd7eea3c30a038b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 20 Feb 2008 02:07:21 +0100 Subject: mac80211: remove sta TIM flag, fix expiry TIM handling The TIM flag that is kept in each station's info is completely useless, there's no code (aside from the debugfs display code) checking it, hence it can be removed. While doing that, I noticed that the TIM handling is broken when buffered frames expire, so fix that. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_sta.c | 3 +-- net/mac80211/rx.c | 7 +++---- net/mac80211/sta_info.c | 28 ++++++++++++++++++---------- net/mac80211/sta_info.h | 14 ++++++-------- net/mac80211/tx.c | 1 - 5 files changed, 28 insertions(+), 25 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index ac61353ae7ce..47db0d4aa433 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -74,11 +74,10 @@ static ssize_t sta_flags_read(struct file *file, char __user *userbuf, { char buf[100]; struct sta_info *sta = file->private_data; - int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s%s", + int res = scnprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s", sta->flags & WLAN_STA_AUTH ? "AUTH\n" : "", sta->flags & WLAN_STA_ASSOC ? "ASSOC\n" : "", sta->flags & WLAN_STA_PS ? "PS\n" : "", - sta->flags & WLAN_STA_TIM ? "TIM\n" : "", sta->flags & WLAN_STA_AUTHORIZED ? "AUTHORIZED\n" : "", sta->flags & WLAN_STA_SHORT_PREAMBLE ? "SHORT PREAMBLE\n" : "", sta->flags & WLAN_STA_WME ? "WME\n" : "", diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index af606f715016..0e8a371496b3 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -598,7 +598,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->bss) atomic_dec(&sdata->bss->num_sta_ps); - sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM | WLAN_STA_PSPOLL); + sta->flags &= ~(WLAN_STA_PS | WLAN_STA_PSPOLL); if (!skb_queue_empty(&sta->ps_tx_buf)) { if (sdata->bss) bss_tim_clear(local, sdata->bss, sta->aid); @@ -938,10 +938,9 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) /* Use MoreData flag to indicate whether there are more * buffered frames for this STA */ - if (no_pending_pkts) { + if (no_pending_pkts) hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREDATA); - rx->sta->flags &= ~WLAN_STA_TIM; - } else + else hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); dev_queue_xmit(skb); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index cbe00979e444..a843bb7dd2d3 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -286,6 +286,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, { unsigned long flags; struct sk_buff *skb; + struct ieee80211_sub_if_data *sdata; DECLARE_MAC_BUF(mac); if (skb_queue_empty(&sta->ps_tx_buf)) @@ -294,21 +295,28 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, for (;;) { spin_lock_irqsave(&sta->ps_tx_buf.lock, flags); skb = skb_peek(&sta->ps_tx_buf); - if (sta_info_buffer_expired(local, sta, skb)) { + if (sta_info_buffer_expired(local, sta, skb)) skb = __skb_dequeue(&sta->ps_tx_buf); - if (skb_queue_empty(&sta->ps_tx_buf)) - sta->flags &= ~WLAN_STA_TIM; - } else + else skb = NULL; spin_unlock_irqrestore(&sta->ps_tx_buf.lock, flags); - if (skb) { - local->total_ps_buffered--; - printk(KERN_DEBUG "Buffered frame expired (STA " - "%s)\n", print_mac(mac, sta->addr)); - dev_kfree_skb(skb); - } else + if (!skb) break; + + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + local->total_ps_buffered--; + printk(KERN_DEBUG "Buffered frame expired (STA " + "%s)\n", print_mac(mac, sta->addr)); + dev_kfree_skb(skb); + + if (skb_queue_empty(&sta->ps_tx_buf)) { + if (sdata->bss) + bss_tim_set(sta->local, sdata->bss, sta->aid); + if (sta->local->ops->set_tim) + sta->local->ops->set_tim(local_to_hw(sta->local), + sta->aid, 0); + } } } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index ca51d29b7008..f3d9f872db4a 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -23,7 +23,6 @@ * @WLAN_STA_AUTH: Station is authenticated. * @WLAN_STA_ASSOC: Station is associated. * @WLAN_STA_PS: Station is in power-save mode - * @WLAN_STA_TIM: TIM bit is on for this PS station (traffic buffered) * @WLAN_STA_AUTHORIZED: Station is authorized to send/receive traffic. * This bit is always checked so needs to be enabled for all stations * when virtual port control is not in use. @@ -38,13 +37,12 @@ enum ieee80211_sta_info_flags { WLAN_STA_AUTH = 1<<0, WLAN_STA_ASSOC = 1<<1, WLAN_STA_PS = 1<<2, - WLAN_STA_TIM = 1<<3, - WLAN_STA_AUTHORIZED = 1<<4, - WLAN_STA_SHORT_PREAMBLE = 1<<5, - WLAN_STA_ASSOC_AP = 1<<6, - WLAN_STA_WME = 1<<7, - WLAN_STA_WDS = 1<<8, - WLAN_STA_PSPOLL = 1<<9, + WLAN_STA_AUTHORIZED = 1<<3, + WLAN_STA_SHORT_PREAMBLE = 1<<4, + WLAN_STA_ASSOC_AP = 1<<5, + WLAN_STA_WME = 1<<6, + WLAN_STA_WDS = 1<<7, + WLAN_STA_PSPOLL = 1<<8, }; #define STA_TID_NUM 16 diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 82474a8f251b..db6a871b51ed 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -404,7 +404,6 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) print_mac(mac, sta->addr), sta->aid, skb_queue_len(&sta->ps_tx_buf)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - sta->flags |= WLAN_STA_TIM; if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) purge_old_ps_buffers(tx->local); if (skb_queue_len(&sta->ps_tx_buf) >= STA_MAX_TX_BUFFER) { -- cgit v1.2.3-59-g8ed1b From 004c872e78d433f84f0a5cd4db7a6c780c0946e1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 20 Feb 2008 11:21:35 +0100 Subject: mac80211: consolidate TIM handling code This consolidates all TIM handling code to avoid re-introducing errors with the bitmap/set_tim order and to reduce code. While reading the code I noticed a possible problem so I also added a comment about that. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 36 +------------------ net/mac80211/rx.c | 29 ++++++++-------- net/mac80211/sta_info.c | 87 ++++++++++++++++++++++++++++++++-------------- net/mac80211/sta_info.h | 4 ++- net/mac80211/tx.c | 11 +++--- 5 files changed, 84 insertions(+), 83 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 1b4a4497030d..b07b3cbfd039 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -207,7 +207,7 @@ struct ieee80211_if_ap { /* yes, this looks ugly, but guarantees that we can later use * bitmap_empty :) - * NB: don't ever use set_bit, use bss_tim_set/bss_tim_clear! */ + * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; atomic_t num_sta_ps; /* number of stations in PS mode */ struct sk_buff_head ps_bc_buf; @@ -640,40 +640,6 @@ struct sta_attribute { ssize_t (*store)(struct sta_info *, const char *buf, size_t count); }; -static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) -{ - /* - * This format has been mandated by the IEEE specifications, - * so this line may not be changed to use the __set_bit() format. - */ - bss->tim[aid / 8] |= (1 << (aid % 8)); -} - -static inline void bss_tim_set(struct ieee80211_local *local, - struct ieee80211_if_ap *bss, u16 aid) -{ - read_lock_bh(&local->sta_lock); - __bss_tim_set(bss, aid); - read_unlock_bh(&local->sta_lock); -} - -static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid) -{ - /* - * This format has been mandated by the IEEE specifications, - * so this line may not be changed to use the __clear_bit() format. - */ - bss->tim[aid / 8] &= ~(1 << (aid % 8)); -} - -static inline void bss_tim_clear(struct ieee80211_local *local, - struct ieee80211_if_ap *bss, u16 aid) -{ - read_lock_bh(&local->sta_lock); - __bss_tim_clear(bss, aid); - read_unlock_bh(&local->sta_lock); -} - static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) { return compare_ether_addr(raddr, addr) == 0 || diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0e8a371496b3..48574f6c0e74 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -596,19 +596,20 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) DECLARE_MAC_BUF(mac); sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + if (sdata->bss) atomic_dec(&sdata->bss->num_sta_ps); + sta->flags &= ~(WLAN_STA_PS | WLAN_STA_PSPOLL); - if (!skb_queue_empty(&sta->ps_tx_buf)) { - if (sdata->bss) - bss_tim_clear(local, sdata->bss, sta->aid); - if (local->ops->set_tim) - local->ops->set_tim(local_to_hw(local), sta->aid, 0); - } + + if (!skb_queue_empty(&sta->ps_tx_buf)) + sta_info_clear_tim_bit(sta); + #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG printk(KERN_DEBUG "%s: STA %s aid %d exits power save mode\n", dev->name, print_mac(mac, sta->addr), sta->aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + /* Send all buffered frames to the station */ while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; @@ -945,20 +946,20 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) dev_queue_xmit(skb); - if (no_pending_pkts) { - if (rx->sdata->bss) - bss_tim_clear(rx->local, rx->sdata->bss, rx->sta->aid); - if (rx->local->ops->set_tim) - rx->local->ops->set_tim(local_to_hw(rx->local), - rx->sta->aid, 0); - } + if (no_pending_pkts) + sta_info_clear_tim_bit(rx->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG } else if (!rx->u.rx.sent_ps_buffered) { + /* + * FIXME: This can be the result of a race condition between + * us expiring a frame and the station polling for it. + * Should we send it a null-func frame indicating we + * have nothing buffered for it? + */ printk(KERN_DEBUG "%s: STA %s sent PS Poll even " "though there is no buffered frames for it\n", rx->dev->name, print_mac(mac, rx->sta->addr)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - } /* Free PS Poll skb here instead of returning RX_DROP that would diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a843bb7dd2d3..b31a627ff97f 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -191,6 +191,64 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, return sta; } +static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) +{ + /* + * This format has been mandated by the IEEE specifications, + * so this line may not be changed to use the __set_bit() format. + */ + bss->tim[aid / 8] |= (1 << (aid % 8)); +} + +static inline void __bss_tim_clear(struct ieee80211_if_ap *bss, u16 aid) +{ + /* + * This format has been mandated by the IEEE specifications, + * so this line may not be changed to use the __clear_bit() format. + */ + bss->tim[aid / 8] &= ~(1 << (aid % 8)); +} + +static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss, + struct sta_info *sta) +{ + if (bss) + __bss_tim_set(bss, sta->aid); + if (sta->local->ops->set_tim) + sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1); +} + +void sta_info_set_tim_bit(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + + read_lock_bh(&sta->local->sta_lock); + __sta_info_set_tim_bit(sdata->bss, sta); + read_unlock_bh(&sta->local->sta_lock); +} + +static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, + struct sta_info *sta) +{ + if (bss) + __bss_tim_clear(bss, sta->aid); + if (sta->local->ops->set_tim) + sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0); +} + +void sta_info_clear_tim_bit(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + + read_lock_bh(&sta->local->sta_lock); + __sta_info_clear_tim_bit(sdata->bss, sta); + read_unlock_bh(&sta->local->sta_lock); +} + /* Caller must hold local->sta_lock */ void sta_info_remove(struct sta_info *sta) { @@ -207,10 +265,9 @@ void sta_info_remove(struct sta_info *sta) sta->flags &= ~WLAN_STA_PS; if (sdata->bss) atomic_dec(&sdata->bss->num_sta_ps); + __sta_info_clear_tim_bit(sdata->bss, sta); } local->num_sta--; - sta_info_remove_aid_ptr(sta); - } void sta_info_free(struct sta_info *sta) @@ -310,13 +367,8 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, "%s)\n", print_mac(mac, sta->addr)); dev_kfree_skb(skb); - if (skb_queue_empty(&sta->ps_tx_buf)) { - if (sdata->bss) - bss_tim_set(sta->local, sdata->bss, sta->aid); - if (sta->local->ops->set_tim) - sta->local->ops->set_tim(local_to_hw(sta->local), - sta->aid, 0); - } + if (skb_queue_empty(&sta->ps_tx_buf)) + sta_info_clear_tim_bit(sta); } } @@ -395,23 +447,6 @@ void sta_info_stop(struct ieee80211_local *local) sta_info_flush(local, NULL); } -void sta_info_remove_aid_ptr(struct sta_info *sta) -{ - struct ieee80211_sub_if_data *sdata; - - if (sta->aid <= 0) - return; - - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); - - if (sdata->bss) - __bss_tim_clear(sdata->bss, sta->aid); - if (sdata->local->ops->set_tim) - sdata->local->ops->set_tim(local_to_hw(sdata->local), - sta->aid, 0); -} - - /** * sta_info_flush - flush matching STA entries from the STA table * @local: local interface data diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index f3d9f872db4a..4099ece143ef 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -244,7 +244,9 @@ void sta_info_free(struct sta_info *sta); void sta_info_init(struct ieee80211_local *local); int sta_info_start(struct ieee80211_local *local); void sta_info_stop(struct ieee80211_local *local); -void sta_info_remove_aid_ptr(struct sta_info *sta); void sta_info_flush(struct ieee80211_local *local, struct net_device *dev); +void sta_info_set_tim_bit(struct sta_info *sta); +void sta_info_clear_tim_bit(struct sta_info *sta); + #endif /* STA_INFO_H */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index db6a871b51ed..69fdb763aa8b 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -416,14 +416,11 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) dev_kfree_skb(old); } else tx->local->total_ps_buffered++; + /* Queue frame to be sent after STA sends an PS Poll frame */ - if (skb_queue_empty(&sta->ps_tx_buf)) { - if (tx->sdata->bss) - bss_tim_set(tx->local, tx->sdata->bss, sta->aid); - if (tx->local->ops->set_tim) - tx->local->ops->set_tim(local_to_hw(tx->local), - sta->aid, 1); - } + if (skb_queue_empty(&sta->ps_tx_buf)) + sta_info_set_tim_bit(sta); + pkt_data = (struct ieee80211_tx_packet_data *)tx->skb->cb; pkt_data->jiffies = jiffies; skb_queue_tail(&sta->ps_tx_buf, tx->skb); -- cgit v1.2.3-59-g8ed1b From d97cf01576e1867d26b5c8de360380f815a1b7df Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Thu, 21 Feb 2008 11:33:58 -0500 Subject: mac80211: fix incorrect use of CONFIG_MAC80211_IBSS_DEBUG Configuration variables are only available to the preprocessor Signed-off-by: Pavel Roskin Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 6e5b57dccc50..8d620baba4fd 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2453,10 +2453,12 @@ static void ieee80211_rx_bss_info(struct net_device *dev, jiffies); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (beacon_timestamp > rx_timestamp) { - if (CONFIG_MAC80211_IBSS_DEBUG || net_ratelimit()) +#ifdef CONFIG_MAC80211_IBSS_DEBUG + if (net_ratelimit()) printk(KERN_DEBUG "%s: beacon TSF higher than " "local TSF - IBSS merge with BSSID %s\n", dev->name, print_mac(mac, mgmt->bssid)); +#endif /* CONFIG_MAC80211_IBSS_DEBUG */ ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); ieee80211_ibss_add_sta(dev, NULL, mgmt->bssid, mgmt->sa); -- cgit v1.2.3-59-g8ed1b From d46e144b65bf053b25d134ec9f52a38e63e04bb4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 20 Feb 2008 23:59:33 +0100 Subject: mac80211: rework TX filtered frame code This reworks the code for TX filtered frames, splitting it out to a new function to handle those cases, making the clear instruction a flag and renaming a few things to be easier to understand and less Atheros hardware specific. Finally, it also makes the comments explain more. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 3 +- net/mac80211/ieee80211.c | 121 +++++++++++++++++++++++++++++++---------------- net/mac80211/sta_info.h | 6 ++- net/mac80211/tx.c | 12 ++--- 4 files changed, 91 insertions(+), 51 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 784ab769b00b..cd4b1c1a0d48 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -228,7 +228,8 @@ struct ieee80211_tx_control { #define IEEE80211_TXCTL_NO_ACK (1<<4) /* tell the low level not to * wait for an ack */ #define IEEE80211_TXCTL_RATE_CTRL_PROBE (1<<5) -#define IEEE80211_TXCTL_CLEAR_DST_MASK (1<<6) +#define IEEE80211_TXCTL_CLEAR_PS_FILT (1<<6) /* clear powersave filter + * for destination station */ #define IEEE80211_TXCTL_REQUEUE (1<<7) #define IEEE80211_TXCTL_FIRST_FRAGMENT (1<<8) /* this is a first fragment of * the frame */ diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 7df14799e38b..a00858dbab18 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -1178,6 +1178,77 @@ no_key: } } +static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, + struct sta_info *sta, + struct sk_buff *skb, + struct ieee80211_tx_status *status) +{ + sta->tx_filtered_count++; + + /* + * Clear the TX filter mask for this STA when sending the next + * packet. If the STA went to power save mode, this will happen + * happen when it wakes up for the next time. + */ + sta->flags |= WLAN_STA_CLEAR_PS_FILT; + + /* + * This code races in the following way: + * + * (1) STA sends frame indicating it will go to sleep and does so + * (2) hardware/firmware adds STA to filter list, passes frame up + * (3) hardware/firmware processes TX fifo and suppresses a frame + * (4) we get TX status before having processed the frame and + * knowing that the STA has gone to sleep. + * + * This is actually quite unlikely even when both those events are + * processed from interrupts coming in quickly after one another or + * even at the same time because we queue both TX status events and + * RX frames to be processed by a tasklet and process them in the + * same order that they were received or TX status last. Hence, there + * is no race as long as the frame RX is processed before the next TX + * status, which drivers can ensure, see below. + * + * Note that this can only happen if the hardware or firmware can + * actually add STAs to the filter list, if this is done by the + * driver in response to set_tim() (which will only reduce the race + * this whole filtering tries to solve, not completely solve it) + * this situation cannot happen. + * + * To completely solve this race drivers need to make sure that they + * (a) don't mix the irq-safe/not irq-safe TX status/RX processing + * functions and + * (b) always process RX events before TX status events if ordering + * can be unknown, for example with different interrupt status + * bits. + */ + if (sta->flags & WLAN_STA_PS && + skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { + ieee80211_remove_tx_extra(local, sta->key, skb, + &status->control); + skb_queue_tail(&sta->tx_filtered, skb); + return; + } + + if (!(sta->flags & WLAN_STA_PS) && + !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) { + /* Software retry the packet once */ + status->control.flags |= IEEE80211_TXCTL_REQUEUE; + ieee80211_remove_tx_extra(local, sta->key, skb, + &status->control); + dev_queue_xmit(skb); + return; + } + + if (net_ratelimit()) + printk(KERN_DEBUG "%s: dropped TX filtered frame, " + "queue_len=%d PS=%d @%lu\n", + wiphy_name(local->hw.wiphy), + skb_queue_len(&sta->tx_filtered), + !!(sta->flags & WLAN_STA_PS), jiffies); + dev_kfree_skb(skb); +} + void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_tx_status *status) { @@ -1202,11 +1273,16 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, sta = sta_info_get(local, hdr->addr1); if (sta) { if (sta->flags & WLAN_STA_PS) { - /* The STA is in power save mode, so assume + /* + * The STA is in power save mode, so assume * that this TX packet failed because of that. */ status->excessive_retries = 0; status->flags |= IEEE80211_TX_STATUS_TX_FILTERED; + ieee80211_handle_filtered_frame(local, sta, + skb, status); + sta_info_put(sta); + return; } sta_info_put(sta); } @@ -1216,47 +1292,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, struct sta_info *sta; sta = sta_info_get(local, hdr->addr1); if (sta) { - sta->tx_filtered_count++; - - /* Clear the TX filter mask for this STA when sending - * the next packet. If the STA went to power save mode, - * this will happen when it is waking up for the next - * time. */ - sta->clear_dst_mask = 1; - - /* TODO: Is the WLAN_STA_PS flag always set here or is - * the race between RX and TX status causing some - * packets to be filtered out before 80211.o gets an - * update for PS status? This seems to be the case, so - * no changes are likely to be needed. */ - if (sta->flags & WLAN_STA_PS && - skb_queue_len(&sta->tx_filtered) < - STA_MAX_TX_BUFFER) { - ieee80211_remove_tx_extra(local, sta->key, - skb, - &status->control); - skb_queue_tail(&sta->tx_filtered, skb); - } else if (!(sta->flags & WLAN_STA_PS) && - !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) { - /* Software retry the packet once */ - status->control.flags |= IEEE80211_TXCTL_REQUEUE; - ieee80211_remove_tx_extra(local, sta->key, - skb, - &status->control); - dev_queue_xmit(skb); - } else { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: dropped TX " - "filtered frame queue_len=%d " - "PS=%d @%lu\n", - wiphy_name(local->hw.wiphy), - skb_queue_len( - &sta->tx_filtered), - !!(sta->flags & WLAN_STA_PS), - jiffies); - } - dev_kfree_skb(skb); - } + ieee80211_handle_filtered_frame(local, sta, skb, + status); sta_info_put(sta); return; } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4099ece143ef..f7e65fa3f9ed 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -32,6 +32,9 @@ * @WLAN_STA_WME: Station is a QoS-STA. * @WLAN_STA_WDS: Station is one of our WDS peers. * @WLAN_STA_PSPOLL: Station has just PS-polled us. + * @WLAN_STA_CLEAR_PS_FILT: Clear PS filter in hardware (using the + * IEEE80211_TXCTL_CLEAR_PS_FILT control flag) when the next + * frame to this station is transmitted. */ enum ieee80211_sta_info_flags { WLAN_STA_AUTH = 1<<0, @@ -43,6 +46,7 @@ enum ieee80211_sta_info_flags { WLAN_STA_WME = 1<<6, WLAN_STA_WDS = 1<<7, WLAN_STA_PSPOLL = 1<<8, + WLAN_STA_CLEAR_PS_FILT = 1<<9, }; #define STA_TID_NUM 16 @@ -136,8 +140,6 @@ struct sta_info { struct sk_buff_head tx_filtered; /* buffer of TX frames that were * already given to low-level driver, * but were filtered */ - int clear_dst_mask; - unsigned long rx_packets, tx_packets; /* number of RX/TX MSDUs */ unsigned long rx_bytes, tx_bytes; unsigned long tx_retry_failed, tx_retry_count; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 69fdb763aa8b..1cd58e01f1ee 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -1020,10 +1020,10 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, } if (!tx->sta) - control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; - else if (tx->sta->clear_dst_mask) { - control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; - tx->sta->clear_dst_mask = 0; + control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; + else if (tx->sta->flags & WLAN_STA_CLEAR_PS_FILT) { + control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; + tx->sta->flags &= ~WLAN_STA_CLEAR_PS_FILT; } hdrlen = ieee80211_get_hdrlen(tx->fc); @@ -1084,7 +1084,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, if (tx->u.tx.extra_frag) { control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | IEEE80211_TXCTL_USE_CTS_PROTECT | - IEEE80211_TXCTL_CLEAR_DST_MASK | + IEEE80211_TXCTL_CLEAR_PS_FILT | IEEE80211_TXCTL_FIRST_FRAGMENT); for (i = 0; i < tx->u.tx.num_extra_frag; i++) { if (!tx->u.tx.extra_frag[i]) @@ -1806,7 +1806,7 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, control->antenna_sel_tx = local->hw.conf.antenna_sel_tx; control->flags |= IEEE80211_TXCTL_NO_ACK; control->retry_limit = 1; - control->flags |= IEEE80211_TXCTL_CLEAR_DST_MASK; + control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; } ap->num_beacons++; -- cgit v1.2.3-59-g8ed1b From 43ba7e958f2ca05e4e9171a15402288419289d71 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Feb 2008 14:09:30 +0100 Subject: mac80211: atomically check whether STA exists already When a STA structure is added, it is often checked whether it already exists before adding it. This, however, isn't done atomically so there is a race condition that could lead to two STA structures being added with the same MAC address. This patch changes sta_info_add() to return an ERR_PTR in case of failure and adds the failure mode -EEXIST when the STA already exists. Signed-off-by: Johannes Berg Cc: Luis Carlos Cobo Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 11 ++--------- net/mac80211/ieee80211.c | 4 ++-- net/mac80211/ieee80211_sta.c | 6 +++--- net/mac80211/sta_info.c | 38 +++++++++++++++++++++++++++----------- net/mac80211/sta_info.h | 4 ++-- 5 files changed, 36 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a083cc78855e..b0c41a0cee79 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -562,13 +562,6 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, if (!netif_running(dev)) return -ENETDOWN; - /* XXX: get sta belonging to dev */ - sta = sta_info_get(local, mac); - if (sta) { - sta_info_put(sta); - return -EEXIST; - } - if (params->vlan) { sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); @@ -579,8 +572,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); sta = sta_info_add(local, dev, mac, GFP_KERNEL); - if (!sta) - return -ENOMEM; + if (IS_ERR(sta)) + return PTR_ERR(sta); sta->dev = sdata->dev; if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index a00858dbab18..f82ebdd53d48 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -838,8 +838,8 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) /* Create STA entry for the new peer */ sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); - if (!sta) - return -ENOMEM; + if (IS_ERR(sta)) + return PTR_ERR(sta); sta->flags |= WLAN_STA_AUTHORIZED; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 8d620baba4fd..64476d9e8d77 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1807,9 +1807,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (!sta) { struct ieee80211_sta_bss *bss; sta = sta_info_add(local, dev, ifsta->bssid, GFP_KERNEL); - if (!sta) { + if (IS_ERR(sta)) { printk(KERN_DEBUG "%s: failed to add STA entry for the" - " AP\n", dev->name); + " AP (error %ld)\n", dev->name, PTR_ERR(sta)); return; } bss = ieee80211_rx_bss_get(dev, ifsta->bssid, @@ -3820,7 +3820,7 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); sta = sta_info_add(local, dev, addr, GFP_ATOMIC); - if (!sta) + if (IS_ERR(sta)) return NULL; sta->flags |= WLAN_STA_AUTHORIZED; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index b31a627ff97f..c6c0df4bbd2c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -55,19 +55,29 @@ static int sta_info_hash_del(struct ieee80211_local *local, return -ENOENT; } -struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) +/* must hold local->sta_lock */ +static struct sta_info *__sta_info_find(struct ieee80211_local *local, + u8 *addr) { struct sta_info *sta; - read_lock_bh(&local->sta_lock); sta = local->sta_hash[STA_HASH(addr)]; while (sta) { - if (memcmp(sta->addr, addr, ETH_ALEN) == 0) { - __sta_info_get(sta); + if (compare_ether_addr(sta->addr, addr) == 0) break; - } sta = sta->hnext; } + return sta; +} + +struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) +{ + struct sta_info *sta; + + read_lock_bh(&local->sta_lock); + sta = __sta_info_find(local, addr); + if (sta) + __sta_info_get(sta); read_unlock_bh(&local->sta_lock); return sta; @@ -110,8 +120,8 @@ void sta_info_put(struct sta_info *sta) EXPORT_SYMBOL(sta_info_put); -struct sta_info * sta_info_add(struct ieee80211_local *local, - struct net_device *dev, u8 *addr, gfp_t gfp) +struct sta_info *sta_info_add(struct ieee80211_local *local, + struct net_device *dev, u8 *addr, gfp_t gfp) { struct sta_info *sta; int i; @@ -119,7 +129,7 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, sta = kzalloc(sizeof(*sta), gfp); if (!sta) - return NULL; + return ERR_PTR(-ENOMEM); kref_init(&sta->kref); @@ -128,7 +138,7 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, if (!sta->rate_ctrl_priv) { rate_control_put(sta->rate_ctrl); kfree(sta); - return NULL; + return ERR_PTR(-ENOMEM); } memcpy(sta->addr, addr, ETH_ALEN); @@ -158,9 +168,15 @@ struct sta_info * sta_info_add(struct ieee80211_local *local, } skb_queue_head_init(&sta->ps_tx_buf); skb_queue_head_init(&sta->tx_filtered); - __sta_info_get(sta); /* sta used by caller, decremented by - * sta_info_put() */ write_lock_bh(&local->sta_lock); + /* mark sta as used (by caller) */ + __sta_info_get(sta); + /* check if STA exists already */ + if (__sta_info_find(local, addr)) { + write_unlock_bh(&local->sta_lock); + sta_info_put(sta); + return ERR_PTR(-EEXIST); + } list_add(&sta->list, &local->sta_list); local->num_sta++; sta_info_hash_add(local, sta); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index f7e65fa3f9ed..7b5be309fe0a 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -239,8 +239,8 @@ static inline void __sta_info_get(struct sta_info *sta) struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); void sta_info_put(struct sta_info *sta); -struct sta_info * sta_info_add(struct ieee80211_local *local, - struct net_device *dev, u8 *addr, gfp_t gfp); +struct sta_info *sta_info_add(struct ieee80211_local *local, + struct net_device *dev, u8 *addr, gfp_t gfp); void sta_info_remove(struct sta_info *sta); void sta_info_free(struct sta_info *sta); void sta_info_init(struct ieee80211_local *local); -- cgit v1.2.3-59-g8ed1b From 665e8aafb4e0826caec9db25617b186ea3f3ec91 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Feb 2008 01:10:07 +0100 Subject: mac80211: Disallow concurrent IBSS/STA mode interfaces Disallow having more than one IBSS interface up at any time because of beacon distribution issues, and for now also disallow having more than one IBSS/STA interface up at the same time because we use the master interface's BSS struct which would be completely corrupted when we have more than one up. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 51 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index f82ebdd53d48..2133c9fd27a4 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -183,8 +183,52 @@ static int ieee80211_open(struct net_device *dev) list_for_each_entry(nsdata, &local->interfaces, list) { struct net_device *ndev = nsdata->dev; - if (ndev != dev && ndev != local->mdev && netif_running(ndev) && - compare_ether_addr(dev->dev_addr, ndev->dev_addr) == 0) { + if (ndev != dev && ndev != local->mdev && netif_running(ndev)) { + /* + * Allow only a single IBSS interface to be up at any + * time. This is restricted because beacon distribution + * cannot work properly if both are in the same IBSS. + * + * To remove this restriction we'd have to disallow them + * from setting the same SSID on different IBSS interfaces + * belonging to the same hardware. Then, however, we're + * faced with having to adopt two different TSF timers... + */ + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && + nsdata->vif.type == IEEE80211_IF_TYPE_IBSS) + return -EBUSY; + + /* + * Disallow multiple IBSS/STA mode interfaces. + * + * This is a technical restriction, it is possible although + * most likely not IEEE 802.11 compliant to have multiple + * STAs with just a single hardware (the TSF timer will not + * be adjusted properly.) + * + * However, because mac80211 uses the master device's BSS + * information for each STA/IBSS interface, doing this will + * currently corrupt that BSS information completely, unless, + * a not very useful case, both STAs are associated to the + * same BSS. + * + * To remove this restriction, the BSS information needs to + * be embedded in the STA/IBSS mode sdata instead of using + * the master device's BSS structure. + */ + if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) && + (nsdata->vif.type == IEEE80211_IF_TYPE_STA || + nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)) + return -EBUSY; + + /* + * The remaining checks are only performed for interfaces + * with the same MAC address. + */ + if (compare_ether_addr(dev->dev_addr, ndev->dev_addr)) + continue; + /* * check whether it may have the same address */ @@ -196,8 +240,7 @@ static int ieee80211_open(struct net_device *dev) * can only add VLANs to enabled APs */ if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN && - nsdata->vif.type == IEEE80211_IF_TYPE_AP && - netif_running(nsdata->dev)) + nsdata->vif.type == IEEE80211_IF_TYPE_AP) sdata->u.vlan.ap = nsdata; } } -- cgit v1.2.3-59-g8ed1b From f3af89d1aaaf2d2ef3bc6afe5eadb7127c51fe12 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Feb 2008 11:22:12 +0100 Subject: mac80211: fix debugfs_sta print_mac() warning When print_mac() was marked as __pure to avoid emitting a function call in pr_debug() scenarios, a warning in this code surfaced since it relies on the fact that the buffer is modified and doesn't use the return value. This patch makes it use the return value instead. Signed-off-by: Johannes Berg Reported-by: Harvey Harrison Signed-off-by: John W. Linville --- net/mac80211/debugfs_sta.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 47db0d4aa433..1a4d2c3775af 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -297,12 +297,13 @@ STA_OPS_WR(agg_status); void ieee80211_sta_debugfs_add(struct sta_info *sta) { struct dentry *stations_dir = sta->local->debugfs.stations; - DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mbuf); + u8 *mac; if (!stations_dir) return; - print_mac(mac, sta->addr); + mac = print_mac(mbuf, sta->addr); sta->debugfs.dir = debugfs_create_dir(mac, stations_dir); if (!sta->debugfs.dir) -- cgit v1.2.3-59-g8ed1b From fba4a1e63723b5ef16c21a90f06520ae37c5da98 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 21 Feb 2008 11:08:33 +0100 Subject: mac80211: fix IBSS code This patch fixes two errors introduced by commit 19d35612f3cd7f60dd9174c0100584e21f5a1025 Author: Bruno Randolf Date: Mon Feb 18 11:21:36 2008 +0900 mac80211: enable IBSS merging The first error is an endianness problem that sparse found and the second is a build failure when CONFIG_MAC80211_IBSS_DEBUG is not set. Signed-off-by: Johannes Berg Cc: Bruno Randolf Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 64476d9e8d77..ddb5832f37cb 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2413,7 +2413,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev, /* check if we need to merge IBSS */ if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && !local->sta_sw_scanning && !local->sta_hw_scanning && - mgmt->u.beacon.capab_info & WLAN_CAPABILITY_IBSS && + bss->capability & WLAN_CAPABILITY_IBSS && bss->freq == local->oper_channel->center_freq && elems.ssid_len == sdata->u.sta.ssid_len && memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) { @@ -2453,12 +2453,12 @@ static void ieee80211_rx_bss_info(struct net_device *dev, jiffies); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (beacon_timestamp > rx_timestamp) { -#ifdef CONFIG_MAC80211_IBSS_DEBUG +#ifndef CONFIG_MAC80211_IBSS_DEBUG if (net_ratelimit()) +#endif printk(KERN_DEBUG "%s: beacon TSF higher than " "local TSF - IBSS merge with BSSID %s\n", dev->name, print_mac(mac, mgmt->bssid)); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); ieee80211_ibss_add_sta(dev, NULL, mgmt->bssid, mgmt->sa); -- cgit v1.2.3-59-g8ed1b From e6a5ddf20886206caf1c4a2431f6ff01198ab0f7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 16:27:42 +0100 Subject: mac80211: safely free beacon in ieee80211_if_reinit If ieee80211_if_reinit() is called from ieee80211_unregister_hw() then it is possible that the driver will still request a beacon (it is allowed to until ieee80211_unregister_hw() has returned.) This means we need to use an RCU-protected write to the beacon information even in this function. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_iface.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index f66f1ddc3fda..0d6824bca92b 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -193,6 +193,7 @@ void ieee80211_if_reinit(struct net_device *dev) /* Remove all virtual interfaces that use this BSS * as their sdata->bss */ struct ieee80211_sub_if_data *tsdata, *n; + struct beacon_data *beacon; list_for_each_entry_safe(tsdata, n, &local->interfaces, list) { if (tsdata != sdata && tsdata->bss == &sdata->u.ap) { @@ -210,7 +211,10 @@ void ieee80211_if_reinit(struct net_device *dev) } } - kfree(sdata->u.ap.beacon); + beacon = sdata->u.ap.beacon; + rcu_assign_pointer(sdata->u.ap.beacon, NULL); + synchronize_rcu(); + kfree(beacon); while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { local->total_ps_buffered--; -- cgit v1.2.3-59-g8ed1b From 6f48422a29714ed92f6136d9e7d3ff39c75607d7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 16:27:44 +0100 Subject: mac80211: remove STA infos last_ack stuff These things aren't used and the only possible use is within rate control algorithms, however those can, if they need it, keep track of it in their private data. last_ack_ms isn't even updated so completely useless. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_sta.c | 29 ----------------------------- net/mac80211/rc80211_pid_algo.c | 3 --- net/mac80211/rc80211_simple.c | 3 --- net/mac80211/sta_info.h | 4 ---- 4 files changed, 39 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 1a4d2c3775af..ed7c9f3b4602 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -98,31 +98,6 @@ static ssize_t sta_num_ps_buf_frames_read(struct file *file, } STA_OPS(num_ps_buf_frames); -static ssize_t sta_last_ack_rssi_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - char buf[100]; - struct sta_info *sta = file->private_data; - int res = scnprintf(buf, sizeof(buf), "%d %d %d\n", - sta->last_ack_rssi[0], - sta->last_ack_rssi[1], - sta->last_ack_rssi[2]); - return simple_read_from_buffer(userbuf, count, ppos, buf, res); -} -STA_OPS(last_ack_rssi); - -static ssize_t sta_last_ack_ms_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) -{ - char buf[20]; - struct sta_info *sta = file->private_data; - int res = scnprintf(buf, sizeof(buf), "%d\n", - sta->last_ack ? - jiffies_to_msecs(jiffies - sta->last_ack) : -1); - return simple_read_from_buffer(userbuf, count, ppos, buf, res); -} -STA_OPS(last_ack_ms); - static ssize_t sta_inactive_ms_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { @@ -311,8 +286,6 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) DEBUGFS_ADD(flags); DEBUGFS_ADD(num_ps_buf_frames); - DEBUGFS_ADD(last_ack_rssi); - DEBUGFS_ADD(last_ack_ms); DEBUGFS_ADD(inactive_ms); DEBUGFS_ADD(last_seq_ctrl); #ifdef CONFIG_MAC80211_DEBUG_COUNTERS @@ -326,8 +299,6 @@ void ieee80211_sta_debugfs_remove(struct sta_info *sta) { DEBUGFS_DEL(flags); DEBUGFS_DEL(num_ps_buf_frames); - DEBUGFS_DEL(last_ack_rssi); - DEBUGFS_DEL(last_ack_ms); DEBUGFS_DEL(inactive_ms); DEBUGFS_DEL(last_seq_ctrl); #ifdef CONFIG_MAC80211_DEBUG_COUNTERS diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index da8462bbd5f4..9762803e4876 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -280,9 +280,6 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, sta->tx_num_consecutive_failures++; sta->tx_num_mpdu_fail++; } else { - sta->last_ack_rssi[0] = sta->last_ack_rssi[1]; - sta->last_ack_rssi[1] = sta->last_ack_rssi[2]; - sta->last_ack_rssi[2] = status->ack_signal; sta->tx_num_consecutive_failures = 0; sta->tx_num_mpdu_ok++; } diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index a669bcb8739f..bcc541d4b95c 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c @@ -131,9 +131,6 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, sta->tx_num_consecutive_failures++; sta->tx_num_mpdu_fail++; } else { - sta->last_ack_rssi[0] = sta->last_ack_rssi[1]; - sta->last_ack_rssi[1] = sta->last_ack_rssi[2]; - sta->last_ack_rssi[2] = status->ack_signal; sta->tx_num_consecutive_failures = 0; sta->tx_num_mpdu_ok++; } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 7b5be309fe0a..86eed40ada78 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -177,8 +177,6 @@ struct sta_info { int last_rssi; /* RSSI of last received frame from this STA */ int last_signal; /* signal of last received frame from this STA */ int last_noise; /* noise of last received frame from this STA */ - int last_ack_rssi[3]; /* RSSI of last received ACKs from this STA */ - unsigned long last_ack; int channel_use; int channel_use_raw; @@ -200,8 +198,6 @@ struct sta_info { struct dentry *dir; struct dentry *flags; struct dentry *num_ps_buf_frames; - struct dentry *last_ack_rssi; - struct dentry *last_ack_ms; struct dentry *inactive_ms; struct dentry *last_seq_ctrl; #ifdef CONFIG_MAC80211_DEBUG_COUNTERS -- cgit v1.2.3-59-g8ed1b From db4d1169d0b893bfb7923b6526748fe2c5a7373f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 16:27:45 +0100 Subject: mac80211: split ieee80211_key_alloc/free In order to RCU-ify sta_info, we need to be able to allocate a key without linking it to an sdata/sta structure (because allocation cannot be done in an rcu critical section). This patch splits up ieee80211_key_alloc() and updates all users appropriately. While at it, this patch fixes a number of race conditions such as finally making key replacement atomic, unfortunately at the expense of more complex code. Note that this patch documents /existing/ bugs with sta info and key interaction, there is currently a race condition when a sta info is freed without holding the RTNL. This will finally be fixed by a followup patch. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 27 ++++--- net/mac80211/ieee80211_ioctl.c | 90 +++++++++++++----------- net/mac80211/ieee80211_key.h | 26 +++++-- net/mac80211/key.c | 156 +++++++++++++++++++++++++++++------------ net/mac80211/sta_info.c | 2 +- 5 files changed, 203 insertions(+), 98 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b0c41a0cee79..e7535ffc8e1c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -123,6 +123,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, struct sta_info *sta = NULL; enum ieee80211_key_alg alg; int ret; + struct ieee80211_key *key; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -141,16 +142,21 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, return -EINVAL; } + key = ieee80211_key_alloc(alg, key_idx, params->key_len, params->key); + if (!key) + return -ENOMEM; + if (mac_addr) { sta = sta_info_get(sdata->local, mac_addr); - if (!sta) + if (!sta) { + ieee80211_key_free(key); return -ENOENT; + } } + ieee80211_key_link(key, sdata, sta); + ret = 0; - if (!ieee80211_key_alloc(sdata, sta, alg, key_idx, - params->key_len, params->key)) - ret = -ENOMEM; if (sta) sta_info_put(sta); @@ -164,6 +170,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_sub_if_data *sdata; struct sta_info *sta; int ret; + struct ieee80211_key *key; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -173,9 +180,11 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, return -ENOENT; ret = 0; - if (sta->key) - ieee80211_key_free(sta->key); - else + if (sta->key) { + key = sta->key; + ieee80211_key_free(key); + WARN_ON(sta->key); + } else ret = -ENOENT; sta_info_put(sta); @@ -185,7 +194,9 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, if (!sdata->keys[key_idx]) return -ENOENT; - ieee80211_key_free(sdata->keys[key_idx]); + key = sdata->keys[key_idx]; + ieee80211_key_free(key); + WARN_ON(sdata->keys[key_idx]); return 0; } diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 54ad07aafe2d..7551db3f3abc 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -33,8 +33,8 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, size_t key_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int ret = 0; - struct sta_info *sta; + int ret; + struct sta_info *sta = NULL; struct ieee80211_key *key; struct ieee80211_sub_if_data *sdata; @@ -46,58 +46,64 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, return -EINVAL; } - if (is_broadcast_ether_addr(sta_addr)) { - sta = NULL; - key = sdata->keys[idx]; - } else { - set_tx_key = 0; - /* - * According to the standard, the key index of a pairwise - * key must be zero. However, some AP are broken when it - * comes to WEP key indices, so we work around this. - */ - if (idx != 0 && alg != ALG_WEP) { - printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for " - "individual key\n", dev->name); - return -EINVAL; + if (remove) { + if (is_broadcast_ether_addr(sta_addr)) { + key = sdata->keys[idx]; + } else { + sta = sta_info_get(local, sta_addr); + if (!sta) { + ret = -ENOENT; + key = NULL; + goto err_out; + } + + key = sta->key; } - sta = sta_info_get(local, sta_addr); - if (!sta) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s: set_encrypt - unknown addr " - "%s\n", - dev->name, print_mac(mac, sta_addr)); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + if (!key) + ret = -ENOENT; + else + ret = 0; + } else { + key = ieee80211_key_alloc(alg, idx, key_len, _key); + if (!key) + return -ENOMEM; + + if (!is_broadcast_ether_addr(sta_addr)) { + set_tx_key = 0; + /* + * According to the standard, the key index of a + * pairwise key must be zero. However, some AP are + * broken when it comes to WEP key indices, so we + * work around this. + */ + if (idx != 0 && alg != ALG_WEP) { + ret = -EINVAL; + goto err_out; + } - return -ENOENT; + sta = sta_info_get(local, sta_addr); + if (!sta) { + ret = -ENOENT; + goto err_out; + } } - key = sta->key; - } + ieee80211_key_link(key, sdata, sta); - if (remove) { - ieee80211_key_free(key); + if (set_tx_key || (!sta && !sdata->default_key && key)) + ieee80211_set_default_key(sdata, idx); + + /* don't free key later */ key = NULL; - } else { - /* - * Automatically frees any old key if present. - */ - key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key); - if (!key) { - ret = -ENOMEM; - goto err_out; - } - } - if (set_tx_key || (!sta && !sdata->default_key && key)) - ieee80211_set_default_key(sdata, idx); + ret = 0; + } - ret = 0; err_out: if (sta) sta_info_put(sta); + ieee80211_key_free(key); return ret; } diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h index fc770e98d47b..d670e6dbfa39 100644 --- a/net/mac80211/ieee80211_key.h +++ b/net/mac80211/ieee80211_key.h @@ -13,6 +13,7 @@ #include #include #include +#include #include /* ALG_TKIP @@ -45,7 +46,19 @@ struct ieee80211_local; struct ieee80211_sub_if_data; struct sta_info; -#define KEY_FLAG_UPLOADED_TO_HARDWARE (1<<0) +/** + * enum ieee80211_internal_key_flags - internal key flags + * + * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present + * in the hardware for TX crypto hardware acceleration. + * @KEY_FLAG_REMOVE_FROM_HARDWARE: Indicates to the key code that this + * key is present in the hardware (but it cannot be used for + * hardware acceleration any more!) + */ +enum ieee80211_internal_key_flags { + KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), + KEY_FLAG_REMOVE_FROM_HARDWARE = BIT(1), +}; struct ieee80211_key { struct ieee80211_local *local; @@ -112,12 +125,17 @@ struct ieee80211_key { struct ieee80211_key_conf conf; }; -struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, - enum ieee80211_key_alg alg, +struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, int idx, size_t key_len, const u8 *key_data); +/* + * Insert a key into data structures (sdata, sta if necessary) + * to make it used, free old key. + */ +void ieee80211_key_link(struct ieee80211_key *key, + struct ieee80211_sub_if_data *sdata, + struct sta_info *sta); void ieee80211_key_free(struct ieee80211_key *key); void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ed57fb8e82fc..60aaaf471544 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "ieee80211_i.h" #include "debugfs_key.h" @@ -34,6 +35,10 @@ * * All operations here are called under RTNL so no extra locking is * required. + * + * NOTE: This code requires that sta info *destruction* is done under + * RTNL, otherwise it can try to access already freed STA structs + * when a STA key is being freed. */ static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; @@ -84,16 +89,25 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) key->conf.keyidx, print_mac(mac, addr), ret); } +static void ieee80211_key_mark_hw_accel_off(struct ieee80211_key *key) +{ + if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { + key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; + key->flags |= KEY_FLAG_REMOVE_FROM_HARDWARE; + } +} + static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) { const u8 *addr; int ret; DECLARE_MAC_BUF(mac); - if (!key->local->ops->set_key) + if (!key || !key->local->ops->set_key) return; - if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && + !(key->flags & KEY_FLAG_REMOVE_FROM_HARDWARE)) return; addr = get_mac_for_key(key); @@ -108,12 +122,11 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) wiphy_name(key->local->hw.wiphy), key->conf.keyidx, print_mac(mac, addr), ret); - key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; + key->flags &= ~(KEY_FLAG_UPLOADED_TO_HARDWARE | + KEY_FLAG_REMOVE_FROM_HARDWARE); } -struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, - enum ieee80211_key_alg alg, +struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, int idx, size_t key_len, const u8 *key_data) @@ -138,10 +151,6 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, key->conf.keylen = key_len; memcpy(key->conf.key, key_data, key_len); - key->local = sdata->local; - key->sdata = sdata; - key->sta = sta; - if (alg == ALG_CCMP) { /* * Initialize AES key state here as an optimization so that @@ -154,13 +163,62 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, } } - ieee80211_debugfs_key_add(key->local, key); + return key; +} - /* remove key first */ - if (sta) - ieee80211_key_free(sta->key); - else - ieee80211_key_free(sdata->keys[idx]); +static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, + struct ieee80211_key *key, + struct ieee80211_key *new) +{ + int idx, defkey; + + if (sta) { + rcu_assign_pointer(sta->key, new); + } else { + WARN_ON(new && key && new->conf.keyidx != key->conf.keyidx); + + if (key) + idx = key->conf.keyidx; + else + idx = new->conf.keyidx; + + defkey = key && sdata->default_key == key; + + if (defkey && !new) + ieee80211_set_default_key(sdata, -1); + + rcu_assign_pointer(sdata->keys[idx], new); + + if (defkey && new) + ieee80211_set_default_key(sdata, new->conf.keyidx); + } + + if (key) { + ieee80211_key_mark_hw_accel_off(key); + list_del(&key->list); + } +} + +void ieee80211_key_link(struct ieee80211_key *key, + struct ieee80211_sub_if_data *sdata, + struct sta_info *sta) +{ + struct ieee80211_key *old_key; + int idx; + + ASSERT_RTNL(); + might_sleep(); + + BUG_ON(!sdata); + BUG_ON(!key); + + idx = key->conf.keyidx; + key->local = sdata->local; + key->sdata = sdata; + key->sta = sta; + + ieee80211_debugfs_key_add(key->local, key); if (sta) { ieee80211_debugfs_key_sta_link(key, sta); @@ -186,50 +244,53 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, } } - /* enable hwaccel if appropriate */ - if (netif_running(key->sdata->dev)) - ieee80211_key_enable_hw_accel(key); - if (sta) - rcu_assign_pointer(sta->key, key); + old_key = sta->key; else - rcu_assign_pointer(sdata->keys[idx], key); + old_key = sdata->keys[idx]; + + __ieee80211_key_replace(sdata, sta, old_key, key); list_add(&key->list, &sdata->key_list); - return key; + synchronize_rcu(); + + ieee80211_key_free(old_key); + ieee80211_key_enable_hw_accel(key); } void ieee80211_key_free(struct ieee80211_key *key) { + ASSERT_RTNL(); + might_sleep(); + if (!key) return; - if (key->sta) { - rcu_assign_pointer(key->sta->key, NULL); - } else { - if (key->sdata->default_key == key) - ieee80211_set_default_key(key->sdata, -1); - if (key->conf.keyidx >= 0 && - key->conf.keyidx < NUM_DEFAULT_KEYS) - rcu_assign_pointer(key->sdata->keys[key->conf.keyidx], - NULL); - else - WARN_ON(1); - } + if (key->sdata) { + /* + * Replace key with nothingness. + * + * Because other code may have key reference (RCU protected) + * right now, we then wait for a grace period before freeing + * it. + */ + __ieee80211_key_replace(key->sdata, key->sta, key, NULL); - /* wait for all key users to complete */ - synchronize_rcu(); + synchronize_rcu(); - /* remove from hwaccel if appropriate */ - ieee80211_key_disable_hw_accel(key); + /* + * Remove from hwaccel if appropriate, this will + * only happen when the key is actually unlinked, + * it will already be done when the key was replaced. + */ + ieee80211_key_disable_hw_accel(key); + } if (key->conf.alg == ALG_CCMP) ieee80211_aes_key_free(key->u.ccmp.tfm); ieee80211_debugfs_key_remove(key); - list_del(&key->list); - kfree(key); } @@ -253,6 +314,10 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) { struct ieee80211_key *key, *tmp; + LIST_HEAD(tmp_list); + + ASSERT_RTNL(); + might_sleep(); list_for_each_entry_safe(key, tmp, &sdata->key_list, list) ieee80211_key_free(key); @@ -262,8 +327,10 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) { struct ieee80211_key *key; - WARN_ON(!netif_running(sdata->dev)); - if (!netif_running(sdata->dev)) + ASSERT_RTNL(); + might_sleep(); + + if (WARN_ON(!netif_running(sdata->dev))) return; list_for_each_entry(key, &sdata->key_list, list) @@ -274,6 +341,9 @@ void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) { struct ieee80211_key *key; + ASSERT_RTNL(); + might_sleep(); + list_for_each_entry(key, &sdata->key_list, list) ieee80211_key_disable_hw_accel(key); } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index c6c0df4bbd2c..e384e6632d97 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -312,7 +312,7 @@ void sta_info_free(struct sta_info *sta) #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ ieee80211_key_free(sta->key); - sta->key = NULL; + WARN_ON(sta->key); if (local->ops->sta_notify) { struct ieee80211_sub_if_data *sdata; -- cgit v1.2.3-59-g8ed1b From e4861829072c61883114c64a3af61f305a789ff0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 27 Feb 2008 13:39:00 +0100 Subject: mac80211: fix key replacing, hw accel Even though I thought about it a lot and had also tested it, some of my recent changes in the key code broke replacing keys, making the kernel oops because a key is removed from a list while not on it. This patch fixes that using the list as an indication whether or not the key is on it (an empty list means it's not on any list.) Also, this patch fixes hw accel enabling, the check for not doing hw accel when the interface is down was lost and is restored by this. Additionally, move adding the key to the list into the function __ieee80211_key_replace() for more consistency. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/key.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 60aaaf471544..eac9c59dbc4d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -150,6 +150,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, key->conf.keyidx = idx; key->conf.keylen = key_len; memcpy(key->conf.key, key_data, key_len); + INIT_LIST_HEAD(&key->list); if (alg == ALG_CCMP) { /* @@ -189,6 +190,8 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, ieee80211_set_default_key(sdata, -1); rcu_assign_pointer(sdata->keys[idx], new); + if (new) + list_add(&new->list, &sdata->key_list); if (defkey && new) ieee80211_set_default_key(sdata, new->conf.keyidx); @@ -196,7 +199,11 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, if (key) { ieee80211_key_mark_hw_accel_off(key); - list_del(&key->list); + /* + * We'll use an empty list to indicate that the key + * has already been removed. + */ + list_del_init(&key->list); } } @@ -251,12 +258,13 @@ void ieee80211_key_link(struct ieee80211_key *key, __ieee80211_key_replace(sdata, sta, old_key, key); - list_add(&key->list, &sdata->key_list); - - synchronize_rcu(); + if (old_key) { + synchronize_rcu(); + ieee80211_key_free(old_key); + } - ieee80211_key_free(old_key); - ieee80211_key_enable_hw_accel(key); + if (netif_running(sdata->dev)) + ieee80211_key_enable_hw_accel(key); } void ieee80211_key_free(struct ieee80211_key *key) @@ -274,8 +282,13 @@ void ieee80211_key_free(struct ieee80211_key *key) * Because other code may have key reference (RCU protected) * right now, we then wait for a grace period before freeing * it. + * An empty list indicates it was never added to the key list + * or has been removed already. It may, however, still be in + * hardware for acceleration. */ - __ieee80211_key_replace(key->sdata, key->sta, key, NULL); + if (!list_empty(&key->list)) + __ieee80211_key_replace(key->sdata, key->sta, + key, NULL); synchronize_rcu(); -- cgit v1.2.3-59-g8ed1b From 1d1c8d13c4f7690d382bca5de2f9dc88f22a4aab Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 29 Feb 2008 14:15:19 -0800 Subject: [ICMP]: Section conflict between icmp_sk_init/icmp_sk_exit. Functions from __exit section should not be called from ones in __init section. Fix this conflict. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index b51f4b0a3264..cee77d606fbe 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -1198,7 +1198,9 @@ int __net_init icmp_sk_init(struct net *net) return 0; fail: - icmp_sk_exit(net); + for_each_possible_cpu(i) + sk_release_kernel(net->ipv4.icmp_sk[i]); + kfree(net->ipv4.icmp_sk); return err; } -- cgit v1.2.3-59-g8ed1b From da7ef338a2982a3a0c7e2b1cdfd55ba35b34471e Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 3 Mar 2008 11:50:10 -0800 Subject: [IPV4]: skb->dst can't be NULL in ip_options_echo. ip_options_echo is called on the packet input path after the initial routing. The dst entry on the packet is cleared only in the several very specific places and immidiately assigned back (may be new). Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/ip_options.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 4d315158fd3c..baaedd9689a0 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -107,10 +107,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) sptr = skb_network_header(skb); dptr = dopt->__data; - if (skb->dst) - daddr = ((struct rtable*)skb->dst)->rt_spec_dst; - else - daddr = ip_hdr(skb)->daddr; + daddr = ((struct rtable*)skb->dst)->rt_spec_dst; if (sopt->rr) { optlen = sptr[sopt->rr+1]; -- cgit v1.2.3-59-g8ed1b From f0fd56ed40ec5fb889bfc7efccd1c5759e6e9937 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 3 Mar 2008 11:55:54 -0800 Subject: [SCTP]: seq_printf format warning. (fixed) sctp_association->hbinterval is unsigned long. Replace %8d with %8lu. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/sctp/proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 82bea300308d..b99bb6bda5d5 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -325,7 +325,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "%8p %8p %-3d %-3d %-2d %-4d " "%4d %8d %8d %7d %5lu %-5d %5d " - "%8d %5d %5d %4d %4d %4d %8d ", + "%8lu %5d %5d %4d %4d %4d %8d ", assoc, sk, sctp_sk(sk)->type, sk->sk_state, assoc->state, hash, assoc->assoc_id, -- cgit v1.2.3-59-g8ed1b From 7cd04fa7e35100877592f6be4efdccac0fed62b2 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 3 Mar 2008 11:59:32 -0800 Subject: [TCP]: Merge exit paths in tcp_v4_conn_request. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 3b26f9586dcb..3873c4dbeaeb 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1355,8 +1355,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) (s32)(peer->tcp_ts - req->ts_recent) > TCP_PAWS_WINDOW) { NET_INC_STATS_BH(LINUX_MIB_PAWSPASSIVEREJECTED); - dst_release(dst); - goto drop_and_free; + goto drop_and_release; } } /* Kill the following clause, if you dislike this way. */ @@ -1376,24 +1375,21 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) "request from %u.%u.%u.%u/%u\n", NIPQUAD(saddr), ntohs(tcp_hdr(skb)->source)); - dst_release(dst); - goto drop_and_free; + goto drop_and_release; } isn = tcp_v4_init_sequence(skb); } tcp_rsk(req)->snt_isn = isn; - if (__tcp_v4_send_synack(sk, req, dst)) + if (__tcp_v4_send_synack(sk, req, dst) || want_cookie) goto drop_and_free; - if (want_cookie) { - reqsk_free(req); - } else { - inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); - } + inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); return 0; +drop_and_release: + dst_release(dst); drop_and_free: reqsk_free(req); drop: -- cgit v1.2.3-59-g8ed1b From 8ed7edce82ca0d8d3adba8c08cd42337af6c758c Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 3 Mar 2008 12:02:54 -0800 Subject: ipv6: fix inet6_init/icmpv6_cleanup sections mismatch Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- net/ipv6/icmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 9f55a965c884..8f44d49fcee2 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -844,7 +844,7 @@ static void __net_exit icmpv6_sk_exit(struct net *net) kfree(net->ipv6.icmp_sk); } -static struct pernet_operations __net_initdata icmpv6_sk_ops = { +static struct pernet_operations icmpv6_sk_ops = { .init = icmpv6_sk_init, .exit = icmpv6_sk_exit, }; @@ -868,7 +868,7 @@ fail: return err; } -void __exit icmpv6_cleanup(void) +void icmpv6_cleanup(void) { unregister_pernet_subsys(&icmpv6_sk_ops); inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); -- cgit v1.2.3-59-g8ed1b From 988b705077d8f922408913f4f521ae073256d4a1 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 3 Mar 2008 12:20:57 -0800 Subject: [ARP]: Introduce the arp_hdr_len helper. There are some place, that calculate the ARP header length. These calculations are correct, but a) some operate with "magic" constants, b) enlarge the code length (sometimes at the cost of coding style), c) are not informative from the first glance. The proposal is to introduce a helper, that includes all the good sides of these calculations. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 5 +---- include/linux/if_arp.h | 6 ++++++ net/core/netpoll.c | 6 ++---- net/ipv4/arp.c | 9 +++------ net/ipv4/ipconfig.c | 5 +---- net/ipv4/netfilter/arp_tables.c | 5 +---- 6 files changed, 14 insertions(+), 22 deletions(-) (limited to 'net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 966643473da7..5fc9d8d58ece 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2646,10 +2646,7 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack if (!slave || !slave_do_arp_validate(bond, slave)) goto out_unlock; - /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ - if (!pskb_may_pull(skb, (sizeof(struct arphdr) + - (2 * dev->addr_len) + - (2 * sizeof(u32))))) + if (!pskb_may_pull(skb, arp_hdr_len(dev))) goto out_unlock; arp = arp_hdr(skb); diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index 296e8e86e91d..4d3401812e6c 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -156,6 +156,12 @@ static inline struct arphdr *arp_hdr(const struct sk_buff *skb) { return (struct arphdr *)skb_network_header(skb); } + +static inline int arp_hdr_len(struct net_device *dev) +{ + /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ + return sizeof(struct arphdr) + (dev->addr_len + sizeof(u32)) * 2; +} #endif #endif /* _LINUX_IF_ARP_H */ diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 6faa128a4c8e..7ae98659d79d 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -384,9 +384,7 @@ static void arp_reply(struct sk_buff *skb) if (skb->dev->flags & IFF_NOARP) return; - if (!pskb_may_pull(skb, (sizeof(struct arphdr) + - (2 * skb->dev->addr_len) + - (2 * sizeof(u32))))) + if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) return; skb_reset_network_header(skb); @@ -414,7 +412,7 @@ static void arp_reply(struct sk_buff *skb) ipv4_is_loopback(tip) || ipv4_is_multicast(tip)) return; - size = sizeof(struct arphdr) + 2 * (skb->dev->addr_len + 4); + size = arp_hdr_len(skb->dev); send_skb = find_skb(np, size + LL_RESERVED_SPACE(np->dev), LL_RESERVED_SPACE(np->dev)); diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 8e17f65f4002..69e80bd9774a 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -570,14 +570,13 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, * Allocate a buffer */ - skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) - + LL_RESERVED_SPACE(dev), GFP_ATOMIC); + skb = alloc_skb(arp_hdr_len(dev) + LL_RESERVED_SPACE(dev), GFP_ATOMIC); if (skb == NULL) return NULL; skb_reserve(skb, LL_RESERVED_SPACE(dev)); skb_reset_network_header(skb); - arp = (struct arphdr *) skb_put(skb,sizeof(struct arphdr) + 2*(dev->addr_len+4)); + arp = (struct arphdr *) skb_put(skb, arp_hdr_len(dev)); skb->dev = dev; skb->protocol = htons(ETH_P_ARP); if (src_hw == NULL) @@ -916,9 +915,7 @@ static int arp_rcv(struct sk_buff *skb, struct net_device *dev, goto freeskb; /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ - if (!pskb_may_pull(skb, (sizeof(struct arphdr) + - (2 * dev->addr_len) + - (2 * sizeof(u32))))) + if (!pskb_may_pull(skb, arp_hdr_len(dev))) goto freeskb; arp = arp_hdr(skb); diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index c90e75a66e81..f84041d1f623 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -459,10 +459,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt if (rarp->ar_pro != htons(ETH_P_IP)) goto drop; - if (!pskb_may_pull(skb, - sizeof(struct arphdr) + - (2 * dev->addr_len) + - (2 * 4))) + if (!pskb_may_pull(skb, arp_hdr_len(dev))) goto drop; /* OK, it is all there and looks valid, process... */ diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index a7591ce344d2..9b5904486184 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -233,10 +233,7 @@ unsigned int arpt_do_table(struct sk_buff *skb, void *table_base; struct xt_table_info *private; - /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ - if (!pskb_may_pull(skb, (sizeof(struct arphdr) + - (2 * skb->dev->addr_len) + - (2 * sizeof(u32))))) + if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) return NF_DROP; indev = in ? in->name : nulldevname; -- cgit v1.2.3-59-g8ed1b From 11baab7ac34723ad481e0f97fca733272ef364d4 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 7 Feb 2008 10:40:19 +0100 Subject: [TCP]: lower stack usage in cookie_hash() function 400 bytes allocated on stack might be a litle bit too much. Using a per_cpu var is more friendly. Signed-off-by: Eric Dumazet Signed-off-by: YOSHIFUJI Hideaki --- net/ipv4/syncookies.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index f470fe4511db..177da14f6b14 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -35,10 +35,12 @@ module_init(init_syncookies); #define COOKIEBITS 24 /* Upper bits store count */ #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) +static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS]; + static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, u32 count, int c) { - __u32 tmp[16 + 5 + SHA_WORKSPACE_WORDS]; + __u32 *tmp = __get_cpu_var(cookie_scratch); memcpy(tmp + 3, syncookie_secret[c], sizeof(syncookie_secret[c])); tmp[0] = (__force u32)saddr; -- cgit v1.2.3-59-g8ed1b From c6aefafb7ec620911d46174eed514f9df639e5a4 Mon Sep 17 00:00:00 2001 From: Glenn Griffin Date: Thu, 7 Feb 2008 21:49:26 -0800 Subject: [TCP]: Add IPv6 support to TCP SYN cookies Updated to incorporate Eric's suggestion of using a per cpu buffer rather than allocating on the stack. Just a two line change, but will resend in it's entirety. Signed-off-by: Glenn Griffin Signed-off-by: YOSHIFUJI Hideaki --- include/net/tcp.h | 8 ++ net/ipv4/syncookies.c | 7 +- net/ipv4/tcp_input.c | 1 + net/ipv4/tcp_minisocks.c | 2 + net/ipv4/tcp_output.c | 1 + net/ipv6/Makefile | 1 + net/ipv6/syncookies.c | 267 +++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/tcp_ipv6.c | 77 ++++++++++---- 8 files changed, 338 insertions(+), 26 deletions(-) create mode 100644 net/ipv6/syncookies.c (limited to 'net') diff --git a/include/net/tcp.h b/include/net/tcp.h index ae9774b478f5..11119e33acfe 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -434,11 +435,17 @@ extern int tcp_disconnect(struct sock *sk, int flags); extern void tcp_unhash(struct sock *sk); /* From syncookies.c */ +extern __u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS]; extern struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, struct ip_options *opt); extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mss); +/* From net/ipv6/syncookies.c */ +extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb); +extern __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, + __u16 *mss); + /* tcp_output.c */ extern void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss, @@ -1332,6 +1339,7 @@ extern int tcp_proc_register(struct tcp_seq_afinfo *afinfo); extern void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo); extern struct request_sock_ops tcp_request_sock_ops; +extern struct request_sock_ops tcp6_request_sock_ops; extern int tcp_v4_destroy_sock(struct sock *sk); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 177da14f6b14..4704f27f6c0b 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -10,8 +10,6 @@ * 2 of the License, or (at your option) any later version. * * $Id: syncookies.c,v 1.18 2002/02/01 22:01:04 davem Exp $ - * - * Missing: IPv6 support. */ #include @@ -23,14 +21,15 @@ extern int sysctl_tcp_syncookies; -static __u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS]; +__u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS]; +EXPORT_SYMBOL(syncookie_secret); static __init int init_syncookies(void) { get_random_bytes(syncookie_secret, sizeof(syncookie_secret)); return 0; } -module_init(init_syncookies); +__initcall(init_syncookies); #define COOKIEBITS 24 /* Upper bits store count */ #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 19c449f62672..93e128c239c4 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -5326,6 +5326,7 @@ discard: EXPORT_SYMBOL(sysctl_tcp_ecn); EXPORT_SYMBOL(sysctl_tcp_reordering); +EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); EXPORT_SYMBOL(tcp_parse_options); EXPORT_SYMBOL(tcp_rcv_established); EXPORT_SYMBOL(tcp_rcv_state_process); diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 0fdd1db641ac..8245247a6ceb 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -35,6 +35,8 @@ #endif int sysctl_tcp_syncookies __read_mostly = SYNC_INIT; +EXPORT_SYMBOL(sysctl_tcp_syncookies); + int sysctl_tcp_abort_on_overflow __read_mostly; struct inet_timewait_death_row tcp_death_row = { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index ed750f9ceb07..cbfef8b1f5e8 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2560,6 +2560,7 @@ void tcp_send_probe0(struct sock *sk) } } +EXPORT_SYMBOL(tcp_select_initial_window); EXPORT_SYMBOL(tcp_connect); EXPORT_SYMBOL(tcp_make_synack); EXPORT_SYMBOL(tcp_simple_retransmit); diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 24f3aa0f2a35..ae14617e607f 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -16,6 +16,7 @@ ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ ipv6-$(CONFIG_NETFILTER) += netfilter.o ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o ipv6-$(CONFIG_PROC_FS) += proc.o +ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o ipv6-objs += $(ipv6-y) diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c new file mode 100644 index 000000000000..827c5aa7524c --- /dev/null +++ b/net/ipv6/syncookies.c @@ -0,0 +1,267 @@ +/* + * IPv6 Syncookies implementation for the Linux kernel + * + * Authors: + * Glenn Griffin + * + * Based on IPv4 implementation by Andi Kleen + * linux/net/ipv4/syncookies.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +extern int sysctl_tcp_syncookies; +extern __u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS]; + +#define COOKIEBITS 24 /* Upper bits store count */ +#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) + +/* + * This table has to be sorted and terminated with (__u16)-1. + * XXX generate a better table. + * Unresolved Issues: HIPPI with a 64k MSS is not well supported. + * + * Taken directly from ipv4 implementation. + * Should this list be modified for ipv6 use or is it close enough? + * rfc 2460 8.3 suggests mss values 20 bytes less than ipv4 counterpart + */ +static __u16 const msstab[] = { + 64 - 1, + 256 - 1, + 512 - 1, + 536 - 1, + 1024 - 1, + 1440 - 1, + 1460 - 1, + 4312 - 1, + (__u16)-1 +}; +/* The number doesn't include the -1 terminator */ +#define NUM_MSS (ARRAY_SIZE(msstab) - 1) + +/* + * This (misnamed) value is the age of syncookie which is permitted. + * Its ideal value should be dependent on TCP_TIMEOUT_INIT and + * sysctl_tcp_retries1. It's a rather complicated formula (exponential + * backoff) to compute at runtime so it's currently hardcoded here. + */ +#define COUNTER_TRIES 4 + +static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb, + struct request_sock *req, + struct dst_entry *dst) +{ + struct inet_connection_sock *icsk = inet_csk(sk); + struct sock *child; + + child = icsk->icsk_af_ops->syn_recv_sock(sk, skb, req, dst); + if (child) + inet_csk_reqsk_queue_add(sk, req, child); + else + reqsk_free(req); + + return child; +} + +static DEFINE_PER_CPU(__u32, cookie_scratch)[16 + 5 + SHA_WORKSPACE_WORDS]; + +static u32 cookie_hash(struct in6_addr *saddr, struct in6_addr *daddr, + __be16 sport, __be16 dport, u32 count, int c) +{ + __u32 *tmp = __get_cpu_var(cookie_scratch); + + /* + * we have 320 bits of information to hash, copy in the remaining + * 192 bits required for sha_transform, from the syncookie_secret + * and overwrite the digest with the secret + */ + memcpy(tmp + 10, syncookie_secret[c], 44); + memcpy(tmp, saddr, 16); + memcpy(tmp + 4, daddr, 16); + tmp[8] = ((__force u32)sport << 16) + (__force u32)dport; + tmp[9] = count; + sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5); + + return tmp[17]; +} + +static __u32 secure_tcp_syn_cookie(struct in6_addr *saddr, struct in6_addr *daddr, + __be16 sport, __be16 dport, __u32 sseq, + __u32 count, __u32 data) +{ + return (cookie_hash(saddr, daddr, sport, dport, 0, 0) + + sseq + (count << COOKIEBITS) + + ((cookie_hash(saddr, daddr, sport, dport, count, 1) + data) + & COOKIEMASK)); +} + +static __u32 check_tcp_syn_cookie(__u32 cookie, struct in6_addr *saddr, + struct in6_addr *daddr, __be16 sport, + __be16 dport, __u32 sseq, __u32 count, + __u32 maxdiff) +{ + __u32 diff; + + cookie -= cookie_hash(saddr, daddr, sport, dport, 0, 0) + sseq; + + diff = (count - (cookie >> COOKIEBITS)) & ((__u32) -1 >> COOKIEBITS); + if (diff >= maxdiff) + return (__u32)-1; + + return (cookie - + cookie_hash(saddr, daddr, sport, dport, count - diff, 1)) + & COOKIEMASK; +} + +__u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp) +{ + struct ipv6hdr *iph = ipv6_hdr(skb); + const struct tcphdr *th = tcp_hdr(skb); + int mssind; + const __u16 mss = *mssp; + + tcp_sk(sk)->last_synq_overflow = jiffies; + + for (mssind = 0; mss > msstab[mssind + 1]; mssind++) + ; + *mssp = msstab[mssind] + 1; + + NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESSENT); + + return secure_tcp_syn_cookie(&iph->saddr, &iph->daddr, th->source, + th->dest, ntohl(th->seq), + jiffies / (HZ * 60), mssind); +} + +static inline int cookie_check(struct sk_buff *skb, __u32 cookie) +{ + struct ipv6hdr *iph = ipv6_hdr(skb); + const struct tcphdr *th = tcp_hdr(skb); + __u32 seq = ntohl(th->seq) - 1; + __u32 mssind = check_tcp_syn_cookie(cookie, &iph->saddr, &iph->daddr, + th->source, th->dest, seq, + jiffies / (HZ * 60), COUNTER_TRIES); + + return mssind < NUM_MSS ? msstab[mssind] + 1 : 0; +} + +struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) +{ + struct inet_request_sock *ireq; + struct inet6_request_sock *ireq6; + struct tcp_request_sock *treq; + struct ipv6_pinfo *np = inet6_sk(sk); + struct tcp_sock *tp = tcp_sk(sk); + const struct tcphdr *th = tcp_hdr(skb); + __u32 cookie = ntohl(th->ack_seq) - 1; + struct sock *ret = sk; + struct request_sock *req; + int mss; + struct dst_entry *dst; + __u8 rcv_wscale; + + if (!sysctl_tcp_syncookies || !th->ack) + goto out; + + if (time_after(jiffies, tp->last_synq_overflow + TCP_TIMEOUT_INIT) || + (mss = cookie_check(skb, cookie)) == 0) { + NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESFAILED); + goto out; + } + + NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV); + + ret = NULL; + req = inet6_reqsk_alloc(&tcp6_request_sock_ops); + if (!req) + goto out; + + ireq = inet_rsk(req); + ireq6 = inet6_rsk(req); + treq = tcp_rsk(req); + ireq6->pktopts = NULL; + + if (security_inet_conn_request(sk, skb, req)) { + reqsk_free(req); + goto out; + } + + req->mss = mss; + ireq->rmt_port = th->source; + ipv6_addr_copy(&ireq6->rmt_addr, &ipv6_hdr(skb)->saddr); + ipv6_addr_copy(&ireq6->loc_addr, &ipv6_hdr(skb)->daddr); + if (ipv6_opt_accepted(sk, skb) || + np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || + np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { + atomic_inc(&skb->users); + ireq6->pktopts = skb; + } + + ireq6->iif = sk->sk_bound_dev_if; + /* So that link locals have meaning */ + if (!sk->sk_bound_dev_if && + ipv6_addr_type(&ireq6->rmt_addr) & IPV6_ADDR_LINKLOCAL) + ireq6->iif = inet6_iif(skb); + + req->expires = 0UL; + req->retrans = 0; + ireq->snd_wscale = ireq->rcv_wscale = ireq->tstamp_ok = 0; + ireq->wscale_ok = ireq->sack_ok = 0; + treq->rcv_isn = ntohl(th->seq) - 1; + treq->snt_isn = cookie; + + /* + * We need to lookup the dst_entry to get the correct window size. + * This is taken from tcp_v6_syn_recv_sock. Somebody please enlighten + * me if there is a preferred way. + */ + { + struct in6_addr *final_p = NULL, final; + struct flowi fl; + memset(&fl, 0, sizeof(fl)); + fl.proto = IPPROTO_TCP; + ipv6_addr_copy(&fl.fl6_dst, &ireq6->rmt_addr); + if (np->opt && np->opt->srcrt) { + struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; + ipv6_addr_copy(&final, &fl.fl6_dst); + ipv6_addr_copy(&fl.fl6_dst, rt0->addr); + final_p = &final; + } + ipv6_addr_copy(&fl.fl6_src, &ireq6->loc_addr); + fl.oif = sk->sk_bound_dev_if; + fl.fl_ip_dport = inet_rsk(req)->rmt_port; + fl.fl_ip_sport = inet_sk(sk)->sport; + security_req_classify_flow(req, &fl); + if (ip6_dst_lookup(sk, &dst, &fl)) { + reqsk_free(req); + goto out; + } + if (final_p) + ipv6_addr_copy(&fl.fl6_dst, final_p); + if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0) + goto out; + } + + req->window_clamp = dst_metric(dst, RTAX_WINDOW); + tcp_select_initial_window(tcp_full_space(sk), req->mss, + &req->rcv_wnd, &req->window_clamp, + 0, &rcv_wscale); + + ireq->rcv_wscale = rcv_wscale; + + ret = get_cookie_sock(sk, skb, req, dst); + +out: return ret; +} + diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 1cbbb87dbad2..fd773ac7531a 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -512,6 +512,20 @@ done: return err; } +static inline void syn_flood_warning(struct sk_buff *skb) +{ +#ifdef CONFIG_SYN_COOKIES + if (sysctl_tcp_syncookies) + printk(KERN_INFO + "TCPv6: Possible SYN flooding on port %d. " + "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest)); + else +#endif + printk(KERN_INFO + "TCPv6: Possible SYN flooding on port %d. " + "Dropping request.\n", ntohs(tcp_hdr(skb)->dest)); +} + static void tcp_v6_reqsk_destructor(struct request_sock *req) { if (inet6_rsk(req)->pktopts) @@ -915,7 +929,7 @@ done_opts: } #endif -static struct request_sock_ops tcp6_request_sock_ops __read_mostly = { +struct request_sock_ops tcp6_request_sock_ops __read_mostly = { .family = AF_INET6, .obj_size = sizeof(struct tcp6_request_sock), .rtx_syn_ack = tcp_v6_send_synack, @@ -1213,9 +1227,9 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) return NULL; } -#if 0 /*def CONFIG_SYN_COOKIES*/ +#ifdef CONFIG_SYN_COOKIES if (!th->rst && !th->syn && th->ack) - sk = cookie_v6_check(sk, skb, &(IPCB(skb)->opt)); + sk = cookie_v6_check(sk, skb); #endif return sk; } @@ -1231,6 +1245,11 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) struct tcp_sock *tp = tcp_sk(sk); struct request_sock *req = NULL; __u32 isn = TCP_SKB_CB(skb)->when; +#ifdef CONFIG_SYN_COOKIES + int want_cookie = 0; +#else +#define want_cookie 0 +#endif if (skb->protocol == htons(ETH_P_IP)) return tcp_v4_conn_request(sk, skb); @@ -1238,12 +1257,14 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) if (!ipv6_unicast_destination(skb)) goto drop; - /* - * There are no SYN attacks on IPv6, yet... - */ if (inet_csk_reqsk_queue_is_full(sk) && !isn) { if (net_ratelimit()) - printk(KERN_INFO "TCPv6: dropping request, synflood is possible\n"); + syn_flood_warning(skb); +#ifdef CONFIG_SYN_COOKIES + if (sysctl_tcp_syncookies) + want_cookie = 1; + else +#endif goto drop; } @@ -1264,29 +1285,39 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) tcp_parse_options(skb, &tmp_opt, 0); + if (want_cookie) { + tcp_clear_options(&tmp_opt); + tmp_opt.saw_tstamp = 0; + } + tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; tcp_openreq_init(req, &tmp_opt, skb); treq = inet6_rsk(req); ipv6_addr_copy(&treq->rmt_addr, &ipv6_hdr(skb)->saddr); ipv6_addr_copy(&treq->loc_addr, &ipv6_hdr(skb)->daddr); - TCP_ECN_create_request(req, tcp_hdr(skb)); treq->pktopts = NULL; - if (ipv6_opt_accepted(sk, skb) || - np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || - np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { - atomic_inc(&skb->users); - treq->pktopts = skb; - } - treq->iif = sk->sk_bound_dev_if; + if (!want_cookie) + TCP_ECN_create_request(req, tcp_hdr(skb)); + + if (want_cookie) { + isn = cookie_v6_init_sequence(sk, skb, &req->mss); + } else if (!isn) { + if (ipv6_opt_accepted(sk, skb) || + np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || + np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) { + atomic_inc(&skb->users); + treq->pktopts = skb; + } + treq->iif = sk->sk_bound_dev_if; - /* So that link locals have meaning */ - if (!sk->sk_bound_dev_if && - ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) - treq->iif = inet6_iif(skb); + /* So that link locals have meaning */ + if (!sk->sk_bound_dev_if && + ipv6_addr_type(&treq->rmt_addr) & IPV6_ADDR_LINKLOCAL) + treq->iif = inet6_iif(skb); - if (isn == 0) isn = tcp_v6_init_sequence(skb); + } tcp_rsk(req)->snt_isn = isn; @@ -1295,8 +1326,10 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) if (tcp_v6_send_synack(sk, req)) goto drop; - inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); - return 0; + if (!want_cookie) { + inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); + return 0; + } drop: if (req) -- cgit v1.2.3-59-g8ed1b From e898d4db2749c6052072e9bc4448e396cbdeb06a Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sat, 1 Mar 2008 01:06:47 +0900 Subject: [UDP]: Allow users to configure UDP-Lite. Let's give users an option for disabling UDP-Lite (~4K). old: | text data bss dec hex filename | 286498 12432 6072 305002 4a76a net/ipv4/built-in.o | 193830 8192 3204 205226 321aa net/ipv6/ipv6.o new (without UDP-Lite): | text data bss dec hex filename | 284086 12136 5432 301654 49a56 net/ipv4/built-in.o | 191835 7832 3076 202743 317f7 net/ipv6/ipv6.o Signed-off-by: YOSHIFUJI Hideaki --- include/linux/udp.h | 11 +++++++++++ include/net/ipv6.h | 5 +++++ include/net/transp_v6.h | 5 +++++ include/net/udplite.h | 9 +++++++-- net/ipv4/Kconfig | 10 ++++++++++ net/ipv4/Makefile | 3 ++- net/ipv4/af_inet.c | 7 ++++++- net/ipv4/proc.c | 5 ++++- net/ipv4/udp.c | 24 ++++++++++++++---------- net/ipv6/Makefile | 3 ++- net/ipv6/af_inet6.c | 14 ++++++++++++++ net/ipv6/ipv6_sockglue.c | 6 +++++- net/ipv6/proc.c | 6 ++++++ net/ipv6/udp.c | 16 ++++++++-------- 14 files changed, 99 insertions(+), 25 deletions(-) (limited to 'net') diff --git a/include/linux/udp.h b/include/linux/udp.h index 8ec703f462da..4144664d69d9 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -70,8 +70,10 @@ struct udp_sock { #define UDPLITE_BIT 0x1 /* set by udplite proto init function */ #define UDPLITE_SEND_CC 0x2 /* set via udplite setsockopt */ #define UDPLITE_RECV_CC 0x4 /* set via udplite setsocktopt */ +#ifdef CONFIG_IP_UDPLITE __u8 pcflag; /* marks socket as UDP-Lite if > 0 */ __u8 unused[3]; +#endif /* * For encapsulation sockets. */ @@ -82,7 +84,16 @@ static inline struct udp_sock *udp_sk(const struct sock *sk) { return (struct udp_sock *)sk; } + +#ifdef CONFIG_IP_UDPLITE #define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag) +#define IS_PROTO_UDPLITE(__proto) ((__proto) == IPPROTO_UDPLITE) +#define IS_SOL_UDPFAMILY(level) ((level) == SOL_UDP || (level) == SOL_UDPLITE) +#else +#define IS_UDPLITE(__sk) 0 +#define IS_PROTO_UDPLITE(__proto) 0 +#define IS_SOL_UDPFAMILY(level) ((level) == SOL_UDP) +#endif #endif diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 8b05c65415cb..96b1763bfcaa 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -603,8 +603,13 @@ extern int tcp6_proc_init(void); extern void tcp6_proc_exit(void); extern int udp6_proc_init(void); extern void udp6_proc_exit(void); +#ifdef CONFIG_IP_UDPLITE extern int udplite6_proc_init(void); extern void udplite6_proc_exit(void); +#else +static inline int udplite6_proc_init(void) { return 0; } +static inline void udplite6_proc_exit(void) { } +#endif extern int ipv6_misc_proc_init(void); extern void ipv6_misc_proc_exit(void); extern int snmp6_register_dev(struct inet6_dev *idev); diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index 27394e0447d8..902e6c6bc793 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h @@ -27,8 +27,13 @@ extern int rawv6_init(void); extern void rawv6_exit(void); extern int udpv6_init(void); extern void udpv6_exit(void); +#ifdef CONFIG_IP_UDPLITE extern int udplitev6_init(void); extern void udplitev6_exit(void); +#else +static inline int udplitev6_init(void) { return 0; } +static inline void udplitev6_exit(void) { } +#endif extern int tcpv6_init(void); extern void tcpv6_exit(void); diff --git a/include/net/udplite.h b/include/net/udplite.h index b76b2e377af4..01ddb2c20264 100644 --- a/include/net/udplite.h +++ b/include/net/udplite.h @@ -25,7 +25,9 @@ static __inline__ int udplite_getfrag(void *from, char *to, int offset, /* Designate sk as UDP-Lite socket */ static inline int udplite_sk_init(struct sock *sk) { +#ifdef CONFIG_IP_UDPLITE udp_sk(sk)->pcflag = UDPLITE_BIT; +#endif return 0; } @@ -69,7 +71,7 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) { int cscov = up->len; - +#ifdef CONFIG_IP_UDPLITE /* * Sender has set `partial coverage' option on UDP-Lite socket */ @@ -93,13 +95,15 @@ static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) * illegal, we fall back to the defaults here. */ } +#endif return cscov; } static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) { - int cscov = udplite_sender_cscov(udp_sk(sk), udp_hdr(skb)); __wsum csum = 0; +#ifdef CONFIG_IP_UDPLITE + int cscov = udplite_sender_cscov(udp_sk(sk), udp_hdr(skb)); skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ @@ -112,6 +116,7 @@ static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) if ((cscov -= len) <= 0) break; } +#endif return csum; } diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 19880b086e71..efe3832c4ad8 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -632,5 +632,15 @@ config TCP_MD5SIG If unsure, say N. +config IP_UDPLITE + bool "IP: UDP-Lite Protocol (RFC 3828)" + default n + ---help--- + UDP-Lite (RFC 3828) is a UDP-like protocol with variable-length + checksum. Read for + details. + + If unsure, say N. + source "net/ipv4/ipvs/Kconfig" diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index ad40ef3f9ebc..e88cebdf3e30 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -8,7 +8,7 @@ obj-y := route.o inetpeer.o protocol.o \ inet_timewait_sock.o inet_connection_sock.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ tcp_minisocks.o tcp_cong.o \ - datagram.o raw.o udp.o udplite.o \ + datagram.o raw.o udp.o \ arp.o icmp.o devinet.o af_inet.o igmp.o \ fib_frontend.o fib_semantics.o \ inet_fragment.o @@ -49,6 +49,7 @@ obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o +obj-$(CONFIG_IP_UDPLITE) += udplite.o obj-$(CONFIG_NETLABEL) += cipso_ipv4.o obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 4f539bd48718..67260c0eaaa8 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1317,15 +1317,18 @@ static int __init init_ipv4_mibs(void) if (snmp_mib_init((void **)udp_statistics, sizeof(struct udp_mib)) < 0) goto err_udp_mib; +#ifdef CONFIG_IP_UDPLITE if (snmp_mib_init((void **)udplite_statistics, sizeof(struct udp_mib)) < 0) goto err_udplite_mib; - +#endif tcp_mib_init(); return 0; +#ifdef CONFIG_IP_UDPLITE err_udplite_mib: +#endif snmp_mib_free((void **)udp_statistics); err_udp_mib: snmp_mib_free((void **)tcp_statistics); @@ -1423,8 +1426,10 @@ static int __init inet_init(void) /* Setup UDP memory threshold */ udp_init(); +#ifdef CONFIG_IP_UDPLITE /* Add UDP-Lite (RFC 3828) */ udplite4_register(); +#endif /* * Set the ICMP layer up diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index d63474c6b400..d75ddb7fa4b8 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -59,7 +59,9 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) atomic_read(&tcp_memory_allocated)); seq_printf(seq, "UDP: inuse %d mem %d\n", sock_prot_inuse_get(&udp_prot), atomic_read(&udp_memory_allocated)); +#ifdef CONFIG_IP_UDPLITE seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse_get(&udplite_prot)); +#endif seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse_get(&raw_prot)); seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues(&init_net), ip_frag_mem(&init_net)); @@ -349,6 +351,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) snmp_fold_field((void **)udp_statistics, snmp4_udp_list[i].entry)); +#ifdef CONFIG_IP_UDPLITE /* the UDP and UDP-Lite MIBs are the same */ seq_puts(seq, "\nUdpLite:"); for (i = 0; snmp4_udp_list[i].name != NULL; i++) @@ -359,7 +362,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) seq_printf(seq, " %lu", snmp_fold_field((void **)udplite_statistics, snmp4_udp_list[i].entry)); - +#endif seq_putc(seq, '\n'); return 0; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 7ea1b67b6de1..acc353aa89eb 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1127,7 +1127,7 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, UDP_SKB_CB(skb)->partial_cov = 0; UDP_SKB_CB(skb)->cscov = skb->len; - if (proto == IPPROTO_UDPLITE) { + if (IS_PROTO_UDPLITE(proto)) { err = udplite_checksum_init(skb, uh); if (err) return err; @@ -1175,7 +1175,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], if (ulen > skb->len) goto short_packet; - if (proto == IPPROTO_UDP) { + if (IS_PROTO_UDPLITE(proto)) { /* UDP validates ulen. */ if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) goto short_packet; @@ -1217,7 +1217,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], if (udp_lib_checksum_complete(skb)) goto csum_error; - UDP_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); + UDP_INC_STATS_BH(UDP_MIB_NOPORTS, IS_PROTO_UDPLITE(proto)); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); /* @@ -1229,7 +1229,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], short_packet: LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", - proto == IPPROTO_UDPLITE ? "-Lite" : "", + IS_PROTO_UDPLITE(proto) ? "-Lite" : "", NIPQUAD(saddr), ntohs(uh->source), ulen, @@ -1244,14 +1244,14 @@ csum_error: * the network is concerned, anyway) as per 4.1.3.4 (MUST). */ LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", - proto == IPPROTO_UDPLITE ? "-Lite" : "", + IS_PROTO_UDPLITE(proto) ? "-Lite" : "", NIPQUAD(saddr), ntohs(uh->source), NIPQUAD(daddr), ntohs(uh->dest), ulen); drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); + UDP_INC_STATS_BH(UDP_MIB_INERRORS, IS_PROTO_UDPLITE(proto)); kfree_skb(skb); return 0; } @@ -1279,7 +1279,9 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, struct udp_sock *up = udp_sk(sk); int val; int err = 0; +#ifdef CONFIG_IP_UDPLITE int is_udplite = IS_UDPLITE(sk); +#endif if (optlenpcrlen = val; up->pcflag |= UDPLITE_RECV_CC; break; +#endif default: err = -ENOPROTOOPT; @@ -1352,7 +1356,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, int udp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_setsockopt(sk, level, optname, optval, optlen, udp_push_pending_frames); return ip_setsockopt(sk, level, optname, optval, optlen); @@ -1362,7 +1366,7 @@ int udp_setsockopt(struct sock *sk, int level, int optname, int compat_udp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_setsockopt(sk, level, optname, optval, optlen, udp_push_pending_frames); return compat_ip_setsockopt(sk, level, optname, optval, optlen); @@ -1416,7 +1420,7 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname, int udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_getsockopt(sk, level, optname, optval, optlen); return ip_getsockopt(sk, level, optname, optval, optlen); } @@ -1425,7 +1429,7 @@ int udp_getsockopt(struct sock *sk, int level, int optname, int compat_udp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_getsockopt(sk, level, optname, optval, optlen); return compat_ip_getsockopt(sk, level, optname, optval, optlen); } diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index ae14617e607f..81969479955f 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_IPV6) += ipv6.o ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ addrlabel.o \ - route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \ + route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o \ raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o @@ -17,6 +17,7 @@ ipv6-$(CONFIG_NETFILTER) += netfilter.o ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o ipv6-$(CONFIG_PROC_FS) += proc.o ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o +ipv6-$(CONFIG_IP_UDPLITE) += udplite.o ipv6-objs += $(ipv6-y) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 9869f87243cf..243c42a6b80d 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -691,12 +691,16 @@ static int __init init_ipv6_mibs(void) goto err_icmpmsg_mib; if (snmp_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib)) < 0) goto err_udp_mib; +#ifdef CONFIG_IP_UDPLITE if (snmp_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib)) < 0) goto err_udplite_mib; +#endif return 0; +#ifdef CONFIG_IP_UDPLITE err_udplite_mib: +#endif snmp_mib_free((void **)udp_stats_in6); err_udp_mib: snmp_mib_free((void **)icmpv6msg_statistics); @@ -715,7 +719,9 @@ static void cleanup_ipv6_mibs(void) snmp_mib_free((void **)icmpv6_statistics); snmp_mib_free((void **)icmpv6msg_statistics); snmp_mib_free((void **)udp_stats_in6); +#ifdef CONFIG_IP_UDPLITE snmp_mib_free((void **)udplite_stats_in6); +#endif } static int inet6_net_init(struct net *net) @@ -760,9 +766,11 @@ static int __init inet6_init(void) if (err) goto out_unregister_tcp_proto; +#ifdef CONFIG_IP_UDPLITE err = proto_register(&udplitev6_prot, 1); if (err) goto out_unregister_udp_proto; +#endif err = proto_register(&rawv6_prot, 1); if (err) @@ -933,8 +941,10 @@ out_sock_register_fail: out_unregister_raw_proto: proto_unregister(&rawv6_prot); out_unregister_udplite_proto: +#ifdef CONFIG_IP_UDPLITE proto_unregister(&udplitev6_prot); out_unregister_udp_proto: +#endif proto_unregister(&udpv6_prot); out_unregister_tcp_proto: proto_unregister(&tcpv6_prot); @@ -950,7 +960,9 @@ static void __exit inet6_exit(void) rtnl_unregister_all(PF_INET6); udpv6_exit(); +#ifdef CONFIG_IP_UDPLITE udplitev6_exit(); +#endif tcpv6_exit(); /* Cleanup code parts. */ @@ -982,7 +994,9 @@ static void __exit inet6_exit(void) unregister_pernet_subsys(&inet6_net_ops); cleanup_ipv6_mibs(); proto_unregister(&rawv6_prot); +#ifdef CONFIG_IP_UDPLITE proto_unregister(&udplitev6_prot); +#endif proto_unregister(&udpv6_prot); proto_unregister(&tcpv6_prot); } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index bf2a686aa13d..0a18fecb93d1 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -239,7 +239,9 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, struct sk_buff *pktopt; if (sk->sk_protocol != IPPROTO_UDP && +#ifdef CONFIG_IP_UDPLITE sk->sk_protocol != IPPROTO_UDPLITE && +#endif sk->sk_protocol != IPPROTO_TCP) break; @@ -279,7 +281,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, } else { struct proto *prot = &udp_prot; - if (sk->sk_protocol == IPPROTO_UDPLITE) + if (IS_PROTO_UDPLITE(sk->sk_protocol)) prot = &udplite_prot; local_bh_disable(); sock_prot_inuse_add(sk->sk_prot, -1); @@ -844,7 +846,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, switch (optname) { case IPV6_ADDRFORM: if (sk->sk_protocol != IPPROTO_UDP && +#ifdef CONFIG_IP_UDPLITE sk->sk_protocol != IPPROTO_UDPLITE && +#endif sk->sk_protocol != IPPROTO_TCP) return -EINVAL; if (sk->sk_state != TCP_ESTABLISHED) diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 199ef379e501..5ba7ae849d04 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -39,8 +39,10 @@ static int sockstat6_seq_show(struct seq_file *seq, void *v) sock_prot_inuse_get(&tcpv6_prot)); seq_printf(seq, "UDP6: inuse %d\n", sock_prot_inuse_get(&udpv6_prot)); +#ifdef CONFIG_IP_UDPLITE seq_printf(seq, "UDPLITE6: inuse %d\n", sock_prot_inuse_get(&udplitev6_prot)); +#endif seq_printf(seq, "RAW6: inuse %d\n", sock_prot_inuse_get(&rawv6_prot)); seq_printf(seq, "FRAG6: inuse %d memory %d\n", @@ -111,6 +113,7 @@ static struct snmp_mib snmp6_udp6_list[] = { SNMP_MIB_SENTINEL }; +#ifdef CONFIG_IP_UDPLITE static struct snmp_mib snmp6_udplite6_list[] = { SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), @@ -118,6 +121,7 @@ static struct snmp_mib snmp6_udplite6_list[] = { SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), SNMP_MIB_SENTINEL }; +#endif static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib) { @@ -176,7 +180,9 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list); snmp6_seq_show_icmpv6msg(seq, (void **)icmpv6msg_statistics); snmp6_seq_show_item(seq, (void **)udp_stats_in6, snmp6_udp6_list); +#ifdef CONFIG_IP_UDPLITE snmp6_seq_show_item(seq, (void **)udplite_stats_in6, snmp6_udplite6_list); +#endif } return 0; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 53739de829db..55feac7ba717 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -400,7 +400,7 @@ static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, UDP_SKB_CB(skb)->partial_cov = 0; UDP_SKB_CB(skb)->cscov = skb->len; - if (proto == IPPROTO_UDPLITE) { + if (IS_PROTO_UDPLITE(proto)) { err = udplite_checksum_init(skb, uh); if (err) return err; @@ -489,7 +489,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], if (udp_lib_checksum_complete(skb)) goto discard; - UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); + UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, IS_PROTO_UDPLITE(proto)); icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); @@ -510,11 +510,11 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], short_packet: LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", - proto == IPPROTO_UDPLITE ? "-Lite" : "", + IS_PROTO_UDPLITE(proto) ? "-Lite" : "", ulen, skb->len); discard: - UDP6_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); + UDP6_INC_STATS_BH(UDP_MIB_INERRORS, IS_PROTO_UDPLITE(proto)); kfree_skb(skb); return 0; } @@ -890,7 +890,7 @@ int udpv6_destroy_sock(struct sock *sk) int udpv6_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_setsockopt(sk, level, optname, optval, optlen, udp_v6_push_pending_frames); return ipv6_setsockopt(sk, level, optname, optval, optlen); @@ -900,7 +900,7 @@ int udpv6_setsockopt(struct sock *sk, int level, int optname, int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_setsockopt(sk, level, optname, optval, optlen, udp_v6_push_pending_frames); return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); @@ -910,7 +910,7 @@ int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, int udpv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_getsockopt(sk, level, optname, optval, optlen); return ipv6_getsockopt(sk, level, optname, optval, optlen); } @@ -919,7 +919,7 @@ int udpv6_getsockopt(struct sock *sk, int level, int optname, int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { - if (level == SOL_UDP || level == SOL_UDPLITE) + if (IS_SOL_UDPFAMILY(level)) return udp_lib_getsockopt(sk, level, optname, optval, optlen); return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); } -- cgit v1.2.3-59-g8ed1b From cf80efc27d68d4e0717aa0b8647c4e161397ced7 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 12 Feb 2008 17:35:16 +0900 Subject: [IPV4]: Fix size description of CONFIG_INET. CONFIG_INET now enlarges about 400KB, not 140KB. Signed-off-by: YOSHIFUJI Hideaki --- net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/Kconfig b/net/Kconfig index 6627c6ae5db6..acbf7c60e89b 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -45,7 +45,7 @@ config INET ---help--- These are the protocols used on the Internet and on most local Ethernets. It is highly recommended to say Y here (this will enlarge - your kernel by about 144 KB), since some programs (e.g. the X window + your kernel by about 400 KB), since some programs (e.g. the X window system) use TCP/IP even if your machine is not connected to any other computer. You will get the so-called loopback device which allows you to ping yourself (great fun, that!). -- cgit v1.2.3-59-g8ed1b From 8be8af8fa4405652e6c0797db5465a4be8afb998 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 4 Mar 2008 14:50:52 +0900 Subject: [IPV4] UDP: Move IPv4-specific bits to other file. Move IPv4-specific UDP bits from net/ipv4/udp.c into (new) net/ipv4/udp_ipv4.c. Rename net/ipv4/udplite.c to net/ipv4/udplite_ipv4.c. Signed-off-by: YOSHIFUJI Hideaki --- net/ipv4/Makefile | 4 +- net/ipv4/udp.c | 1086 --------------------------------------------- net/ipv4/udp_ipv4.c | 1134 +++++++++++++++++++++++++++++++++++++++++++++++ net/ipv4/udplite.c | 121 ----- net/ipv4/udplite_ipv4.c | 121 +++++ 5 files changed, 1257 insertions(+), 1209 deletions(-) create mode 100644 net/ipv4/udp_ipv4.c delete mode 100644 net/ipv4/udplite.c create mode 100644 net/ipv4/udplite_ipv4.c (limited to 'net') diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index e88cebdf3e30..d5226241d5ed 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -8,7 +8,7 @@ obj-y := route.o inetpeer.o protocol.o \ inet_timewait_sock.o inet_connection_sock.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ tcp_minisocks.o tcp_cong.o \ - datagram.o raw.o udp.o \ + datagram.o raw.o udp.o udp_ipv4.o \ arp.o icmp.o devinet.o af_inet.o igmp.o \ fib_frontend.o fib_semantics.o \ inet_fragment.o @@ -49,7 +49,7 @@ obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o -obj-$(CONFIG_IP_UDPLITE) += udplite.o +obj-$(CONFIG_IP_UDPLITE) += udplite_ipv4.o obj-$(CONFIG_NETLABEL) += cipso_ipv4.o obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index acc353aa89eb..c53d7673b57d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -246,553 +246,6 @@ int udp_get_port(struct sock *sk, unsigned short snum, return __udp_lib_get_port(sk, snum, udp_hash, scmp); } -int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) -{ - struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); - - return ( !ipv6_only_sock(sk2) && - (!inet1->rcv_saddr || !inet2->rcv_saddr || - inet1->rcv_saddr == inet2->rcv_saddr )); -} - -static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) -{ - return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); -} - -/* UDP is nearly always wildcards out the wazoo, it makes no sense to try - * harder than this. -DaveM - */ -static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, - __be16 sport, __be32 daddr, __be16 dport, - int dif, struct hlist_head udptable[]) -{ - struct sock *sk, *result = NULL; - struct hlist_node *node; - unsigned short hnum = ntohs(dport); - int badness = -1; - - read_lock(&udp_hash_lock); - sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { - struct inet_sock *inet = inet_sk(sk); - - if (sk->sk_net == net && sk->sk_hash == hnum && - !ipv6_only_sock(sk)) { - int score = (sk->sk_family == PF_INET ? 1 : 0); - if (inet->rcv_saddr) { - if (inet->rcv_saddr != daddr) - continue; - score+=2; - } - if (inet->daddr) { - if (inet->daddr != saddr) - continue; - score+=2; - } - if (inet->dport) { - if (inet->dport != sport) - continue; - score+=2; - } - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - continue; - score+=2; - } - if (score == 9) { - result = sk; - break; - } else if (score > badness) { - result = sk; - badness = score; - } - } - } - if (result) - sock_hold(result); - read_unlock(&udp_hash_lock); - return result; -} - -static inline struct sock *udp_v4_mcast_next(struct sock *sk, - __be16 loc_port, __be32 loc_addr, - __be16 rmt_port, __be32 rmt_addr, - int dif) -{ - struct hlist_node *node; - struct sock *s = sk; - unsigned short hnum = ntohs(loc_port); - - sk_for_each_from(s, node) { - struct inet_sock *inet = inet_sk(s); - - if (s->sk_hash != hnum || - (inet->daddr && inet->daddr != rmt_addr) || - (inet->dport != rmt_port && inet->dport) || - (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || - ipv6_only_sock(s) || - (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) - continue; - if (!ip_mc_sf_allow(s, loc_addr, rmt_addr, dif)) - continue; - goto found; - } - s = NULL; -found: - return s; -} - -/* - * This routine is called by the ICMP module when it gets some - * sort of error condition. If err < 0 then the socket should - * be closed and the error returned to the user. If err > 0 - * it's just the icmp type << 8 | icmp code. - * Header points to the ip header of the error packet. We move - * on past this. Then (as it used to claim before adjustment) - * header points to the first 8 bytes of the udp header. We need - * to find the appropriate port. - */ - -void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) -{ - struct inet_sock *inet; - struct iphdr *iph = (struct iphdr*)skb->data; - struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2)); - const int type = icmp_hdr(skb)->type; - const int code = icmp_hdr(skb)->code; - struct sock *sk; - int harderr; - int err; - - sk = __udp4_lib_lookup(skb->dev->nd_net, iph->daddr, uh->dest, - iph->saddr, uh->source, skb->dev->ifindex, udptable); - if (sk == NULL) { - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); - return; /* No socket for error */ - } - - err = 0; - harderr = 0; - inet = inet_sk(sk); - - switch (type) { - default: - case ICMP_TIME_EXCEEDED: - err = EHOSTUNREACH; - break; - case ICMP_SOURCE_QUENCH: - goto out; - case ICMP_PARAMETERPROB: - err = EPROTO; - harderr = 1; - break; - case ICMP_DEST_UNREACH: - if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ - if (inet->pmtudisc != IP_PMTUDISC_DONT) { - err = EMSGSIZE; - harderr = 1; - break; - } - goto out; - } - err = EHOSTUNREACH; - if (code <= NR_ICMP_UNREACH) { - harderr = icmp_err_convert[code].fatal; - err = icmp_err_convert[code].errno; - } - break; - } - - /* - * RFC1122: OK. Passes ICMP errors back to application, as per - * 4.1.3.3. - */ - if (!inet->recverr) { - if (!harderr || sk->sk_state != TCP_ESTABLISHED) - goto out; - } else { - ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1)); - } - sk->sk_err = err; - sk->sk_error_report(sk); -out: - sock_put(sk); -} - -void udp_err(struct sk_buff *skb, u32 info) -{ - __udp4_lib_err(skb, info, udp_hash); -} - -/* - * Throw away all pending data and cancel the corking. Socket is locked. - */ -static void udp_flush_pending_frames(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - - if (up->pending) { - up->len = 0; - up->pending = 0; - ip_flush_pending_frames(sk); - } -} - -/** - * udp4_hwcsum_outgoing - handle outgoing HW checksumming - * @sk: socket we are sending on - * @skb: sk_buff containing the filled-in UDP header - * (checksum field must be zeroed out) - */ -static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, - __be32 src, __be32 dst, int len ) -{ - unsigned int offset; - struct udphdr *uh = udp_hdr(skb); - __wsum csum = 0; - - if (skb_queue_len(&sk->sk_write_queue) == 1) { - /* - * Only one fragment on the socket. - */ - skb->csum_start = skb_transport_header(skb) - skb->head; - skb->csum_offset = offsetof(struct udphdr, check); - uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); - } else { - /* - * HW-checksum won't work as there are two or more - * fragments on the socket so that all csums of sk_buffs - * should be together - */ - offset = skb_transport_offset(skb); - skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); - - skb->ip_summed = CHECKSUM_NONE; - - skb_queue_walk(&sk->sk_write_queue, skb) { - csum = csum_add(csum, skb->csum); - } - - uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - } -} - -/* - * Push out all pending data as one UDP datagram. Socket is locked. - */ -static int udp_push_pending_frames(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct flowi *fl = &inet->cork.fl; - struct sk_buff *skb; - struct udphdr *uh; - int err = 0; - int is_udplite = IS_UDPLITE(sk); - __wsum csum = 0; - - /* Grab the skbuff where UDP header space exists. */ - if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) - goto out; - - /* - * Create a UDP header - */ - uh = udp_hdr(skb); - uh->source = fl->fl_ip_sport; - uh->dest = fl->fl_ip_dport; - uh->len = htons(up->len); - uh->check = 0; - - if (is_udplite) /* UDP-Lite */ - csum = udplite_csum_outgoing(sk, skb); - - else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ - - skb->ip_summed = CHECKSUM_NONE; - goto send; - - } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ - - udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); - goto send; - - } else /* `normal' UDP */ - csum = udp_csum_outgoing(sk, skb); - - /* add protocol-dependent pseudo-header */ - uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, - sk->sk_protocol, csum ); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - -send: - err = ip_push_pending_frames(sk); -out: - up->len = 0; - up->pending = 0; - if (!err) - UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); - return err; -} - -int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - size_t len) -{ - struct inet_sock *inet = inet_sk(sk); - struct udp_sock *up = udp_sk(sk); - int ulen = len; - struct ipcm_cookie ipc; - struct rtable *rt = NULL; - int free = 0; - int connected = 0; - __be32 daddr, faddr, saddr; - __be16 dport; - u8 tos; - int err, is_udplite = IS_UDPLITE(sk); - int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; - int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); - - if (len > 0xFFFF) - return -EMSGSIZE; - - /* - * Check the flags. - */ - - if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */ - return -EOPNOTSUPP; - - ipc.opt = NULL; - - if (up->pending) { - /* - * There are pending frames. - * The socket lock must be held while it's corked. - */ - lock_sock(sk); - if (likely(up->pending)) { - if (unlikely(up->pending != AF_INET)) { - release_sock(sk); - return -EINVAL; - } - goto do_append_data; - } - release_sock(sk); - } - ulen += sizeof(struct udphdr); - - /* - * Get and verify the address. - */ - if (msg->msg_name) { - struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name; - if (msg->msg_namelen < sizeof(*usin)) - return -EINVAL; - if (usin->sin_family != AF_INET) { - if (usin->sin_family != AF_UNSPEC) - return -EAFNOSUPPORT; - } - - daddr = usin->sin_addr.s_addr; - dport = usin->sin_port; - if (dport == 0) - return -EINVAL; - } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - daddr = inet->daddr; - dport = inet->dport; - /* Open fast path for connected socket. - Route will not be used, if at least one option is set. - */ - connected = 1; - } - ipc.addr = inet->saddr; - - ipc.oif = sk->sk_bound_dev_if; - if (msg->msg_controllen) { - err = ip_cmsg_send(msg, &ipc); - if (err) - return err; - if (ipc.opt) - free = 1; - connected = 0; - } - if (!ipc.opt) - ipc.opt = inet->opt; - - saddr = ipc.addr; - ipc.addr = faddr = daddr; - - if (ipc.opt && ipc.opt->srr) { - if (!daddr) - return -EINVAL; - faddr = ipc.opt->faddr; - connected = 0; - } - tos = RT_TOS(inet->tos); - if (sock_flag(sk, SOCK_LOCALROUTE) || - (msg->msg_flags & MSG_DONTROUTE) || - (ipc.opt && ipc.opt->is_strictroute)) { - tos |= RTO_ONLINK; - connected = 0; - } - - if (ipv4_is_multicast(daddr)) { - if (!ipc.oif) - ipc.oif = inet->mc_index; - if (!saddr) - saddr = inet->mc_addr; - connected = 0; - } - - if (connected) - rt = (struct rtable*)sk_dst_check(sk, 0); - - if (rt == NULL) { - struct flowi fl = { .oif = ipc.oif, - .nl_u = { .ip4_u = - { .daddr = faddr, - .saddr = saddr, - .tos = tos } }, - .proto = sk->sk_protocol, - .uli_u = { .ports = - { .sport = inet->sport, - .dport = dport } } }; - security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(&init_net, &rt, &fl, sk, 1); - if (err) { - if (err == -ENETUNREACH) - IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); - goto out; - } - - err = -EACCES; - if ((rt->rt_flags & RTCF_BROADCAST) && - !sock_flag(sk, SOCK_BROADCAST)) - goto out; - if (connected) - sk_dst_set(sk, dst_clone(&rt->u.dst)); - } - - if (msg->msg_flags&MSG_CONFIRM) - goto do_confirm; -back_from_confirm: - - saddr = rt->rt_src; - if (!ipc.addr) - daddr = ipc.addr = rt->rt_dst; - - lock_sock(sk); - if (unlikely(up->pending)) { - /* The socket is already corked while preparing it. */ - /* ... which is an evident application bug. --ANK */ - release_sock(sk); - - LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); - err = -EINVAL; - goto out; - } - /* - * Now cork the socket to pend data. - */ - inet->cork.fl.fl4_dst = daddr; - inet->cork.fl.fl_ip_dport = dport; - inet->cork.fl.fl4_src = saddr; - inet->cork.fl.fl_ip_sport = inet->sport; - up->pending = AF_INET; - -do_append_data: - up->len += ulen; - getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; - err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, - sizeof(struct udphdr), &ipc, rt, - corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); - if (err) - udp_flush_pending_frames(sk); - else if (!corkreq) - err = udp_push_pending_frames(sk); - else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) - up->pending = 0; - release_sock(sk); - -out: - ip_rt_put(rt); - if (free) - kfree(ipc.opt); - if (!err) - return len; - /* - * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting - * ENOBUFS might not be good (it's not tunable per se), but otherwise - * we don't have a good statistic (IpOutDiscards but it can be too many - * things). We could add another new stat but at least for now that - * seems like overkill. - */ - if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); - } - return err; - -do_confirm: - dst_confirm(&rt->u.dst); - if (!(msg->msg_flags&MSG_PROBE) || len) - goto back_from_confirm; - err = 0; - goto out; -} - -int udp_sendpage(struct sock *sk, struct page *page, int offset, - size_t size, int flags) -{ - struct udp_sock *up = udp_sk(sk); - int ret; - - if (!up->pending) { - struct msghdr msg = { .msg_flags = flags|MSG_MORE }; - - /* Call udp_sendmsg to specify destination address which - * sendpage interface can't pass. - * This will succeed only when the socket is connected. - */ - ret = udp_sendmsg(NULL, sk, &msg, 0); - if (ret < 0) - return ret; - } - - lock_sock(sk); - - if (unlikely(!up->pending)) { - release_sock(sk); - - LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 3\n"); - return -EINVAL; - } - - ret = ip_append_page(sk, page, offset, size, flags); - if (ret == -EOPNOTSUPP) { - release_sock(sk); - return sock_no_sendpage(sk->sk_socket, page, offset, - size, flags); - } - if (ret < 0) { - udp_flush_pending_frames(sk); - goto out; - } - - up->len += size; - if (!(up->corkflag || (flags&MSG_MORE))) - ret = udp_push_pending_frames(sk); - if (!ret) - ret = size; -out: - release_sock(sk); - return ret; -} - /* * IOCTL requests applicable to the UDP protocol */ @@ -833,107 +286,6 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) return 0; } -/* - * This should be easy, if there is something there we - * return it, otherwise we block. - */ - -int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - size_t len, int noblock, int flags, int *addr_len) -{ - struct inet_sock *inet = inet_sk(sk); - struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; - struct sk_buff *skb; - unsigned int ulen, copied; - int peeked; - int err; - int is_udplite = IS_UDPLITE(sk); - - /* - * Check any passed addresses - */ - if (addr_len) - *addr_len=sizeof(*sin); - - if (flags & MSG_ERRQUEUE) - return ip_recv_error(sk, msg, len); - -try_again: - skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, &err); - if (!skb) - goto out; - - ulen = skb->len - sizeof(struct udphdr); - copied = len; - if (copied > ulen) - copied = ulen; - else if (copied < ulen) - msg->msg_flags |= MSG_TRUNC; - - /* - * If checksum is needed at all, try to do it while copying the - * data. If the data is truncated, or if we only want a partial - * coverage checksum (UDP-Lite), do it before the copy. - */ - - if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { - if (udp_lib_checksum_complete(skb)) - goto csum_copy_err; - } - - if (skb_csum_unnecessary(skb)) - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), - msg->msg_iov, copied ); - else { - err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); - - if (err == -EINVAL) - goto csum_copy_err; - } - - if (err) - goto out_free; - - if (!peeked) - UDP_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); - - sock_recv_timestamp(msg, sk, skb); - - /* Copy the address. */ - if (sin) - { - sin->sin_family = AF_INET; - sin->sin_port = udp_hdr(skb)->source; - sin->sin_addr.s_addr = ip_hdr(skb)->saddr; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } - if (inet->cmsg_flags) - ip_cmsg_recv(msg, skb); - - err = copied; - if (flags & MSG_TRUNC) - err = ulen; - -out_free: - lock_sock(sk); - skb_free_datagram(sk, skb); - release_sock(sk); -out: - return err; - -csum_copy_err: - lock_sock(sk); - if (!skb_kill_datagram(sk, skb, flags)) - UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); - release_sock(sk); - - if (noblock) - return -EAGAIN; - goto try_again; -} - - int udp_disconnect(struct sock *sk, int flags) { struct inet_sock *inet = inet_sk(sk); @@ -956,319 +308,6 @@ int udp_disconnect(struct sock *sk, int flags) return 0; } -/* returns: - * -1: error - * 0: success - * >0: "udp encap" protocol resubmission - * - * Note that in the success and error cases, the skb is assumed to - * have either been requeued or freed. - */ -int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) -{ - struct udp_sock *up = udp_sk(sk); - int rc; - int is_udplite = IS_UDPLITE(sk); - - /* - * Charge it to the socket, dropping if the queue is full. - */ - if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) - goto drop; - nf_reset(skb); - - if (up->encap_type) { - /* - * This is an encapsulation socket so pass the skb to - * the socket's udp_encap_rcv() hook. Otherwise, just - * fall through and pass this up the UDP socket. - * up->encap_rcv() returns the following value: - * =0 if skb was successfully passed to the encap - * handler or was discarded by it. - * >0 if skb should be passed on to UDP. - * <0 if skb should be resubmitted as proto -N - */ - - /* if we're overly short, let UDP handle it */ - if (skb->len > sizeof(struct udphdr) && - up->encap_rcv != NULL) { - int ret; - - ret = (*up->encap_rcv)(sk, skb); - if (ret <= 0) { - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, - is_udplite); - return -ret; - } - } - - /* FALLTHROUGH -- it's a UDP Packet */ - } - - /* - * UDP-Lite specific tests, ignored on UDP sockets - */ - if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { - - /* - * MIB statistics other than incrementing the error count are - * disabled for the following two types of errors: these depend - * on the application settings, not on the functioning of the - * protocol stack as such. - * - * RFC 3828 here recommends (sec 3.3): "There should also be a - * way ... to ... at least let the receiving application block - * delivery of packets with coverage values less than a value - * provided by the application." - */ - if (up->pcrlen == 0) { /* full coverage was set */ - LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " - "%d while full coverage %d requested\n", - UDP_SKB_CB(skb)->cscov, skb->len); - goto drop; - } - /* The next case involves violating the min. coverage requested - * by the receiver. This is subtle: if receiver wants x and x is - * greater than the buffersize/MTU then receiver will complain - * that it wants x while sender emits packets of smaller size y. - * Therefore the above ...()->partial_cov statement is essential. - */ - if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { - LIMIT_NETDEBUG(KERN_WARNING - "UDPLITE: coverage %d too small, need min %d\n", - UDP_SKB_CB(skb)->cscov, up->pcrlen); - goto drop; - } - } - - if (sk->sk_filter) { - if (udp_lib_checksum_complete(skb)) - goto drop; - } - - if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { - /* Note that an ENOMEM error is charged twice */ - if (rc == -ENOMEM) - UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); - goto drop; - } - - return 0; - -drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); - kfree_skb(skb); - return -1; -} - -/* - * Multicasts and broadcasts go to each listener. - * - * Note: called only from the BH handler context, - * so we don't need to lock the hashes. - */ -static int __udp4_lib_mcast_deliver(struct sk_buff *skb, - struct udphdr *uh, - __be32 saddr, __be32 daddr, - struct hlist_head udptable[]) -{ - struct sock *sk; - int dif; - - read_lock(&udp_hash_lock); - sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); - dif = skb->dev->ifindex; - sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); - if (sk) { - struct sock *sknext = NULL; - - do { - struct sk_buff *skb1 = skb; - - sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr, - uh->source, saddr, dif); - if (sknext) - skb1 = skb_clone(skb, GFP_ATOMIC); - - if (skb1) { - int ret = 0; - - bh_lock_sock_nested(sk); - if (!sock_owned_by_user(sk)) - ret = udp_queue_rcv_skb(sk, skb1); - else - sk_add_backlog(sk, skb1); - bh_unlock_sock(sk); - - if (ret > 0) - /* we should probably re-process instead - * of dropping packets here. */ - kfree_skb(skb1); - } - sk = sknext; - } while (sknext); - } else - kfree_skb(skb); - read_unlock(&udp_hash_lock); - return 0; -} - -/* Initialize UDP checksum. If exited with zero value (success), - * CHECKSUM_UNNECESSARY means, that no more checks are required. - * Otherwise, csum completion requires chacksumming packet body, - * including udp header and folding it to skb->csum. - */ -static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, - int proto) -{ - const struct iphdr *iph; - int err; - - UDP_SKB_CB(skb)->partial_cov = 0; - UDP_SKB_CB(skb)->cscov = skb->len; - - if (IS_PROTO_UDPLITE(proto)) { - err = udplite_checksum_init(skb, uh); - if (err) - return err; - } - - iph = ip_hdr(skb); - if (uh->check == 0) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else if (skb->ip_summed == CHECKSUM_COMPLETE) { - if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, - proto, skb->csum)) - skb->ip_summed = CHECKSUM_UNNECESSARY; - } - if (!skb_csum_unnecessary(skb)) - skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, - skb->len, proto, 0); - /* Probably, we should checksum udp header (it should be in cache - * in any case) and data in tiny packets (< rx copybreak). - */ - - return 0; -} - -/* - * All we need to do is get the socket, and then do a checksum. - */ - -int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], - int proto) -{ - struct sock *sk; - struct udphdr *uh = udp_hdr(skb); - unsigned short ulen; - struct rtable *rt = (struct rtable*)skb->dst; - __be32 saddr = ip_hdr(skb)->saddr; - __be32 daddr = ip_hdr(skb)->daddr; - - /* - * Validate the packet. - */ - if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto drop; /* No space for header. */ - - ulen = ntohs(uh->len); - if (ulen > skb->len) - goto short_packet; - - if (IS_PROTO_UDPLITE(proto)) { - /* UDP validates ulen. */ - if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) - goto short_packet; - uh = udp_hdr(skb); - } - - if (udp4_csum_init(skb, uh, proto)) - goto csum_error; - - if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) - return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); - - sk = __udp4_lib_lookup(skb->dev->nd_net, saddr, uh->source, daddr, - uh->dest, inet_iif(skb), udptable); - - if (sk != NULL) { - int ret = 0; - bh_lock_sock_nested(sk); - if (!sock_owned_by_user(sk)) - ret = udp_queue_rcv_skb(sk, skb); - else - sk_add_backlog(sk, skb); - bh_unlock_sock(sk); - sock_put(sk); - - /* a return value > 0 means to resubmit the input, but - * it wants the return to be -protocol, or 0 - */ - if (ret > 0) - return -ret; - return 0; - } - - if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) - goto drop; - nf_reset(skb); - - /* No socket. Drop packet silently, if checksum is wrong */ - if (udp_lib_checksum_complete(skb)) - goto csum_error; - - UDP_INC_STATS_BH(UDP_MIB_NOPORTS, IS_PROTO_UDPLITE(proto)); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - - /* - * Hmm. We got an UDP packet to a port to which we - * don't wanna listen. Ignore it. - */ - kfree_skb(skb); - return 0; - -short_packet: - LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", - IS_PROTO_UDPLITE(proto) ? "-Lite" : "", - NIPQUAD(saddr), - ntohs(uh->source), - ulen, - skb->len, - NIPQUAD(daddr), - ntohs(uh->dest)); - goto drop; - -csum_error: - /* - * RFC1122: OK. Discards the bad packet silently (as far as - * the network is concerned, anyway) as per 4.1.3.4 (MUST). - */ - LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", - IS_PROTO_UDPLITE(proto) ? "-Lite" : "", - NIPQUAD(saddr), - ntohs(uh->source), - NIPQUAD(daddr), - ntohs(uh->dest), - ulen); -drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS, IS_PROTO_UDPLITE(proto)); - kfree_skb(skb); - return 0; -} - -int udp_rcv(struct sk_buff *skb) -{ - return __udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP); -} - -int udp_destroy_sock(struct sock *sk) -{ - lock_sock(sk); - udp_flush_pending_frames(sk); - release_sock(sk); - return 0; -} - /* * Socket option code for UDP */ @@ -1353,26 +392,6 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, return err; } -int udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_push_pending_frames); - return ip_setsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_push_pending_frames); - return compat_ip_setsockopt(sk, level, optname, optval, optlen); -} -#endif - int udp_lib_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { @@ -1417,23 +436,6 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname, return 0; } -int udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return ip_getsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return compat_ip_getsockopt(sk, level, optname, optval, optlen); -} -#endif /** * udp_poll - wait for a UDP event. * @file - file struct @@ -1478,36 +480,6 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) } -DEFINE_PROTO_INUSE(udp) - -struct proto udp_prot = { - .name = "UDP", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip4_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .destroy = udp_destroy_sock, - .setsockopt = udp_setsockopt, - .getsockopt = udp_getsockopt, - .sendmsg = udp_sendmsg, - .recvmsg = udp_recvmsg, - .sendpage = udp_sendpage, - .backlog_rcv = udp_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udp_v4_get_port, - .memory_allocated = &udp_memory_allocated, - .sysctl_mem = sysctl_udp_mem, - .sysctl_wmem = &sysctl_udp_wmem_min, - .sysctl_rmem = &sysctl_udp_rmem_min, - .obj_size = sizeof(struct udp_sock), -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udp_setsockopt, - .compat_getsockopt = compat_udp_getsockopt, -#endif - REF_PROTO_INUSE(udp) -}; /* ------------------------------------------------------------------------ */ #ifdef CONFIG_PROC_FS @@ -1640,62 +612,6 @@ void udp_proc_unregister(struct udp_seq_afinfo *afinfo) proc_net_remove(&init_net, afinfo->name); memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } - -/* ------------------------------------------------------------------------ */ -static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket) -{ - struct inet_sock *inet = inet_sk(sp); - __be32 dest = inet->daddr; - __be32 src = inet->rcv_saddr; - __u16 destp = ntohs(inet->dport); - __u16 srcp = ntohs(inet->sport); - - sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p", - bucket, src, srcp, dest, destp, sp->sk_state, - atomic_read(&sp->sk_wmem_alloc), - atomic_read(&sp->sk_rmem_alloc), - 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp); -} - -int udp4_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_printf(seq, "%-127s\n", - " sl local_address rem_address st tx_queue " - "rx_queue tr tm->when retrnsmt uid timeout " - "inode"); - else { - char tmpbuf[129]; - struct udp_iter_state *state = seq->private; - - udp4_format_sock(v, tmpbuf, state->bucket); - seq_printf(seq, "%-127s\n", tmpbuf); - } - return 0; -} - -/* ------------------------------------------------------------------------ */ -static struct file_operations udp4_seq_fops; -static struct udp_seq_afinfo udp4_seq_afinfo = { - .owner = THIS_MODULE, - .name = "udp", - .family = AF_INET, - .hashtable = udp_hash, - .seq_show = udp4_seq_show, - .seq_fops = &udp4_seq_fops, -}; - -int __init udp4_proc_init(void) -{ - return udp_proc_register(&udp4_seq_afinfo); -} - -void udp4_proc_exit(void) -{ - udp_proc_unregister(&udp4_seq_afinfo); -} #endif /* CONFIG_PROC_FS */ void __init udp_init(void) @@ -1722,8 +638,6 @@ EXPORT_SYMBOL(udp_hash); EXPORT_SYMBOL(udp_hash_lock); EXPORT_SYMBOL(udp_ioctl); EXPORT_SYMBOL(udp_get_port); -EXPORT_SYMBOL(udp_prot); -EXPORT_SYMBOL(udp_sendmsg); EXPORT_SYMBOL(udp_lib_getsockopt); EXPORT_SYMBOL(udp_lib_setsockopt); EXPORT_SYMBOL(udp_poll); diff --git a/net/ipv4/udp_ipv4.c b/net/ipv4/udp_ipv4.c new file mode 100644 index 000000000000..40978de7fb51 --- /dev/null +++ b/net/ipv4/udp_ipv4.c @@ -0,0 +1,1134 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * UDP for IPv4. + * + * For full credits, see net/ipv4/udp.c. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "udp_impl.h" + +int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) +{ + struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); + + return ( !ipv6_only_sock(sk2) && + (!inet1->rcv_saddr || !inet2->rcv_saddr || + inet1->rcv_saddr == inet2->rcv_saddr )); +} + +static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) +{ + return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); +} + +/* UDP is nearly always wildcards out the wazoo, it makes no sense to try + * harder than this. -DaveM + */ +static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, + __be16 sport, __be32 daddr, __be16 dport, + int dif, struct hlist_head udptable[]) +{ + struct sock *sk, *result = NULL; + struct hlist_node *node; + unsigned short hnum = ntohs(dport); + int badness = -1; + + read_lock(&udp_hash_lock); + sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { + struct inet_sock *inet = inet_sk(sk); + + if (sk->sk_net == net && sk->sk_hash == hnum && + !ipv6_only_sock(sk)) { + int score = (sk->sk_family == PF_INET ? 1 : 0); + if (inet->rcv_saddr) { + if (inet->rcv_saddr != daddr) + continue; + score+=2; + } + if (inet->daddr) { + if (inet->daddr != saddr) + continue; + score+=2; + } + if (inet->dport) { + if (inet->dport != sport) + continue; + score+=2; + } + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) + continue; + score+=2; + } + if (score == 9) { + result = sk; + break; + } else if (score > badness) { + result = sk; + badness = score; + } + } + } + if (result) + sock_hold(result); + read_unlock(&udp_hash_lock); + return result; +} + +static inline struct sock *udp_v4_mcast_next(struct sock *sk, + __be16 loc_port, __be32 loc_addr, + __be16 rmt_port, __be32 rmt_addr, + int dif) +{ + struct hlist_node *node; + struct sock *s = sk; + unsigned short hnum = ntohs(loc_port); + + sk_for_each_from(s, node) { + struct inet_sock *inet = inet_sk(s); + + if (s->sk_hash != hnum || + (inet->daddr && inet->daddr != rmt_addr) || + (inet->dport != rmt_port && inet->dport) || + (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || + ipv6_only_sock(s) || + (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) + continue; + if (!ip_mc_sf_allow(s, loc_addr, rmt_addr, dif)) + continue; + goto found; + } + s = NULL; +found: + return s; +} + +/* + * This routine is called by the ICMP module when it gets some + * sort of error condition. If err < 0 then the socket should + * be closed and the error returned to the user. If err > 0 + * it's just the icmp type << 8 | icmp code. + * Header points to the ip header of the error packet. We move + * on past this. Then (as it used to claim before adjustment) + * header points to the first 8 bytes of the udp header. We need + * to find the appropriate port. + */ + +void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) +{ + struct inet_sock *inet; + struct iphdr *iph = (struct iphdr*)skb->data; + struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2)); + const int type = icmp_hdr(skb)->type; + const int code = icmp_hdr(skb)->code; + struct sock *sk; + int harderr; + int err; + + sk = __udp4_lib_lookup(skb->dev->nd_net, iph->daddr, uh->dest, + iph->saddr, uh->source, skb->dev->ifindex, udptable); + if (sk == NULL) { + ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + return; /* No socket for error */ + } + + err = 0; + harderr = 0; + inet = inet_sk(sk); + + switch (type) { + default: + case ICMP_TIME_EXCEEDED: + err = EHOSTUNREACH; + break; + case ICMP_SOURCE_QUENCH: + goto out; + case ICMP_PARAMETERPROB: + err = EPROTO; + harderr = 1; + break; + case ICMP_DEST_UNREACH: + if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ + if (inet->pmtudisc != IP_PMTUDISC_DONT) { + err = EMSGSIZE; + harderr = 1; + break; + } + goto out; + } + err = EHOSTUNREACH; + if (code <= NR_ICMP_UNREACH) { + harderr = icmp_err_convert[code].fatal; + err = icmp_err_convert[code].errno; + } + break; + } + + /* + * RFC1122: OK. Passes ICMP errors back to application, as per + * 4.1.3.3. + */ + if (!inet->recverr) { + if (!harderr || sk->sk_state != TCP_ESTABLISHED) + goto out; + } else { + ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1)); + } + sk->sk_err = err; + sk->sk_error_report(sk); +out: + sock_put(sk); +} + +void udp_err(struct sk_buff *skb, u32 info) +{ + __udp4_lib_err(skb, info, udp_hash); +} + +/* + * Throw away all pending data and cancel the corking. Socket is locked. + */ +static void udp_flush_pending_frames(struct sock *sk) +{ + struct udp_sock *up = udp_sk(sk); + + if (up->pending) { + up->len = 0; + up->pending = 0; + ip_flush_pending_frames(sk); + } +} + +/** + * udp4_hwcsum_outgoing - handle outgoing HW checksumming + * @sk: socket we are sending on + * @skb: sk_buff containing the filled-in UDP header + * (checksum field must be zeroed out) + */ +static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, + __be32 src, __be32 dst, int len ) +{ + unsigned int offset; + struct udphdr *uh = udp_hdr(skb); + __wsum csum = 0; + + if (skb_queue_len(&sk->sk_write_queue) == 1) { + /* + * Only one fragment on the socket. + */ + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct udphdr, check); + uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); + } else { + /* + * HW-checksum won't work as there are two or more + * fragments on the socket so that all csums of sk_buffs + * should be together + */ + offset = skb_transport_offset(skb); + skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); + + skb->ip_summed = CHECKSUM_NONE; + + skb_queue_walk(&sk->sk_write_queue, skb) { + csum = csum_add(csum, skb->csum); + } + + uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + } +} + +/* + * Push out all pending data as one UDP datagram. Socket is locked. + */ +static int udp_push_pending_frames(struct sock *sk) +{ + struct udp_sock *up = udp_sk(sk); + struct inet_sock *inet = inet_sk(sk); + struct flowi *fl = &inet->cork.fl; + struct sk_buff *skb; + struct udphdr *uh; + int err = 0; + int is_udplite = IS_UDPLITE(sk); + __wsum csum = 0; + + /* Grab the skbuff where UDP header space exists. */ + if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) + goto out; + + /* + * Create a UDP header + */ + uh = udp_hdr(skb); + uh->source = fl->fl_ip_sport; + uh->dest = fl->fl_ip_dport; + uh->len = htons(up->len); + uh->check = 0; + + if (is_udplite) /* UDP-Lite */ + csum = udplite_csum_outgoing(sk, skb); + + else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ + + skb->ip_summed = CHECKSUM_NONE; + goto send; + + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ + + udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); + goto send; + + } else /* `normal' UDP */ + csum = udp_csum_outgoing(sk, skb); + + /* add protocol-dependent pseudo-header */ + uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, + sk->sk_protocol, csum ); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + +send: + err = ip_push_pending_frames(sk); +out: + up->len = 0; + up->pending = 0; + if (!err) + UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); + return err; +} + +int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len) +{ + struct inet_sock *inet = inet_sk(sk); + struct udp_sock *up = udp_sk(sk); + int ulen = len; + struct ipcm_cookie ipc; + struct rtable *rt = NULL; + int free = 0; + int connected = 0; + __be32 daddr, faddr, saddr; + __be16 dport; + u8 tos; + int err, is_udplite = IS_UDPLITE(sk); + int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; + int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); + + if (len > 0xFFFF) + return -EMSGSIZE; + + /* + * Check the flags. + */ + + if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */ + return -EOPNOTSUPP; + + ipc.opt = NULL; + + if (up->pending) { + /* + * There are pending frames. + * The socket lock must be held while it's corked. + */ + lock_sock(sk); + if (likely(up->pending)) { + if (unlikely(up->pending != AF_INET)) { + release_sock(sk); + return -EINVAL; + } + goto do_append_data; + } + release_sock(sk); + } + ulen += sizeof(struct udphdr); + + /* + * Get and verify the address. + */ + if (msg->msg_name) { + struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name; + if (msg->msg_namelen < sizeof(*usin)) + return -EINVAL; + if (usin->sin_family != AF_INET) { + if (usin->sin_family != AF_UNSPEC) + return -EAFNOSUPPORT; + } + + daddr = usin->sin_addr.s_addr; + dport = usin->sin_port; + if (dport == 0) + return -EINVAL; + } else { + if (sk->sk_state != TCP_ESTABLISHED) + return -EDESTADDRREQ; + daddr = inet->daddr; + dport = inet->dport; + /* Open fast path for connected socket. + Route will not be used, if at least one option is set. + */ + connected = 1; + } + ipc.addr = inet->saddr; + + ipc.oif = sk->sk_bound_dev_if; + if (msg->msg_controllen) { + err = ip_cmsg_send(msg, &ipc); + if (err) + return err; + if (ipc.opt) + free = 1; + connected = 0; + } + if (!ipc.opt) + ipc.opt = inet->opt; + + saddr = ipc.addr; + ipc.addr = faddr = daddr; + + if (ipc.opt && ipc.opt->srr) { + if (!daddr) + return -EINVAL; + faddr = ipc.opt->faddr; + connected = 0; + } + tos = RT_TOS(inet->tos); + if (sock_flag(sk, SOCK_LOCALROUTE) || + (msg->msg_flags & MSG_DONTROUTE) || + (ipc.opt && ipc.opt->is_strictroute)) { + tos |= RTO_ONLINK; + connected = 0; + } + + if (ipv4_is_multicast(daddr)) { + if (!ipc.oif) + ipc.oif = inet->mc_index; + if (!saddr) + saddr = inet->mc_addr; + connected = 0; + } + + if (connected) + rt = (struct rtable*)sk_dst_check(sk, 0); + + if (rt == NULL) { + struct flowi fl = { .oif = ipc.oif, + .nl_u = { .ip4_u = + { .daddr = faddr, + .saddr = saddr, + .tos = tos } }, + .proto = sk->sk_protocol, + .uli_u = { .ports = + { .sport = inet->sport, + .dport = dport } } }; + security_sk_classify_flow(sk, &fl); + err = ip_route_output_flow(&init_net, &rt, &fl, sk, 1); + if (err) { + if (err == -ENETUNREACH) + IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); + goto out; + } + + err = -EACCES; + if ((rt->rt_flags & RTCF_BROADCAST) && + !sock_flag(sk, SOCK_BROADCAST)) + goto out; + if (connected) + sk_dst_set(sk, dst_clone(&rt->u.dst)); + } + + if (msg->msg_flags&MSG_CONFIRM) + goto do_confirm; +back_from_confirm: + + saddr = rt->rt_src; + if (!ipc.addr) + daddr = ipc.addr = rt->rt_dst; + + lock_sock(sk); + if (unlikely(up->pending)) { + /* The socket is already corked while preparing it. */ + /* ... which is an evident application bug. --ANK */ + release_sock(sk); + + LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); + err = -EINVAL; + goto out; + } + /* + * Now cork the socket to pend data. + */ + inet->cork.fl.fl4_dst = daddr; + inet->cork.fl.fl_ip_dport = dport; + inet->cork.fl.fl4_src = saddr; + inet->cork.fl.fl_ip_sport = inet->sport; + up->pending = AF_INET; + +do_append_data: + up->len += ulen; + getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, + sizeof(struct udphdr), &ipc, rt, + corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); + if (err) + udp_flush_pending_frames(sk); + else if (!corkreq) + err = udp_push_pending_frames(sk); + else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) + up->pending = 0; + release_sock(sk); + +out: + ip_rt_put(rt); + if (free) + kfree(ipc.opt); + if (!err) + return len; + /* + * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting + * ENOBUFS might not be good (it's not tunable per se), but otherwise + * we don't have a good statistic (IpOutDiscards but it can be too many + * things). We could add another new stat but at least for now that + * seems like overkill. + */ + if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { + UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); + } + return err; + +do_confirm: + dst_confirm(&rt->u.dst); + if (!(msg->msg_flags&MSG_PROBE) || len) + goto back_from_confirm; + err = 0; + goto out; +} + +int udp_sendpage(struct sock *sk, struct page *page, int offset, + size_t size, int flags) +{ + struct udp_sock *up = udp_sk(sk); + int ret; + + if (!up->pending) { + struct msghdr msg = { .msg_flags = flags|MSG_MORE }; + + /* Call udp_sendmsg to specify destination address which + * sendpage interface can't pass. + * This will succeed only when the socket is connected. + */ + ret = udp_sendmsg(NULL, sk, &msg, 0); + if (ret < 0) + return ret; + } + + lock_sock(sk); + + if (unlikely(!up->pending)) { + release_sock(sk); + + LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 3\n"); + return -EINVAL; + } + + ret = ip_append_page(sk, page, offset, size, flags); + if (ret == -EOPNOTSUPP) { + release_sock(sk); + return sock_no_sendpage(sk->sk_socket, page, offset, + size, flags); + } + if (ret < 0) { + udp_flush_pending_frames(sk); + goto out; + } + + up->len += size; + if (!(up->corkflag || (flags&MSG_MORE))) + ret = udp_push_pending_frames(sk); + if (!ret) + ret = size; +out: + release_sock(sk); + return ret; +} + +/* + * This should be easy, if there is something there we + * return it, otherwise we block. + */ + +int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int noblock, int flags, int *addr_len) +{ + struct inet_sock *inet = inet_sk(sk); + struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; + struct sk_buff *skb; + unsigned int ulen, copied; + int peeked; + int err; + int is_udplite = IS_UDPLITE(sk); + + /* + * Check any passed addresses + */ + if (addr_len) + *addr_len=sizeof(*sin); + + if (flags & MSG_ERRQUEUE) + return ip_recv_error(sk, msg, len); + +try_again: + skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), + &peeked, &err); + if (!skb) + goto out; + + ulen = skb->len - sizeof(struct udphdr); + copied = len; + if (copied > ulen) + copied = ulen; + else if (copied < ulen) + msg->msg_flags |= MSG_TRUNC; + + /* + * If checksum is needed at all, try to do it while copying the + * data. If the data is truncated, or if we only want a partial + * coverage checksum (UDP-Lite), do it before the copy. + */ + + if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { + if (udp_lib_checksum_complete(skb)) + goto csum_copy_err; + } + + if (skb_csum_unnecessary(skb)) + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied ); + else { + err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); + + if (err == -EINVAL) + goto csum_copy_err; + } + + if (err) + goto out_free; + + if (!peeked) + UDP_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); + + sock_recv_timestamp(msg, sk, skb); + + /* Copy the address. */ + if (sin) + { + sin->sin_family = AF_INET; + sin->sin_port = udp_hdr(skb)->source; + sin->sin_addr.s_addr = ip_hdr(skb)->saddr; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } + if (inet->cmsg_flags) + ip_cmsg_recv(msg, skb); + + err = copied; + if (flags & MSG_TRUNC) + err = ulen; + +out_free: + lock_sock(sk); + skb_free_datagram(sk, skb); + release_sock(sk); +out: + return err; + +csum_copy_err: + lock_sock(sk); + if (!skb_kill_datagram(sk, skb, flags)) + UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); + release_sock(sk); + + if (noblock) + return -EAGAIN; + goto try_again; +} + + +/* returns: + * -1: error + * 0: success + * >0: "udp encap" protocol resubmission + * + * Note that in the success and error cases, the skb is assumed to + * have either been requeued or freed. + */ +int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) +{ + struct udp_sock *up = udp_sk(sk); + int rc; + int is_udplite = IS_UDPLITE(sk); + + /* + * Charge it to the socket, dropping if the queue is full. + */ + if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) + goto drop; + nf_reset(skb); + + if (up->encap_type) { + /* + * This is an encapsulation socket so pass the skb to + * the socket's udp_encap_rcv() hook. Otherwise, just + * fall through and pass this up the UDP socket. + * up->encap_rcv() returns the following value: + * =0 if skb was successfully passed to the encap + * handler or was discarded by it. + * >0 if skb should be passed on to UDP. + * <0 if skb should be resubmitted as proto -N + */ + + /* if we're overly short, let UDP handle it */ + if (skb->len > sizeof(struct udphdr) && + up->encap_rcv != NULL) { + int ret; + + ret = (*up->encap_rcv)(sk, skb); + if (ret <= 0) { + UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, + is_udplite); + return -ret; + } + } + + /* FALLTHROUGH -- it's a UDP Packet */ + } + + /* + * UDP-Lite specific tests, ignored on UDP sockets + */ + if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { + + /* + * MIB statistics other than incrementing the error count are + * disabled for the following two types of errors: these depend + * on the application settings, not on the functioning of the + * protocol stack as such. + * + * RFC 3828 here recommends (sec 3.3): "There should also be a + * way ... to ... at least let the receiving application block + * delivery of packets with coverage values less than a value + * provided by the application." + */ + if (up->pcrlen == 0) { /* full coverage was set */ + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " + "%d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); + goto drop; + } + /* The next case involves violating the min. coverage requested + * by the receiver. This is subtle: if receiver wants x and x is + * greater than the buffersize/MTU then receiver will complain + * that it wants x while sender emits packets of smaller size y. + * Therefore the above ...()->partial_cov statement is essential. + */ + if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { + LIMIT_NETDEBUG(KERN_WARNING + "UDPLITE: coverage %d too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); + goto drop; + } + } + + if (sk->sk_filter) { + if (udp_lib_checksum_complete(skb)) + goto drop; + } + + if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { + /* Note that an ENOMEM error is charged twice */ + if (rc == -ENOMEM) + UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); + goto drop; + } + + return 0; + +drop: + UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); + kfree_skb(skb); + return -1; +} + +/* + * Multicasts and broadcasts go to each listener. + * + * Note: called only from the BH handler context, + * so we don't need to lock the hashes. + */ +static int __udp4_lib_mcast_deliver(struct sk_buff *skb, + struct udphdr *uh, + __be32 saddr, __be32 daddr, + struct hlist_head udptable[]) +{ + struct sock *sk; + int dif; + + read_lock(&udp_hash_lock); + sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); + dif = skb->dev->ifindex; + sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); + if (sk) { + struct sock *sknext = NULL; + + do { + struct sk_buff *skb1 = skb; + + sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr, + uh->source, saddr, dif); + if (sknext) + skb1 = skb_clone(skb, GFP_ATOMIC); + + if (skb1) { + int ret = 0; + + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + ret = udp_queue_rcv_skb(sk, skb1); + else + sk_add_backlog(sk, skb1); + bh_unlock_sock(sk); + + if (ret > 0) + /* we should probably re-process instead + * of dropping packets here. */ + kfree_skb(skb1); + } + sk = sknext; + } while (sknext); + } else + kfree_skb(skb); + read_unlock(&udp_hash_lock); + return 0; +} + +/* Initialize UDP checksum. If exited with zero value (success), + * CHECKSUM_UNNECESSARY means, that no more checks are required. + * Otherwise, csum completion requires chacksumming packet body, + * including udp header and folding it to skb->csum. + */ +static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, + int proto) +{ + const struct iphdr *iph; + int err; + + UDP_SKB_CB(skb)->partial_cov = 0; + UDP_SKB_CB(skb)->cscov = skb->len; + + if (IS_PROTO_UDPLITE(proto)) { + err = udplite_checksum_init(skb, uh); + if (err) + return err; + } + + iph = ip_hdr(skb); + if (uh->check == 0) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else if (skb->ip_summed == CHECKSUM_COMPLETE) { + if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, + proto, skb->csum)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + if (!skb_csum_unnecessary(skb)) + skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, + skb->len, proto, 0); + /* Probably, we should checksum udp header (it should be in cache + * in any case) and data in tiny packets (< rx copybreak). + */ + + return 0; +} + +/* + * All we need to do is get the socket, and then do a checksum. + */ + +int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], + int proto) +{ + struct sock *sk; + struct udphdr *uh = udp_hdr(skb); + unsigned short ulen; + struct rtable *rt = (struct rtable*)skb->dst; + __be32 saddr = ip_hdr(skb)->saddr; + __be32 daddr = ip_hdr(skb)->daddr; + + /* + * Validate the packet. + */ + if (!pskb_may_pull(skb, sizeof(struct udphdr))) + goto drop; /* No space for header. */ + + ulen = ntohs(uh->len); + if (ulen > skb->len) + goto short_packet; + + if (IS_PROTO_UDPLITE(proto)) { + /* UDP validates ulen. */ + if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) + goto short_packet; + uh = udp_hdr(skb); + } + + if (udp4_csum_init(skb, uh, proto)) + goto csum_error; + + if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) + return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); + + sk = __udp4_lib_lookup(skb->dev->nd_net, saddr, uh->source, daddr, + uh->dest, inet_iif(skb), udptable); + + if (sk != NULL) { + int ret = 0; + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + ret = udp_queue_rcv_skb(sk, skb); + else + sk_add_backlog(sk, skb); + bh_unlock_sock(sk); + sock_put(sk); + + /* a return value > 0 means to resubmit the input, but + * it wants the return to be -protocol, or 0 + */ + if (ret > 0) + return -ret; + return 0; + } + + if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto drop; + nf_reset(skb); + + /* No socket. Drop packet silently, if checksum is wrong */ + if (udp_lib_checksum_complete(skb)) + goto csum_error; + + UDP_INC_STATS_BH(UDP_MIB_NOPORTS, IS_PROTO_UDPLITE(proto)); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); + + /* + * Hmm. We got an UDP packet to a port to which we + * don't wanna listen. Ignore it. + */ + kfree_skb(skb); + return 0; + +short_packet: + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", + IS_PROTO_UDPLITE(proto) ? "-Lite" : "", + NIPQUAD(saddr), + ntohs(uh->source), + ulen, + skb->len, + NIPQUAD(daddr), + ntohs(uh->dest)); + goto drop; + +csum_error: + /* + * RFC1122: OK. Discards the bad packet silently (as far as + * the network is concerned, anyway) as per 4.1.3.4 (MUST). + */ + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", + IS_PROTO_UDPLITE(proto) ? "-Lite" : "", + NIPQUAD(saddr), + ntohs(uh->source), + NIPQUAD(daddr), + ntohs(uh->dest), + ulen); +drop: + UDP_INC_STATS_BH(UDP_MIB_INERRORS, IS_PROTO_UDPLITE(proto)); + kfree_skb(skb); + return 0; +} + +int udp_rcv(struct sk_buff *skb) +{ + return __udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP); +} + +int udp_destroy_sock(struct sock *sk) +{ + lock_sock(sk); + udp_flush_pending_frames(sk); + release_sock(sk); + return 0; +} + +int udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) +{ + if (IS_SOL_UDPFAMILY(level)) + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_push_pending_frames); + return ip_setsockopt(sk, level, optname, optval, optlen); +} + +#ifdef CONFIG_COMPAT +int compat_udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) +{ + if (IS_SOL_UDPFAMILY(level)) + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_push_pending_frames); + return compat_ip_setsockopt(sk, level, optname, optval, optlen); +} +#endif + +int udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) +{ + if (IS_SOL_UDPFAMILY(level)) + return udp_lib_getsockopt(sk, level, optname, optval, optlen); + return ip_getsockopt(sk, level, optname, optval, optlen); +} + +#ifdef CONFIG_COMPAT +int compat_udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) +{ + if (IS_SOL_UDPFAMILY(level)) + return udp_lib_getsockopt(sk, level, optname, optval, optlen); + return compat_ip_getsockopt(sk, level, optname, optval, optlen); +} +#endif + +/* ------------------------------------------------------------------------ */ +DEFINE_PROTO_INUSE(udp) + +struct proto udp_prot = { + .name = "UDP", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip4_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .destroy = udp_destroy_sock, + .setsockopt = udp_setsockopt, + .getsockopt = udp_getsockopt, + .sendmsg = udp_sendmsg, + .recvmsg = udp_recvmsg, + .sendpage = udp_sendpage, + .backlog_rcv = udp_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udp_v4_get_port, + .memory_allocated = &udp_memory_allocated, + .sysctl_mem = sysctl_udp_mem, + .sysctl_wmem = &sysctl_udp_wmem_min, + .sysctl_rmem = &sysctl_udp_rmem_min, + .obj_size = sizeof(struct udp_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udp_setsockopt, + .compat_getsockopt = compat_udp_getsockopt, +#endif + REF_PROTO_INUSE(udp) +}; + +/* ------------------------------------------------------------------------ */ +static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket) +{ + struct inet_sock *inet = inet_sk(sp); + __be32 dest = inet->daddr; + __be32 src = inet->rcv_saddr; + __u16 destp = ntohs(inet->dport); + __u16 srcp = ntohs(inet->sport); + + sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p", + bucket, src, srcp, dest, destp, sp->sk_state, + atomic_read(&sp->sk_wmem_alloc), + atomic_read(&sp->sk_rmem_alloc), + 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), + atomic_read(&sp->sk_refcnt), sp); +} + +int udp4_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_printf(seq, "%-127s\n", + " sl local_address rem_address st tx_queue " + "rx_queue tr tm->when retrnsmt uid timeout " + "inode"); + else { + char tmpbuf[129]; + struct udp_iter_state *state = seq->private; + + udp4_format_sock(v, tmpbuf, state->bucket); + seq_printf(seq, "%-127s\n", tmpbuf); + } + return 0; +} + +/* ------------------------------------------------------------------------ */ +#ifdef CONFIG_PROC_FS +static struct file_operations udp4_seq_fops; +static struct udp_seq_afinfo udp4_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udp", + .family = AF_INET, + .hashtable = udp_hash, + .seq_show = udp4_seq_show, + .seq_fops = &udp4_seq_fops, +}; + +int __init udp4_proc_init(void) +{ + return udp_proc_register(&udp4_seq_afinfo); +} + +void udp4_proc_exit(void) +{ + udp_proc_unregister(&udp4_seq_afinfo); +} +#endif /* CONFIG_PROC_FS */ + +EXPORT_SYMBOL(udp_prot); +EXPORT_SYMBOL(udp_sendmsg); + diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c deleted file mode 100644 index 001b881ca36f..000000000000 --- a/net/ipv4/udplite.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * UDPLITE An implementation of the UDP-Lite protocol (RFC 3828). - * - * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $ - * - * Authors: Gerrit Renker - * - * Changes: - * Fixes: - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include "udp_impl.h" -DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; - -struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; - -int udplite_get_port(struct sock *sk, unsigned short p, - int (*c)(const struct sock *, const struct sock *)) -{ - return __udp_lib_get_port(sk, p, udplite_hash, c); -} - -static int udplite_v4_get_port(struct sock *sk, unsigned short snum) -{ - return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); -} - -static int udplite_rcv(struct sk_buff *skb) -{ - return __udp4_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); -} - -static void udplite_err(struct sk_buff *skb, u32 info) -{ - __udp4_lib_err(skb, info, udplite_hash); -} - -static struct net_protocol udplite_protocol = { - .handler = udplite_rcv, - .err_handler = udplite_err, - .no_policy = 1, -}; - -DEFINE_PROTO_INUSE(udplite) - -struct proto udplite_prot = { - .name = "UDP-Lite", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip4_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .init = udplite_sk_init, - .destroy = udp_destroy_sock, - .setsockopt = udp_setsockopt, - .getsockopt = udp_getsockopt, - .sendmsg = udp_sendmsg, - .recvmsg = udp_recvmsg, - .sendpage = udp_sendpage, - .backlog_rcv = udp_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udplite_v4_get_port, - .obj_size = sizeof(struct udp_sock), -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udp_setsockopt, - .compat_getsockopt = compat_udp_getsockopt, -#endif - REF_PROTO_INUSE(udplite) -}; - -static struct inet_protosw udplite4_protosw = { - .type = SOCK_DGRAM, - .protocol = IPPROTO_UDPLITE, - .prot = &udplite_prot, - .ops = &inet_dgram_ops, - .capability = -1, - .no_check = 0, /* must checksum (RFC 3828) */ - .flags = INET_PROTOSW_PERMANENT, -}; - -#ifdef CONFIG_PROC_FS -static struct file_operations udplite4_seq_fops; -static struct udp_seq_afinfo udplite4_seq_afinfo = { - .owner = THIS_MODULE, - .name = "udplite", - .family = AF_INET, - .hashtable = udplite_hash, - .seq_show = udp4_seq_show, - .seq_fops = &udplite4_seq_fops, -}; -#endif - -void __init udplite4_register(void) -{ - if (proto_register(&udplite_prot, 1)) - goto out_register_err; - - if (inet_add_protocol(&udplite_protocol, IPPROTO_UDPLITE) < 0) - goto out_unregister_proto; - - inet_register_protosw(&udplite4_protosw); - -#ifdef CONFIG_PROC_FS - if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ - printk(KERN_ERR "%s: Cannot register /proc!\n", __FUNCTION__); -#endif - return; - -out_unregister_proto: - proto_unregister(&udplite_prot); -out_register_err: - printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __FUNCTION__); -} - -EXPORT_SYMBOL(udplite_hash); -EXPORT_SYMBOL(udplite_prot); -EXPORT_SYMBOL(udplite_get_port); diff --git a/net/ipv4/udplite_ipv4.c b/net/ipv4/udplite_ipv4.c new file mode 100644 index 000000000000..001b881ca36f --- /dev/null +++ b/net/ipv4/udplite_ipv4.c @@ -0,0 +1,121 @@ +/* + * UDPLITE An implementation of the UDP-Lite protocol (RFC 3828). + * + * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $ + * + * Authors: Gerrit Renker + * + * Changes: + * Fixes: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "udp_impl.h" +DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; + +struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; + +int udplite_get_port(struct sock *sk, unsigned short p, + int (*c)(const struct sock *, const struct sock *)) +{ + return __udp_lib_get_port(sk, p, udplite_hash, c); +} + +static int udplite_v4_get_port(struct sock *sk, unsigned short snum) +{ + return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); +} + +static int udplite_rcv(struct sk_buff *skb) +{ + return __udp4_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); +} + +static void udplite_err(struct sk_buff *skb, u32 info) +{ + __udp4_lib_err(skb, info, udplite_hash); +} + +static struct net_protocol udplite_protocol = { + .handler = udplite_rcv, + .err_handler = udplite_err, + .no_policy = 1, +}; + +DEFINE_PROTO_INUSE(udplite) + +struct proto udplite_prot = { + .name = "UDP-Lite", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip4_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .init = udplite_sk_init, + .destroy = udp_destroy_sock, + .setsockopt = udp_setsockopt, + .getsockopt = udp_getsockopt, + .sendmsg = udp_sendmsg, + .recvmsg = udp_recvmsg, + .sendpage = udp_sendpage, + .backlog_rcv = udp_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udplite_v4_get_port, + .obj_size = sizeof(struct udp_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udp_setsockopt, + .compat_getsockopt = compat_udp_getsockopt, +#endif + REF_PROTO_INUSE(udplite) +}; + +static struct inet_protosw udplite4_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDPLITE, + .prot = &udplite_prot, + .ops = &inet_dgram_ops, + .capability = -1, + .no_check = 0, /* must checksum (RFC 3828) */ + .flags = INET_PROTOSW_PERMANENT, +}; + +#ifdef CONFIG_PROC_FS +static struct file_operations udplite4_seq_fops; +static struct udp_seq_afinfo udplite4_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udplite", + .family = AF_INET, + .hashtable = udplite_hash, + .seq_show = udp4_seq_show, + .seq_fops = &udplite4_seq_fops, +}; +#endif + +void __init udplite4_register(void) +{ + if (proto_register(&udplite_prot, 1)) + goto out_register_err; + + if (inet_add_protocol(&udplite_protocol, IPPROTO_UDPLITE) < 0) + goto out_unregister_proto; + + inet_register_protosw(&udplite4_protosw); + +#ifdef CONFIG_PROC_FS + if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ + printk(KERN_ERR "%s: Cannot register /proc!\n", __FUNCTION__); +#endif + return; + +out_unregister_proto: + proto_unregister(&udplite_prot); +out_register_err: + printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __FUNCTION__); +} + +EXPORT_SYMBOL(udplite_hash); +EXPORT_SYMBOL(udplite_prot); +EXPORT_SYMBOL(udplite_get_port); -- cgit v1.2.3-59-g8ed1b From db1ed684f6c430c4cdad67d058688b8a1b5e607c Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 21 Feb 2008 16:13:26 +0900 Subject: [IPV6] UDP: Rename IPv6 UDP files. Rename net/ipv6/udp.c to net/ipv6/udp_ipv6.c Rename net/ipv6/udplite.c to net/ipv6/udplite_ipv6.c. Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/Makefile | 4 +- net/ipv6/udp.c | 1065 ----------------------------------------------- net/ipv6/udp_ipv6.c | 1065 +++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/udplite.c | 125 ------ net/ipv6/udplite_ipv6.c | 125 ++++++ 5 files changed, 1192 insertions(+), 1192 deletions(-) delete mode 100644 net/ipv6/udp.c create mode 100644 net/ipv6/udp_ipv6.c delete mode 100644 net/ipv6/udplite.c create mode 100644 net/ipv6/udplite_ipv6.c (limited to 'net') diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 81969479955f..107051f7c227 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_IPV6) += ipv6.o ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ addrlabel.o \ - route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o \ + route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp_ipv6.o \ raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o @@ -17,7 +17,7 @@ ipv6-$(CONFIG_NETFILTER) += netfilter.o ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o ipv6-$(CONFIG_PROC_FS) += proc.o ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o -ipv6-$(CONFIG_IP_UDPLITE) += udplite.o +ipv6-$(CONFIG_IP_UDPLITE) += udplite_ipv6.o ipv6-objs += $(ipv6-y) diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c deleted file mode 100644 index 55feac7ba717..000000000000 --- a/net/ipv6/udp.c +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * UDP over IPv6 - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Based on linux/ipv4/udp.c - * - * $Id: udp.c,v 1.65 2002/02/01 22:01:04 davem Exp $ - * - * Fixes: - * Hideaki YOSHIFUJI : sin6_scope_id support - * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which - * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind - * a single port at the same time. - * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data - * YOSHIFUJI Hideaki @USAGI: convert /proc/net/udp6 to seq_file. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "udp_impl.h" - -static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) -{ - return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); -} - -static struct sock *__udp6_lib_lookup(struct net *net, - struct in6_addr *saddr, __be16 sport, - struct in6_addr *daddr, __be16 dport, - int dif, struct hlist_head udptable[]) -{ - struct sock *sk, *result = NULL; - struct hlist_node *node; - unsigned short hnum = ntohs(dport); - int badness = -1; - - read_lock(&udp_hash_lock); - sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { - struct inet_sock *inet = inet_sk(sk); - - if (sk->sk_net == net && sk->sk_hash == hnum && - sk->sk_family == PF_INET6) { - struct ipv6_pinfo *np = inet6_sk(sk); - int score = 0; - if (inet->dport) { - if (inet->dport != sport) - continue; - score++; - } - if (!ipv6_addr_any(&np->rcv_saddr)) { - if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) - continue; - score++; - } - if (!ipv6_addr_any(&np->daddr)) { - if (!ipv6_addr_equal(&np->daddr, saddr)) - continue; - score++; - } - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - continue; - score++; - } - if (score == 4) { - result = sk; - break; - } else if (score > badness) { - result = sk; - badness = score; - } - } - } - if (result) - sock_hold(result); - read_unlock(&udp_hash_lock); - return result; -} - -/* - * This should be easy, if there is something there we - * return it, otherwise we block. - */ - -int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, - struct msghdr *msg, size_t len, - int noblock, int flags, int *addr_len) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct sk_buff *skb; - unsigned int ulen, copied; - int peeked; - int err; - int is_udplite = IS_UDPLITE(sk); - - if (addr_len) - *addr_len=sizeof(struct sockaddr_in6); - - if (flags & MSG_ERRQUEUE) - return ipv6_recv_error(sk, msg, len); - -try_again: - skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, &err); - if (!skb) - goto out; - - ulen = skb->len - sizeof(struct udphdr); - copied = len; - if (copied > ulen) - copied = ulen; - else if (copied < ulen) - msg->msg_flags |= MSG_TRUNC; - - /* - * If checksum is needed at all, try to do it while copying the - * data. If the data is truncated, or if we only want a partial - * coverage checksum (UDP-Lite), do it before the copy. - */ - - if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { - if (udp_lib_checksum_complete(skb)) - goto csum_copy_err; - } - - if (skb_csum_unnecessary(skb)) - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), - msg->msg_iov, copied ); - else { - err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); - if (err == -EINVAL) - goto csum_copy_err; - } - if (err) - goto out_free; - - if (!peeked) - UDP6_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); - - sock_recv_timestamp(msg, sk, skb); - - /* Copy the address. */ - if (msg->msg_name) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *) msg->msg_name; - sin6->sin6_family = AF_INET6; - sin6->sin6_port = udp_hdr(skb)->source; - sin6->sin6_flowinfo = 0; - sin6->sin6_scope_id = 0; - - if (skb->protocol == htons(ETH_P_IP)) - ipv6_addr_set(&sin6->sin6_addr, 0, 0, - htonl(0xffff), ip_hdr(skb)->saddr); - else { - ipv6_addr_copy(&sin6->sin6_addr, - &ipv6_hdr(skb)->saddr); - if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) - sin6->sin6_scope_id = IP6CB(skb)->iif; - } - - } - if (skb->protocol == htons(ETH_P_IP)) { - if (inet->cmsg_flags) - ip_cmsg_recv(msg, skb); - } else { - if (np->rxopt.all) - datagram_recv_ctl(sk, msg, skb); - } - - err = copied; - if (flags & MSG_TRUNC) - err = ulen; - -out_free: - lock_sock(sk); - skb_free_datagram(sk, skb); - release_sock(sk); -out: - return err; - -csum_copy_err: - lock_sock(sk); - if (!skb_kill_datagram(sk, skb, flags)) - UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); - release_sock(sk); - - if (flags & MSG_DONTWAIT) - return -EAGAIN; - goto try_again; -} - -void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info, - struct hlist_head udptable[] ) -{ - struct ipv6_pinfo *np; - struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; - struct in6_addr *saddr = &hdr->saddr; - struct in6_addr *daddr = &hdr->daddr; - struct udphdr *uh = (struct udphdr*)(skb->data+offset); - struct sock *sk; - int err; - - sk = __udp6_lib_lookup(skb->dev->nd_net, daddr, uh->dest, - saddr, uh->source, inet6_iif(skb), udptable); - if (sk == NULL) - return; - - np = inet6_sk(sk); - - if (!icmpv6_err_convert(type, code, &err) && !np->recverr) - goto out; - - if (sk->sk_state != TCP_ESTABLISHED && !np->recverr) - goto out; - - if (np->recverr) - ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1)); - - sk->sk_err = err; - sk->sk_error_report(sk); -out: - sock_put(sk); -} - -static __inline__ void udpv6_err(struct sk_buff *skb, - struct inet6_skb_parm *opt, int type, - int code, int offset, __be32 info ) -{ - __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); -} - -int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) -{ - struct udp_sock *up = udp_sk(sk); - int rc; - int is_udplite = IS_UDPLITE(sk); - - if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) - goto drop; - - /* - * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). - */ - if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { - - if (up->pcrlen == 0) { /* full coverage was set */ - LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage" - " %d while full coverage %d requested\n", - UDP_SKB_CB(skb)->cscov, skb->len); - goto drop; - } - if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { - LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: coverage %d " - "too small, need min %d\n", - UDP_SKB_CB(skb)->cscov, up->pcrlen); - goto drop; - } - } - - if (sk->sk_filter) { - if (udp_lib_checksum_complete(skb)) - goto drop; - } - - if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { - /* Note that an ENOMEM error is charged twice */ - if (rc == -ENOMEM) - UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); - goto drop; - } - - return 0; -drop: - UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); - kfree_skb(skb); - return -1; -} - -static struct sock *udp_v6_mcast_next(struct sock *sk, - __be16 loc_port, struct in6_addr *loc_addr, - __be16 rmt_port, struct in6_addr *rmt_addr, - int dif) -{ - struct hlist_node *node; - struct sock *s = sk; - unsigned short num = ntohs(loc_port); - - sk_for_each_from(s, node) { - struct inet_sock *inet = inet_sk(s); - - if (s->sk_hash == num && s->sk_family == PF_INET6) { - struct ipv6_pinfo *np = inet6_sk(s); - if (inet->dport) { - if (inet->dport != rmt_port) - continue; - } - if (!ipv6_addr_any(&np->daddr) && - !ipv6_addr_equal(&np->daddr, rmt_addr)) - continue; - - if (s->sk_bound_dev_if && s->sk_bound_dev_if != dif) - continue; - - if (!ipv6_addr_any(&np->rcv_saddr)) { - if (!ipv6_addr_equal(&np->rcv_saddr, loc_addr)) - continue; - } - if (!inet6_mc_check(s, loc_addr, rmt_addr)) - continue; - return s; - } - } - return NULL; -} - -/* - * Note: called only from the BH handler context, - * so we don't need to lock the hashes. - */ -static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, - struct in6_addr *daddr, struct hlist_head udptable[]) -{ - struct sock *sk, *sk2; - const struct udphdr *uh = udp_hdr(skb); - int dif; - - read_lock(&udp_hash_lock); - sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); - dif = inet6_iif(skb); - sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); - if (!sk) { - kfree_skb(skb); - goto out; - } - - sk2 = sk; - while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, - uh->source, saddr, dif))) { - struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); - if (buff) { - bh_lock_sock_nested(sk2); - if (!sock_owned_by_user(sk2)) - udpv6_queue_rcv_skb(sk2, buff); - else - sk_add_backlog(sk2, buff); - bh_unlock_sock(sk2); - } - } - bh_lock_sock_nested(sk); - if (!sock_owned_by_user(sk)) - udpv6_queue_rcv_skb(sk, skb); - else - sk_add_backlog(sk, skb); - bh_unlock_sock(sk); -out: - read_unlock(&udp_hash_lock); - return 0; -} - -static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, - int proto) -{ - int err; - - UDP_SKB_CB(skb)->partial_cov = 0; - UDP_SKB_CB(skb)->cscov = skb->len; - - if (IS_PROTO_UDPLITE(proto)) { - err = udplite_checksum_init(skb, uh); - if (err) - return err; - } - - if (uh->check == 0) { - /* RFC 2460 section 8.1 says that we SHOULD log - this error. Well, it is reasonable. - */ - LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); - return 1; - } - if (skb->ip_summed == CHECKSUM_COMPLETE && - !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, - skb->len, proto, skb->csum)) - skb->ip_summed = CHECKSUM_UNNECESSARY; - - if (!skb_csum_unnecessary(skb)) - skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - skb->len, proto, 0)); - - return 0; -} - -int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], - int proto) -{ - struct sock *sk; - struct udphdr *uh; - struct net_device *dev = skb->dev; - struct in6_addr *saddr, *daddr; - u32 ulen = 0; - - if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto short_packet; - - saddr = &ipv6_hdr(skb)->saddr; - daddr = &ipv6_hdr(skb)->daddr; - uh = udp_hdr(skb); - - ulen = ntohs(uh->len); - if (ulen > skb->len) - goto short_packet; - - if (proto == IPPROTO_UDP) { - /* UDP validates ulen. */ - - /* Check for jumbo payload */ - if (ulen == 0) - ulen = skb->len; - - if (ulen < sizeof(*uh)) - goto short_packet; - - if (ulen < skb->len) { - if (pskb_trim_rcsum(skb, ulen)) - goto short_packet; - saddr = &ipv6_hdr(skb)->saddr; - daddr = &ipv6_hdr(skb)->daddr; - uh = udp_hdr(skb); - } - } - - if (udp6_csum_init(skb, uh, proto)) - goto discard; - - /* - * Multicast receive code - */ - if (ipv6_addr_is_multicast(daddr)) - return __udp6_lib_mcast_deliver(skb, saddr, daddr, udptable); - - /* Unicast */ - - /* - * check socket cache ... must talk to Alan about his plans - * for sock caches... i'll skip this for now. - */ - sk = __udp6_lib_lookup(skb->dev->nd_net, saddr, uh->source, - daddr, uh->dest, inet6_iif(skb), udptable); - - if (sk == NULL) { - if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) - goto discard; - - if (udp_lib_checksum_complete(skb)) - goto discard; - UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, IS_PROTO_UDPLITE(proto)); - - icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); - - kfree_skb(skb); - return 0; - } - - /* deliver */ - - bh_lock_sock_nested(sk); - if (!sock_owned_by_user(sk)) - udpv6_queue_rcv_skb(sk, skb); - else - sk_add_backlog(sk, skb); - bh_unlock_sock(sk); - sock_put(sk); - return 0; - -short_packet: - LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", - IS_PROTO_UDPLITE(proto) ? "-Lite" : "", - ulen, skb->len); - -discard: - UDP6_INC_STATS_BH(UDP_MIB_INERRORS, IS_PROTO_UDPLITE(proto)); - kfree_skb(skb); - return 0; -} - -static __inline__ int udpv6_rcv(struct sk_buff *skb) -{ - return __udp6_lib_rcv(skb, udp_hash, IPPROTO_UDP); -} - -/* - * Throw away all pending data and cancel the corking. Socket is locked. - */ -static void udp_v6_flush_pending_frames(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - - if (up->pending) { - up->len = 0; - up->pending = 0; - ip6_flush_pending_frames(sk); - } -} - -/* - * Sending - */ - -static int udp_v6_push_pending_frames(struct sock *sk) -{ - struct sk_buff *skb; - struct udphdr *uh; - struct udp_sock *up = udp_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct flowi *fl = &inet->cork.fl; - int err = 0; - int is_udplite = IS_UDPLITE(sk); - __wsum csum = 0; - - /* Grab the skbuff where UDP header space exists. */ - if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) - goto out; - - /* - * Create a UDP header - */ - uh = udp_hdr(skb); - uh->source = fl->fl_ip_sport; - uh->dest = fl->fl_ip_dport; - uh->len = htons(up->len); - uh->check = 0; - - if (is_udplite) - csum = udplite_csum_outgoing(sk, skb); - else - csum = udp_csum_outgoing(sk, skb); - - /* add protocol-dependent pseudo-header */ - uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, - up->len, fl->proto, csum ); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - - err = ip6_push_pending_frames(sk); -out: - up->len = 0; - up->pending = 0; - if (!err) - UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); - return err; -} - -int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, - struct msghdr *msg, size_t len) -{ - struct ipv6_txoptions opt_space; - struct udp_sock *up = udp_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name; - struct in6_addr *daddr, *final_p = NULL, final; - struct ipv6_txoptions *opt = NULL; - struct ip6_flowlabel *flowlabel = NULL; - struct flowi fl; - struct dst_entry *dst; - int addr_len = msg->msg_namelen; - int ulen = len; - int hlimit = -1; - int tclass = -1; - int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; - int err; - int connected = 0; - int is_udplite = IS_UDPLITE(sk); - int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); - - /* destination address check */ - if (sin6) { - if (addr_len < offsetof(struct sockaddr, sa_data)) - return -EINVAL; - - switch (sin6->sin6_family) { - case AF_INET6: - if (addr_len < SIN6_LEN_RFC2133) - return -EINVAL; - daddr = &sin6->sin6_addr; - break; - case AF_INET: - goto do_udp_sendmsg; - case AF_UNSPEC: - msg->msg_name = sin6 = NULL; - msg->msg_namelen = addr_len = 0; - daddr = NULL; - break; - default: - return -EINVAL; - } - } else if (!up->pending) { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - daddr = &np->daddr; - } else - daddr = NULL; - - if (daddr) { - if (ipv6_addr_v4mapped(daddr)) { - struct sockaddr_in sin; - sin.sin_family = AF_INET; - sin.sin_port = sin6 ? sin6->sin6_port : inet->dport; - sin.sin_addr.s_addr = daddr->s6_addr32[3]; - msg->msg_name = &sin; - msg->msg_namelen = sizeof(sin); -do_udp_sendmsg: - if (__ipv6_only_sock(sk)) - return -ENETUNREACH; - return udp_sendmsg(iocb, sk, msg, len); - } - } - - if (up->pending == AF_INET) - return udp_sendmsg(iocb, sk, msg, len); - - /* Rough check on arithmetic overflow, - better check is made in ip6_append_data(). - */ - if (len > INT_MAX - sizeof(struct udphdr)) - return -EMSGSIZE; - - if (up->pending) { - /* - * There are pending frames. - * The socket lock must be held while it's corked. - */ - lock_sock(sk); - if (likely(up->pending)) { - if (unlikely(up->pending != AF_INET6)) { - release_sock(sk); - return -EAFNOSUPPORT; - } - dst = NULL; - goto do_append_data; - } - release_sock(sk); - } - ulen += sizeof(struct udphdr); - - memset(&fl, 0, sizeof(fl)); - - if (sin6) { - if (sin6->sin6_port == 0) - return -EINVAL; - - fl.fl_ip_dport = sin6->sin6_port; - daddr = &sin6->sin6_addr; - - if (np->sndflow) { - fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; - if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { - flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); - if (flowlabel == NULL) - return -EINVAL; - daddr = &flowlabel->dst; - } - } - - /* - * Otherwise it will be difficult to maintain - * sk->sk_dst_cache. - */ - if (sk->sk_state == TCP_ESTABLISHED && - ipv6_addr_equal(daddr, &np->daddr)) - daddr = &np->daddr; - - if (addr_len >= sizeof(struct sockaddr_in6) && - sin6->sin6_scope_id && - ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) - fl.oif = sin6->sin6_scope_id; - } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - - fl.fl_ip_dport = inet->dport; - daddr = &np->daddr; - fl.fl6_flowlabel = np->flow_label; - connected = 1; - } - - if (!fl.oif) - fl.oif = sk->sk_bound_dev_if; - - if (msg->msg_controllen) { - opt = &opt_space; - memset(opt, 0, sizeof(struct ipv6_txoptions)); - opt->tot_len = sizeof(*opt); - - err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass); - if (err < 0) { - fl6_sock_release(flowlabel); - return err; - } - if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { - flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); - if (flowlabel == NULL) - return -EINVAL; - } - if (!(opt->opt_nflen|opt->opt_flen)) - opt = NULL; - connected = 0; - } - if (opt == NULL) - opt = np->opt; - if (flowlabel) - opt = fl6_merge_options(&opt_space, flowlabel, opt); - opt = ipv6_fixup_options(&opt_space, opt); - - fl.proto = sk->sk_protocol; - ipv6_addr_copy(&fl.fl6_dst, daddr); - if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) - ipv6_addr_copy(&fl.fl6_src, &np->saddr); - fl.fl_ip_sport = inet->sport; - - /* merge ip6_build_xmit from ip6_output */ - if (opt && opt->srcrt) { - struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; - ipv6_addr_copy(&final, &fl.fl6_dst); - ipv6_addr_copy(&fl.fl6_dst, rt0->addr); - final_p = &final; - connected = 0; - } - - if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) { - fl.oif = np->mcast_oif; - connected = 0; - } - - security_sk_classify_flow(sk, &fl); - - err = ip6_sk_dst_lookup(sk, &dst, &fl); - if (err) - goto out; - if (final_p) - ipv6_addr_copy(&fl.fl6_dst, final_p); - - if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) { - if (err == -EREMOTE) - err = ip6_dst_blackhole(sk, &dst, &fl); - if (err < 0) - goto out; - } - - if (hlimit < 0) { - if (ipv6_addr_is_multicast(&fl.fl6_dst)) - hlimit = np->mcast_hops; - else - hlimit = np->hop_limit; - if (hlimit < 0) - hlimit = dst_metric(dst, RTAX_HOPLIMIT); - if (hlimit < 0) - hlimit = ipv6_get_hoplimit(dst->dev); - } - - if (tclass < 0) { - tclass = np->tclass; - if (tclass < 0) - tclass = 0; - } - - if (msg->msg_flags&MSG_CONFIRM) - goto do_confirm; -back_from_confirm: - - lock_sock(sk); - if (unlikely(up->pending)) { - /* The socket is already corked while preparing it. */ - /* ... which is an evident application bug. --ANK */ - release_sock(sk); - - LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); - err = -EINVAL; - goto out; - } - - up->pending = AF_INET6; - -do_append_data: - up->len += ulen; - getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; - err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, - sizeof(struct udphdr), hlimit, tclass, opt, &fl, - (struct rt6_info*)dst, - corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); - if (err) - udp_v6_flush_pending_frames(sk); - else if (!corkreq) - err = udp_v6_push_pending_frames(sk); - else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) - up->pending = 0; - - if (dst) { - if (connected) { - ip6_dst_store(sk, dst, - ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? - &np->daddr : NULL, -#ifdef CONFIG_IPV6_SUBTREES - ipv6_addr_equal(&fl.fl6_src, &np->saddr) ? - &np->saddr : -#endif - NULL); - } else { - dst_release(dst); - } - } - - if (err > 0) - err = np->recverr ? net_xmit_errno(err) : 0; - release_sock(sk); -out: - fl6_sock_release(flowlabel); - if (!err) - return len; - /* - * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting - * ENOBUFS might not be good (it's not tunable per se), but otherwise - * we don't have a good statistic (IpOutDiscards but it can be too many - * things). We could add another new stat but at least for now that - * seems like overkill. - */ - if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); - } - return err; - -do_confirm: - dst_confirm(dst); - if (!(msg->msg_flags&MSG_PROBE) || len) - goto back_from_confirm; - err = 0; - goto out; -} - -int udpv6_destroy_sock(struct sock *sk) -{ - lock_sock(sk); - udp_v6_flush_pending_frames(sk); - release_sock(sk); - - inet6_destroy_sock(sk); - - return 0; -} - -/* - * Socket option code for UDP - */ -int udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_v6_push_pending_frames); - return ipv6_setsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_v6_push_pending_frames); - return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); -} -#endif - -int udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return ipv6_getsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); -} -#endif - -static struct inet6_protocol udpv6_protocol = { - .handler = udpv6_rcv, - .err_handler = udpv6_err, - .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, -}; - -/* ------------------------------------------------------------------------ */ -#ifdef CONFIG_PROC_FS - -static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket) -{ - struct inet_sock *inet = inet_sk(sp); - struct ipv6_pinfo *np = inet6_sk(sp); - struct in6_addr *dest, *src; - __u16 destp, srcp; - - dest = &np->daddr; - src = &np->rcv_saddr; - destp = ntohs(inet->dport); - srcp = ntohs(inet->sport); - seq_printf(seq, - "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p\n", - bucket, - src->s6_addr32[0], src->s6_addr32[1], - src->s6_addr32[2], src->s6_addr32[3], srcp, - dest->s6_addr32[0], dest->s6_addr32[1], - dest->s6_addr32[2], dest->s6_addr32[3], destp, - sp->sk_state, - atomic_read(&sp->sk_wmem_alloc), - atomic_read(&sp->sk_rmem_alloc), - 0, 0L, 0, - sock_i_uid(sp), 0, - sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp); -} - -int udp6_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_printf(seq, - " sl " - "local_address " - "remote_address " - "st tx_queue rx_queue tr tm->when retrnsmt" - " uid timeout inode\n"); - else - udp6_sock_seq_show(seq, v, ((struct udp_iter_state *)seq->private)->bucket); - return 0; -} - -static struct file_operations udp6_seq_fops; -static struct udp_seq_afinfo udp6_seq_afinfo = { - .owner = THIS_MODULE, - .name = "udp6", - .family = AF_INET6, - .hashtable = udp_hash, - .seq_show = udp6_seq_show, - .seq_fops = &udp6_seq_fops, -}; - -int __init udp6_proc_init(void) -{ - return udp_proc_register(&udp6_seq_afinfo); -} - -void udp6_proc_exit(void) { - udp_proc_unregister(&udp6_seq_afinfo); -} -#endif /* CONFIG_PROC_FS */ - -/* ------------------------------------------------------------------------ */ - -DEFINE_PROTO_INUSE(udpv6) - -struct proto udpv6_prot = { - .name = "UDPv6", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip6_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .destroy = udpv6_destroy_sock, - .setsockopt = udpv6_setsockopt, - .getsockopt = udpv6_getsockopt, - .sendmsg = udpv6_sendmsg, - .recvmsg = udpv6_recvmsg, - .backlog_rcv = udpv6_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udp_v6_get_port, - .memory_allocated = &udp_memory_allocated, - .sysctl_mem = sysctl_udp_mem, - .sysctl_wmem = &sysctl_udp_wmem_min, - .sysctl_rmem = &sysctl_udp_rmem_min, - .obj_size = sizeof(struct udp6_sock), -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udpv6_setsockopt, - .compat_getsockopt = compat_udpv6_getsockopt, -#endif - REF_PROTO_INUSE(udpv6) -}; - -static struct inet_protosw udpv6_protosw = { - .type = SOCK_DGRAM, - .protocol = IPPROTO_UDP, - .prot = &udpv6_prot, - .ops = &inet6_dgram_ops, - .capability =-1, - .no_check = UDP_CSUM_DEFAULT, - .flags = INET_PROTOSW_PERMANENT, -}; - - -int __init udpv6_init(void) -{ - int ret; - - ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP); - if (ret) - goto out; - - ret = inet6_register_protosw(&udpv6_protosw); - if (ret) - goto out_udpv6_protocol; -out: - return ret; - -out_udpv6_protocol: - inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); - goto out; -} - -void udpv6_exit(void) -{ - inet6_unregister_protosw(&udpv6_protosw); - inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); -} diff --git a/net/ipv6/udp_ipv6.c b/net/ipv6/udp_ipv6.c new file mode 100644 index 000000000000..55feac7ba717 --- /dev/null +++ b/net/ipv6/udp_ipv6.c @@ -0,0 +1,1065 @@ +/* + * UDP over IPv6 + * Linux INET6 implementation + * + * Authors: + * Pedro Roque + * + * Based on linux/ipv4/udp.c + * + * $Id: udp.c,v 1.65 2002/02/01 22:01:04 davem Exp $ + * + * Fixes: + * Hideaki YOSHIFUJI : sin6_scope_id support + * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which + * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind + * a single port at the same time. + * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data + * YOSHIFUJI Hideaki @USAGI: convert /proc/net/udp6 to seq_file. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "udp_impl.h" + +static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) +{ + return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); +} + +static struct sock *__udp6_lib_lookup(struct net *net, + struct in6_addr *saddr, __be16 sport, + struct in6_addr *daddr, __be16 dport, + int dif, struct hlist_head udptable[]) +{ + struct sock *sk, *result = NULL; + struct hlist_node *node; + unsigned short hnum = ntohs(dport); + int badness = -1; + + read_lock(&udp_hash_lock); + sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { + struct inet_sock *inet = inet_sk(sk); + + if (sk->sk_net == net && sk->sk_hash == hnum && + sk->sk_family == PF_INET6) { + struct ipv6_pinfo *np = inet6_sk(sk); + int score = 0; + if (inet->dport) { + if (inet->dport != sport) + continue; + score++; + } + if (!ipv6_addr_any(&np->rcv_saddr)) { + if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) + continue; + score++; + } + if (!ipv6_addr_any(&np->daddr)) { + if (!ipv6_addr_equal(&np->daddr, saddr)) + continue; + score++; + } + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) + continue; + score++; + } + if (score == 4) { + result = sk; + break; + } else if (score > badness) { + result = sk; + badness = score; + } + } + } + if (result) + sock_hold(result); + read_unlock(&udp_hash_lock); + return result; +} + +/* + * This should be easy, if there is something there we + * return it, otherwise we block. + */ + +int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len, + int noblock, int flags, int *addr_len) +{ + struct ipv6_pinfo *np = inet6_sk(sk); + struct inet_sock *inet = inet_sk(sk); + struct sk_buff *skb; + unsigned int ulen, copied; + int peeked; + int err; + int is_udplite = IS_UDPLITE(sk); + + if (addr_len) + *addr_len=sizeof(struct sockaddr_in6); + + if (flags & MSG_ERRQUEUE) + return ipv6_recv_error(sk, msg, len); + +try_again: + skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), + &peeked, &err); + if (!skb) + goto out; + + ulen = skb->len - sizeof(struct udphdr); + copied = len; + if (copied > ulen) + copied = ulen; + else if (copied < ulen) + msg->msg_flags |= MSG_TRUNC; + + /* + * If checksum is needed at all, try to do it while copying the + * data. If the data is truncated, or if we only want a partial + * coverage checksum (UDP-Lite), do it before the copy. + */ + + if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { + if (udp_lib_checksum_complete(skb)) + goto csum_copy_err; + } + + if (skb_csum_unnecessary(skb)) + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied ); + else { + err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); + if (err == -EINVAL) + goto csum_copy_err; + } + if (err) + goto out_free; + + if (!peeked) + UDP6_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); + + sock_recv_timestamp(msg, sk, skb); + + /* Copy the address. */ + if (msg->msg_name) { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *) msg->msg_name; + sin6->sin6_family = AF_INET6; + sin6->sin6_port = udp_hdr(skb)->source; + sin6->sin6_flowinfo = 0; + sin6->sin6_scope_id = 0; + + if (skb->protocol == htons(ETH_P_IP)) + ipv6_addr_set(&sin6->sin6_addr, 0, 0, + htonl(0xffff), ip_hdr(skb)->saddr); + else { + ipv6_addr_copy(&sin6->sin6_addr, + &ipv6_hdr(skb)->saddr); + if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) + sin6->sin6_scope_id = IP6CB(skb)->iif; + } + + } + if (skb->protocol == htons(ETH_P_IP)) { + if (inet->cmsg_flags) + ip_cmsg_recv(msg, skb); + } else { + if (np->rxopt.all) + datagram_recv_ctl(sk, msg, skb); + } + + err = copied; + if (flags & MSG_TRUNC) + err = ulen; + +out_free: + lock_sock(sk); + skb_free_datagram(sk, skb); + release_sock(sk); +out: + return err; + +csum_copy_err: + lock_sock(sk); + if (!skb_kill_datagram(sk, skb, flags)) + UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); + release_sock(sk); + + if (flags & MSG_DONTWAIT) + return -EAGAIN; + goto try_again; +} + +void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + int type, int code, int offset, __be32 info, + struct hlist_head udptable[] ) +{ + struct ipv6_pinfo *np; + struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; + struct in6_addr *saddr = &hdr->saddr; + struct in6_addr *daddr = &hdr->daddr; + struct udphdr *uh = (struct udphdr*)(skb->data+offset); + struct sock *sk; + int err; + + sk = __udp6_lib_lookup(skb->dev->nd_net, daddr, uh->dest, + saddr, uh->source, inet6_iif(skb), udptable); + if (sk == NULL) + return; + + np = inet6_sk(sk); + + if (!icmpv6_err_convert(type, code, &err) && !np->recverr) + goto out; + + if (sk->sk_state != TCP_ESTABLISHED && !np->recverr) + goto out; + + if (np->recverr) + ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1)); + + sk->sk_err = err; + sk->sk_error_report(sk); +out: + sock_put(sk); +} + +static __inline__ void udpv6_err(struct sk_buff *skb, + struct inet6_skb_parm *opt, int type, + int code, int offset, __be32 info ) +{ + __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); +} + +int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) +{ + struct udp_sock *up = udp_sk(sk); + int rc; + int is_udplite = IS_UDPLITE(sk); + + if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) + goto drop; + + /* + * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). + */ + if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { + + if (up->pcrlen == 0) { /* full coverage was set */ + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage" + " %d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); + goto drop; + } + if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: coverage %d " + "too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); + goto drop; + } + } + + if (sk->sk_filter) { + if (udp_lib_checksum_complete(skb)) + goto drop; + } + + if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { + /* Note that an ENOMEM error is charged twice */ + if (rc == -ENOMEM) + UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); + goto drop; + } + + return 0; +drop: + UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); + kfree_skb(skb); + return -1; +} + +static struct sock *udp_v6_mcast_next(struct sock *sk, + __be16 loc_port, struct in6_addr *loc_addr, + __be16 rmt_port, struct in6_addr *rmt_addr, + int dif) +{ + struct hlist_node *node; + struct sock *s = sk; + unsigned short num = ntohs(loc_port); + + sk_for_each_from(s, node) { + struct inet_sock *inet = inet_sk(s); + + if (s->sk_hash == num && s->sk_family == PF_INET6) { + struct ipv6_pinfo *np = inet6_sk(s); + if (inet->dport) { + if (inet->dport != rmt_port) + continue; + } + if (!ipv6_addr_any(&np->daddr) && + !ipv6_addr_equal(&np->daddr, rmt_addr)) + continue; + + if (s->sk_bound_dev_if && s->sk_bound_dev_if != dif) + continue; + + if (!ipv6_addr_any(&np->rcv_saddr)) { + if (!ipv6_addr_equal(&np->rcv_saddr, loc_addr)) + continue; + } + if (!inet6_mc_check(s, loc_addr, rmt_addr)) + continue; + return s; + } + } + return NULL; +} + +/* + * Note: called only from the BH handler context, + * so we don't need to lock the hashes. + */ +static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, + struct in6_addr *daddr, struct hlist_head udptable[]) +{ + struct sock *sk, *sk2; + const struct udphdr *uh = udp_hdr(skb); + int dif; + + read_lock(&udp_hash_lock); + sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); + dif = inet6_iif(skb); + sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); + if (!sk) { + kfree_skb(skb); + goto out; + } + + sk2 = sk; + while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, + uh->source, saddr, dif))) { + struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); + if (buff) { + bh_lock_sock_nested(sk2); + if (!sock_owned_by_user(sk2)) + udpv6_queue_rcv_skb(sk2, buff); + else + sk_add_backlog(sk2, buff); + bh_unlock_sock(sk2); + } + } + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + udpv6_queue_rcv_skb(sk, skb); + else + sk_add_backlog(sk, skb); + bh_unlock_sock(sk); +out: + read_unlock(&udp_hash_lock); + return 0; +} + +static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, + int proto) +{ + int err; + + UDP_SKB_CB(skb)->partial_cov = 0; + UDP_SKB_CB(skb)->cscov = skb->len; + + if (IS_PROTO_UDPLITE(proto)) { + err = udplite_checksum_init(skb, uh); + if (err) + return err; + } + + if (uh->check == 0) { + /* RFC 2460 section 8.1 says that we SHOULD log + this error. Well, it is reasonable. + */ + LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); + return 1; + } + if (skb->ip_summed == CHECKSUM_COMPLETE && + !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, + skb->len, proto, skb->csum)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + if (!skb_csum_unnecessary(skb)) + skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + skb->len, proto, 0)); + + return 0; +} + +int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], + int proto) +{ + struct sock *sk; + struct udphdr *uh; + struct net_device *dev = skb->dev; + struct in6_addr *saddr, *daddr; + u32 ulen = 0; + + if (!pskb_may_pull(skb, sizeof(struct udphdr))) + goto short_packet; + + saddr = &ipv6_hdr(skb)->saddr; + daddr = &ipv6_hdr(skb)->daddr; + uh = udp_hdr(skb); + + ulen = ntohs(uh->len); + if (ulen > skb->len) + goto short_packet; + + if (proto == IPPROTO_UDP) { + /* UDP validates ulen. */ + + /* Check for jumbo payload */ + if (ulen == 0) + ulen = skb->len; + + if (ulen < sizeof(*uh)) + goto short_packet; + + if (ulen < skb->len) { + if (pskb_trim_rcsum(skb, ulen)) + goto short_packet; + saddr = &ipv6_hdr(skb)->saddr; + daddr = &ipv6_hdr(skb)->daddr; + uh = udp_hdr(skb); + } + } + + if (udp6_csum_init(skb, uh, proto)) + goto discard; + + /* + * Multicast receive code + */ + if (ipv6_addr_is_multicast(daddr)) + return __udp6_lib_mcast_deliver(skb, saddr, daddr, udptable); + + /* Unicast */ + + /* + * check socket cache ... must talk to Alan about his plans + * for sock caches... i'll skip this for now. + */ + sk = __udp6_lib_lookup(skb->dev->nd_net, saddr, uh->source, + daddr, uh->dest, inet6_iif(skb), udptable); + + if (sk == NULL) { + if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto discard; + + if (udp_lib_checksum_complete(skb)) + goto discard; + UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, IS_PROTO_UDPLITE(proto)); + + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); + + kfree_skb(skb); + return 0; + } + + /* deliver */ + + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + udpv6_queue_rcv_skb(sk, skb); + else + sk_add_backlog(sk, skb); + bh_unlock_sock(sk); + sock_put(sk); + return 0; + +short_packet: + LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", + IS_PROTO_UDPLITE(proto) ? "-Lite" : "", + ulen, skb->len); + +discard: + UDP6_INC_STATS_BH(UDP_MIB_INERRORS, IS_PROTO_UDPLITE(proto)); + kfree_skb(skb); + return 0; +} + +static __inline__ int udpv6_rcv(struct sk_buff *skb) +{ + return __udp6_lib_rcv(skb, udp_hash, IPPROTO_UDP); +} + +/* + * Throw away all pending data and cancel the corking. Socket is locked. + */ +static void udp_v6_flush_pending_frames(struct sock *sk) +{ + struct udp_sock *up = udp_sk(sk); + + if (up->pending) { + up->len = 0; + up->pending = 0; + ip6_flush_pending_frames(sk); + } +} + +/* + * Sending + */ + +static int udp_v6_push_pending_frames(struct sock *sk) +{ + struct sk_buff *skb; + struct udphdr *uh; + struct udp_sock *up = udp_sk(sk); + struct inet_sock *inet = inet_sk(sk); + struct flowi *fl = &inet->cork.fl; + int err = 0; + int is_udplite = IS_UDPLITE(sk); + __wsum csum = 0; + + /* Grab the skbuff where UDP header space exists. */ + if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) + goto out; + + /* + * Create a UDP header + */ + uh = udp_hdr(skb); + uh->source = fl->fl_ip_sport; + uh->dest = fl->fl_ip_dport; + uh->len = htons(up->len); + uh->check = 0; + + if (is_udplite) + csum = udplite_csum_outgoing(sk, skb); + else + csum = udp_csum_outgoing(sk, skb); + + /* add protocol-dependent pseudo-header */ + uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, + up->len, fl->proto, csum ); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + + err = ip6_push_pending_frames(sk); +out: + up->len = 0; + up->pending = 0; + if (!err) + UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); + return err; +} + +int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len) +{ + struct ipv6_txoptions opt_space; + struct udp_sock *up = udp_sk(sk); + struct inet_sock *inet = inet_sk(sk); + struct ipv6_pinfo *np = inet6_sk(sk); + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name; + struct in6_addr *daddr, *final_p = NULL, final; + struct ipv6_txoptions *opt = NULL; + struct ip6_flowlabel *flowlabel = NULL; + struct flowi fl; + struct dst_entry *dst; + int addr_len = msg->msg_namelen; + int ulen = len; + int hlimit = -1; + int tclass = -1; + int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; + int err; + int connected = 0; + int is_udplite = IS_UDPLITE(sk); + int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); + + /* destination address check */ + if (sin6) { + if (addr_len < offsetof(struct sockaddr, sa_data)) + return -EINVAL; + + switch (sin6->sin6_family) { + case AF_INET6: + if (addr_len < SIN6_LEN_RFC2133) + return -EINVAL; + daddr = &sin6->sin6_addr; + break; + case AF_INET: + goto do_udp_sendmsg; + case AF_UNSPEC: + msg->msg_name = sin6 = NULL; + msg->msg_namelen = addr_len = 0; + daddr = NULL; + break; + default: + return -EINVAL; + } + } else if (!up->pending) { + if (sk->sk_state != TCP_ESTABLISHED) + return -EDESTADDRREQ; + daddr = &np->daddr; + } else + daddr = NULL; + + if (daddr) { + if (ipv6_addr_v4mapped(daddr)) { + struct sockaddr_in sin; + sin.sin_family = AF_INET; + sin.sin_port = sin6 ? sin6->sin6_port : inet->dport; + sin.sin_addr.s_addr = daddr->s6_addr32[3]; + msg->msg_name = &sin; + msg->msg_namelen = sizeof(sin); +do_udp_sendmsg: + if (__ipv6_only_sock(sk)) + return -ENETUNREACH; + return udp_sendmsg(iocb, sk, msg, len); + } + } + + if (up->pending == AF_INET) + return udp_sendmsg(iocb, sk, msg, len); + + /* Rough check on arithmetic overflow, + better check is made in ip6_append_data(). + */ + if (len > INT_MAX - sizeof(struct udphdr)) + return -EMSGSIZE; + + if (up->pending) { + /* + * There are pending frames. + * The socket lock must be held while it's corked. + */ + lock_sock(sk); + if (likely(up->pending)) { + if (unlikely(up->pending != AF_INET6)) { + release_sock(sk); + return -EAFNOSUPPORT; + } + dst = NULL; + goto do_append_data; + } + release_sock(sk); + } + ulen += sizeof(struct udphdr); + + memset(&fl, 0, sizeof(fl)); + + if (sin6) { + if (sin6->sin6_port == 0) + return -EINVAL; + + fl.fl_ip_dport = sin6->sin6_port; + daddr = &sin6->sin6_addr; + + if (np->sndflow) { + fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; + if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { + flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); + if (flowlabel == NULL) + return -EINVAL; + daddr = &flowlabel->dst; + } + } + + /* + * Otherwise it will be difficult to maintain + * sk->sk_dst_cache. + */ + if (sk->sk_state == TCP_ESTABLISHED && + ipv6_addr_equal(daddr, &np->daddr)) + daddr = &np->daddr; + + if (addr_len >= sizeof(struct sockaddr_in6) && + sin6->sin6_scope_id && + ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) + fl.oif = sin6->sin6_scope_id; + } else { + if (sk->sk_state != TCP_ESTABLISHED) + return -EDESTADDRREQ; + + fl.fl_ip_dport = inet->dport; + daddr = &np->daddr; + fl.fl6_flowlabel = np->flow_label; + connected = 1; + } + + if (!fl.oif) + fl.oif = sk->sk_bound_dev_if; + + if (msg->msg_controllen) { + opt = &opt_space; + memset(opt, 0, sizeof(struct ipv6_txoptions)); + opt->tot_len = sizeof(*opt); + + err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass); + if (err < 0) { + fl6_sock_release(flowlabel); + return err; + } + if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { + flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); + if (flowlabel == NULL) + return -EINVAL; + } + if (!(opt->opt_nflen|opt->opt_flen)) + opt = NULL; + connected = 0; + } + if (opt == NULL) + opt = np->opt; + if (flowlabel) + opt = fl6_merge_options(&opt_space, flowlabel, opt); + opt = ipv6_fixup_options(&opt_space, opt); + + fl.proto = sk->sk_protocol; + ipv6_addr_copy(&fl.fl6_dst, daddr); + if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) + ipv6_addr_copy(&fl.fl6_src, &np->saddr); + fl.fl_ip_sport = inet->sport; + + /* merge ip6_build_xmit from ip6_output */ + if (opt && opt->srcrt) { + struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; + ipv6_addr_copy(&final, &fl.fl6_dst); + ipv6_addr_copy(&fl.fl6_dst, rt0->addr); + final_p = &final; + connected = 0; + } + + if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) { + fl.oif = np->mcast_oif; + connected = 0; + } + + security_sk_classify_flow(sk, &fl); + + err = ip6_sk_dst_lookup(sk, &dst, &fl); + if (err) + goto out; + if (final_p) + ipv6_addr_copy(&fl.fl6_dst, final_p); + + if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) { + if (err == -EREMOTE) + err = ip6_dst_blackhole(sk, &dst, &fl); + if (err < 0) + goto out; + } + + if (hlimit < 0) { + if (ipv6_addr_is_multicast(&fl.fl6_dst)) + hlimit = np->mcast_hops; + else + hlimit = np->hop_limit; + if (hlimit < 0) + hlimit = dst_metric(dst, RTAX_HOPLIMIT); + if (hlimit < 0) + hlimit = ipv6_get_hoplimit(dst->dev); + } + + if (tclass < 0) { + tclass = np->tclass; + if (tclass < 0) + tclass = 0; + } + + if (msg->msg_flags&MSG_CONFIRM) + goto do_confirm; +back_from_confirm: + + lock_sock(sk); + if (unlikely(up->pending)) { + /* The socket is already corked while preparing it. */ + /* ... which is an evident application bug. --ANK */ + release_sock(sk); + + LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); + err = -EINVAL; + goto out; + } + + up->pending = AF_INET6; + +do_append_data: + up->len += ulen; + getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, + sizeof(struct udphdr), hlimit, tclass, opt, &fl, + (struct rt6_info*)dst, + corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); + if (err) + udp_v6_flush_pending_frames(sk); + else if (!corkreq) + err = udp_v6_push_pending_frames(sk); + else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) + up->pending = 0; + + if (dst) { + if (connected) { + ip6_dst_store(sk, dst, + ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? + &np->daddr : NULL, +#ifdef CONFIG_IPV6_SUBTREES + ipv6_addr_equal(&fl.fl6_src, &np->saddr) ? + &np->saddr : +#endif + NULL); + } else { + dst_release(dst); + } + } + + if (err > 0) + err = np->recverr ? net_xmit_errno(err) : 0; + release_sock(sk); +out: + fl6_sock_release(flowlabel); + if (!err) + return len; + /* + * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting + * ENOBUFS might not be good (it's not tunable per se), but otherwise + * we don't have a good statistic (IpOutDiscards but it can be too many + * things). We could add another new stat but at least for now that + * seems like overkill. + */ + if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { + UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); + } + return err; + +do_confirm: + dst_confirm(dst); + if (!(msg->msg_flags&MSG_PROBE) || len) + goto back_from_confirm; + err = 0; + goto out; +} + +int udpv6_destroy_sock(struct sock *sk) +{ + lock_sock(sk); + udp_v6_flush_pending_frames(sk); + release_sock(sk); + + inet6_destroy_sock(sk); + + return 0; +} + +/* + * Socket option code for UDP + */ +int udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) +{ + if (IS_SOL_UDPFAMILY(level)) + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_v6_push_pending_frames); + return ipv6_setsockopt(sk, level, optname, optval, optlen); +} + +#ifdef CONFIG_COMPAT +int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) +{ + if (IS_SOL_UDPFAMILY(level)) + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_v6_push_pending_frames); + return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); +} +#endif + +int udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) +{ + if (IS_SOL_UDPFAMILY(level)) + return udp_lib_getsockopt(sk, level, optname, optval, optlen); + return ipv6_getsockopt(sk, level, optname, optval, optlen); +} + +#ifdef CONFIG_COMPAT +int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) +{ + if (IS_SOL_UDPFAMILY(level)) + return udp_lib_getsockopt(sk, level, optname, optval, optlen); + return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); +} +#endif + +static struct inet6_protocol udpv6_protocol = { + .handler = udpv6_rcv, + .err_handler = udpv6_err, + .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, +}; + +/* ------------------------------------------------------------------------ */ +#ifdef CONFIG_PROC_FS + +static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket) +{ + struct inet_sock *inet = inet_sk(sp); + struct ipv6_pinfo *np = inet6_sk(sp); + struct in6_addr *dest, *src; + __u16 destp, srcp; + + dest = &np->daddr; + src = &np->rcv_saddr; + destp = ntohs(inet->dport); + srcp = ntohs(inet->sport); + seq_printf(seq, + "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " + "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p\n", + bucket, + src->s6_addr32[0], src->s6_addr32[1], + src->s6_addr32[2], src->s6_addr32[3], srcp, + dest->s6_addr32[0], dest->s6_addr32[1], + dest->s6_addr32[2], dest->s6_addr32[3], destp, + sp->sk_state, + atomic_read(&sp->sk_wmem_alloc), + atomic_read(&sp->sk_rmem_alloc), + 0, 0L, 0, + sock_i_uid(sp), 0, + sock_i_ino(sp), + atomic_read(&sp->sk_refcnt), sp); +} + +int udp6_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_printf(seq, + " sl " + "local_address " + "remote_address " + "st tx_queue rx_queue tr tm->when retrnsmt" + " uid timeout inode\n"); + else + udp6_sock_seq_show(seq, v, ((struct udp_iter_state *)seq->private)->bucket); + return 0; +} + +static struct file_operations udp6_seq_fops; +static struct udp_seq_afinfo udp6_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udp6", + .family = AF_INET6, + .hashtable = udp_hash, + .seq_show = udp6_seq_show, + .seq_fops = &udp6_seq_fops, +}; + +int __init udp6_proc_init(void) +{ + return udp_proc_register(&udp6_seq_afinfo); +} + +void udp6_proc_exit(void) { + udp_proc_unregister(&udp6_seq_afinfo); +} +#endif /* CONFIG_PROC_FS */ + +/* ------------------------------------------------------------------------ */ + +DEFINE_PROTO_INUSE(udpv6) + +struct proto udpv6_prot = { + .name = "UDPv6", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip6_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .destroy = udpv6_destroy_sock, + .setsockopt = udpv6_setsockopt, + .getsockopt = udpv6_getsockopt, + .sendmsg = udpv6_sendmsg, + .recvmsg = udpv6_recvmsg, + .backlog_rcv = udpv6_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udp_v6_get_port, + .memory_allocated = &udp_memory_allocated, + .sysctl_mem = sysctl_udp_mem, + .sysctl_wmem = &sysctl_udp_wmem_min, + .sysctl_rmem = &sysctl_udp_rmem_min, + .obj_size = sizeof(struct udp6_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udpv6_setsockopt, + .compat_getsockopt = compat_udpv6_getsockopt, +#endif + REF_PROTO_INUSE(udpv6) +}; + +static struct inet_protosw udpv6_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDP, + .prot = &udpv6_prot, + .ops = &inet6_dgram_ops, + .capability =-1, + .no_check = UDP_CSUM_DEFAULT, + .flags = INET_PROTOSW_PERMANENT, +}; + + +int __init udpv6_init(void) +{ + int ret; + + ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP); + if (ret) + goto out; + + ret = inet6_register_protosw(&udpv6_protosw); + if (ret) + goto out_udpv6_protocol; +out: + return ret; + +out_udpv6_protocol: + inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); + goto out; +} + +void udpv6_exit(void) +{ + inet6_unregister_protosw(&udpv6_protosw); + inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); +} diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c deleted file mode 100644 index 87d4202522ee..000000000000 --- a/net/ipv6/udplite.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * UDPLITEv6 An implementation of the UDP-Lite protocol over IPv6. - * See also net/ipv4/udplite.c - * - * Version: $Id: udplite.c,v 1.9 2006/10/19 08:28:10 gerrit Exp $ - * - * Authors: Gerrit Renker - * - * Changes: - * Fixes: - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include "udp_impl.h" - -DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6) __read_mostly; - -static int udplitev6_rcv(struct sk_buff *skb) -{ - return __udp6_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); -} - -static void udplitev6_err(struct sk_buff *skb, - struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) -{ - __udp6_lib_err(skb, opt, type, code, offset, info, udplite_hash); -} - -static struct inet6_protocol udplitev6_protocol = { - .handler = udplitev6_rcv, - .err_handler = udplitev6_err, - .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, -}; - -static int udplite_v6_get_port(struct sock *sk, unsigned short snum) -{ - return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal); -} - -DEFINE_PROTO_INUSE(udplitev6) - -struct proto udplitev6_prot = { - .name = "UDPLITEv6", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip6_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .init = udplite_sk_init, - .destroy = udpv6_destroy_sock, - .setsockopt = udpv6_setsockopt, - .getsockopt = udpv6_getsockopt, - .sendmsg = udpv6_sendmsg, - .recvmsg = udpv6_recvmsg, - .backlog_rcv = udpv6_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udplite_v6_get_port, - .obj_size = sizeof(struct udp6_sock), -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udpv6_setsockopt, - .compat_getsockopt = compat_udpv6_getsockopt, -#endif - REF_PROTO_INUSE(udplitev6) -}; - -static struct inet_protosw udplite6_protosw = { - .type = SOCK_DGRAM, - .protocol = IPPROTO_UDPLITE, - .prot = &udplitev6_prot, - .ops = &inet6_dgram_ops, - .capability = -1, - .no_check = 0, - .flags = INET_PROTOSW_PERMANENT, -}; - -int __init udplitev6_init(void) -{ - int ret; - - ret = inet6_add_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); - if (ret) - goto out; - - ret = inet6_register_protosw(&udplite6_protosw); - if (ret) - goto out_udplitev6_protocol; -out: - return ret; - -out_udplitev6_protocol: - inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); - goto out; -} - -void udplitev6_exit(void) -{ - inet6_unregister_protosw(&udplite6_protosw); - inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); -} - -#ifdef CONFIG_PROC_FS -static struct file_operations udplite6_seq_fops; -static struct udp_seq_afinfo udplite6_seq_afinfo = { - .owner = THIS_MODULE, - .name = "udplite6", - .family = AF_INET6, - .hashtable = udplite_hash, - .seq_show = udp6_seq_show, - .seq_fops = &udplite6_seq_fops, -}; - -int __init udplite6_proc_init(void) -{ - return udp_proc_register(&udplite6_seq_afinfo); -} - -void udplite6_proc_exit(void) -{ - udp_proc_unregister(&udplite6_seq_afinfo); -} -#endif diff --git a/net/ipv6/udplite_ipv6.c b/net/ipv6/udplite_ipv6.c new file mode 100644 index 000000000000..87d4202522ee --- /dev/null +++ b/net/ipv6/udplite_ipv6.c @@ -0,0 +1,125 @@ +/* + * UDPLITEv6 An implementation of the UDP-Lite protocol over IPv6. + * See also net/ipv4/udplite.c + * + * Version: $Id: udplite.c,v 1.9 2006/10/19 08:28:10 gerrit Exp $ + * + * Authors: Gerrit Renker + * + * Changes: + * Fixes: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "udp_impl.h" + +DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6) __read_mostly; + +static int udplitev6_rcv(struct sk_buff *skb) +{ + return __udp6_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); +} + +static void udplitev6_err(struct sk_buff *skb, + struct inet6_skb_parm *opt, + int type, int code, int offset, __be32 info) +{ + __udp6_lib_err(skb, opt, type, code, offset, info, udplite_hash); +} + +static struct inet6_protocol udplitev6_protocol = { + .handler = udplitev6_rcv, + .err_handler = udplitev6_err, + .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, +}; + +static int udplite_v6_get_port(struct sock *sk, unsigned short snum) +{ + return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal); +} + +DEFINE_PROTO_INUSE(udplitev6) + +struct proto udplitev6_prot = { + .name = "UDPLITEv6", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip6_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .init = udplite_sk_init, + .destroy = udpv6_destroy_sock, + .setsockopt = udpv6_setsockopt, + .getsockopt = udpv6_getsockopt, + .sendmsg = udpv6_sendmsg, + .recvmsg = udpv6_recvmsg, + .backlog_rcv = udpv6_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udplite_v6_get_port, + .obj_size = sizeof(struct udp6_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udpv6_setsockopt, + .compat_getsockopt = compat_udpv6_getsockopt, +#endif + REF_PROTO_INUSE(udplitev6) +}; + +static struct inet_protosw udplite6_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDPLITE, + .prot = &udplitev6_prot, + .ops = &inet6_dgram_ops, + .capability = -1, + .no_check = 0, + .flags = INET_PROTOSW_PERMANENT, +}; + +int __init udplitev6_init(void) +{ + int ret; + + ret = inet6_add_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); + if (ret) + goto out; + + ret = inet6_register_protosw(&udplite6_protosw); + if (ret) + goto out_udplitev6_protocol; +out: + return ret; + +out_udplitev6_protocol: + inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); + goto out; +} + +void udplitev6_exit(void) +{ + inet6_unregister_protosw(&udplite6_protosw); + inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); +} + +#ifdef CONFIG_PROC_FS +static struct file_operations udplite6_seq_fops; +static struct udp_seq_afinfo udplite6_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udplite6", + .family = AF_INET6, + .hashtable = udplite_hash, + .seq_show = udp6_seq_show, + .seq_fops = &udplite6_seq_fops, +}; + +int __init udplite6_proc_init(void) +{ + return udp_proc_register(&udplite6_seq_afinfo); +} + +void udplite6_proc_exit(void) +{ + udp_proc_unregister(&udplite6_seq_afinfo); +} +#endif -- cgit v1.2.3-59-g8ed1b From 662397fd7aaa10afdbdc55a0bfdb7e9701454c27 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 27 Feb 2008 23:14:03 +0900 Subject: [IPV6]: Move packet_type{} related bits to af_inet6.c. Signed-off-by: YOSHIFUJI Hideaki --- include/net/ipv6.h | 4 -- net/ipv6/af_inet6.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/ipv6_sockglue.c | 122 ---------------------------------------------- 3 files changed, 123 insertions(+), 126 deletions(-) (limited to 'net') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 96b1763bfcaa..5dc8164e5d3b 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -555,10 +555,6 @@ extern int compat_ipv6_getsockopt(struct sock *sk, char __user *optval, int __user *optlen); -extern int ipv6_packet_init(void); - -extern void ipv6_packet_cleanup(void); - extern int ip6_datagram_connect(struct sock *sk, struct sockaddr *addr, int addr_len); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 243c42a6b80d..73021d5baece 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -678,6 +678,129 @@ int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb) EXPORT_SYMBOL_GPL(ipv6_opt_accepted); +static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb, + int proto) +{ + struct inet6_protocol *ops = NULL; + + for (;;) { + struct ipv6_opt_hdr *opth; + int len; + + if (proto != NEXTHDR_HOP) { + ops = rcu_dereference(inet6_protos[proto]); + + if (unlikely(!ops)) + break; + + if (!(ops->flags & INET6_PROTO_GSO_EXTHDR)) + break; + } + + if (unlikely(!pskb_may_pull(skb, 8))) + break; + + opth = (void *)skb->data; + len = ipv6_optlen(opth); + + if (unlikely(!pskb_may_pull(skb, len))) + break; + + proto = opth->nexthdr; + __skb_pull(skb, len); + } + + return ops; +} + +static int ipv6_gso_send_check(struct sk_buff *skb) +{ + struct ipv6hdr *ipv6h; + struct inet6_protocol *ops; + int err = -EINVAL; + + if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) + goto out; + + ipv6h = ipv6_hdr(skb); + __skb_pull(skb, sizeof(*ipv6h)); + err = -EPROTONOSUPPORT; + + rcu_read_lock(); + ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); + if (likely(ops && ops->gso_send_check)) { + skb_reset_transport_header(skb); + err = ops->gso_send_check(skb); + } + rcu_read_unlock(); + +out: + return err; +} + +static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) +{ + struct sk_buff *segs = ERR_PTR(-EINVAL); + struct ipv6hdr *ipv6h; + struct inet6_protocol *ops; + + if (!(features & NETIF_F_V6_CSUM)) + features &= ~NETIF_F_SG; + + if (unlikely(skb_shinfo(skb)->gso_type & + ~(SKB_GSO_UDP | + SKB_GSO_DODGY | + SKB_GSO_TCP_ECN | + SKB_GSO_TCPV6 | + 0))) + goto out; + + if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) + goto out; + + ipv6h = ipv6_hdr(skb); + __skb_pull(skb, sizeof(*ipv6h)); + segs = ERR_PTR(-EPROTONOSUPPORT); + + rcu_read_lock(); + ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); + if (likely(ops && ops->gso_segment)) { + skb_reset_transport_header(skb); + segs = ops->gso_segment(skb, features); + } + rcu_read_unlock(); + + if (unlikely(IS_ERR(segs))) + goto out; + + for (skb = segs; skb; skb = skb->next) { + ipv6h = ipv6_hdr(skb); + ipv6h->payload_len = htons(skb->len - skb->mac_len - + sizeof(*ipv6h)); + } + +out: + return segs; +} + +static struct packet_type ipv6_packet_type = { + .type = __constant_htons(ETH_P_IPV6), + .func = ipv6_rcv, + .gso_send_check = ipv6_gso_send_check, + .gso_segment = ipv6_gso_segment, +}; + +static int __init ipv6_packet_init(void) +{ + dev_add_pack(&ipv6_packet_type); + return 0; +} + +static void ipv6_packet_cleanup(void) +{ + dev_remove_pack(&ipv6_packet_type); +} + static int __init init_ipv6_mibs(void) { if (snmp_mib_init((void **)ipv6_statistics, diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 0a18fecb93d1..3bbfdff698d2 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -57,118 +57,6 @@ DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics) __read_mostly; -static struct inet6_protocol *ipv6_gso_pull_exthdrs(struct sk_buff *skb, - int proto) -{ - struct inet6_protocol *ops = NULL; - - for (;;) { - struct ipv6_opt_hdr *opth; - int len; - - if (proto != NEXTHDR_HOP) { - ops = rcu_dereference(inet6_protos[proto]); - - if (unlikely(!ops)) - break; - - if (!(ops->flags & INET6_PROTO_GSO_EXTHDR)) - break; - } - - if (unlikely(!pskb_may_pull(skb, 8))) - break; - - opth = (void *)skb->data; - len = opth->hdrlen * 8 + 8; - - if (unlikely(!pskb_may_pull(skb, len))) - break; - - proto = opth->nexthdr; - __skb_pull(skb, len); - } - - return ops; -} - -static int ipv6_gso_send_check(struct sk_buff *skb) -{ - struct ipv6hdr *ipv6h; - struct inet6_protocol *ops; - int err = -EINVAL; - - if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) - goto out; - - ipv6h = ipv6_hdr(skb); - __skb_pull(skb, sizeof(*ipv6h)); - err = -EPROTONOSUPPORT; - - rcu_read_lock(); - ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); - if (likely(ops && ops->gso_send_check)) { - skb_reset_transport_header(skb); - err = ops->gso_send_check(skb); - } - rcu_read_unlock(); - -out: - return err; -} - -static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features) -{ - struct sk_buff *segs = ERR_PTR(-EINVAL); - struct ipv6hdr *ipv6h; - struct inet6_protocol *ops; - - if (!(features & NETIF_F_V6_CSUM)) - features &= ~NETIF_F_SG; - - if (unlikely(skb_shinfo(skb)->gso_type & - ~(SKB_GSO_UDP | - SKB_GSO_DODGY | - SKB_GSO_TCP_ECN | - SKB_GSO_TCPV6 | - 0))) - goto out; - - if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) - goto out; - - ipv6h = ipv6_hdr(skb); - __skb_pull(skb, sizeof(*ipv6h)); - segs = ERR_PTR(-EPROTONOSUPPORT); - - rcu_read_lock(); - ops = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); - if (likely(ops && ops->gso_segment)) { - skb_reset_transport_header(skb); - segs = ops->gso_segment(skb, features); - } - rcu_read_unlock(); - - if (unlikely(IS_ERR(segs))) - goto out; - - for (skb = segs; skb; skb = skb->next) { - ipv6h = ipv6_hdr(skb); - ipv6h->payload_len = htons(skb->len - skb->mac_len - - sizeof(*ipv6h)); - } - -out: - return segs; -} - -static struct packet_type ipv6_packet_type = { - .type = __constant_htons(ETH_P_IPV6), - .func = ipv6_rcv, - .gso_send_check = ipv6_gso_send_check, - .gso_segment = ipv6_gso_segment, -}; - struct ip6_ra_chain *ip6_ra_chain; DEFINE_RWLOCK(ip6_ra_lock); @@ -1132,13 +1020,3 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, EXPORT_SYMBOL(compat_ipv6_getsockopt); #endif -int __init ipv6_packet_init(void) -{ - dev_add_pack(&ipv6_packet_type); - return 0; -} - -void ipv6_packet_cleanup(void) -{ - dev_remove_pack(&ipv6_packet_type); -} -- cgit v1.2.3-59-g8ed1b From 5ee091050986796856cc6207d86b38b4ef6bd8f4 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 28 Feb 2008 00:24:28 +0900 Subject: [IPV6] SYSCTL: complete initialization for sysctl table in subsystem code. Move initialization bits for subsystem sysctl tables to appropriate functions. - route - icmp Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/icmp.c | 4 ++++ net/ipv6/route.c | 14 ++++++++++++++ net/ipv6/sysctl_net_ipv6.c | 15 +-------------- 3 files changed, 19 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 8f44d49fcee2..12c0b85d6c46 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -955,6 +955,10 @@ struct ctl_table *ipv6_icmp_sysctl_init(struct net *net) table = kmemdup(ipv6_icmp_table_template, sizeof(ipv6_icmp_table_template), GFP_KERNEL); + + if (table) + table[0].data = &net->ipv6.sysctl.icmpv6_time; + return table; } #endif diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e8b241cb60bc..1b15e1708409 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2505,6 +2505,20 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net) table = kmemdup(ipv6_route_table_template, sizeof(ipv6_route_table_template), GFP_KERNEL); + + if (table) { + table[0].data = &net->ipv6.sysctl.flush_delay; + /* table[1].data will be handled when we have + routes per namespace */ + table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; + table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; + table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout; + table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval; + table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity; + table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires; + table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss; + } + return table; } #endif diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index d6d3e68086f8..3804dcbbfab0 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -71,24 +71,11 @@ static int ipv6_sysctl_net_init(struct net *net) ipv6_route_table = ipv6_route_sysctl_init(net); if (!ipv6_route_table) goto out_ipv6_table; + ipv6_table[0].child = ipv6_route_table; ipv6_icmp_table = ipv6_icmp_sysctl_init(net); if (!ipv6_icmp_table) goto out_ipv6_route_table; - - ipv6_route_table[0].data = &net->ipv6.sysctl.flush_delay; - /* ipv6_route_table[1].data will be handled when we have - routes per namespace */ - ipv6_route_table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; - ipv6_route_table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; - ipv6_route_table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout; - ipv6_route_table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval; - ipv6_route_table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity; - ipv6_route_table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires; - ipv6_route_table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss; - ipv6_table[0].child = ipv6_route_table; - - ipv6_icmp_table[0].data = &net->ipv6.sysctl.icmpv6_time; ipv6_table[1].child = ipv6_icmp_table; ipv6_table[2].data = &net->ipv6.sysctl.bindv6only; -- cgit v1.2.3-59-g8ed1b From 5e5f3f0f801321078c897a5de0b4b4304f234da0 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Mon, 3 Mar 2008 21:44:34 +0900 Subject: [IPV6] ADDRCONF: Convert ipv6_get_saddr() to ipv6_dev_get_saddr(). Since most users of ipv6_get_saddr() pass non-NULL as dst argument, use ipv6_dev_get_saddr() directly. Signed-off-by: YOSHIFUJI Hideaki --- include/net/addrconf.h | 3 --- net/ipv6/addrconf.c | 9 +-------- net/ipv6/fib6_rules.c | 4 ++-- net/ipv6/ip6_output.c | 3 ++- net/ipv6/route.c | 3 ++- net/ipv6/xfrm6_policy.c | 5 +++-- net/sctp/ipv6.c | 3 ++- 7 files changed, 12 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/include/net/addrconf.h b/include/net/addrconf.h index a9ff97c120c7..89e3c53c8886 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -73,9 +73,6 @@ extern struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, struct net_device *dev, int strict); -extern int ipv6_get_saddr(struct dst_entry *dst, - struct in6_addr *daddr, - struct in6_addr *saddr); extern int ipv6_dev_get_saddr(struct net_device *dev, struct in6_addr *daddr, struct in6_addr *saddr); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 18e3a9825d81..9b3a2d0e4269 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1167,14 +1167,7 @@ record_it: return 0; } - -int ipv6_get_saddr(struct dst_entry *dst, - struct in6_addr *daddr, struct in6_addr *saddr) -{ - return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr); -} - -EXPORT_SYMBOL(ipv6_get_saddr); +EXPORT_SYMBOL(ipv6_dev_get_saddr); int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, unsigned char banned_flags) diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 695c0ca8a417..157db3a1ce00 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -85,8 +85,8 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, if ((rule->flags & FIB_RULE_FIND_SADDR) && r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) { struct in6_addr saddr; - if (ipv6_get_saddr(&rt->u.dst, &flp->fl6_dst, - &saddr)) + if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev, + &flp->fl6_dst, &saddr)) goto again; if (!ipv6_prefix_equal(&saddr, &r->src.addr, r->src.plen)) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index a59d259cf97e..ff3971173e1e 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -919,7 +919,8 @@ static int ip6_dst_lookup_tail(struct sock *sk, goto out_err_release; if (ipv6_addr_any(&fl->fl6_src)) { - err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); + err = ipv6_dev_get_saddr(ip6_dst_idev(*dst)->dev, + &fl->fl6_dst, &fl->fl6_src); if (err) goto out_err_release; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 1b15e1708409..6abe7da45ef7 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2122,7 +2122,8 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, NLA_PUT_U32(skb, RTA_IIF, iif); else if (dst) { struct in6_addr saddr_buf; - if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) + if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev, + dst, &saddr_buf) == 0) NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 7d20199ee1f3..6ef56303e69e 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -57,8 +57,9 @@ static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) if (IS_ERR(dst)) return -EHOSTUNREACH; - ipv6_get_saddr(dst, (struct in6_addr *)&daddr->a6, - (struct in6_addr *)&saddr->a6); + ipv6_dev_get_saddr(ip6_dst_idev(dst)->dev, + (struct in6_addr *)&daddr->a6, + (struct in6_addr *)&saddr->a6); dst_release(dst); return 0; } diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 87f940587d5f..3e4878800b36 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -313,7 +313,8 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc, __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr)); if (!asoc) { - ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr); + ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, + &daddr->v6.sin6_addr, &saddr->v6.sin6_addr); SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n", NIP6(saddr->v6.sin6_addr)); return; -- cgit v1.2.3-59-g8ed1b From 95e41e93e18d8e1e272ce23d96bae4f17ce11d42 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 6 Dec 2007 15:43:30 -0800 Subject: [IPV6]: Make ndisc_flow_init() common for later use. For later use, this patch is renaming ndisc_flow_init() to icmpv6_flow_init() and putting it in common place. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/icmpv6.h | 8 ++++++++ net/ipv6/icmp.c | 16 ++++++++++++++++ net/ipv6/ndisc.c | 23 ++++------------------- 3 files changed, 28 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/include/linux/icmpv6.h b/include/linux/icmpv6.h index 8f86d6b621c8..e4d4300d768f 100644 --- a/include/linux/icmpv6.h +++ b/include/linux/icmpv6.h @@ -182,6 +182,14 @@ extern int icmpv6_err_convert(int type, int code, extern void icmpv6_cleanup(void); extern void icmpv6_param_prob(struct sk_buff *skb, int code, int pos); + +struct flowi; +extern void icmpv6_flow_init(struct sock *sk, + struct flowi *fl, + u8 type, + const struct in6_addr *saddr, + const struct in6_addr *daddr, + int oif); #endif #endif diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 12c0b85d6c46..cff74127ea32 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -777,6 +777,22 @@ drop_no_count: return 0; } +void icmpv6_flow_init(struct sock *sk, struct flowi *fl, + u8 type, + const struct in6_addr *saddr, + const struct in6_addr *daddr, + int oif) +{ + memset(fl, 0, sizeof(*fl)); + ipv6_addr_copy(&fl->fl6_src, saddr); + ipv6_addr_copy(&fl->fl6_dst, daddr); + fl->proto = IPPROTO_ICMPV6; + fl->fl_icmp_type = type; + fl->fl_icmp_code = 0; + fl->oif = oif; + security_sk_classify_flow(sk, fl); +} + /* * Special lock-class for __icmpv6_sk: */ diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 1fc33c8c7232..8db5f4a419aa 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -441,21 +441,6 @@ static void pndisc_destructor(struct pneigh_entry *n) /* * Send a Neighbour Advertisement */ - -static inline void ndisc_flow_init(struct flowi *fl, u8 type, - struct in6_addr *saddr, struct in6_addr *daddr, - int oif) -{ - memset(fl, 0, sizeof(*fl)); - ipv6_addr_copy(&fl->fl6_src, saddr); - ipv6_addr_copy(&fl->fl6_dst, daddr); - fl->proto = IPPROTO_ICMPV6; - fl->fl_icmp_type = type; - fl->fl_icmp_code = 0; - fl->oif = oif; - security_sk_classify_flow(ndisc_socket->sk, fl); -} - static void __ndisc_send(struct net_device *dev, struct neighbour *neigh, struct in6_addr *daddr, struct in6_addr *saddr, @@ -474,8 +459,8 @@ static void __ndisc_send(struct net_device *dev, type = icmp6h->icmp6_type; - ndisc_flow_init(&fl, type, saddr, daddr, - dev->ifindex); + icmpv6_flow_init(ndisc_socket->sk, &fl, type, + saddr, daddr, dev->ifindex); dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); if (!dst) @@ -1439,8 +1424,8 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, return; } - ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &ipv6_hdr(skb)->saddr, - dev->ifindex); + icmpv6_flow_init(ndisc_socket->sk, &fl, NDISC_REDIRECT, + &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); dst = ip6_route_output(NULL, &fl); if (dst == NULL) -- cgit v1.2.3-59-g8ed1b From 3b00944c5c73c49ef52bf17b66557c43c1d945fe Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 6 Dec 2007 16:11:48 -0800 Subject: [IPV6]: Make ndisc_dst_alloc() common for later use. For later use, this patch is renaming ndisc_dst_alloc() (and related function/structures) to icmp6_dst_alloc() (and so on). This patch also removing unused function- pointer argument for it. Signed-off-by: YOSHIFUJI Hideaki --- include/net/ip6_route.h | 8 ++++---- net/ipv6/ip6_fib.c | 2 +- net/ipv6/ndisc.c | 2 +- net/ipv6/route.c | 27 +++++++++++++-------------- 4 files changed, 19 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index f99e4f0f568f..8d155a645aba 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -73,11 +73,11 @@ extern struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, int oif, int flags); -extern struct dst_entry *ndisc_dst_alloc(struct net_device *dev, +extern struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct neighbour *neigh, - struct in6_addr *addr, - int (*output)(struct sk_buff *)); -extern int ndisc_dst_gc(int *more); + struct in6_addr *addr); +extern int icmp6_dst_gc(int *more); + extern void fib6_force_start_gc(void); extern struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index bab72b6f1444..c70fd38b54b7 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1464,7 +1464,7 @@ void fib6_run_gc(unsigned long dummy) } gc_args.more = 0; - ndisc_dst_gc(&gc_args.more); + icmp6_dst_gc(&gc_args.more); fib6_clean_all(fib6_age, 0, NULL); if (gc_args.more) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 8db5f4a419aa..eb322959a3e1 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -462,7 +462,7 @@ static void __ndisc_send(struct net_device *dev, icmpv6_flow_init(ndisc_socket->sk, &fl, type, saddr, daddr, dev->ifindex); - dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output); + dst = icmp6_dst_alloc(dev, neigh, daddr); if (!dst) return; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6abe7da45ef7..cd717450fb10 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -904,13 +904,12 @@ static inline unsigned int ipv6_advmss(unsigned int mtu) return mtu; } -static struct dst_entry *ndisc_dst_gc_list; -static DEFINE_SPINLOCK(ndisc_lock); +static struct dst_entry *icmp6_dst_gc_list; +static DEFINE_SPINLOCK(icmp6_dst_lock); -struct dst_entry *ndisc_dst_alloc(struct net_device *dev, +struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct neighbour *neigh, - struct in6_addr *addr, - int (*output)(struct sk_buff *)) + struct in6_addr *addr) { struct rt6_info *rt; struct inet6_dev *idev = in6_dev_get(dev); @@ -937,7 +936,7 @@ struct dst_entry *ndisc_dst_alloc(struct net_device *dev, rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255; rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); - rt->u.dst.output = output; + rt->u.dst.output = ip6_output; #if 0 /* there's no chance to use these for ndisc */ rt->u.dst.flags = ipv6_addr_type(addr) & IPV6_ADDR_UNICAST @@ -947,10 +946,10 @@ struct dst_entry *ndisc_dst_alloc(struct net_device *dev, rt->rt6i_dst.plen = 128; #endif - spin_lock_bh(&ndisc_lock); - rt->u.dst.next = ndisc_dst_gc_list; - ndisc_dst_gc_list = &rt->u.dst; - spin_unlock_bh(&ndisc_lock); + spin_lock_bh(&icmp6_dst_lock); + rt->u.dst.next = icmp6_dst_gc_list; + icmp6_dst_gc_list = &rt->u.dst; + spin_unlock_bh(&icmp6_dst_lock); fib6_force_start_gc(); @@ -958,7 +957,7 @@ out: return &rt->u.dst; } -int ndisc_dst_gc(int *more) +int icmp6_dst_gc(int *more) { struct dst_entry *dst, *next, **pprev; int freed; @@ -966,8 +965,8 @@ int ndisc_dst_gc(int *more) next = NULL; freed = 0; - spin_lock_bh(&ndisc_lock); - pprev = &ndisc_dst_gc_list; + spin_lock_bh(&icmp6_dst_lock); + pprev = &icmp6_dst_gc_list; while ((dst = *pprev) != NULL) { if (!atomic_read(&dst->__refcnt)) { @@ -980,7 +979,7 @@ int ndisc_dst_gc(int *more) } } - spin_unlock_bh(&ndisc_lock); + spin_unlock_bh(&icmp6_dst_lock); return freed; } -- cgit v1.2.3-59-g8ed1b From 419271780712091ff2738aee513fa4b5b051fbdc Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 6 Dec 2007 17:40:56 -0800 Subject: [IPV6] MCAST: Use standard path for sending MLD/MLDv2 messages. This is changing the paths for sending MLD/MLDv2 messages from dev_queue_xmit() to standard dst_output(). Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/mcast.c | 66 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 8ce894d90063..a373b8e7f241 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1433,25 +1433,6 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) return skb; } -static inline int mld_dev_queue_xmit2(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - unsigned char ha[MAX_ADDR_LEN]; - - ndisc_mc_map(&ipv6_hdr(skb)->daddr, ha, dev, 1); - if (dev_hard_header(skb, dev, ETH_P_IPV6, ha, NULL, skb->len) < 0) { - kfree_skb(skb); - return -EINVAL; - } - return dev_queue_xmit(skb); -} - -static inline int mld_dev_queue_xmit(struct sk_buff *skb) -{ - return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dev, - mld_dev_queue_xmit2); -} - static void mld_sendpack(struct sk_buff *skb) { struct ipv6hdr *pip6 = ipv6_hdr(skb); @@ -1460,6 +1441,7 @@ static void mld_sendpack(struct sk_buff *skb) int payload_len, mldlen; struct inet6_dev *idev = in6_dev_get(skb->dev); int err; + struct flowi fl; IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); payload_len = (skb->tail - skb->network_header) - sizeof(*pip6); @@ -1469,8 +1451,25 @@ static void mld_sendpack(struct sk_buff *skb) pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen, IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb), mldlen, 0)); + + skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); + + if (!skb->dst) { + err = -ENOMEM; + goto err_out; + } + + icmpv6_flow_init(igmp6_socket->sk, &fl, ICMPV6_MLD2_REPORT, + &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, + skb->dev->ifindex); + + err = xfrm_lookup(&skb->dst, &fl, NULL, 0); + if (err) + goto err_out; + err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, - mld_dev_queue_xmit); + dst_output); +out: if (!err) { ICMP6MSGOUT_INC_STATS_BH(idev, ICMPV6_MLD2_REPORT); ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); @@ -1480,6 +1479,11 @@ static void mld_sendpack(struct sk_buff *skb) if (likely(idev != NULL)) in6_dev_put(idev); + return; + +err_out: + kfree_skb(skb); + goto out; } static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel) @@ -1761,6 +1765,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) u8 ra[8] = { IPPROTO_ICMPV6, 0, IPV6_TLV_ROUTERALERT, 2, 0, 0, IPV6_TLV_PADN, 0 }; + struct flowi fl; rcu_read_lock(); IP6_INC_STATS(__in6_dev_get(dev), @@ -1813,8 +1818,23 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) idev = in6_dev_get(skb->dev); + skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); + if (!skb->dst) { + err = -ENOMEM; + goto err_out; + } + + icmpv6_flow_init(igmp6_socket->sk, &fl, type, + &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, + skb->dev->ifindex); + + err = xfrm_lookup(&skb->dst, &fl, NULL, 0); + if (err) + goto err_out; + err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, - mld_dev_queue_xmit); + dst_output); +out: if (!err) { ICMP6MSGOUT_INC_STATS(idev, type); ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); @@ -1825,6 +1845,10 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) if (likely(idev != NULL)) in6_dev_put(idev); return; + +err_out: + kfree_skb(skb); + goto out; } static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, -- cgit v1.2.3-59-g8ed1b From e0b85590bc1b50c9bbef4dd4738d9995fb1d1f64 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 3 Mar 2008 23:24:31 -0800 Subject: [NETNS][IPV6] ip6_fib - dynamically allocate the fib tables This patch changes the fib6 tables to be dynamically allocated. That provides the ability to make several instances of them when a new network namespace is created. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- net/ipv6/ip6_fib.c | 71 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 23 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index c70fd38b54b7..04d774963f3c 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -166,20 +166,14 @@ static __inline__ void rt6_release(struct rt6_info *rt) dst_free(&rt->u.dst); } -static struct fib6_table fib6_main_tbl = { - .tb6_id = RT6_TABLE_MAIN, - .tb6_root = { - .leaf = &ip6_null_entry, - .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO, - }, -}; +static struct fib6_table *fib6_main_tbl; #ifdef CONFIG_IPV6_MULTIPLE_TABLES #define FIB_TABLE_HASHSZ 256 #else #define FIB_TABLE_HASHSZ 1 #endif -static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ]; +static struct hlist_head *fib_table_hash; static void fib6_link_table(struct fib6_table *tb) { @@ -201,13 +195,8 @@ static void fib6_link_table(struct fib6_table *tb) } #ifdef CONFIG_IPV6_MULTIPLE_TABLES -static struct fib6_table fib6_local_tbl = { - .tb6_id = RT6_TABLE_LOCAL, - .tb6_root = { - .leaf = &ip6_null_entry, - .fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO, - }, -}; + +static struct fib6_table *fib6_local_tbl; static struct fib6_table *fib6_alloc_table(u32 id) { @@ -263,8 +252,8 @@ struct fib6_table *fib6_get_table(u32 id) static void __init fib6_tables_init(void) { - fib6_link_table(&fib6_main_tbl); - fib6_link_table(&fib6_local_tbl); + fib6_link_table(fib6_main_tbl); + fib6_link_table(fib6_local_tbl); } #else @@ -276,18 +265,18 @@ struct fib6_table *fib6_new_table(u32 id) struct fib6_table *fib6_get_table(u32 id) { - return &fib6_main_tbl; + return fib6_main_tbl; } struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags, pol_lookup_t lookup) { - return (struct dst_entry *) lookup(&fib6_main_tbl, fl, flags); + return (struct dst_entry *) lookup(fib6_main_tbl, fl, flags); } static void __init fib6_tables_init(void) { - fib6_link_table(&fib6_main_tbl); + fib6_link_table(fib6_main_tbl); } #endif @@ -1479,22 +1468,53 @@ void fib6_run_gc(unsigned long dummy) int __init fib6_init(void) { - int ret; + int ret = -ENOMEM; fib6_node_kmem = kmem_cache_create("fib6_nodes", sizeof(struct fib6_node), 0, SLAB_HWCACHE_ALIGN, NULL); if (!fib6_node_kmem) - return -ENOMEM; + goto out; + + fib_table_hash = kzalloc(sizeof(*fib_table_hash)*FIB_TABLE_HASHSZ, + GFP_KERNEL); + if (!fib_table_hash) + goto out_kmem_cache_create; + + fib6_main_tbl = kzalloc(sizeof(*fib6_main_tbl), GFP_KERNEL); + if (!fib6_main_tbl) + goto out_fib_table_hash; + + fib6_main_tbl->tb6_id = RT6_TABLE_MAIN; + fib6_main_tbl->tb6_root.leaf = &ip6_null_entry; + fib6_main_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; + +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + fib6_local_tbl = kzalloc(sizeof(*fib6_local_tbl), GFP_KERNEL); + if (!fib6_local_tbl) + goto out_fib6_main_tbl; + + fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL; + fib6_local_tbl->tb6_root.leaf = &ip6_null_entry; + fib6_local_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; +#endif fib6_tables_init(); ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib); if (ret) - goto out_kmem_cache_create; + goto out_fib6_local_tbl; out: return ret; +out_fib6_local_tbl: +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(fib6_local_tbl); +out_fib6_main_tbl: +#endif + kfree(fib6_main_tbl); +out_fib_table_hash: + kfree(fib_table_hash); out_kmem_cache_create: kmem_cache_destroy(fib6_node_kmem); goto out; @@ -1503,5 +1523,10 @@ out_kmem_cache_create: void fib6_gc_cleanup(void) { del_timer(&ip6_fib_timer); +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(fib6_local_tbl); +#endif + kfree(fib6_main_tbl); + kfree(fib_table_hash); kmem_cache_destroy(fib6_node_kmem); } -- cgit v1.2.3-59-g8ed1b From 58f09b78b730cf0d936597272bf35b3d615e967c Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 3 Mar 2008 23:25:27 -0800 Subject: [NETNS][IPV6] ip6_fib - make it per network namespace The fib table for ipv6 are moved to the network namespace structure. All references to them are made relatively to the network namespace. All external calls to the ip6_fib functions taking the network namespace parameter are made using the init_net variable, so the ip6_fib engine is ready for the namespaces but the callers not yet. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 9 +-- include/net/netns/ipv6.h | 5 ++ net/ipv6/fib6_rules.c | 8 +-- net/ipv6/ip6_fib.c | 161 +++++++++++++++++++++++++++-------------------- net/ipv6/route.c | 22 ++++--- 5 files changed, 119 insertions(+), 86 deletions(-) (limited to 'net') diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 953d6040ff50..4d4c8aca8fb9 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -181,10 +181,11 @@ typedef struct rt6_info *(*pol_lookup_t)(struct fib6_table *, * exported functions */ -extern struct fib6_table * fib6_get_table(u32 id); -extern struct fib6_table * fib6_new_table(u32 id); -extern struct dst_entry * fib6_rule_lookup(struct flowi *fl, int flags, - pol_lookup_t lookup); +extern struct fib6_table *fib6_get_table(struct net *net, u32 id); +extern struct fib6_table *fib6_new_table(struct net *net, u32 id); +extern struct dst_entry *fib6_rule_lookup(struct net *net, + struct flowi *fl, int flags, + pol_lookup_t lookup); extern struct fib6_node *fib6_lookup(struct fib6_node *root, struct in6_addr *daddr, diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 82623d3a8e35..b0653261c5a3 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -35,6 +35,11 @@ struct netns_ipv6 { struct xt_table *ip6table_filter; struct xt_table *ip6table_mangle; struct xt_table *ip6table_raw; +#endif + struct hlist_head *fib_table_hash; + struct fib6_table *fib6_main_tbl; +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + struct fib6_table *fib6_local_tbl; #endif struct sock **icmp_sk; }; diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 157db3a1ce00..03ad23a5fd3c 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -31,8 +31,8 @@ struct fib6_rule static struct fib_rules_ops fib6_rules_ops; -struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags, - pol_lookup_t lookup) +struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, + int flags, pol_lookup_t lookup) { struct fib_lookup_arg arg = { .lookup_ptr = lookup, @@ -71,7 +71,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, goto discard_pkt; } - table = fib6_get_table(rule->table); + table = fib6_get_table(&init_net, rule->table); if (table) rt = lookup(table, flp, flags); @@ -151,7 +151,7 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, if (rule->table == RT6_TABLE_UNSPEC) goto errout; - if (fib6_new_table(rule->table) == NULL) { + if (fib6_new_table(&init_net, rule->table) == NULL) { err = -ENOBUFS; goto errout; } diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 04d774963f3c..7b549f0bc428 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -166,16 +166,13 @@ static __inline__ void rt6_release(struct rt6_info *rt) dst_free(&rt->u.dst); } -static struct fib6_table *fib6_main_tbl; - #ifdef CONFIG_IPV6_MULTIPLE_TABLES #define FIB_TABLE_HASHSZ 256 #else #define FIB_TABLE_HASHSZ 1 #endif -static struct hlist_head *fib_table_hash; -static void fib6_link_table(struct fib6_table *tb) +static void fib6_link_table(struct net *net, struct fib6_table *tb) { unsigned int h; @@ -191,13 +188,11 @@ static void fib6_link_table(struct fib6_table *tb) * No protection necessary, this is the only list mutatation * operation, tables never disappear once they exist. */ - hlist_add_head_rcu(&tb->tb6_hlist, &fib_table_hash[h]); + hlist_add_head_rcu(&tb->tb6_hlist, &net->ipv6.fib_table_hash[h]); } #ifdef CONFIG_IPV6_MULTIPLE_TABLES -static struct fib6_table *fib6_local_tbl; - static struct fib6_table *fib6_alloc_table(u32 id) { struct fib6_table *table; @@ -212,26 +207,27 @@ static struct fib6_table *fib6_alloc_table(u32 id) return table; } -struct fib6_table *fib6_new_table(u32 id) +struct fib6_table *fib6_new_table(struct net *net, u32 id) { struct fib6_table *tb; if (id == 0) id = RT6_TABLE_MAIN; - tb = fib6_get_table(id); + tb = fib6_get_table(net, id); if (tb) return tb; tb = fib6_alloc_table(id); if (tb != NULL) - fib6_link_table(tb); + fib6_link_table(net, tb); return tb; } -struct fib6_table *fib6_get_table(u32 id) +struct fib6_table *fib6_get_table(struct net *net, u32 id) { struct fib6_table *tb; + struct hlist_head *head; struct hlist_node *node; unsigned int h; @@ -239,7 +235,8 @@ struct fib6_table *fib6_get_table(u32 id) id = RT6_TABLE_MAIN; h = id & (FIB_TABLE_HASHSZ - 1); rcu_read_lock(); - hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb6_hlist) { + head = &net->ipv6.fib_table_hash[h]; + hlist_for_each_entry_rcu(tb, node, head, tb6_hlist) { if (tb->tb6_id == id) { rcu_read_unlock(); return tb; @@ -250,33 +247,32 @@ struct fib6_table *fib6_get_table(u32 id) return NULL; } -static void __init fib6_tables_init(void) +static void fib6_tables_init(struct net *net) { - fib6_link_table(fib6_main_tbl); - fib6_link_table(fib6_local_tbl); + fib6_link_table(net, net->ipv6.fib6_main_tbl); + fib6_link_table(net, net->ipv6.fib6_local_tbl); } - #else -struct fib6_table *fib6_new_table(u32 id) +struct fib6_table *fib6_new_table(struct net *net, u32 id) { - return fib6_get_table(id); + return fib6_get_table(net, id); } -struct fib6_table *fib6_get_table(u32 id) +struct fib6_table *fib6_get_table(struct net *net, u32 id) { - return fib6_main_tbl; + return net->ipv6.fib6_main_tbl; } -struct dst_entry *fib6_rule_lookup(struct flowi *fl, int flags, - pol_lookup_t lookup) +struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, + int flags, pol_lookup_t lookup) { - return (struct dst_entry *) lookup(fib6_main_tbl, fl, flags); + return (struct dst_entry *) lookup(net->ipv6.fib6_main_tbl, fl, flags); } -static void __init fib6_tables_init(void) +static void fib6_tables_init(struct net *net) { - fib6_link_table(fib6_main_tbl); + fib6_link_table(net, net->ipv6.fib6_main_tbl); } #endif @@ -357,11 +353,9 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) struct fib6_walker_t *w; struct fib6_table *tb; struct hlist_node *node; + struct hlist_head *head; int res = 0; - if (net != &init_net) - return 0; - s_h = cb->args[0]; s_e = cb->args[1]; @@ -390,7 +384,8 @@ static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { e = 0; - hlist_for_each_entry(tb, node, &fib_table_hash[h], tb6_hlist) { + head = &net->ipv6.fib_table_hash[h]; + hlist_for_each_entry(tb, node, head, tb6_hlist) { if (e < s_e) goto next; res = fib6_dump_table(tb, skb, cb); @@ -1360,12 +1355,13 @@ void fib6_clean_all(int (*func)(struct rt6_info *, void *arg), { struct fib6_table *table; struct hlist_node *node; + struct hlist_head *head; unsigned int h; rcu_read_lock(); for (h = 0; h < FIB_TABLE_HASHSZ; h++) { - hlist_for_each_entry_rcu(table, node, &fib_table_hash[h], - tb6_hlist) { + head = &init_net.ipv6.fib_table_hash[h]; + hlist_for_each_entry_rcu(table, node, head, tb6_hlist) { write_lock_bh(&table->tb6_lock); fib6_clean_tree(&table->tb6_root, func, prune, arg); write_unlock_bh(&table->tb6_lock); @@ -1466,55 +1462,88 @@ void fib6_run_gc(unsigned long dummy) spin_unlock_bh(&fib6_gc_lock); } -int __init fib6_init(void) +static int fib6_net_init(struct net *net) { - int ret = -ENOMEM; - fib6_node_kmem = kmem_cache_create("fib6_nodes", - sizeof(struct fib6_node), - 0, SLAB_HWCACHE_ALIGN, - NULL); - if (!fib6_node_kmem) - goto out; + int ret; - fib_table_hash = kzalloc(sizeof(*fib_table_hash)*FIB_TABLE_HASHSZ, - GFP_KERNEL); - if (!fib_table_hash) - goto out_kmem_cache_create; + ret = -ENOMEM; + net->ipv6.fib_table_hash = + kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ, + GFP_KERNEL); + if (!net->ipv6.fib_table_hash) + goto out; - fib6_main_tbl = kzalloc(sizeof(*fib6_main_tbl), GFP_KERNEL); - if (!fib6_main_tbl) + net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl), + GFP_KERNEL); + if (!net->ipv6.fib6_main_tbl) goto out_fib_table_hash; - fib6_main_tbl->tb6_id = RT6_TABLE_MAIN; - fib6_main_tbl->tb6_root.leaf = &ip6_null_entry; - fib6_main_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; + net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN; + net->ipv6.fib6_main_tbl->tb6_root.leaf = &ip6_null_entry; + net->ipv6.fib6_main_tbl->tb6_root.fn_flags = + RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; #ifdef CONFIG_IPV6_MULTIPLE_TABLES - fib6_local_tbl = kzalloc(sizeof(*fib6_local_tbl), GFP_KERNEL); - if (!fib6_local_tbl) + net->ipv6.fib6_local_tbl = kzalloc(sizeof(*net->ipv6.fib6_local_tbl), + GFP_KERNEL); + if (!net->ipv6.fib6_local_tbl) goto out_fib6_main_tbl; - - fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL; - fib6_local_tbl->tb6_root.leaf = &ip6_null_entry; - fib6_local_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; + net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL; + net->ipv6.fib6_local_tbl->tb6_root.leaf = &ip6_null_entry; + net->ipv6.fib6_local_tbl->tb6_root.fn_flags = + RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; #endif + fib6_tables_init(net); - fib6_tables_init(); - - ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib); - if (ret) - goto out_fib6_local_tbl; + ret = 0; out: return ret; -out_fib6_local_tbl: #ifdef CONFIG_IPV6_MULTIPLE_TABLES - kfree(fib6_local_tbl); out_fib6_main_tbl: + kfree(net->ipv6.fib6_main_tbl); #endif - kfree(fib6_main_tbl); out_fib_table_hash: - kfree(fib_table_hash); + kfree(net->ipv6.fib_table_hash); + goto out; + } + +static void fib6_net_exit(struct net *net) +{ +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(net->ipv6.fib6_local_tbl); +#endif + kfree(net->ipv6.fib6_main_tbl); + kfree(net->ipv6.fib_table_hash); +} + +static struct pernet_operations fib6_net_ops = { + .init = fib6_net_init, + .exit = fib6_net_exit, +}; + +int __init fib6_init(void) +{ + int ret = -ENOMEM; + fib6_node_kmem = kmem_cache_create("fib6_nodes", + sizeof(struct fib6_node), + 0, SLAB_HWCACHE_ALIGN, + NULL); + if (!fib6_node_kmem) + goto out; + + ret = register_pernet_subsys(&fib6_net_ops); + if (ret) + goto out_kmem_cache_create; + + ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib); + if (ret) + goto out_unregister_subsys; +out: + return ret; + +out_unregister_subsys: + unregister_pernet_subsys(&fib6_net_ops); out_kmem_cache_create: kmem_cache_destroy(fib6_node_kmem); goto out; @@ -1523,10 +1552,6 @@ out_kmem_cache_create: void fib6_gc_cleanup(void) { del_timer(&ip6_fib_timer); -#ifdef CONFIG_IPV6_MULTIPLE_TABLES - kfree(fib6_local_tbl); -#endif - kfree(fib6_main_tbl); - kfree(fib_table_hash); + unregister_pernet_subsys(&fib6_net_ops); kmem_cache_destroy(fib6_node_kmem); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index cd717450fb10..09206f7ba525 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -571,7 +571,7 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, flags |= RT6_LOOKUP_F_HAS_SADDR; } - dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup); + dst = fib6_rule_lookup(&init_net, &fl, flags, ip6_pol_route_lookup); if (dst->error == 0) return (struct rt6_info *) dst; @@ -758,7 +758,7 @@ void ip6_route_input(struct sk_buff *skb) if (rt6_need_strict(&iph->daddr)) flags |= RT6_LOOKUP_F_IFACE; - skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input); + skb->dst = fib6_rule_lookup(&init_net, &fl, flags, ip6_pol_route_input); } static struct rt6_info *ip6_pol_route_output(struct fib6_table *table, @@ -777,7 +777,7 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) if (!ipv6_addr_any(&fl->fl6_src)) flags |= RT6_LOOKUP_F_HAS_SADDR; - return fib6_rule_lookup(fl, flags, ip6_pol_route_output); + return fib6_rule_lookup(&init_net, fl, flags, ip6_pol_route_output); } EXPORT_SYMBOL(ip6_route_output); @@ -1069,7 +1069,7 @@ int ip6_route_add(struct fib6_config *cfg) if (cfg->fc_metric == 0) cfg->fc_metric = IP6_RT_PRIO_USER; - table = fib6_new_table(cfg->fc_table); + table = fib6_new_table(&init_net, cfg->fc_table); if (table == NULL) { err = -ENOBUFS; goto out; @@ -1275,7 +1275,7 @@ static int ip6_route_del(struct fib6_config *cfg) struct rt6_info *rt; int err = -ESRCH; - table = fib6_get_table(cfg->fc_table); + table = fib6_get_table(&init_net, cfg->fc_table); if (table == NULL) return err; @@ -1390,7 +1390,9 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, if (rt6_need_strict(dest)) flags |= RT6_LOOKUP_F_IFACE; - return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect); + return (struct rt6_info *)fib6_rule_lookup(&init_net, + (struct flowi *)&rdfl, + flags, __ip6_route_redirect); } void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, @@ -1589,7 +1591,7 @@ static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixle struct rt6_info *rt = NULL; struct fib6_table *table; - table = fib6_get_table(RT6_TABLE_INFO); + table = fib6_get_table(&init_net, RT6_TABLE_INFO); if (table == NULL) return NULL; @@ -1644,7 +1646,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d struct rt6_info *rt; struct fib6_table *table; - table = fib6_get_table(RT6_TABLE_DFLT); + table = fib6_get_table(&init_net, RT6_TABLE_DFLT); if (table == NULL) return NULL; @@ -1688,7 +1690,7 @@ void rt6_purge_dflt_routers(void) struct fib6_table *table; /* NOTE: Keep consistent with rt6_get_dflt_router */ - table = fib6_get_table(RT6_TABLE_DFLT); + table = fib6_get_table(&init_net, RT6_TABLE_DFLT); if (table == NULL) return; @@ -1851,7 +1853,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, ipv6_addr_copy(&rt->rt6i_dst.addr, addr); rt->rt6i_dst.plen = 128; - rt->rt6i_table = fib6_get_table(RT6_TABLE_LOCAL); + rt->rt6i_table = fib6_get_table(&init_net, RT6_TABLE_LOCAL); atomic_set(&rt->u.dst.__refcnt, 1); -- cgit v1.2.3-59-g8ed1b From f3db48517f59133610f558f29de8834d7b007691 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 3 Mar 2008 23:27:06 -0800 Subject: [NETNS][IPV6] ip6_fib - fib6_clean_all handle several network namespaces The function fib6_clean_all takes the network namespace as parameter. That allows to flush the routes related to a specific network namespace. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 3 ++- include/net/ip6_route.h | 2 +- net/ipv6/addrconf.c | 3 ++- net/ipv6/ip6_fib.c | 7 ++++--- net/ipv6/route.c | 28 ++++++++++++++++++++-------- 5 files changed, 29 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 4d4c8aca8fb9..e54075d902db 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -195,7 +195,8 @@ struct fib6_node *fib6_locate(struct fib6_node *root, struct in6_addr *daddr, int dst_len, struct in6_addr *saddr, int src_len); -extern void fib6_clean_all(int (*func)(struct rt6_info *, void *arg), +extern void fib6_clean_all(struct net *net, + int (*func)(struct rt6_info *, void *arg), int prune, void *arg); extern int fib6_add(struct fib6_node *root, diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 8d155a645aba..a158abe71933 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -121,7 +121,7 @@ struct rt6_rtnl_dump_arg }; extern int rt6_dump_route(struct rt6_info *rt, void *p_arg); -extern void rt6_ifdown(struct net_device *dev); +extern void rt6_ifdown(struct net *net, struct net_device *dev); extern void rt6_mtu_change(struct net_device *dev, unsigned mtu); extern rwlock_t rt6_lock; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 9b3a2d0e4269..a1d872dacad6 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2431,6 +2431,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) { struct inet6_dev *idev; struct inet6_ifaddr *ifa, **bifa; + struct net *net = dev->nd_net; int i; ASSERT_RTNL(); @@ -2438,7 +2439,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) if (dev == init_net.loopback_dev && how == 1) how = 0; - rt6_ifdown(dev); + rt6_ifdown(net, dev); neigh_ifdown(&nd_tbl, dev); idev = __in6_dev_get(dev); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 7b549f0bc428..0f9dc81f0e61 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1350,7 +1350,7 @@ static void fib6_clean_tree(struct fib6_node *root, fib6_walk(&c.w); } -void fib6_clean_all(int (*func)(struct rt6_info *, void *arg), +void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), int prune, void *arg) { struct fib6_table *table; @@ -1360,7 +1360,7 @@ void fib6_clean_all(int (*func)(struct rt6_info *, void *arg), rcu_read_lock(); for (h = 0; h < FIB_TABLE_HASHSZ; h++) { - head = &init_net.ipv6.fib_table_hash[h]; + head = &net->ipv6.fib_table_hash[h]; hlist_for_each_entry_rcu(table, node, head, tb6_hlist) { write_lock_bh(&table->tb6_lock); fib6_clean_tree(&table->tb6_root, func, prune, arg); @@ -1450,7 +1450,8 @@ void fib6_run_gc(unsigned long dummy) gc_args.more = 0; icmp6_dst_gc(&gc_args.more); - fib6_clean_all(fib6_age, 0, NULL); + + fib6_clean_all(&init_net, fib6_age, 0, NULL); if (gc_args.more) mod_timer(&ip6_fib_timer, jiffies + diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 09206f7ba525..2e6da2afd948 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1870,9 +1870,9 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg) return 0; } -void rt6_ifdown(struct net_device *dev) +void rt6_ifdown(struct net *net, struct net_device *dev) { - fib6_clean_all(fib6_ifdown, 0, dev); + fib6_clean_all(net, fib6_ifdown, 0, dev); } struct rt6_mtu_change_arg @@ -1928,7 +1928,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned mtu) .mtu = mtu, }; - fib6_clean_all(rt6_mtu_change_route, 0, &arg); + fib6_clean_all(dev->nd_net, rt6_mtu_change_route, 0, &arg); } static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { @@ -2318,13 +2318,25 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) static int ipv6_route_show(struct seq_file *m, void *v) { - fib6_clean_all(rt6_info_route, 0, m); + struct net *net = (struct net *)m->private; + fib6_clean_all(net, rt6_info_route, 0, m); return 0; } static int ipv6_route_open(struct inode *inode, struct file *file) { - return single_open(file, ipv6_route_show, NULL); + struct net *net = get_proc_net(inode); + if (!net) + return -ENXIO; + return single_open(file, ipv6_route_show, net); +} + +static int ipv6_route_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct net *net = seq->private; + put_net(net); + return single_release(inode, file); } static const struct file_operations ipv6_route_proc_fops = { @@ -2332,7 +2344,7 @@ static const struct file_operations ipv6_route_proc_fops = { .open = ipv6_route_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = ipv6_route_release, }; static int rt6_stats_seq_show(struct seq_file *seq, void *v) @@ -2570,7 +2582,7 @@ xfrm6_init: out_proc_init: ipv6_route_proc_fini(&init_net); out_fib6_init: - rt6_ifdown(NULL); + rt6_ifdown(&init_net, NULL); fib6_gc_cleanup(); out_kmem_cache: kmem_cache_destroy(ip6_dst_ops.kmem_cachep); @@ -2582,7 +2594,7 @@ void ip6_route_cleanup(void) fib6_rules_cleanup(); ipv6_route_proc_fini(&init_net); xfrm6_fini(); - rt6_ifdown(NULL); + rt6_ifdown(&init_net, NULL); fib6_gc_cleanup(); kmem_cache_destroy(ip6_dst_ops.kmem_cachep); } -- cgit v1.2.3-59-g8ed1b From 5b7c931dff03621ae7ac524c4fa280d4e5f187a4 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 3 Mar 2008 23:28:58 -0800 Subject: [NETNS][IPV6] ip6_fib - add net to gc timer parameter The fib tables are now relative to the network namespace. When the garbage collector timer expires, we must have a network namespace parameter in order to retrieve the tables. For now this is the init_net, but we should be able to have a timer per namespace and use the timer callback parameter to pass the network namespace from the expired timer. The timer callback, fib6_run_gc, is actually used to be called synchronously by some functions and asynchronously when the timer expires. When the timer expires, the delay specified for fib6_run_gc parameter is always zero. So, I changed fib6_run_gc to not be a timer callback but a function called by the timer callback and I added a timer callback where its work is just to retrieve from the data arg of the timer the network namespace and call fib6_run_gc with zero expiring time and the network namespace parameters. That makes the code cleaner for the fib6_run_gc callers. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 3 ++- net/ipv6/ip6_fib.c | 24 ++++++++++++++++-------- net/ipv6/ndisc.c | 5 +++-- net/ipv6/route.c | 8 +++++--- 4 files changed, 26 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index e54075d902db..fae267f65341 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -209,7 +209,8 @@ extern int fib6_del(struct rt6_info *rt, extern void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info); -extern void fib6_run_gc(unsigned long dummy); +extern void fib6_run_gc(unsigned long expires, + struct net *net); extern void fib6_gc_cleanup(void); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 0f9dc81f0e61..9b1c232a29ee 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -93,7 +93,10 @@ static int fib6_walk_continue(struct fib6_walker_t *w); static __u32 rt_sernum; -static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0); +static void fib6_gc_timer_cb(unsigned long arg); + +static DEFINE_TIMER(ip6_fib_timer, fib6_gc_timer_cb, 0, + (unsigned long)&init_net); static struct fib6_walker_t fib6_walker_list = { .prev = &fib6_walker_list, @@ -1432,12 +1435,12 @@ static int fib6_age(struct rt6_info *rt, void *arg) static DEFINE_SPINLOCK(fib6_gc_lock); -void fib6_run_gc(unsigned long dummy) +void fib6_run_gc(unsigned long expires, struct net *net) { - if (dummy != ~0UL) { + if (expires != ~0UL) { spin_lock_bh(&fib6_gc_lock); - gc_args.timeout = dummy ? (int)dummy : - init_net.ipv6.sysctl.ip6_rt_gc_interval; + gc_args.timeout = expires ? (int)expires : + net->ipv6.sysctl.ip6_rt_gc_interval; } else { local_bh_disable(); if (!spin_trylock(&fib6_gc_lock)) { @@ -1445,17 +1448,17 @@ void fib6_run_gc(unsigned long dummy) local_bh_enable(); return; } - gc_args.timeout = init_net.ipv6.sysctl.ip6_rt_gc_interval; + gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval; } gc_args.more = 0; icmp6_dst_gc(&gc_args.more); - fib6_clean_all(&init_net, fib6_age, 0, NULL); + fib6_clean_all(net, fib6_age, 0, NULL); if (gc_args.more) mod_timer(&ip6_fib_timer, jiffies + - init_net.ipv6.sysctl.ip6_rt_gc_interval); + net->ipv6.sysctl.ip6_rt_gc_interval); else { del_timer(&ip6_fib_timer); ip6_fib_timer.expires = 0; @@ -1463,6 +1466,11 @@ void fib6_run_gc(unsigned long dummy) spin_unlock_bh(&fib6_gc_lock); } +static void fib6_gc_timer_cb(unsigned long arg) +{ + fib6_run_gc(0, (struct net *)arg); +} + static int fib6_net_init(struct net *net) { int ret; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index eb322959a3e1..f1c95125100d 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1598,6 +1598,7 @@ int ndisc_rcv(struct sk_buff *skb) static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; + struct net *net = dev->nd_net; if (dev->nd_net != &init_net) return NOTIFY_DONE; @@ -1605,11 +1606,11 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, switch (event) { case NETDEV_CHANGEADDR: neigh_changeaddr(&nd_tbl, dev); - fib6_run_gc(~0UL); + fib6_run_gc(~0UL, net); break; case NETDEV_DOWN: neigh_ifdown(&nd_tbl, dev); - fib6_run_gc(~0UL); + fib6_run_gc(~0UL, net); break; default: break; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 2e6da2afd948..fd44721abebb 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -995,7 +996,7 @@ static int ip6_dst_gc(struct dst_ops *ops) goto out; expire++; - fib6_run_gc(expire); + fib6_run_gc(expire, &init_net); last_gc = now; if (atomic_read(&ip6_dst_ops.entries) < ip6_dst_ops.gc_thresh) expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1; @@ -2413,10 +2414,11 @@ static int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos) { - int delay = init_net.ipv6.sysctl.flush_delay; + struct net *net = current->nsproxy->net_ns; + int delay = net->ipv6.sysctl.flush_delay; if (write) { proc_dointvec(ctl, write, filp, buffer, lenp, ppos); - fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay); + fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net); return 0; } else return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 450d19f8ab35fad4ef2b129cb383a5b8d1326611 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 3 Mar 2008 23:29:33 -0800 Subject: [NETNS][IPV6] ip6_fib - dynamically allocate gc-timer The ip6_fib_timer gc timer is dynamically allocated and initialized in the ip6 fib init function. There are no more references to a static global variable. That will allow to make multiple instance of the garbage collecting timer and make them per namespace. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- net/ipv6/ip6_fib.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 9b1c232a29ee..77ad1002c904 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -95,8 +95,7 @@ static __u32 rt_sernum; static void fib6_gc_timer_cb(unsigned long arg); -static DEFINE_TIMER(ip6_fib_timer, fib6_gc_timer_cb, 0, - (unsigned long)&init_net); +static struct timer_list *ip6_fib_timer; static struct fib6_walker_t fib6_walker_list = { .prev = &fib6_walker_list, @@ -666,16 +665,16 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, static __inline__ void fib6_start_gc(struct rt6_info *rt) { - if (ip6_fib_timer.expires == 0 && + if (ip6_fib_timer->expires == 0 && (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE))) - mod_timer(&ip6_fib_timer, jiffies + + mod_timer(ip6_fib_timer, jiffies + init_net.ipv6.sysctl.ip6_rt_gc_interval); } void fib6_force_start_gc(void) { - if (ip6_fib_timer.expires == 0) - mod_timer(&ip6_fib_timer, jiffies + + if (ip6_fib_timer->expires == 0) + mod_timer(ip6_fib_timer, jiffies + init_net.ipv6.sysctl.ip6_rt_gc_interval); } @@ -1444,7 +1443,7 @@ void fib6_run_gc(unsigned long expires, struct net *net) } else { local_bh_disable(); if (!spin_trylock(&fib6_gc_lock)) { - mod_timer(&ip6_fib_timer, jiffies + HZ); + mod_timer(ip6_fib_timer, jiffies + HZ); local_bh_enable(); return; } @@ -1457,11 +1456,11 @@ void fib6_run_gc(unsigned long expires, struct net *net) fib6_clean_all(net, fib6_age, 0, NULL); if (gc_args.more) - mod_timer(&ip6_fib_timer, jiffies + + mod_timer(ip6_fib_timer, jiffies + net->ipv6.sysctl.ip6_rt_gc_interval); else { - del_timer(&ip6_fib_timer); - ip6_fib_timer.expires = 0; + del_timer(ip6_fib_timer); + ip6_fib_timer->expires = 0; } spin_unlock_bh(&fib6_gc_lock); } @@ -1541,9 +1540,16 @@ int __init fib6_init(void) if (!fib6_node_kmem) goto out; + ret = -ENOMEM; + ip6_fib_timer = kzalloc(sizeof(*ip6_fib_timer), GFP_KERNEL); + if (!ip6_fib_timer) + goto out_kmem_cache_create; + + setup_timer(ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)&init_net); + ret = register_pernet_subsys(&fib6_net_ops); if (ret) - goto out_kmem_cache_create; + goto out_timer; ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib); if (ret) @@ -1553,6 +1559,8 @@ out: out_unregister_subsys: unregister_pernet_subsys(&fib6_net_ops); +out_timer: + kfree(ip6_fib_timer); out_kmem_cache_create: kmem_cache_destroy(fib6_node_kmem); goto out; @@ -1560,7 +1568,8 @@ out_kmem_cache_create: void fib6_gc_cleanup(void) { - del_timer(&ip6_fib_timer); + del_timer(ip6_fib_timer); + kfree(ip6_fib_timer); unregister_pernet_subsys(&fib6_net_ops); kmem_cache_destroy(fib6_node_kmem); } -- cgit v1.2.3-59-g8ed1b From 63152fc0de4dfe83da543bf133cef73d885a50fc Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 3 Mar 2008 23:31:11 -0800 Subject: [NETNS][IPV6] ip6_fib - gc timer per namespace Move the timer initialization at the network namespace creation and store the network namespace in the timer argument. That enables multiple timers (one per network namespace) to do garbage collecting. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/ip6_route.h | 2 +- include/net/netns/ipv6.h | 1 + net/ipv6/ip6_fib.c | 56 ++++++++++++++++++++++++------------------------ net/ipv6/route.c | 5 ++++- 4 files changed, 34 insertions(+), 30 deletions(-) (limited to 'net') diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index a158abe71933..79dce496f4d4 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -78,7 +78,7 @@ extern struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct in6_addr *addr); extern int icmp6_dst_gc(int *more); -extern void fib6_force_start_gc(void); +extern void fib6_force_start_gc(struct net *net); extern struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, const struct in6_addr *addr, diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index b0653261c5a3..5279cd6a00ba 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -36,6 +36,7 @@ struct netns_ipv6 { struct xt_table *ip6table_mangle; struct xt_table *ip6table_raw; #endif + struct timer_list *ip6_fib_timer; struct hlist_head *fib_table_hash; struct fib6_table *fib6_main_tbl; #ifdef CONFIG_IPV6_MULTIPLE_TABLES diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 77ad1002c904..4aa67988f518 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -95,8 +95,6 @@ static __u32 rt_sernum; static void fib6_gc_timer_cb(unsigned long arg); -static struct timer_list *ip6_fib_timer; - static struct fib6_walker_t fib6_walker_list = { .prev = &fib6_walker_list, .next = &fib6_walker_list, @@ -663,19 +661,19 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, return 0; } -static __inline__ void fib6_start_gc(struct rt6_info *rt) +static __inline__ void fib6_start_gc(struct net *net, struct rt6_info *rt) { - if (ip6_fib_timer->expires == 0 && + if (net->ipv6.ip6_fib_timer->expires == 0 && (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE))) - mod_timer(ip6_fib_timer, jiffies + - init_net.ipv6.sysctl.ip6_rt_gc_interval); + mod_timer(net->ipv6.ip6_fib_timer, jiffies + + net->ipv6.sysctl.ip6_rt_gc_interval); } -void fib6_force_start_gc(void) +void fib6_force_start_gc(struct net *net) { - if (ip6_fib_timer->expires == 0) - mod_timer(ip6_fib_timer, jiffies + - init_net.ipv6.sysctl.ip6_rt_gc_interval); + if (net->ipv6.ip6_fib_timer->expires == 0) + mod_timer(net->ipv6.ip6_fib_timer, jiffies + + net->ipv6.sysctl.ip6_rt_gc_interval); } /* @@ -762,7 +760,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) err = fib6_add_rt2node(fn, rt, info); if (err == 0) { - fib6_start_gc(rt); + fib6_start_gc(info->nl_net, rt); if (!(rt->rt6i_flags&RTF_CACHE)) fib6_prune_clones(pn, rt); } @@ -1443,7 +1441,7 @@ void fib6_run_gc(unsigned long expires, struct net *net) } else { local_bh_disable(); if (!spin_trylock(&fib6_gc_lock)) { - mod_timer(ip6_fib_timer, jiffies + HZ); + mod_timer(net->ipv6.ip6_fib_timer, jiffies + HZ); local_bh_enable(); return; } @@ -1456,11 +1454,11 @@ void fib6_run_gc(unsigned long expires, struct net *net) fib6_clean_all(net, fib6_age, 0, NULL); if (gc_args.more) - mod_timer(ip6_fib_timer, jiffies + + mod_timer(net->ipv6.ip6_fib_timer, jiffies + net->ipv6.sysctl.ip6_rt_gc_interval); else { - del_timer(ip6_fib_timer); - ip6_fib_timer->expires = 0; + del_timer(net->ipv6.ip6_fib_timer); + net->ipv6.ip6_fib_timer->expires = 0; } spin_unlock_bh(&fib6_gc_lock); } @@ -1473,13 +1471,21 @@ static void fib6_gc_timer_cb(unsigned long arg) static int fib6_net_init(struct net *net) { int ret; + struct timer_list *timer; ret = -ENOMEM; + timer = kzalloc(sizeof(*timer), GFP_KERNEL); + if (!timer) + goto out; + + setup_timer(timer, fib6_gc_timer_cb, (unsigned long)net); + net->ipv6.ip6_fib_timer = timer; + net->ipv6.fib_table_hash = kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ, GFP_KERNEL); if (!net->ipv6.fib_table_hash) - goto out; + goto out_timer; net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl), GFP_KERNEL); @@ -1513,11 +1519,15 @@ out_fib6_main_tbl: #endif out_fib_table_hash: kfree(net->ipv6.fib_table_hash); +out_timer: + kfree(timer); goto out; } static void fib6_net_exit(struct net *net) { + del_timer(net->ipv6.ip6_fib_timer); + kfree(net->ipv6.ip6_fib_timer); #ifdef CONFIG_IPV6_MULTIPLE_TABLES kfree(net->ipv6.fib6_local_tbl); #endif @@ -1533,6 +1543,7 @@ static struct pernet_operations fib6_net_ops = { int __init fib6_init(void) { int ret = -ENOMEM; + fib6_node_kmem = kmem_cache_create("fib6_nodes", sizeof(struct fib6_node), 0, SLAB_HWCACHE_ALIGN, @@ -1540,16 +1551,9 @@ int __init fib6_init(void) if (!fib6_node_kmem) goto out; - ret = -ENOMEM; - ip6_fib_timer = kzalloc(sizeof(*ip6_fib_timer), GFP_KERNEL); - if (!ip6_fib_timer) - goto out_kmem_cache_create; - - setup_timer(ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)&init_net); - ret = register_pernet_subsys(&fib6_net_ops); if (ret) - goto out_timer; + goto out_kmem_cache_create; ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib); if (ret) @@ -1559,8 +1563,6 @@ out: out_unregister_subsys: unregister_pernet_subsys(&fib6_net_ops); -out_timer: - kfree(ip6_fib_timer); out_kmem_cache_create: kmem_cache_destroy(fib6_node_kmem); goto out; @@ -1568,8 +1570,6 @@ out_kmem_cache_create: void fib6_gc_cleanup(void) { - del_timer(ip6_fib_timer); - kfree(ip6_fib_timer); unregister_pernet_subsys(&fib6_net_ops); kmem_cache_destroy(fib6_node_kmem); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index fd44721abebb..b13eb0111270 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -952,7 +952,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, icmp6_dst_gc_list = &rt->u.dst; spin_unlock_bh(&icmp6_dst_lock); - fib6_force_start_gc(); + fib6_force_start_gc(dev->nd_net); out: return &rt->u.dst; @@ -1230,6 +1230,9 @@ install_route: rt->u.dst.dev = dev; rt->rt6i_idev = idev; rt->rt6i_table = table; + + cfg->fc_nlinfo.nl_net = dev->nd_net; + return __ip6_ins_rt(rt, &cfg->fc_nlinfo); out: -- cgit v1.2.3-59-g8ed1b From ec7d43c291df9f6e978733f892f7255be89feedb Mon Sep 17 00:00:00 2001 From: Benjamin Thery Date: Mon, 3 Mar 2008 23:31:57 -0800 Subject: [NETNS][IPV6] ip6_fib - clean node use namespace The fib6_clean_node function should have the network namespace it is working on. The fib6_cleaner_t structure is extended with the network namespace field to be passed to the fib6_clean_node function. The different functions calling the fib6_clean_node function are extended with the netns parameter when needed to propagate the netns pointer. Signed-off-by: Benjamin Thery Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv6/ip6_fib.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 4aa67988f518..350a970ca1e3 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -66,6 +66,7 @@ enum fib_walk_state_t struct fib6_cleaner_t { struct fib6_walker_t w; + struct net *net; int (*func)(struct rt6_info *, void *arg); void *arg; }; @@ -78,7 +79,8 @@ static DEFINE_RWLOCK(fib6_walker_lock); #define FWS_INIT FWS_L #endif -static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt); +static void fib6_prune_clones(struct net *net, struct fib6_node *fn, + struct rt6_info *rt); static struct rt6_info * fib6_find_prefix(struct fib6_node *fn); static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); static int fib6_walk(struct fib6_walker_t *w); @@ -762,7 +764,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) if (err == 0) { fib6_start_gc(info->nl_net, rt); if (!(rt->rt6i_flags&RTF_CACHE)) - fib6_prune_clones(pn, rt); + fib6_prune_clones(info->nl_net, pn, rt); } out: @@ -1168,7 +1170,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info) pn = pn->parent; } #endif - fib6_prune_clones(pn, rt); + fib6_prune_clones(info->nl_net, pn, rt); } /* @@ -1298,12 +1300,12 @@ static int fib6_walk(struct fib6_walker_t *w) static int fib6_clean_node(struct fib6_walker_t *w) { - struct nl_info info = { - .nl_net = &init_net, - }; int res; struct rt6_info *rt; struct fib6_cleaner_t *c = container_of(w, struct fib6_cleaner_t, w); + struct nl_info info = { + .nl_net = c->net, + }; for (rt = w->leaf; rt; rt = rt->u.dst.rt6_next) { res = c->func(rt, c->arg); @@ -1335,7 +1337,7 @@ static int fib6_clean_node(struct fib6_walker_t *w) * ignoring pure split nodes) will be scanned. */ -static void fib6_clean_tree(struct fib6_node *root, +static void fib6_clean_tree(struct net *net, struct fib6_node *root, int (*func)(struct rt6_info *, void *arg), int prune, void *arg) { @@ -1346,6 +1348,7 @@ static void fib6_clean_tree(struct fib6_node *root, c.w.prune = prune; c.func = func; c.arg = arg; + c.net = net; fib6_walk(&c.w); } @@ -1363,7 +1366,8 @@ void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), head = &net->ipv6.fib_table_hash[h]; hlist_for_each_entry_rcu(table, node, head, tb6_hlist) { write_lock_bh(&table->tb6_lock); - fib6_clean_tree(&table->tb6_root, func, prune, arg); + fib6_clean_tree(net, &table->tb6_root, + func, prune, arg); write_unlock_bh(&table->tb6_lock); } } @@ -1380,9 +1384,10 @@ static int fib6_prune_clone(struct rt6_info *rt, void *arg) return 0; } -static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt) +static void fib6_prune_clones(struct net *net, struct fib6_node *fn, + struct rt6_info *rt) { - fib6_clean_tree(fn, fib6_prune_clone, 1, rt); + fib6_clean_tree(net, fn, fib6_prune_clone, 1, rt); } /* -- cgit v1.2.3-59-g8ed1b From eb5564b8532eec6b49379095df2b979aab85661f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 3 Mar 2008 23:32:30 -0800 Subject: [NETNS][IPV6] fib6 rule - dynamic allocation of the rules struct ops The fib6_rules_ops structure is dynamically allocated, so that allows to make several instances of it per network namespace. The global static fib6_rules_ops structure is renamed to fib6_rules_ops_template in order to quickly memcopy it for the structure initialization. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- net/ipv6/fib6_rules.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 03ad23a5fd3c..60af08f12547 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -29,7 +29,7 @@ struct fib6_rule u8 tclass; }; -static struct fib_rules_ops fib6_rules_ops; +static struct fib_rules_ops *fib6_rules_ops; struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, int flags, pol_lookup_t lookup) @@ -38,7 +38,7 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, .lookup_ptr = lookup, }; - fib_rules_lookup(&fib6_rules_ops, fl, flags, &arg); + fib_rules_lookup(fib6_rules_ops, fl, flags, &arg); if (arg.rule) fib_rule_put(arg.rule); @@ -234,7 +234,7 @@ static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule) + nla_total_size(16); /* src */ } -static struct fib_rules_ops fib6_rules_ops = { +static struct fib_rules_ops fib6_rules_ops_template = { .family = AF_INET6, .rule_size = sizeof(struct fib6_rule), .addr_size = sizeof(struct in6_addr), @@ -247,7 +247,6 @@ static struct fib_rules_ops fib6_rules_ops = { .nlmsg_payload = fib6_rule_nlmsg_payload, .nlgroup = RTNLGRP_IPV6_RULE, .policy = fib6_rule_policy, - .rules_list = LIST_HEAD_INIT(fib6_rules_ops.rules_list), .owner = THIS_MODULE, .fro_net = &init_net, }; @@ -256,11 +255,18 @@ static int __init fib6_default_rules_init(void) { int err; - err = fib_default_rule_add(&fib6_rules_ops, 0, + fib6_rules_ops = kmemdup(&fib6_rules_ops_template, + sizeof(*fib6_rules_ops), GFP_KERNEL); + if (!fib6_rules_ops) + return -ENOMEM; + + INIT_LIST_HEAD(&fib6_rules_ops->rules_list); + + err = fib_default_rule_add(fib6_rules_ops, 0, RT6_TABLE_LOCAL, FIB_RULE_PERMANENT); if (err < 0) return err; - err = fib_default_rule_add(&fib6_rules_ops, 0x7FFE, RT6_TABLE_MAIN, 0); + err = fib_default_rule_add(fib6_rules_ops, 0x7FFE, RT6_TABLE_MAIN, 0); if (err < 0) return err; return 0; @@ -274,18 +280,20 @@ int __init fib6_rules_init(void) if (ret) goto out; - ret = fib_rules_register(&fib6_rules_ops); + ret = fib_rules_register(fib6_rules_ops); if (ret) goto out_default_rules_init; out: return ret; out_default_rules_init: - fib_rules_cleanup_ops(&fib6_rules_ops); + fib_rules_cleanup_ops(fib6_rules_ops); + kfree(fib6_rules_ops); goto out; } void fib6_rules_cleanup(void) { - fib_rules_unregister(&fib6_rules_ops); + fib_rules_unregister(fib6_rules_ops); + kfree(fib6_rules_ops); } -- cgit v1.2.3-59-g8ed1b From dcabb819a6eced95ef531b001e663d0d592c8d9f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 3 Mar 2008 23:33:08 -0800 Subject: [NETNS][IPV6] fib6_rules - handle several network namespaces The fib6_rules_ops is moved to the network namespace structure. All references are changed to have it relatively to it. Each time a network namespace is created a new fib6_rules_ops is allocated, initialized and stored into the network namespace structure. The common part of the fib rules is namespace aware, so it is quite easy to retrieve the network namespace from the rules and use it in the different callbacks. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/netns/ipv6.h | 1 + net/ipv6/fib6_rules.c | 82 +++++++++++++++++++++++++++--------------------- 2 files changed, 47 insertions(+), 36 deletions(-) (limited to 'net') diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 5279cd6a00ba..66bf9c0f745b 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -41,6 +41,7 @@ struct netns_ipv6 { struct fib6_table *fib6_main_tbl; #ifdef CONFIG_IPV6_MULTIPLE_TABLES struct fib6_table *fib6_local_tbl; + struct fib_rules_ops *fib6_rules_ops; #endif struct sock **icmp_sk; }; diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 60af08f12547..89cb092c9732 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -29,8 +29,6 @@ struct fib6_rule u8 tclass; }; -static struct fib_rules_ops *fib6_rules_ops; - struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, int flags, pol_lookup_t lookup) { @@ -38,7 +36,7 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, .lookup_ptr = lookup, }; - fib_rules_lookup(fib6_rules_ops, fl, flags, &arg); + fib_rules_lookup(net->ipv6.fib6_rules_ops, fl, flags, &arg); if (arg.rule) fib_rule_put(arg.rule); @@ -71,7 +69,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, goto discard_pkt; } - table = fib6_get_table(&init_net, rule->table); + table = fib6_get_table(rule->fr_net, rule->table); if (table) rt = lookup(table, flp, flags); @@ -145,13 +143,14 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, struct nlattr **tb) { int err = -EINVAL; + struct net *net = skb->sk->sk_net; struct fib6_rule *rule6 = (struct fib6_rule *) rule; if (rule->action == FR_ACT_TO_TBL) { if (rule->table == RT6_TABLE_UNSPEC) goto errout; - if (fib6_new_table(&init_net, rule->table) == NULL) { + if (fib6_new_table(net, rule->table) == NULL) { err = -ENOBUFS; goto errout; } @@ -251,49 +250,60 @@ static struct fib_rules_ops fib6_rules_ops_template = { .fro_net = &init_net, }; -static int __init fib6_default_rules_init(void) +static int fib6_rules_net_init(struct net *net) { - int err; + int err = -ENOMEM; - fib6_rules_ops = kmemdup(&fib6_rules_ops_template, - sizeof(*fib6_rules_ops), GFP_KERNEL); - if (!fib6_rules_ops) - return -ENOMEM; + net->ipv6.fib6_rules_ops = kmemdup(&fib6_rules_ops_template, + sizeof(*net->ipv6.fib6_rules_ops), + GFP_KERNEL); + if (!net->ipv6.fib6_rules_ops) + goto out; - INIT_LIST_HEAD(&fib6_rules_ops->rules_list); + net->ipv6.fib6_rules_ops->fro_net = net; + INIT_LIST_HEAD(&net->ipv6.fib6_rules_ops->rules_list); - err = fib_default_rule_add(fib6_rules_ops, 0, + err = fib_default_rule_add(net->ipv6.fib6_rules_ops, 0, RT6_TABLE_LOCAL, FIB_RULE_PERMANENT); - if (err < 0) - return err; - err = fib_default_rule_add(fib6_rules_ops, 0x7FFE, RT6_TABLE_MAIN, 0); - if (err < 0) - return err; - return 0; -} - -int __init fib6_rules_init(void) -{ - int ret; + if (err) + goto out_fib6_rules_ops; - ret = fib6_default_rules_init(); - if (ret) - goto out; + err = fib_default_rule_add(net->ipv6.fib6_rules_ops, + 0x7FFE, RT6_TABLE_MAIN, 0); + if (err) + goto out_fib6_default_rule_add; - ret = fib_rules_register(fib6_rules_ops); - if (ret) - goto out_default_rules_init; + err = fib_rules_register(net->ipv6.fib6_rules_ops); + if (err) + goto out_fib6_default_rule_add; out: - return ret; + return err; -out_default_rules_init: - fib_rules_cleanup_ops(fib6_rules_ops); - kfree(fib6_rules_ops); +out_fib6_default_rule_add: + fib_rules_cleanup_ops(net->ipv6.fib6_rules_ops); +out_fib6_rules_ops: + kfree(net->ipv6.fib6_rules_ops); goto out; } +static void fib6_rules_net_exit(struct net *net) +{ + fib_rules_unregister(net->ipv6.fib6_rules_ops); + kfree(net->ipv6.fib6_rules_ops); +} + +static struct pernet_operations fib6_rules_net_ops = { + .init = fib6_rules_net_init, + .exit = fib6_rules_net_exit, +}; + +int __init fib6_rules_init(void) +{ + return register_pernet_subsys(&fib6_rules_net_ops); +} + + void fib6_rules_cleanup(void) { - fib_rules_unregister(fib6_rules_ops); - kfree(fib6_rules_ops); + return unregister_pernet_subsys(&fib6_rules_net_ops); } -- cgit v1.2.3-59-g8ed1b From 6cc118bd506ae8c6436f507b838a0e1f6185fec2 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Mon, 3 Mar 2008 23:33:43 -0800 Subject: [NETNS][IPV6] rt6_stats - dynamically allocate the routes statistics This patch allocates the rt6_stats struct dynamically when the fib6 is initialized. That provides the ability to create several instances of this structure for the network namespaces. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/ipv6.h | 2 +- net/ipv6/ip6_fib.c | 22 +++++++++++++++------- net/ipv6/route.c | 8 ++++---- 3 files changed, 20 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 5dc8164e5d3b..9a00f35ae773 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -611,7 +611,7 @@ extern void ipv6_misc_proc_exit(void); extern int snmp6_register_dev(struct inet6_dev *idev); extern int snmp6_unregister_dev(struct inet6_dev *idev); -extern struct rt6_statistics rt6_stats; +extern struct rt6_statistics *rt6_stats; #else static inline int snmp6_register_dev(struct inet6_dev *idev) { diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 350a970ca1e3..7d82ad540140 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -48,7 +48,7 @@ #define RT6_TRACE(x...) do { ; } while (0) #endif -struct rt6_statistics rt6_stats; +struct rt6_statistics *rt6_stats; static struct kmem_cache * fib6_node_kmem __read_mostly; @@ -653,10 +653,10 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, rt->rt6i_node = fn; atomic_inc(&rt->rt6i_ref); inet6_rt_notify(RTM_NEWROUTE, rt, info); - rt6_stats.fib_rt_entries++; + rt6_stats->fib_rt_entries++; if ((fn->fn_flags & RTN_RTINFO) == 0) { - rt6_stats.fib_route_nodes++; + rt6_stats->fib_route_nodes++; fn->fn_flags |= RTN_RTINFO; } @@ -1093,8 +1093,8 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, /* Unlink it */ *rtp = rt->u.dst.rt6_next; rt->rt6i_node = NULL; - rt6_stats.fib_rt_entries--; - rt6_stats.fib_discarded_routes++; + rt6_stats->fib_rt_entries--; + rt6_stats->fib_discarded_routes++; /* Reset round-robin state, if necessary */ if (fn->rr_ptr == rt) @@ -1117,7 +1117,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, /* If it was last route, expunge its radix tree node */ if (fn->leaf == NULL) { fn->fn_flags &= ~RTN_RTINFO; - rt6_stats.fib_route_nodes--; + rt6_stats->fib_route_nodes--; fn = fib6_repair_tree(fn); } @@ -1556,9 +1556,14 @@ int __init fib6_init(void) if (!fib6_node_kmem) goto out; + ret = -ENOMEM; + rt6_stats = kzalloc(sizeof(*rt6_stats), GFP_KERNEL); + if (!rt6_stats) + goto out_kmem_cache_create; + ret = register_pernet_subsys(&fib6_net_ops); if (ret) - goto out_kmem_cache_create; + goto out_rt6_stats; ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib); if (ret) @@ -1568,6 +1573,8 @@ out: out_unregister_subsys: unregister_pernet_subsys(&fib6_net_ops); +out_rt6_stats: + kfree(rt6_stats); out_kmem_cache_create: kmem_cache_destroy(fib6_node_kmem); goto out; @@ -1576,5 +1583,6 @@ out_kmem_cache_create: void fib6_gc_cleanup(void) { unregister_pernet_subsys(&fib6_net_ops); + kfree(rt6_stats); kmem_cache_destroy(fib6_node_kmem); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b13eb0111270..370f2aef6909 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2354,11 +2354,11 @@ static const struct file_operations ipv6_route_proc_fops = { static int rt6_stats_seq_show(struct seq_file *seq, void *v) { seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n", - rt6_stats.fib_nodes, rt6_stats.fib_route_nodes, - rt6_stats.fib_rt_alloc, rt6_stats.fib_rt_entries, - rt6_stats.fib_rt_cache, + rt6_stats->fib_nodes, rt6_stats->fib_route_nodes, + rt6_stats->fib_rt_alloc, rt6_stats->fib_rt_entries, + rt6_stats->fib_rt_cache, atomic_read(&ip6_dst_ops.entries), - rt6_stats.fib_discarded_routes); + rt6_stats->fib_discarded_routes); return 0; } -- cgit v1.2.3-59-g8ed1b From c572872f89e46e38cdb35a43b81122bfb7ff43fc Mon Sep 17 00:00:00 2001 From: Benjamin Thery Date: Mon, 3 Mar 2008 23:34:17 -0800 Subject: [NETNS][IPV6] rt6_stats - make the stats per network namespace The rt6_stats is now per namespace with this patch. It is allocated when a network namespace is created and freed when the network namespace exits and references are relative to the network namespace. Signed-off-by: Benjamin Thery Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/net/ipv6.h | 1 - include/net/netns/ipv6.h | 1 + net/ipv6/ip6_fib.c | 32 +++++++++++++++----------------- net/ipv6/route.c | 12 +++++++----- 4 files changed, 23 insertions(+), 23 deletions(-) (limited to 'net') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 9a00f35ae773..5f6df50a33a9 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -611,7 +611,6 @@ extern void ipv6_misc_proc_exit(void); extern int snmp6_register_dev(struct inet6_dev *idev); extern int snmp6_unregister_dev(struct inet6_dev *idev); -extern struct rt6_statistics *rt6_stats; #else static inline int snmp6_register_dev(struct inet6_dev *idev) { diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 66bf9c0f745b..c6c9afff13ef 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -36,6 +36,7 @@ struct netns_ipv6 { struct xt_table *ip6table_mangle; struct xt_table *ip6table_raw; #endif + struct rt6_statistics *rt6_stats; struct timer_list *ip6_fib_timer; struct hlist_head *fib_table_hash; struct fib6_table *fib6_main_tbl; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 7d82ad540140..1c2566e3d392 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -48,8 +48,6 @@ #define RT6_TRACE(x...) do { ; } while (0) #endif -struct rt6_statistics *rt6_stats; - static struct kmem_cache * fib6_node_kmem __read_mostly; enum fib_walk_state_t @@ -653,10 +651,10 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, rt->rt6i_node = fn; atomic_inc(&rt->rt6i_ref); inet6_rt_notify(RTM_NEWROUTE, rt, info); - rt6_stats->fib_rt_entries++; + info->nl_net->ipv6.rt6_stats->fib_rt_entries++; if ((fn->fn_flags & RTN_RTINFO) == 0) { - rt6_stats->fib_route_nodes++; + info->nl_net->ipv6.rt6_stats->fib_route_nodes++; fn->fn_flags |= RTN_RTINFO; } @@ -1087,14 +1085,15 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, { struct fib6_walker_t *w; struct rt6_info *rt = *rtp; + struct net *net = info->nl_net; RT6_TRACE("fib6_del_route\n"); /* Unlink it */ *rtp = rt->u.dst.rt6_next; rt->rt6i_node = NULL; - rt6_stats->fib_rt_entries--; - rt6_stats->fib_discarded_routes++; + net->ipv6.rt6_stats->fib_rt_entries--; + net->ipv6.rt6_stats->fib_discarded_routes++; /* Reset round-robin state, if necessary */ if (fn->rr_ptr == rt) @@ -1117,7 +1116,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, /* If it was last route, expunge its radix tree node */ if (fn->leaf == NULL) { fn->fn_flags &= ~RTN_RTINFO; - rt6_stats->fib_route_nodes--; + net->ipv6.rt6_stats->fib_route_nodes--; fn = fib6_repair_tree(fn); } @@ -1486,11 +1485,15 @@ static int fib6_net_init(struct net *net) setup_timer(timer, fib6_gc_timer_cb, (unsigned long)net); net->ipv6.ip6_fib_timer = timer; + net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL); + if (!net->ipv6.rt6_stats) + goto out_timer; + net->ipv6.fib_table_hash = kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ, GFP_KERNEL); if (!net->ipv6.fib_table_hash) - goto out_timer; + goto out_rt6_stats; net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl), GFP_KERNEL); @@ -1524,6 +1527,8 @@ out_fib6_main_tbl: #endif out_fib_table_hash: kfree(net->ipv6.fib_table_hash); +out_rt6_stats: + kfree(net->ipv6.rt6_stats); out_timer: kfree(timer); goto out; @@ -1538,6 +1543,7 @@ static void fib6_net_exit(struct net *net) #endif kfree(net->ipv6.fib6_main_tbl); kfree(net->ipv6.fib_table_hash); + kfree(net->ipv6.rt6_stats); } static struct pernet_operations fib6_net_ops = { @@ -1556,14 +1562,9 @@ int __init fib6_init(void) if (!fib6_node_kmem) goto out; - ret = -ENOMEM; - rt6_stats = kzalloc(sizeof(*rt6_stats), GFP_KERNEL); - if (!rt6_stats) - goto out_kmem_cache_create; - ret = register_pernet_subsys(&fib6_net_ops); if (ret) - goto out_rt6_stats; + goto out_kmem_cache_create; ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib); if (ret) @@ -1573,8 +1574,6 @@ out: out_unregister_subsys: unregister_pernet_subsys(&fib6_net_ops); -out_rt6_stats: - kfree(rt6_stats); out_kmem_cache_create: kmem_cache_destroy(fib6_node_kmem); goto out; @@ -1583,6 +1582,5 @@ out_kmem_cache_create: void fib6_gc_cleanup(void) { unregister_pernet_subsys(&fib6_net_ops); - kfree(rt6_stats); kmem_cache_destroy(fib6_node_kmem); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 370f2aef6909..3afc3f41f2d5 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2354,11 +2354,13 @@ static const struct file_operations ipv6_route_proc_fops = { static int rt6_stats_seq_show(struct seq_file *seq, void *v) { seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n", - rt6_stats->fib_nodes, rt6_stats->fib_route_nodes, - rt6_stats->fib_rt_alloc, rt6_stats->fib_rt_entries, - rt6_stats->fib_rt_cache, - atomic_read(&ip6_dst_ops.entries), - rt6_stats->fib_discarded_routes); + init_net.ipv6.rt6_stats->fib_nodes, + init_net.ipv6.rt6_stats->fib_route_nodes, + init_net.ipv6.rt6_stats->fib_rt_alloc, + init_net.ipv6.rt6_stats->fib_rt_entries, + init_net.ipv6.rt6_stats->fib_rt_cache, + atomic_read(&ip6_dst_ops.entries), + init_net.ipv6.rt6_stats->fib_discarded_routes); return 0; } -- cgit v1.2.3-59-g8ed1b From 26bad2c05eef400d9af16979bd96e301902ebd13 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Mon, 3 Mar 2008 23:35:53 -0800 Subject: [TIPC]: Convert tsock->sem in a mutex The semaphore tsock->sem is used as mutex, convert it to the mutex API Signed-off-by: Matthias Kaehlcke Signed-off-by: David S. Miller --- net/tipc/socket.c | 56 +++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) (limited to 'net') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 22909036b9bc..9ae8e9f74028 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include @@ -63,7 +63,7 @@ struct tipc_sock { struct sock sk; struct tipc_port *p; - struct semaphore sem; + struct mutex lock; }; #define tipc_sk(sk) ((struct tipc_sock*)sk) @@ -217,7 +217,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol) tsock->p = port; port->usr_handle = tsock; - init_MUTEX(&tsock->sem); + mutex_init(&tsock->lock); dbg("sock_create: %x\n",tsock); @@ -253,9 +253,9 @@ static int release(struct socket *sock) dbg("sock_delete: %x\n",tsock); if (!tsock) return 0; - down(&tsock->sem); + mutex_lock(&tsock->lock); if (!sock->sk) { - up(&tsock->sem); + mutex_unlock(&tsock->lock); return 0; } @@ -288,7 +288,7 @@ static int release(struct socket *sock) atomic_dec(&tipc_queue_size); } - up(&tsock->sem); + mutex_unlock(&tsock->lock); sock_put(sk); @@ -315,7 +315,7 @@ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len) struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; int res; - if (down_interruptible(&tsock->sem)) + if (mutex_lock_interruptible(&tsock->lock)) return -ERESTARTSYS; if (unlikely(!uaddr_len)) { @@ -346,7 +346,7 @@ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len) res = tipc_withdraw(tsock->p->ref, -addr->scope, &addr->addr.nameseq); exit: - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } @@ -367,7 +367,7 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr, struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; u32 res; - if (down_interruptible(&tsock->sem)) + if (mutex_lock_interruptible(&tsock->lock)) return -ERESTARTSYS; *uaddr_len = sizeof(*addr); @@ -380,7 +380,7 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr, res = tipc_ownidentity(tsock->p->ref, &addr->addr.id); addr->addr.name.domain = 0; - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } @@ -477,7 +477,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, } } - if (down_interruptible(&tsock->sem)) + if (mutex_lock_interruptible(&tsock->lock)) return -ERESTARTSYS; if (needs_conn) { @@ -523,7 +523,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, } if (likely(res != -ELINKCONG)) { exit: - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } if (m->msg_flags & MSG_DONTWAIT) { @@ -562,7 +562,7 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, if (unlikely(dest)) return send_msg(iocb, sock, m, total_len); - if (down_interruptible(&tsock->sem)) { + if (mutex_lock_interruptible(&tsock->lock)) { return -ERESTARTSYS; } @@ -578,7 +578,7 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, res = tipc_send(tsock->p->ref, m->msg_iovlen, m->msg_iov); if (likely(res != -ELINKCONG)) { exit: - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } if (m->msg_flags & MSG_DONTWAIT) { @@ -846,7 +846,7 @@ static int recv_msg(struct kiocb *iocb, struct socket *sock, /* Look for a message in receive queue; wait if necessary */ - if (unlikely(down_interruptible(&tsock->sem))) + if (unlikely(mutex_lock_interruptible(&tsock->lock))) return -ERESTARTSYS; restart: @@ -930,7 +930,7 @@ restart: advance_queue(tsock); } exit: - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } @@ -981,7 +981,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, /* Look for a message in receive queue; wait if necessary */ - if (unlikely(down_interruptible(&tsock->sem))) + if (unlikely(mutex_lock_interruptible(&tsock->lock))) return -ERESTARTSYS; restart: @@ -1077,7 +1077,7 @@ restart: goto restart; exit: - up(&tsock->sem); + mutex_unlock(&tsock->lock); return sz_copied ? sz_copied : res; } @@ -1293,7 +1293,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, return res; } - if (down_interruptible(&tsock->sem)) + if (mutex_lock_interruptible(&tsock->lock)) return -ERESTARTSYS; /* Wait for destination's 'ACK' response */ @@ -1317,7 +1317,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, sock->state = SS_DISCONNECTING; } - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } @@ -1365,7 +1365,7 @@ static int accept(struct socket *sock, struct socket *newsock, int flags) (flags & O_NONBLOCK))) return -EWOULDBLOCK; - if (down_interruptible(&tsock->sem)) + if (mutex_lock_interruptible(&tsock->lock)) return -ERESTARTSYS; if (wait_event_interruptible(*sock->sk->sk_sleep, @@ -1412,7 +1412,7 @@ static int accept(struct socket *sock, struct socket *newsock, int flags) } } exit: - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } @@ -1434,7 +1434,7 @@ static int shutdown(struct socket *sock, int how) /* Could return -EINVAL for an invalid "how", but why bother? */ - if (down_interruptible(&tsock->sem)) + if (mutex_lock_interruptible(&tsock->lock)) return -ERESTARTSYS; sock_lock(tsock); @@ -1484,7 +1484,7 @@ restart: sock_unlock(tsock); - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } @@ -1518,7 +1518,7 @@ static int setsockopt(struct socket *sock, if ((res = get_user(value, (u32 __user *)ov))) return res; - if (down_interruptible(&tsock->sem)) + if (mutex_lock_interruptible(&tsock->lock)) return -ERESTARTSYS; switch (opt) { @@ -1541,7 +1541,7 @@ static int setsockopt(struct socket *sock, res = -EINVAL; } - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } @@ -1574,7 +1574,7 @@ static int getsockopt(struct socket *sock, if ((res = get_user(len, ol))) return res; - if (down_interruptible(&tsock->sem)) + if (mutex_lock_interruptible(&tsock->lock)) return -ERESTARTSYS; switch (opt) { @@ -1607,7 +1607,7 @@ static int getsockopt(struct socket *sock, res = put_user(sizeof(value), ol); } - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } -- cgit v1.2.3-59-g8ed1b From 83321d6b9872b94604e481a79dc2c8acbe4ece31 Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Mon, 3 Mar 2008 23:40:12 -0800 Subject: [AF_KEY]: Dump SA/SP entries non-atomically Stop dumping of entries when af_key socket receive queue is getting full and continue it later when there is more room again. This fixes dumping of large databases. Currently the entries not fitting into the receive queue are just dropped (including the end-of-dump message) which can confuse applications. Signed-off-by: Timo Teras Signed-off-by: David S. Miller --- net/key/af_key.c | 120 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 29 deletions(-) (limited to 'net') diff --git a/net/key/af_key.c b/net/key/af_key.c index 7cb6f1213360..50c442fc99ce 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -48,6 +48,17 @@ struct pfkey_sock { struct sock sk; int registered; int promisc; + + struct { + uint8_t msg_version; + uint32_t msg_pid; + int (*dump)(struct pfkey_sock *sk); + void (*done)(struct pfkey_sock *sk); + union { + struct xfrm_policy_walk policy; + struct xfrm_state_walk state; + } u; + } dump; }; static inline struct pfkey_sock *pfkey_sk(struct sock *sk) @@ -55,6 +66,27 @@ static inline struct pfkey_sock *pfkey_sk(struct sock *sk) return (struct pfkey_sock *)sk; } +static int pfkey_can_dump(struct sock *sk) +{ + if (3 * atomic_read(&sk->sk_rmem_alloc) <= 2 * sk->sk_rcvbuf) + return 1; + return 0; +} + +static int pfkey_do_dump(struct pfkey_sock *pfk) +{ + int rc; + + rc = pfk->dump.dump(pfk); + if (rc == -ENOBUFS) + return 0; + + pfk->dump.done(pfk); + pfk->dump.dump = NULL; + pfk->dump.done = NULL; + return rc; +} + static void pfkey_sock_destruct(struct sock *sk) { skb_queue_purge(&sk->sk_receive_queue); @@ -1709,51 +1741,60 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd return 0; } -struct pfkey_dump_data -{ - struct sk_buff *skb; - struct sadb_msg *hdr; - struct sock *sk; -}; - static int dump_sa(struct xfrm_state *x, int count, void *ptr) { - struct pfkey_dump_data *data = ptr; + struct pfkey_sock *pfk = ptr; struct sk_buff *out_skb; struct sadb_msg *out_hdr; + if (!pfkey_can_dump(&pfk->sk)) + return -ENOBUFS; + out_skb = pfkey_xfrm_state2msg(x); if (IS_ERR(out_skb)) return PTR_ERR(out_skb); out_hdr = (struct sadb_msg *) out_skb->data; - out_hdr->sadb_msg_version = data->hdr->sadb_msg_version; + out_hdr->sadb_msg_version = pfk->dump.msg_version; out_hdr->sadb_msg_type = SADB_DUMP; out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); out_hdr->sadb_msg_errno = 0; out_hdr->sadb_msg_reserved = 0; out_hdr->sadb_msg_seq = count; - out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid; - pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); + out_hdr->sadb_msg_pid = pfk->dump.msg_pid; + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk); return 0; } +static int pfkey_dump_sa(struct pfkey_sock *pfk) +{ + return xfrm_state_walk(&pfk->dump.u.state, dump_sa, (void *) pfk); +} + +static void pfkey_dump_sa_done(struct pfkey_sock *pfk) +{ + xfrm_state_walk_done(&pfk->dump.u.state); +} + static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { u8 proto; - struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; - struct xfrm_state_walk walk; - int rc; + struct pfkey_sock *pfk = pfkey_sk(sk); + + if (pfk->dump.dump != NULL) + return -EBUSY; proto = pfkey_satype2proto(hdr->sadb_msg_satype); if (proto == 0) return -EINVAL; - xfrm_state_walk_init(&walk, proto); - rc = xfrm_state_walk(&walk, dump_sa, &data); - xfrm_state_walk_done(&walk); + pfk->dump.msg_version = hdr->sadb_msg_version; + pfk->dump.msg_pid = hdr->sadb_msg_pid; + pfk->dump.dump = pfkey_dump_sa; + pfk->dump.done = pfkey_dump_sa_done; + xfrm_state_walk_init(&pfk->dump.u.state, proto); - return rc; + return pfkey_do_dump(pfk); } static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) @@ -2648,11 +2689,14 @@ out: static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) { - struct pfkey_dump_data *data = ptr; + struct pfkey_sock *pfk = ptr; struct sk_buff *out_skb; struct sadb_msg *out_hdr; int err; + if (!pfkey_can_dump(&pfk->sk)) + return -ENOBUFS; + out_skb = pfkey_xfrm_policy2msg_prep(xp); if (IS_ERR(out_skb)) return PTR_ERR(out_skb); @@ -2662,27 +2706,40 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) return err; out_hdr = (struct sadb_msg *) out_skb->data; - out_hdr->sadb_msg_version = data->hdr->sadb_msg_version; + out_hdr->sadb_msg_version = pfk->dump.msg_version; out_hdr->sadb_msg_type = SADB_X_SPDDUMP; out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; out_hdr->sadb_msg_errno = 0; out_hdr->sadb_msg_seq = count; - out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid; - pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); + out_hdr->sadb_msg_pid = pfk->dump.msg_pid; + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk); return 0; } +static int pfkey_dump_sp(struct pfkey_sock *pfk) +{ + return xfrm_policy_walk(&pfk->dump.u.policy, dump_sp, (void *) pfk); +} + +static void pfkey_dump_sp_done(struct pfkey_sock *pfk) +{ + xfrm_policy_walk_done(&pfk->dump.u.policy); +} + static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { - struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; - struct xfrm_policy_walk walk; - int rc; + struct pfkey_sock *pfk = pfkey_sk(sk); - xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); - rc = xfrm_policy_walk(&walk, dump_sp, &data); - xfrm_policy_walk_done(&walk); + if (pfk->dump.dump != NULL) + return -EBUSY; - return rc; + pfk->dump.msg_version = hdr->sadb_msg_version; + pfk->dump.msg_pid = hdr->sadb_msg_pid; + pfk->dump.dump = pfkey_dump_sp; + pfk->dump.done = pfkey_dump_sp_done; + xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN); + + return pfkey_do_dump(pfk); } static int key_notify_policy_flush(struct km_event *c) @@ -3687,6 +3744,7 @@ static int pfkey_recvmsg(struct kiocb *kiocb, int flags) { struct sock *sk = sock->sk; + struct pfkey_sock *pfk = pfkey_sk(sk); struct sk_buff *skb; int copied, err; @@ -3714,6 +3772,10 @@ static int pfkey_recvmsg(struct kiocb *kiocb, err = (flags & MSG_TRUNC) ? skb->len : copied; + if (pfk->dump.dump != NULL && + 3 * atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) + pfkey_do_dump(pfk); + out_free: skb_free_datagram(sk, skb); out: -- cgit v1.2.3-59-g8ed1b From cdb1876192dbe680b3ac955717fdf7f863c1762d Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 4 Mar 2008 13:45:33 -0800 Subject: [NETNS][IPV6] route6 - create route6 proc files for the namespace Make /proc/net/ipv6_route and /proc/net/rt6_stats to be per namespace. These proc files are now created when the network namespace is initialized. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- net/ipv6/route.c | 70 ++++++++++++++++++++++---------------------------------- 1 file changed, 27 insertions(+), 43 deletions(-) (limited to 'net') diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 3afc3f41f2d5..5d9d293156cd 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2377,40 +2377,6 @@ static const struct file_operations rt6_stats_seq_fops = { .llseek = seq_lseek, .release = single_release, }; - -static int ipv6_route_proc_init(struct net *net) -{ - int ret = -ENOMEM; - if (!proc_net_fops_create(net, "ipv6_route", - 0, &ipv6_route_proc_fops)) - goto out; - - if (!proc_net_fops_create(net, "rt6_stats", - S_IRUGO, &rt6_stats_seq_fops)) - goto out_ipv6_route; - - ret = 0; -out: - return ret; -out_ipv6_route: - proc_net_remove(net, "ipv6_route"); - goto out; -} - -static void ipv6_route_proc_fini(struct net *net) -{ - proc_net_remove(net, "ipv6_route"); - proc_net_remove(net, "rt6_stats"); -} -#else -static inline int ipv6_route_proc_init(struct net *net) -{ - return 0; -} -static inline void ipv6_route_proc_fini(struct net *net) -{ - return ; -} #endif /* CONFIG_PROC_FS */ #ifdef CONFIG_SYSCTL @@ -2544,6 +2510,28 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net) } #endif +static int ip6_route_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops); + proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); +#endif + return 0; +} + +static void ip6_route_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + proc_net_remove(net, "ipv6_route"); + proc_net_remove(net, "rt6_stats"); +#endif +} + +static struct pernet_operations ip6_route_net_ops = { + .init = ip6_route_net_init, + .exit = ip6_route_net_exit, +}; + int __init ip6_route_init(void) { int ret; @@ -2560,13 +2548,9 @@ int __init ip6_route_init(void) if (ret) goto out_kmem_cache; - ret = ipv6_route_proc_init(&init_net); - if (ret) - goto out_fib6_init; - ret = xfrm6_init(); if (ret) - goto out_proc_init; + goto out_fib6_init; ret = fib6_rules_init(); if (ret) @@ -2578,7 +2562,9 @@ int __init ip6_route_init(void) __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL)) goto fib6_rules_init; - ret = 0; + ret = register_pernet_subsys(&ip6_route_net_ops); + if (ret) + goto fib6_rules_init; out: return ret; @@ -2586,8 +2572,6 @@ fib6_rules_init: fib6_rules_cleanup(); xfrm6_init: xfrm6_fini(); -out_proc_init: - ipv6_route_proc_fini(&init_net); out_fib6_init: rt6_ifdown(&init_net, NULL); fib6_gc_cleanup(); @@ -2598,8 +2582,8 @@ out_kmem_cache: void ip6_route_cleanup(void) { + unregister_pernet_subsys(&ip6_route_net_ops); fib6_rules_cleanup(); - ipv6_route_proc_fini(&init_net); xfrm6_fini(); rt6_ifdown(&init_net, NULL); fib6_gc_cleanup(); -- cgit v1.2.3-59-g8ed1b From 606a2b4862d4be31fa55cad89871fe52a422d511 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 4 Mar 2008 13:45:59 -0800 Subject: [NETNS][IPV6] route6 - Pass the network namespace parameter to rt6_lookup Add a network namespace parameter to rt6_lookup(). Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/ip6_route.h | 3 ++- net/ipv6/addrconf.c | 4 ++-- net/ipv6/anycast.c | 2 +- net/ipv6/ip6_tunnel.c | 4 ++-- net/ipv6/mcast.c | 4 ++-- net/ipv6/route.c | 10 +++++----- net/ipv6/sit.c | 4 ++-- 7 files changed, 16 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 79dce496f4d4..92004c5160c7 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -69,7 +69,8 @@ extern void rt6_sndmsg(int type, struct in6_addr *dst, int dstlen, int srclen, int metric, __u32 flags); -extern struct rt6_info *rt6_lookup(struct in6_addr *daddr, +extern struct rt6_info *rt6_lookup(struct net *net, + struct in6_addr *daddr, struct in6_addr *saddr, int oif, int flags); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index a1d872dacad6..9d894e8c7b72 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -753,7 +753,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) struct rt6_info *rt; ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); - rt = rt6_lookup(&prefix, NULL, ifp->idev->dev->ifindex, 1); + rt = rt6_lookup(&init_net, &prefix, NULL, ifp->idev->dev->ifindex, 1); if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { if (onlink == 0) { @@ -1700,7 +1700,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) if (pinfo->onlink) { struct rt6_info *rt; - rt = rt6_lookup(&pinfo->prefix, NULL, dev->ifindex, 1); + rt = rt6_lookup(&init_net, &pinfo->prefix, NULL, dev->ifindex, 1); if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { if (rt->rt6i_flags&RTF_EXPIRES) { diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 9c7f83fbc3a1..96868b994b37 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -101,7 +101,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) if (ifindex == 0) { struct rt6_info *rt; - rt = rt6_lookup(addr, NULL, 0, 0); + rt = rt6_lookup(&init_net, addr, NULL, 0, 0); if (rt) { dev = rt->rt6i_dev; dev_hold(dev); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 78f438880923..4e1981660b3c 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -602,7 +602,7 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, skb_reset_network_header(skb2); /* Try to guess incoming interface */ - rt = rt6_lookup(&ipv6_hdr(skb2)->saddr, NULL, 0, 0); + rt = rt6_lookup(&init_net, &ipv6_hdr(skb2)->saddr, NULL, 0, 0); if (rt && rt->rt6i_dev) skb2->dev = rt->rt6i_dev; @@ -1112,7 +1112,7 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) int strict = (ipv6_addr_type(&p->raddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL)); - struct rt6_info *rt = rt6_lookup(&p->raddr, &p->laddr, + struct rt6_info *rt = rt6_lookup(&init_net, &p->raddr, &p->laddr, p->link, strict); if (rt == NULL) diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index a373b8e7f241..197ca390a15d 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -208,7 +208,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) if (ifindex == 0) { struct rt6_info *rt; - rt = rt6_lookup(addr, NULL, 0, 0); + rt = rt6_lookup(&init_net, addr, NULL, 0, 0); if (rt) { dev = rt->rt6i_dev; dev_hold(dev); @@ -294,7 +294,7 @@ static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) if (ifindex == 0) { struct rt6_info *rt; - rt = rt6_lookup(group, NULL, 0, 0); + rt = rt6_lookup(&init_net, group, NULL, 0, 0); if (rt) { dev = rt->rt6i_dev; dev_hold(dev); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 5d9d293156cd..d9d840ced1c6 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -553,8 +553,8 @@ out: } -struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, - int oif, int strict) +struct rt6_info *rt6_lookup(struct net *net, struct in6_addr *daddr, + struct in6_addr *saddr, int oif, int strict) { struct flowi fl = { .oif = oif, @@ -572,7 +572,7 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr, flags |= RT6_LOOKUP_F_HAS_SADDR; } - dst = fib6_rule_lookup(&init_net, &fl, flags, ip6_pol_route_lookup); + dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_lookup); if (dst->error == 0) return (struct rt6_info *) dst; @@ -1159,7 +1159,7 @@ int ip6_route_add(struct fib6_config *cfg) if (!(gwa_type&IPV6_ADDR_UNICAST)) goto out; - grt = rt6_lookup(gw_addr, NULL, cfg->fc_ifindex, 1); + grt = rt6_lookup(&init_net, gw_addr, NULL, cfg->fc_ifindex, 1); err = -EHOSTUNREACH; if (grt == NULL) @@ -1483,7 +1483,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, struct rt6_info *rt, *nrt; int allfrag = 0; - rt = rt6_lookup(daddr, saddr, dev->ifindex, 0); + rt = rt6_lookup(dev->nd_net, daddr, saddr, dev->ifindex, 0); if (rt == NULL) return; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 1656c003b989..68720aa63f96 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -339,11 +339,11 @@ out: skb_reset_network_header(skb2); /* Try to guess incoming interface */ - rt6i = rt6_lookup(&iph6->saddr, NULL, NULL, 0); + rt6i = rt6_lookup(&init_net, &iph6->saddr, NULL, NULL, 0); if (rt6i && rt6i->rt6i_dev) { skb2->dev = rt6i->rt6i_dev; - rt6i = rt6_lookup(&iph6->daddr, &iph6->saddr, NULL, 0); + rt6i = rt6_lookup(&init_net, &iph6->daddr, &iph6->saddr, NULL, 0); if (rt6i && rt6i->rt6i_dev && rt6i->rt6i_dev->type == ARPHRD_SIT) { struct ip_tunnel *t = netdev_priv(rt6i->rt6i_dev); -- cgit v1.2.3-59-g8ed1b From 69ddb80562a460d6d9edafe33a5bee06ca18b1a1 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 4 Mar 2008 13:46:23 -0800 Subject: [NETNS][IPV6] route6 - Make proc entry /proc/net/rt6_stats per namespace Make the proc entry /proc/net/rt6_stats work in all network namespace. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- net/ipv6/route.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d9d840ced1c6..ebd9033fece3 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2353,21 +2353,31 @@ static const struct file_operations ipv6_route_proc_fops = { static int rt6_stats_seq_show(struct seq_file *seq, void *v) { + struct net *net = (struct net *)seq->private; seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n", - init_net.ipv6.rt6_stats->fib_nodes, - init_net.ipv6.rt6_stats->fib_route_nodes, - init_net.ipv6.rt6_stats->fib_rt_alloc, - init_net.ipv6.rt6_stats->fib_rt_entries, - init_net.ipv6.rt6_stats->fib_rt_cache, + net->ipv6.rt6_stats->fib_nodes, + net->ipv6.rt6_stats->fib_route_nodes, + net->ipv6.rt6_stats->fib_rt_alloc, + net->ipv6.rt6_stats->fib_rt_entries, + net->ipv6.rt6_stats->fib_rt_cache, atomic_read(&ip6_dst_ops.entries), - init_net.ipv6.rt6_stats->fib_discarded_routes); + net->ipv6.rt6_stats->fib_discarded_routes); return 0; } static int rt6_stats_seq_open(struct inode *inode, struct file *file) { - return single_open(file, rt6_stats_seq_show, NULL); + struct net *net = get_proc_net(inode); + return single_open(file, rt6_stats_seq_show, net); +} + +static int rt6_stats_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct net *net = (struct net *)seq->private; + put_net(net); + return single_release(inode, file); } static const struct file_operations rt6_stats_seq_fops = { @@ -2375,7 +2385,7 @@ static const struct file_operations rt6_stats_seq_fops = { .open = rt6_stats_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = rt6_stats_seq_release, }; #endif /* CONFIG_PROC_FS */ -- cgit v1.2.3-59-g8ed1b From efa2cea0d97a91dbbc067463de702738f7e50748 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 4 Mar 2008 13:46:48 -0800 Subject: [NETNS][IPV6] route6 - Pass network namespace to rt6_add_route_info and rt6_get_route_info Add a network namespace parameter to rt6_add_route_info() and rt6_get_route_info to enable them to handle multiple network namespaces. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- net/ipv6/route.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv6/route.c b/net/ipv6/route.c index ebd9033fece3..4278cec522c5 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -88,10 +88,12 @@ static void ip6_link_failure(struct sk_buff *skb); static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu); #ifdef CONFIG_IPV6_ROUTE_INFO -static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen, +static struct rt6_info *rt6_add_route_info(struct net *net, + struct in6_addr *prefix, int prefixlen, struct in6_addr *gwaddr, int ifindex, unsigned pref); -static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen, +static struct rt6_info *rt6_get_route_info(struct net *net, + struct in6_addr *prefix, int prefixlen, struct in6_addr *gwaddr, int ifindex); #endif @@ -442,6 +444,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, struct in6_addr *gwaddr) { + struct net *net = dev->nd_net; struct route_info *rinfo = (struct route_info *) opt; struct in6_addr prefix_buf, *prefix; unsigned int pref; @@ -489,7 +492,8 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, prefix = &prefix_buf; } - rt = rt6_get_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex); + rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, gwaddr, + dev->ifindex); if (rt && !lifetime) { ip6_del_rt(rt); @@ -497,7 +501,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, } if (!rt && lifetime) - rt = rt6_add_route_info(prefix, rinfo->prefix_len, gwaddr, dev->ifindex, + rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, dev->ifindex, pref); else if (rt) rt->rt6i_flags = RTF_ROUTEINFO | @@ -1588,14 +1592,15 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) } #ifdef CONFIG_IPV6_ROUTE_INFO -static struct rt6_info *rt6_get_route_info(struct in6_addr *prefix, int prefixlen, +static struct rt6_info *rt6_get_route_info(struct net *net, + struct in6_addr *prefix, int prefixlen, struct in6_addr *gwaddr, int ifindex) { struct fib6_node *fn; struct rt6_info *rt = NULL; struct fib6_table *table; - table = fib6_get_table(&init_net, RT6_TABLE_INFO); + table = fib6_get_table(net, RT6_TABLE_INFO); if (table == NULL) return NULL; @@ -1619,7 +1624,8 @@ out: return rt; } -static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixlen, +static struct rt6_info *rt6_add_route_info(struct net *net, + struct in6_addr *prefix, int prefixlen, struct in6_addr *gwaddr, int ifindex, unsigned pref) { @@ -1630,6 +1636,9 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle .fc_dst_len = prefixlen, .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | RTF_UP | RTF_PREF(pref), + .fc_nlinfo.pid = 0, + .fc_nlinfo.nlh = NULL, + .fc_nlinfo.nl_net = net, }; ipv6_addr_copy(&cfg.fc_dst, prefix); @@ -1641,7 +1650,7 @@ static struct rt6_info *rt6_add_route_info(struct in6_addr *prefix, int prefixle ip6_route_add(&cfg); - return rt6_get_route_info(prefix, prefixlen, gwaddr, ifindex); + return rt6_get_route_info(net, prefix, prefixlen, gwaddr, ifindex); } #endif -- cgit v1.2.3-59-g8ed1b From 7b4da53229bb61469bdab321384b9a13406e3485 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 4 Mar 2008 13:47:14 -0800 Subject: [NETNS][IPV6] route6 - Pass the network namespace parameter to rt6_purge_dflt_routers Add a network namespace parameter to rt6_purge_dflt_routers. This is needed to call fib6_get_table with the appropriate network namespace. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/ip6_route.h | 2 +- net/ipv6/addrconf.c | 2 +- net/ipv6/route.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 92004c5160c7..1444d358836d 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -95,7 +95,7 @@ extern struct rt6_info * rt6_add_dflt_router(struct in6_addr *gwaddr, struct net_device *dev, unsigned int pref); -extern void rt6_purge_dflt_routers(void); +extern void rt6_purge_dflt_routers(struct net *net); extern int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 9d894e8c7b72..b37ae421b61b 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -493,7 +493,7 @@ static void addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old) dev_forward_change((struct inet6_dev *)table->extra1); if (*p) - rt6_purge_dflt_routers(); + rt6_purge_dflt_routers(net); } #endif diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 4278cec522c5..ad3d684e544a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1697,13 +1697,13 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, return rt6_get_dflt_router(gwaddr, dev); } -void rt6_purge_dflt_routers(void) +void rt6_purge_dflt_routers(struct net *net) { struct rt6_info *rt; struct fib6_table *table; /* NOTE: Keep consistent with rt6_get_dflt_router */ - table = fib6_get_table(&init_net, RT6_TABLE_DFLT); + table = fib6_get_table(net, RT6_TABLE_DFLT); if (table == NULL) return; -- cgit v1.2.3-59-g8ed1b From 5578689a4e3c04f2d43ea39736fd3fa396d80c6e Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 4 Mar 2008 13:47:47 -0800 Subject: [NETNS][IPV6] route6 - make route6 per namespace This patch makes the routing engine use the network namespaces to access routing informations: Add a network namespace parameter to ipv6_route_ioctl and propagate the network namespace value to all the routing code that have not yet been changed. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/ip6_route.h | 4 +- net/ipv6/af_inet6.c | 3 +- net/ipv6/route.c | 98 ++++++++++++++++++++++++------------------------- 3 files changed, 54 insertions(+), 51 deletions(-) (limited to 'net') diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 1444d358836d..2bcbfb826530 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -49,7 +49,9 @@ extern struct dst_entry * ip6_route_output(struct sock *sk, extern int ip6_route_init(void); extern void ip6_route_cleanup(void); -extern int ipv6_route_ioctl(unsigned int cmd, void __user *arg); +extern int ipv6_route_ioctl(struct net *net, + unsigned int cmd, + void __user *arg); extern int ip6_route_add(struct fib6_config *cfg); extern int ip6_ins_rt(struct rt6_info *); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 73021d5baece..60b8a2254046 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -440,6 +440,7 @@ EXPORT_SYMBOL(inet6_getname); int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; + struct net *net = sk->sk_net; switch(cmd) { @@ -452,7 +453,7 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCADDRT: case SIOCDELRT: - return(ipv6_route_ioctl(cmd,(void __user *)arg)); + return(ipv6_route_ioctl(net, cmd, (void __user *)arg)); case SIOCSIFADDR: return addrconf_add_ifaddr((void __user *) arg); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index ad3d684e544a..b3ac4901af86 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -609,7 +609,7 @@ static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info) int ip6_ins_rt(struct rt6_info *rt) { struct nl_info info = { - .nl_net = &init_net, + .nl_net = rt->rt6i_dev->nd_net, }; return __ip6_ins_rt(rt, &info); } @@ -746,6 +746,7 @@ static struct rt6_info *ip6_pol_route_input(struct fib6_table *table, void ip6_route_input(struct sk_buff *skb) { struct ipv6hdr *iph = ipv6_hdr(skb); + struct net *net = skb->dev->nd_net; int flags = RT6_LOOKUP_F_HAS_SADDR; struct flowi fl = { .iif = skb->dev->ifindex, @@ -763,7 +764,7 @@ void ip6_route_input(struct sk_buff *skb) if (rt6_need_strict(&iph->daddr)) flags |= RT6_LOOKUP_F_IFACE; - skb->dst = fib6_rule_lookup(&init_net, &fl, flags, ip6_pol_route_input); + skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input); } static struct rt6_info *ip6_pol_route_output(struct fib6_table *table, @@ -891,12 +892,12 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu) static int ipv6_get_mtu(struct net_device *dev); -static inline unsigned int ipv6_advmss(unsigned int mtu) +static inline unsigned int ipv6_advmss(struct net *net, unsigned int mtu) { mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr); - if (mtu < init_net.ipv6.sysctl.ip6_rt_min_advmss) - mtu = init_net.ipv6.sysctl.ip6_rt_min_advmss; + if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss) + mtu = net->ipv6.sysctl.ip6_rt_min_advmss; /* * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and @@ -918,6 +919,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, { struct rt6_info *rt; struct inet6_dev *idev = in6_dev_get(dev); + struct net *net = dev->nd_net; if (unlikely(idev == NULL)) return NULL; @@ -940,7 +942,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, atomic_set(&rt->u.dst.__refcnt, 1); rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255; rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); - rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); + rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst)); rt->u.dst.output = ip6_output; #if 0 /* there's no chance to use these for ndisc */ @@ -956,7 +958,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, icmp6_dst_gc_list = &rt->u.dst; spin_unlock_bh(&icmp6_dst_lock); - fib6_force_start_gc(dev->nd_net); + fib6_force_start_gc(net); out: return &rt->u.dst; @@ -1049,6 +1051,7 @@ int ipv6_get_hoplimit(struct net_device *dev) int ip6_route_add(struct fib6_config *cfg) { int err; + struct net *net = cfg->fc_nlinfo.nl_net; struct rt6_info *rt = NULL; struct net_device *dev = NULL; struct inet6_dev *idev = NULL; @@ -1063,7 +1066,7 @@ int ip6_route_add(struct fib6_config *cfg) #endif if (cfg->fc_ifindex) { err = -ENODEV; - dev = dev_get_by_index(&init_net, cfg->fc_ifindex); + dev = dev_get_by_index(net, cfg->fc_ifindex); if (!dev) goto out; idev = in6_dev_get(dev); @@ -1074,7 +1077,7 @@ int ip6_route_add(struct fib6_config *cfg) if (cfg->fc_metric == 0) cfg->fc_metric = IP6_RT_PRIO_USER; - table = fib6_new_table(&init_net, cfg->fc_table); + table = fib6_new_table(net, cfg->fc_table); if (table == NULL) { err = -ENOBUFS; goto out; @@ -1121,12 +1124,12 @@ int ip6_route_add(struct fib6_config *cfg) if ((cfg->fc_flags & RTF_REJECT) || (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) { /* hold loopback dev/idev if we haven't done so. */ - if (dev != init_net.loopback_dev) { + if (dev != net->loopback_dev) { if (dev) { dev_put(dev); in6_dev_put(idev); } - dev = init_net.loopback_dev; + dev = net->loopback_dev; dev_hold(dev); idev = in6_dev_get(dev); if (!idev) { @@ -1163,7 +1166,7 @@ int ip6_route_add(struct fib6_config *cfg) if (!(gwa_type&IPV6_ADDR_UNICAST)) goto out; - grt = rt6_lookup(&init_net, gw_addr, NULL, cfg->fc_ifindex, 1); + grt = rt6_lookup(net, gw_addr, NULL, cfg->fc_ifindex, 1); err = -EHOSTUNREACH; if (grt == NULL) @@ -1230,7 +1233,7 @@ install_route: if (!rt->u.dst.metrics[RTAX_MTU-1]) rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev); if (!rt->u.dst.metrics[RTAX_ADVMSS-1]) - rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); + rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst)); rt->u.dst.dev = dev; rt->rt6i_idev = idev; rt->rt6i_table = table; @@ -1271,7 +1274,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) int ip6_del_rt(struct rt6_info *rt) { struct nl_info info = { - .nl_net = &init_net, + .nl_net = rt->rt6i_dev->nd_net, }; return __ip6_del_rt(rt, &info); } @@ -1283,7 +1286,7 @@ static int ip6_route_del(struct fib6_config *cfg) struct rt6_info *rt; int err = -ESRCH; - table = fib6_get_table(&init_net, cfg->fc_table); + table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table); if (table == NULL) return err; @@ -1382,6 +1385,7 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, struct net_device *dev) { int flags = RT6_LOOKUP_F_HAS_SADDR; + struct net *net = dev->nd_net; struct ip6rd_flowi rdfl = { .fl = { .oif = dev->ifindex, @@ -1398,8 +1402,7 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, if (rt6_need_strict(dest)) flags |= RT6_LOOKUP_F_IFACE; - return (struct rt6_info *)fib6_rule_lookup(&init_net, - (struct flowi *)&rdfl, + return (struct rt6_info *)fib6_rule_lookup(net, (struct flowi *)&rdfl, flags, __ip6_route_redirect); } @@ -1457,7 +1460,8 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, nrt->rt6i_nexthop = neigh_clone(neigh); /* Reset pmtu, it may be better */ nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev); - nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&nrt->u.dst)); + nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(neigh->dev->nd_net, + dst_mtu(&nrt->u.dst)); if (ip6_ins_rt(nrt)) goto out; @@ -1485,9 +1489,10 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, struct net_device *dev, u32 pmtu) { struct rt6_info *rt, *nrt; + struct net *net = dev->nd_net; int allfrag = 0; - rt = rt6_lookup(dev->nd_net, daddr, saddr, dev->ifindex, 0); + rt = rt6_lookup(net, daddr, saddr, dev->ifindex, 0); if (rt == NULL) return; @@ -1520,7 +1525,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, rt->u.dst.metrics[RTAX_MTU-1] = pmtu; if (allfrag) rt->u.dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG; - dst_set_expires(&rt->u.dst, init_net.ipv6.sysctl.ip6_rt_mtu_expires); + dst_set_expires(&rt->u.dst, net->ipv6.sysctl.ip6_rt_mtu_expires); rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES; goto out; } @@ -1546,7 +1551,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, * which is 10 mins. After 10 mins the decreased pmtu is expired * and detecting PMTU increase will be automatically happened. */ - dst_set_expires(&nrt->u.dst, init_net.ipv6.sysctl.ip6_rt_mtu_expires); + dst_set_expires(&nrt->u.dst, net->ipv6.sysctl.ip6_rt_mtu_expires); nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; ip6_ins_rt(nrt); @@ -1659,7 +1664,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d struct rt6_info *rt; struct fib6_table *table; - table = fib6_get_table(&init_net, RT6_TABLE_DFLT); + table = fib6_get_table(dev->nd_net, RT6_TABLE_DFLT); if (table == NULL) return NULL; @@ -1688,6 +1693,9 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, .fc_ifindex = dev->ifindex, .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP | RTF_EXPIRES | RTF_PREF(pref), + .fc_nlinfo.pid = 0, + .fc_nlinfo.nlh = NULL, + .fc_nlinfo.nl_net = dev->nd_net, }; ipv6_addr_copy(&cfg.fc_gateway, gwaddr); @@ -1720,7 +1728,8 @@ restart: read_unlock_bh(&table->tb6_lock); } -static void rtmsg_to_fib6_config(struct in6_rtmsg *rtmsg, +static void rtmsg_to_fib6_config(struct net *net, + struct in6_rtmsg *rtmsg, struct fib6_config *cfg) { memset(cfg, 0, sizeof(*cfg)); @@ -1733,14 +1742,14 @@ static void rtmsg_to_fib6_config(struct in6_rtmsg *rtmsg, cfg->fc_src_len = rtmsg->rtmsg_src_len; cfg->fc_flags = rtmsg->rtmsg_flags; - cfg->fc_nlinfo.nl_net = &init_net; + cfg->fc_nlinfo.nl_net = net; ipv6_addr_copy(&cfg->fc_dst, &rtmsg->rtmsg_dst); ipv6_addr_copy(&cfg->fc_src, &rtmsg->rtmsg_src); ipv6_addr_copy(&cfg->fc_gateway, &rtmsg->rtmsg_gateway); } -int ipv6_route_ioctl(unsigned int cmd, void __user *arg) +int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg) { struct fib6_config cfg; struct in6_rtmsg rtmsg; @@ -1756,7 +1765,7 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg) if (err) return -EFAULT; - rtmsg_to_fib6_config(&rtmsg, &cfg); + rtmsg_to_fib6_config(net, &rtmsg, &cfg); rtnl_lock(); switch (cmd) { @@ -1835,21 +1844,22 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, const struct in6_addr *addr, int anycast) { + struct net *net = idev->dev->nd_net; struct rt6_info *rt = ip6_dst_alloc(); if (rt == NULL) return ERR_PTR(-ENOMEM); - dev_hold(init_net.loopback_dev); + dev_hold(net->loopback_dev); in6_dev_hold(idev); rt->u.dst.flags = DST_HOST; rt->u.dst.input = ip6_input; rt->u.dst.output = ip6_output; - rt->rt6i_dev = init_net.loopback_dev; + rt->rt6i_dev = net->loopback_dev; rt->rt6i_idev = idev; rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); - rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst)); + rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst)); rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1; rt->u.dst.obsolete = -1; @@ -1866,7 +1876,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, ipv6_addr_copy(&rt->rt6i_dst.addr, addr); rt->rt6i_dst.plen = 128; - rt->rt6i_table = fib6_get_table(&init_net, RT6_TABLE_LOCAL); + rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL); atomic_set(&rt->u.dst.__refcnt, 1); @@ -1898,6 +1908,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) { struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg; struct inet6_dev *idev; + struct net *net = arg->dev->nd_net; /* In IPv6 pmtu discovery is not optional, so that RTAX_MTU lock cannot disable it. @@ -1929,7 +1940,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) (dst_mtu(&rt->u.dst) < arg->mtu && dst_mtu(&rt->u.dst) == idev->cnf.mtu6))) { rt->u.dst.metrics[RTAX_MTU-1] = arg->mtu; - rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(arg->mtu); + rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, arg->mtu); } return 0; } @@ -2024,13 +2035,9 @@ errout: static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = skb->sk->sk_net; struct fib6_config cfg; int err; - if (net != &init_net) - return -EINVAL; - err = rtm_to_fib6_config(skb, nlh, &cfg); if (err < 0) return err; @@ -2040,13 +2047,9 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *a static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = skb->sk->sk_net; struct fib6_config cfg; int err; - if (net != &init_net) - return -EINVAL; - err = rtm_to_fib6_config(skb, nlh, &cfg); if (err < 0) return err; @@ -2190,9 +2193,6 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void struct flowi fl; int err, iif = 0; - if (net != &init_net) - return -EINVAL; - err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); if (err < 0) goto errout; @@ -2222,7 +2222,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void if (iif) { struct net_device *dev; - dev = __dev_get_by_index(&init_net, iif); + dev = __dev_get_by_index(net, iif); if (!dev) { err = -ENODEV; goto errout; @@ -2252,7 +2252,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void goto errout; } - err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid); + err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid); errout: return err; } @@ -2260,6 +2260,7 @@ errout: void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) { struct sk_buff *skb; + struct net *net = info->nl_net; u32 seq; int err; @@ -2278,11 +2279,11 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) kfree_skb(skb); goto errout; } - err = rtnl_notify(skb, &init_net, info->pid, - RTNLGRP_IPV6_ROUTE, info->nlh, gfp_any()); + err = rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE, + info->nlh, gfp_any()); errout: if (err < 0) - rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_ROUTE, err); + rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err); } /* @@ -2544,6 +2545,7 @@ static void ip6_route_net_exit(struct net *net) proc_net_remove(net, "ipv6_route"); proc_net_remove(net, "rt6_stats"); #endif + rt6_ifdown(net, NULL); } static struct pernet_operations ip6_route_net_ops = { @@ -2592,7 +2594,6 @@ fib6_rules_init: xfrm6_init: xfrm6_fini(); out_fib6_init: - rt6_ifdown(&init_net, NULL); fib6_gc_cleanup(); out_kmem_cache: kmem_cache_destroy(ip6_dst_ops.kmem_cachep); @@ -2604,7 +2605,6 @@ void ip6_route_cleanup(void) unregister_pernet_subsys(&ip6_route_net_ops); fib6_rules_cleanup(); xfrm6_fini(); - rt6_ifdown(&init_net, NULL); fib6_gc_cleanup(); kmem_cache_destroy(ip6_dst_ops.kmem_cachep); } -- cgit v1.2.3-59-g8ed1b From bdb3289f739e94bcae8b51972ae844ec66c2f4df Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 4 Mar 2008 13:48:10 -0800 Subject: [NETNS][IPV6] rt6_info - make rt6_info accessed as a pointer This patch make mindless changes and prepares the code to use dynamic allocation for rt6_info structure. The code accesses the rt6_info structure as a pointer instead of a global static variable. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/ip6_route.h | 6 ++--- net/ipv6/addrconf.c | 12 ++++----- net/ipv6/fib6_rules.c | 12 ++++----- net/ipv6/ip6_fib.c | 18 ++++++------- net/ipv6/route.c | 70 ++++++++++++++++++++++++++++++++++++++----------- 5 files changed, 78 insertions(+), 40 deletions(-) (limited to 'net') diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 2bcbfb826530..e0caed25bfba 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -34,11 +34,11 @@ struct route_info { #define RT6_LOOKUP_F_REACHABLE 0x2 #define RT6_LOOKUP_F_HAS_SADDR 0x4 -extern struct rt6_info ip6_null_entry; +extern struct rt6_info *ip6_null_entry; #ifdef CONFIG_IPV6_MULTIPLE_TABLES -extern struct rt6_info ip6_prohibit_entry; -extern struct rt6_info ip6_blk_hole_entry; +extern struct rt6_info *ip6_prohibit_entry; +extern struct rt6_info *ip6_blk_hole_entry; #endif extern void ip6_route_input(struct sk_buff *skb); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index b37ae421b61b..3192a848a53a 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4301,13 +4301,13 @@ int __init addrconf_init(void) if (err) goto errlo; - ip6_null_entry.u.dst.dev = init_net.loopback_dev; - ip6_null_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev); + ip6_null_entry->u.dst.dev = init_net.loopback_dev; + ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); #ifdef CONFIG_IPV6_MULTIPLE_TABLES - ip6_prohibit_entry.u.dst.dev = init_net.loopback_dev; - ip6_prohibit_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev); - ip6_blk_hole_entry.u.dst.dev = init_net.loopback_dev; - ip6_blk_hole_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev); + ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev; + ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev; + ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); #endif register_netdevice_notifier(&ipv6_dev_notf); diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 89cb092c9732..c00055f232c4 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -43,8 +43,8 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, if (arg.result) return arg.result; - dst_hold(&ip6_null_entry.u.dst); - return &ip6_null_entry.u.dst; + dst_hold(&ip6_null_entry->u.dst); + return &ip6_null_entry->u.dst; } static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, @@ -58,14 +58,14 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, case FR_ACT_TO_TBL: break; case FR_ACT_UNREACHABLE: - rt = &ip6_null_entry; + rt = ip6_null_entry; goto discard_pkt; default: case FR_ACT_BLACKHOLE: - rt = &ip6_blk_hole_entry; + rt = ip6_blk_hole_entry; goto discard_pkt; case FR_ACT_PROHIBIT: - rt = &ip6_prohibit_entry; + rt = ip6_prohibit_entry; goto discard_pkt; } @@ -73,7 +73,7 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, if (table) rt = lookup(table, flp, flags); - if (rt != &ip6_null_entry) { + if (rt != ip6_null_entry) { struct fib6_rule *r = (struct fib6_rule *)rule; /* diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 1c2566e3d392..f028f7a1a446 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -200,7 +200,7 @@ static struct fib6_table *fib6_alloc_table(u32 id) table = kzalloc(sizeof(*table), GFP_ATOMIC); if (table != NULL) { table->tb6_id = id; - table->tb6_root.leaf = &ip6_null_entry; + table->tb6_root.leaf = ip6_null_entry; table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; } @@ -717,8 +717,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) if (sfn == NULL) goto st_failure; - sfn->leaf = &ip6_null_entry; - atomic_inc(&ip6_null_entry.rt6i_ref); + sfn->leaf = ip6_null_entry; + atomic_inc(&ip6_null_entry->rt6i_ref); sfn->fn_flags = RTN_ROOT; sfn->fn_sernum = fib6_new_sernum(); @@ -777,7 +777,7 @@ out: #if RT6_DEBUG >= 2 if (!pn->leaf) { BUG_TRAP(pn->leaf != NULL); - pn->leaf = &ip6_null_entry; + pn->leaf = ip6_null_entry; } #endif atomic_inc(&pn->leaf->rt6i_ref); @@ -962,7 +962,7 @@ struct fib6_node * fib6_locate(struct fib6_node *root, static struct rt6_info * fib6_find_prefix(struct fib6_node *fn) { if (fn->fn_flags&RTN_ROOT) - return &ip6_null_entry; + return ip6_null_entry; while(fn) { if(fn->left) @@ -1012,7 +1012,7 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) #if RT6_DEBUG >= 2 if (fn->leaf==NULL) { BUG_TRAP(fn->leaf); - fn->leaf = &ip6_null_entry; + fn->leaf = ip6_null_entry; } #endif atomic_inc(&fn->leaf->rt6i_ref); @@ -1154,7 +1154,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info) return -ENOENT; } #endif - if (fn == NULL || rt == &ip6_null_entry) + if (fn == NULL || rt == ip6_null_entry) return -ENOENT; BUG_TRAP(fn->fn_flags&RTN_RTINFO); @@ -1501,7 +1501,7 @@ static int fib6_net_init(struct net *net) goto out_fib_table_hash; net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN; - net->ipv6.fib6_main_tbl->tb6_root.leaf = &ip6_null_entry; + net->ipv6.fib6_main_tbl->tb6_root.leaf = ip6_null_entry; net->ipv6.fib6_main_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; @@ -1511,7 +1511,7 @@ static int fib6_net_init(struct net *net) if (!net->ipv6.fib6_local_tbl) goto out_fib6_main_tbl; net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL; - net->ipv6.fib6_local_tbl->tb6_root.leaf = &ip6_null_entry; + net->ipv6.fib6_local_tbl->tb6_root.leaf = ip6_null_entry; net->ipv6.fib6_local_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; #endif diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b3ac4901af86..8f954c1e961f 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -127,7 +127,7 @@ static struct dst_ops ip6_dst_blackhole_ops = { .entries = ATOMIC_INIT(0), }; -struct rt6_info ip6_null_entry = { +static struct rt6_info ip6_null_entry_template = { .u = { .dst = { .__refcnt = ATOMIC_INIT(1), @@ -138,7 +138,6 @@ struct rt6_info ip6_null_entry = { .input = ip6_pkt_discard, .output = ip6_pkt_discard_out, .ops = &ip6_dst_ops, - .path = (struct dst_entry*)&ip6_null_entry, } }, .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), @@ -146,12 +145,14 @@ struct rt6_info ip6_null_entry = { .rt6i_ref = ATOMIC_INIT(1), }; +struct rt6_info *ip6_null_entry; + #ifdef CONFIG_IPV6_MULTIPLE_TABLES static int ip6_pkt_prohibit(struct sk_buff *skb); static int ip6_pkt_prohibit_out(struct sk_buff *skb); -struct rt6_info ip6_prohibit_entry = { +struct rt6_info ip6_prohibit_entry_template = { .u = { .dst = { .__refcnt = ATOMIC_INIT(1), @@ -162,7 +163,6 @@ struct rt6_info ip6_prohibit_entry = { .input = ip6_pkt_prohibit, .output = ip6_pkt_prohibit_out, .ops = &ip6_dst_ops, - .path = (struct dst_entry*)&ip6_prohibit_entry, } }, .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), @@ -170,7 +170,9 @@ struct rt6_info ip6_prohibit_entry = { .rt6i_ref = ATOMIC_INIT(1), }; -struct rt6_info ip6_blk_hole_entry = { +struct rt6_info *ip6_prohibit_entry; + +static struct rt6_info ip6_blk_hole_entry_template = { .u = { .dst = { .__refcnt = ATOMIC_INIT(1), @@ -181,7 +183,6 @@ struct rt6_info ip6_blk_hole_entry = { .input = dst_discard, .output = dst_discard, .ops = &ip6_dst_ops, - .path = (struct dst_entry*)&ip6_blk_hole_entry, } }, .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), @@ -189,6 +190,8 @@ struct rt6_info ip6_blk_hole_entry = { .rt6i_ref = ATOMIC_INIT(1), }; +struct rt6_info *ip6_blk_hole_entry; + #endif /* allocate dst with ip6_dst_ops */ @@ -271,7 +274,7 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, return local; if (strict) - return &ip6_null_entry; + return ip6_null_entry; } return rt; } @@ -437,7 +440,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) RT6_TRACE("%s() => %p\n", __FUNCTION__, match); - return (match ? match : &ip6_null_entry); + return (match ? match : ip6_null_entry); } #ifdef CONFIG_IPV6_ROUTE_INFO @@ -522,7 +525,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, #define BACKTRACK(saddr) \ do { \ - if (rt == &ip6_null_entry) { \ + if (rt == ip6_null_entry) { \ struct fib6_node *pn; \ while (1) { \ if (fn->fn_flags & RTN_TL_ROOT) \ @@ -686,7 +689,7 @@ restart_2: restart: rt = rt6_select(fn, oif, strict | reachable); BACKTRACK(&fl->fl6_src); - if (rt == &ip6_null_entry || + if (rt == ip6_null_entry || rt->rt6i_flags & RTF_CACHE) goto out; @@ -704,7 +707,7 @@ restart: } dst_release(&rt->u.dst); - rt = nrt ? : &ip6_null_entry; + rt = nrt ? : ip6_null_entry; dst_hold(&rt->u.dst); if (nrt) { @@ -1257,7 +1260,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) int err; struct fib6_table *table; - if (rt == &ip6_null_entry) + if (rt == ip6_null_entry) return -ENOENT; table = rt->rt6i_table; @@ -1369,7 +1372,7 @@ restart: } if (!rt) - rt = &ip6_null_entry; + rt = ip6_null_entry; BACKTRACK(&fl->fl6_src); out: dst_hold(&rt->u.dst); @@ -1415,7 +1418,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, rt = ip6_route_redirect(dest, src, saddr, neigh->dev); - if (rt == &ip6_null_entry) { + if (rt == ip6_null_entry) { if (net_ratelimit()) printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " "for redirect target\n"); @@ -1886,7 +1889,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, static int fib6_ifdown(struct rt6_info *rt, void *arg) { if (((void*)rt->rt6i_dev == arg || arg == NULL) && - rt != &ip6_null_entry) { + rt != ip6_null_entry) { RT6_TRACE("deleted by ifdown %p\n", rt); return -1; } @@ -2565,9 +2568,30 @@ int __init ip6_route_init(void) ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep; + ret = -ENOMEM; + ip6_null_entry = kmemdup(&ip6_null_entry_template, + sizeof(*ip6_null_entry), GFP_KERNEL); + if (!ip6_null_entry) + goto out_kmem_cache; + ip6_null_entry->u.dst.path = (struct dst_entry *)ip6_null_entry; + +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, + sizeof(*ip6_prohibit_entry), GFP_KERNEL); + if (!ip6_prohibit_entry) + goto out_ip6_null_entry; + ip6_prohibit_entry->u.dst.path = (struct dst_entry *)ip6_prohibit_entry; + + ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, + sizeof(*ip6_blk_hole_entry), GFP_KERNEL); + if (!ip6_blk_hole_entry) + goto out_ip6_prohibit_entry; + ip6_blk_hole_entry->u.dst.path = (struct dst_entry *)ip6_blk_hole_entry; +#endif + ret = fib6_init(); if (ret) - goto out_kmem_cache; + goto out_ip6_blk_hole_entry; ret = xfrm6_init(); if (ret) @@ -2595,6 +2619,14 @@ xfrm6_init: xfrm6_fini(); out_fib6_init: fib6_gc_cleanup(); +out_ip6_blk_hole_entry: +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(ip6_blk_hole_entry); +out_ip6_prohibit_entry: + kfree(ip6_prohibit_entry); +out_ip6_null_entry: +#endif + kfree(ip6_null_entry); out_kmem_cache: kmem_cache_destroy(ip6_dst_ops.kmem_cachep); goto out; @@ -2607,4 +2639,10 @@ void ip6_route_cleanup(void) xfrm6_fini(); fib6_gc_cleanup(); kmem_cache_destroy(ip6_dst_ops.kmem_cachep); + + kfree(ip6_null_entry); +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(ip6_prohibit_entry); + kfree(ip6_blk_hole_entry); +#endif } -- cgit v1.2.3-59-g8ed1b From 8ed677896752fff056f6cf3d7ce462adc6c464f0 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 4 Mar 2008 13:48:30 -0800 Subject: [NETNS][IPV6] rt6_info - move rt6_info structure inside the namespace The rt6_info structures are moved inside the network namespace structure. All references to these structures are now relative to the initial network namespace. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 3 +- include/net/netns/ipv6.h | 3 + net/ipv6/addrconf.c | 9 --- net/ipv6/fib6_rules.c | 17 ++-- net/ipv6/ip6_fib.c | 45 ++++++----- net/ipv6/route.c | 202 +++++++++++++++++++++++++++++++---------------- 6 files changed, 171 insertions(+), 108 deletions(-) (limited to 'net') diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index fae267f65341..7c5c0f79168a 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -174,7 +174,8 @@ struct fib6_table { #define RT6_TABLE_LOCAL RT6_TABLE_MAIN #endif -typedef struct rt6_info *(*pol_lookup_t)(struct fib6_table *, +typedef struct rt6_info *(*pol_lookup_t)(struct net *, + struct fib6_table *, struct flowi *, int); /* diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index c6c9afff13ef..311a942f36e9 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -36,11 +36,14 @@ struct netns_ipv6 { struct xt_table *ip6table_mangle; struct xt_table *ip6table_raw; #endif + struct rt6_info *ip6_null_entry; struct rt6_statistics *rt6_stats; struct timer_list *ip6_fib_timer; struct hlist_head *fib_table_hash; struct fib6_table *fib6_main_tbl; #ifdef CONFIG_IPV6_MULTIPLE_TABLES + struct rt6_info *ip6_prohibit_entry; + struct rt6_info *ip6_blk_hole_entry; struct fib6_table *fib6_local_tbl; struct fib_rules_ops *fib6_rules_ops; #endif diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3192a848a53a..17b06d220e95 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4301,15 +4301,6 @@ int __init addrconf_init(void) if (err) goto errlo; - ip6_null_entry->u.dst.dev = init_net.loopback_dev; - ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); -#ifdef CONFIG_IPV6_MULTIPLE_TABLES - ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev; - ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); - ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev; - ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); -#endif - register_netdevice_notifier(&ipv6_dev_notf); addrconf_verify(0); diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index c00055f232c4..55137408f054 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -43,8 +43,8 @@ struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, if (arg.result) return arg.result; - dst_hold(&ip6_null_entry->u.dst); - return &ip6_null_entry->u.dst; + dst_hold(&net->ipv6.ip6_null_entry->u.dst); + return &net->ipv6.ip6_null_entry->u.dst; } static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, @@ -52,28 +52,29 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, { struct rt6_info *rt = NULL; struct fib6_table *table; + struct net *net = rule->fr_net; pol_lookup_t lookup = arg->lookup_ptr; switch (rule->action) { case FR_ACT_TO_TBL: break; case FR_ACT_UNREACHABLE: - rt = ip6_null_entry; + rt = net->ipv6.ip6_null_entry; goto discard_pkt; default: case FR_ACT_BLACKHOLE: - rt = ip6_blk_hole_entry; + rt = net->ipv6.ip6_blk_hole_entry; goto discard_pkt; case FR_ACT_PROHIBIT: - rt = ip6_prohibit_entry; + rt = net->ipv6.ip6_prohibit_entry; goto discard_pkt; } - table = fib6_get_table(rule->fr_net, rule->table); + table = fib6_get_table(net, rule->table); if (table) - rt = lookup(table, flp, flags); + rt = lookup(net, table, flp, flags); - if (rt != ip6_null_entry) { + if (rt != net->ipv6.ip6_null_entry) { struct fib6_rule *r = (struct fib6_rule *)rule; /* diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index f028f7a1a446..b0814b0082e7 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -79,8 +79,8 @@ static DEFINE_RWLOCK(fib6_walker_lock); static void fib6_prune_clones(struct net *net, struct fib6_node *fn, struct rt6_info *rt); -static struct rt6_info * fib6_find_prefix(struct fib6_node *fn); -static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); +static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn); +static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn); static int fib6_walk(struct fib6_walker_t *w); static int fib6_walk_continue(struct fib6_walker_t *w); @@ -193,14 +193,14 @@ static void fib6_link_table(struct net *net, struct fib6_table *tb) #ifdef CONFIG_IPV6_MULTIPLE_TABLES -static struct fib6_table *fib6_alloc_table(u32 id) +static struct fib6_table *fib6_alloc_table(struct net *net, u32 id) { struct fib6_table *table; table = kzalloc(sizeof(*table), GFP_ATOMIC); if (table != NULL) { table->tb6_id = id; - table->tb6_root.leaf = ip6_null_entry; + table->tb6_root.leaf = net->ipv6.ip6_null_entry; table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; } @@ -217,7 +217,7 @@ struct fib6_table *fib6_new_table(struct net *net, u32 id) if (tb) return tb; - tb = fib6_alloc_table(id); + tb = fib6_alloc_table(net, id); if (tb != NULL) fib6_link_table(net, tb); @@ -267,7 +267,7 @@ struct fib6_table *fib6_get_table(struct net *net, u32 id) struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi *fl, int flags, pol_lookup_t lookup) { - return (struct dst_entry *) lookup(net->ipv6.fib6_main_tbl, fl, flags); + return (struct dst_entry *) lookup(net, net->ipv6.fib6_main_tbl, fl, flags); } static void fib6_tables_init(struct net *net) @@ -717,8 +717,8 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) if (sfn == NULL) goto st_failure; - sfn->leaf = ip6_null_entry; - atomic_inc(&ip6_null_entry->rt6i_ref); + sfn->leaf = info->nl_net->ipv6.ip6_null_entry; + atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref); sfn->fn_flags = RTN_ROOT; sfn->fn_sernum = fib6_new_sernum(); @@ -773,11 +773,11 @@ out: * super-tree leaf node we have to find a new one for it. */ if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) { - pn->leaf = fib6_find_prefix(pn); + pn->leaf = fib6_find_prefix(info->nl_net, pn); #if RT6_DEBUG >= 2 if (!pn->leaf) { BUG_TRAP(pn->leaf != NULL); - pn->leaf = ip6_null_entry; + pn->leaf = info->nl_net->ipv6.ip6_null_entry; } #endif atomic_inc(&pn->leaf->rt6i_ref); @@ -793,7 +793,7 @@ out: */ st_failure: if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT))) - fib6_repair_tree(fn); + fib6_repair_tree(info->nl_net, fn); dst_free(&rt->u.dst); return err; #endif @@ -959,10 +959,10 @@ struct fib6_node * fib6_locate(struct fib6_node *root, * */ -static struct rt6_info * fib6_find_prefix(struct fib6_node *fn) +static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn) { if (fn->fn_flags&RTN_ROOT) - return ip6_null_entry; + return net->ipv6.ip6_null_entry; while(fn) { if(fn->left) @@ -981,7 +981,8 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn) * is the node we want to try and remove. */ -static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) +static struct fib6_node *fib6_repair_tree(struct net *net, + struct fib6_node *fn) { int children; int nstate; @@ -1008,11 +1009,11 @@ static struct fib6_node * fib6_repair_tree(struct fib6_node *fn) || (children && fn->fn_flags&RTN_ROOT) #endif ) { - fn->leaf = fib6_find_prefix(fn); + fn->leaf = fib6_find_prefix(net, fn); #if RT6_DEBUG >= 2 if (fn->leaf==NULL) { BUG_TRAP(fn->leaf); - fn->leaf = ip6_null_entry; + fn->leaf = net->ipv6.ip6_null_entry; } #endif atomic_inc(&fn->leaf->rt6i_ref); @@ -1117,7 +1118,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, if (fn->leaf == NULL) { fn->fn_flags &= ~RTN_RTINFO; net->ipv6.rt6_stats->fib_route_nodes--; - fn = fib6_repair_tree(fn); + fn = fib6_repair_tree(net, fn); } if (atomic_read(&rt->rt6i_ref) != 1) { @@ -1129,7 +1130,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, */ while (fn) { if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) { - fn->leaf = fib6_find_prefix(fn); + fn->leaf = fib6_find_prefix(net, fn); atomic_inc(&fn->leaf->rt6i_ref); rt6_release(rt); } @@ -1145,6 +1146,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, int fib6_del(struct rt6_info *rt, struct nl_info *info) { + struct net *net = info->nl_net; struct fib6_node *fn = rt->rt6i_node; struct rt6_info **rtp; @@ -1154,7 +1156,7 @@ int fib6_del(struct rt6_info *rt, struct nl_info *info) return -ENOENT; } #endif - if (fn == NULL || rt == ip6_null_entry) + if (fn == NULL || rt == net->ipv6.ip6_null_entry) return -ENOENT; BUG_TRAP(fn->fn_flags&RTN_RTINFO); @@ -1501,7 +1503,7 @@ static int fib6_net_init(struct net *net) goto out_fib_table_hash; net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN; - net->ipv6.fib6_main_tbl->tb6_root.leaf = ip6_null_entry; + net->ipv6.fib6_main_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry; net->ipv6.fib6_main_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; @@ -1511,7 +1513,7 @@ static int fib6_net_init(struct net *net) if (!net->ipv6.fib6_local_tbl) goto out_fib6_main_tbl; net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL; - net->ipv6.fib6_local_tbl->tb6_root.leaf = ip6_null_entry; + net->ipv6.fib6_local_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry; net->ipv6.fib6_local_tbl->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; #endif @@ -1536,6 +1538,7 @@ out_timer: static void fib6_net_exit(struct net *net) { + rt6_ifdown(net, NULL); del_timer(net->ipv6.ip6_fib_timer); kfree(net->ipv6.ip6_fib_timer); #ifdef CONFIG_IPV6_MULTIPLE_TABLES diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 8f954c1e961f..7ff66cebe77c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -145,8 +145,6 @@ static struct rt6_info ip6_null_entry_template = { .rt6i_ref = ATOMIC_INIT(1), }; -struct rt6_info *ip6_null_entry; - #ifdef CONFIG_IPV6_MULTIPLE_TABLES static int ip6_pkt_prohibit(struct sk_buff *skb); @@ -170,8 +168,6 @@ struct rt6_info ip6_prohibit_entry_template = { .rt6i_ref = ATOMIC_INIT(1), }; -struct rt6_info *ip6_prohibit_entry; - static struct rt6_info ip6_blk_hole_entry_template = { .u = { .dst = { @@ -190,8 +186,6 @@ static struct rt6_info ip6_blk_hole_entry_template = { .rt6i_ref = ATOMIC_INIT(1), }; -struct rt6_info *ip6_blk_hole_entry; - #endif /* allocate dst with ip6_dst_ops */ @@ -245,7 +239,8 @@ static inline int rt6_need_strict(struct in6_addr *daddr) * Route lookup. Any table->tb6_lock is implied. */ -static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, +static inline struct rt6_info *rt6_device_match(struct net *net, + struct rt6_info *rt, int oif, int strict) { @@ -274,7 +269,7 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt, return local; if (strict) - return ip6_null_entry; + return net->ipv6.ip6_null_entry; } return rt; } @@ -415,6 +410,7 @@ static struct rt6_info *find_rr_leaf(struct fib6_node *fn, static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) { struct rt6_info *match, *rt0; + struct net *net; RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n", __FUNCTION__, fn->leaf, oif); @@ -440,7 +436,8 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) RT6_TRACE("%s() => %p\n", __FUNCTION__, match); - return (match ? match : ip6_null_entry); + net = rt0->rt6i_dev->nd_net; + return (match ? match : net->ipv6.ip6_null_entry); } #ifdef CONFIG_IPV6_ROUTE_INFO @@ -523,9 +520,9 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, } #endif -#define BACKTRACK(saddr) \ +#define BACKTRACK(__net, saddr) \ do { \ - if (rt == ip6_null_entry) { \ + if (rt == __net->ipv6.ip6_null_entry) { \ struct fib6_node *pn; \ while (1) { \ if (fn->fn_flags & RTN_TL_ROOT) \ @@ -541,7 +538,8 @@ do { \ } \ } while(0) -static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table, +static struct rt6_info *ip6_pol_route_lookup(struct net *net, + struct fib6_table *table, struct flowi *fl, int flags) { struct fib6_node *fn; @@ -551,8 +549,8 @@ static struct rt6_info *ip6_pol_route_lookup(struct fib6_table *table, fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); restart: rt = fn->leaf; - rt = rt6_device_match(rt, fl->oif, flags); - BACKTRACK(&fl->fl6_src); + rt = rt6_device_match(net, rt, fl->oif, flags); + BACKTRACK(net, &fl->fl6_src); out: dst_use(&rt->u.dst, jiffies); read_unlock_bh(&table->tb6_lock); @@ -668,8 +666,8 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d return rt; } -static struct rt6_info *ip6_pol_route(struct fib6_table *table, int oif, - struct flowi *fl, int flags) +static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, int oif, + struct flowi *fl, int flags) { struct fib6_node *fn; struct rt6_info *rt, *nrt; @@ -688,8 +686,9 @@ restart_2: restart: rt = rt6_select(fn, oif, strict | reachable); - BACKTRACK(&fl->fl6_src); - if (rt == ip6_null_entry || + + BACKTRACK(net, &fl->fl6_src); + if (rt == net->ipv6.ip6_null_entry || rt->rt6i_flags & RTF_CACHE) goto out; @@ -707,7 +706,7 @@ restart: } dst_release(&rt->u.dst); - rt = nrt ? : ip6_null_entry; + rt = nrt ? : net->ipv6.ip6_null_entry; dst_hold(&rt->u.dst); if (nrt) { @@ -740,10 +739,10 @@ out2: return rt; } -static struct rt6_info *ip6_pol_route_input(struct fib6_table *table, +static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table, struct flowi *fl, int flags) { - return ip6_pol_route(table, fl->iif, fl, flags); + return ip6_pol_route(net, table, fl->iif, fl, flags); } void ip6_route_input(struct sk_buff *skb) @@ -770,10 +769,10 @@ void ip6_route_input(struct sk_buff *skb) skb->dst = fib6_rule_lookup(net, &fl, flags, ip6_pol_route_input); } -static struct rt6_info *ip6_pol_route_output(struct fib6_table *table, +static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, struct flowi *fl, int flags) { - return ip6_pol_route(table, fl->oif, fl, flags); + return ip6_pol_route(net, table, fl->oif, fl, flags); } struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) @@ -1259,8 +1258,9 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) { int err; struct fib6_table *table; + struct net *net = rt->rt6i_dev->nd_net; - if (rt == ip6_null_entry) + if (rt == net->ipv6.ip6_null_entry) return -ENOENT; table = rt->rt6i_table; @@ -1329,7 +1329,8 @@ struct ip6rd_flowi { struct in6_addr gateway; }; -static struct rt6_info *__ip6_route_redirect(struct fib6_table *table, +static struct rt6_info *__ip6_route_redirect(struct net *net, + struct fib6_table *table, struct flowi *fl, int flags) { @@ -1372,8 +1373,8 @@ restart: } if (!rt) - rt = ip6_null_entry; - BACKTRACK(&fl->fl6_src); + rt = net->ipv6.ip6_null_entry; + BACKTRACK(net, &fl->fl6_src); out: dst_hold(&rt->u.dst); @@ -1415,10 +1416,11 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, { struct rt6_info *rt, *nrt = NULL; struct netevent_redirect netevent; + struct net *net = neigh->dev->nd_net; rt = ip6_route_redirect(dest, src, saddr, neigh->dev); - if (rt == ip6_null_entry) { + if (rt == net->ipv6.ip6_null_entry) { if (net_ratelimit()) printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " "for redirect target\n"); @@ -1886,10 +1888,18 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, return rt; } +struct arg_dev_net { + struct net_device *dev; + struct net *net; +}; + static int fib6_ifdown(struct rt6_info *rt, void *arg) { - if (((void*)rt->rt6i_dev == arg || arg == NULL) && - rt != ip6_null_entry) { + struct net_device *dev = ((struct arg_dev_net *)arg)->dev; + struct net *net = ((struct arg_dev_net *)arg)->net; + + if (((void *)rt->rt6i_dev == dev || dev == NULL) && + rt != net->ipv6.ip6_null_entry) { RT6_TRACE("deleted by ifdown %p\n", rt); return -1; } @@ -1898,7 +1908,12 @@ static int fib6_ifdown(struct rt6_info *rt, void *arg) void rt6_ifdown(struct net *net, struct net_device *dev) { - fib6_clean_all(net, fib6_ifdown, 0, dev); + struct arg_dev_net adn = { + .dev = dev, + .net = net, + }; + + fib6_clean_all(net, fib6_ifdown, 0, &adn); } struct rt6_mtu_change_arg @@ -2289,6 +2304,26 @@ errout: rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err); } +static int ip6_route_dev_notify(struct notifier_block *this, + unsigned long event, void *data) +{ + struct net_device *dev = (struct net_device *)data; + struct net *net = dev->nd_net; + + if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { + net->ipv6.ip6_null_entry->u.dst.dev = dev; + net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.ip6_prohibit_entry->u.dst.dev = dev; + net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); + net->ipv6.ip6_blk_hole_entry->u.dst.dev = dev; + net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); +#endif + } + + return NOTIFY_OK; +} + /* * /proc */ @@ -2535,11 +2570,47 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net) static int ip6_route_net_init(struct net *net) { + int ret = 0; + + ret = -ENOMEM; + net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, + sizeof(*net->ipv6.ip6_null_entry), + GFP_KERNEL); + if (!net->ipv6.ip6_null_entry) + goto out; + net->ipv6.ip6_null_entry->u.dst.path = + (struct dst_entry *)net->ipv6.ip6_null_entry; + +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, + sizeof(*net->ipv6.ip6_prohibit_entry), + GFP_KERNEL); + if (!net->ipv6.ip6_prohibit_entry) { + kfree(net->ipv6.ip6_null_entry); + goto out; + } + net->ipv6.ip6_prohibit_entry->u.dst.path = + (struct dst_entry *)net->ipv6.ip6_prohibit_entry; + + net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, + sizeof(*net->ipv6.ip6_blk_hole_entry), + GFP_KERNEL); + if (!net->ipv6.ip6_blk_hole_entry) { + kfree(net->ipv6.ip6_null_entry); + kfree(net->ipv6.ip6_prohibit_entry); + goto out; + } + net->ipv6.ip6_blk_hole_entry->u.dst.path = + (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; +#endif + #ifdef CONFIG_PROC_FS proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops); proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); #endif - return 0; + ret = 0; +out: + return ret; } static void ip6_route_net_exit(struct net *net) @@ -2548,7 +2619,11 @@ static void ip6_route_net_exit(struct net *net) proc_net_remove(net, "ipv6_route"); proc_net_remove(net, "rt6_stats"); #endif - rt6_ifdown(net, NULL); + kfree(net->ipv6.ip6_null_entry); +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + kfree(net->ipv6.ip6_prohibit_entry); + kfree(net->ipv6.ip6_blk_hole_entry); +#endif } static struct pernet_operations ip6_route_net_ops = { @@ -2556,6 +2631,11 @@ static struct pernet_operations ip6_route_net_ops = { .exit = ip6_route_net_exit, }; +static struct notifier_block ip6_route_dev_notifier = { + .notifier_call = ip6_route_dev_notify, + .priority = 0, +}; + int __init ip6_route_init(void) { int ret; @@ -2568,30 +2648,24 @@ int __init ip6_route_init(void) ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep; - ret = -ENOMEM; - ip6_null_entry = kmemdup(&ip6_null_entry_template, - sizeof(*ip6_null_entry), GFP_KERNEL); - if (!ip6_null_entry) + ret = register_pernet_subsys(&ip6_route_net_ops); + if (ret) goto out_kmem_cache; - ip6_null_entry->u.dst.path = (struct dst_entry *)ip6_null_entry; - -#ifdef CONFIG_IPV6_MULTIPLE_TABLES - ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, - sizeof(*ip6_prohibit_entry), GFP_KERNEL); - if (!ip6_prohibit_entry) - goto out_ip6_null_entry; - ip6_prohibit_entry->u.dst.path = (struct dst_entry *)ip6_prohibit_entry; - - ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, - sizeof(*ip6_blk_hole_entry), GFP_KERNEL); - if (!ip6_blk_hole_entry) - goto out_ip6_prohibit_entry; - ip6_blk_hole_entry->u.dst.path = (struct dst_entry *)ip6_blk_hole_entry; -#endif + /* Registering of the loopback is done before this portion of code, + * the loopback reference in rt6_info will not be taken, do it + * manually for init_net */ + init_net.ipv6.ip6_null_entry->u.dst.dev = init_net.loopback_dev; + init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + #ifdef CONFIG_IPV6_MULTIPLE_TABLES + init_net.ipv6.ip6_prohibit_entry->u.dst.dev = init_net.loopback_dev; + init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + init_net.ipv6.ip6_blk_hole_entry->u.dst.dev = init_net.loopback_dev; + init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); + #endif ret = fib6_init(); if (ret) - goto out_ip6_blk_hole_entry; + goto out_register_subsys; ret = xfrm6_init(); if (ret) @@ -2607,9 +2681,10 @@ int __init ip6_route_init(void) __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL)) goto fib6_rules_init; - ret = register_pernet_subsys(&ip6_route_net_ops); + ret = register_netdevice_notifier(&ip6_route_dev_notifier); if (ret) goto fib6_rules_init; + out: return ret; @@ -2619,14 +2694,8 @@ xfrm6_init: xfrm6_fini(); out_fib6_init: fib6_gc_cleanup(); -out_ip6_blk_hole_entry: -#ifdef CONFIG_IPV6_MULTIPLE_TABLES - kfree(ip6_blk_hole_entry); -out_ip6_prohibit_entry: - kfree(ip6_prohibit_entry); -out_ip6_null_entry: -#endif - kfree(ip6_null_entry); +out_register_subsys: + unregister_pernet_subsys(&ip6_route_net_ops); out_kmem_cache: kmem_cache_destroy(ip6_dst_ops.kmem_cachep); goto out; @@ -2634,15 +2703,10 @@ out_kmem_cache: void ip6_route_cleanup(void) { - unregister_pernet_subsys(&ip6_route_net_ops); + unregister_netdevice_notifier(&ip6_route_dev_notifier); fib6_rules_cleanup(); xfrm6_fini(); fib6_gc_cleanup(); + unregister_pernet_subsys(&ip6_route_net_ops); kmem_cache_destroy(ip6_dst_ops.kmem_cachep); - - kfree(ip6_null_entry); -#ifdef CONFIG_IPV6_MULTIPLE_TABLES - kfree(ip6_prohibit_entry); - kfree(ip6_blk_hole_entry); -#endif } -- cgit v1.2.3-59-g8ed1b From 9a7ec3a94d8da475fe81810aa55136a81556d445 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 4 Mar 2008 13:48:53 -0800 Subject: [NETNS][IPV6] route6 - dynamically allocate ip6_dst_ops ip6_dst_ops is dynamically allocated in init and exit functions. That provides the ability to do multiple instanciations of this structure. This will be needed for network namespaces, indeed dst_ops stores data that are required to be per namespace: entries and gc_thresh. Signed-off-by: Benjamin Thery Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv6/route.c | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7ff66cebe77c..fa014d701c1a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -97,7 +97,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net, struct in6_addr *gwaddr, int ifindex); #endif -static struct dst_ops ip6_dst_ops = { +static struct dst_ops ip6_dst_ops_template = { .family = AF_INET6, .protocol = __constant_htons(ETH_P_IPV6), .gc = ip6_dst_gc, @@ -113,6 +113,8 @@ static struct dst_ops ip6_dst_ops = { .entries = ATOMIC_INIT(0), }; +static struct dst_ops *ip6_dst_ops; + static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) { } @@ -137,7 +139,6 @@ static struct rt6_info ip6_null_entry_template = { .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, .input = ip6_pkt_discard, .output = ip6_pkt_discard_out, - .ops = &ip6_dst_ops, } }, .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), @@ -160,7 +161,6 @@ struct rt6_info ip6_prohibit_entry_template = { .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, .input = ip6_pkt_prohibit, .output = ip6_pkt_prohibit_out, - .ops = &ip6_dst_ops, } }, .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), @@ -178,7 +178,6 @@ static struct rt6_info ip6_blk_hole_entry_template = { .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, .input = dst_discard, .output = dst_discard, - .ops = &ip6_dst_ops, } }, .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), @@ -191,7 +190,7 @@ static struct rt6_info ip6_blk_hole_entry_template = { /* allocate dst with ip6_dst_ops */ static __inline__ struct rt6_info *ip6_dst_alloc(void) { - return (struct rt6_info *)dst_alloc(&ip6_dst_ops); + return (struct rt6_info *)dst_alloc(ip6_dst_ops); } static void ip6_dst_destroy(struct dst_entry *dst) @@ -1000,18 +999,18 @@ static int ip6_dst_gc(struct dst_ops *ops) unsigned long now = jiffies; if (time_after(last_gc + init_net.ipv6.sysctl.ip6_rt_gc_min_interval, now) && - atomic_read(&ip6_dst_ops.entries) <= init_net.ipv6.sysctl.ip6_rt_max_size) + atomic_read(&ip6_dst_ops->entries) <= init_net.ipv6.sysctl.ip6_rt_max_size) goto out; expire++; fib6_run_gc(expire, &init_net); last_gc = now; - if (atomic_read(&ip6_dst_ops.entries) < ip6_dst_ops.gc_thresh) + if (atomic_read(&ip6_dst_ops->entries) < ip6_dst_ops->gc_thresh) expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1; out: expire -= expire>>init_net.ipv6.sysctl.ip6_rt_gc_elasticity; - return (atomic_read(&ip6_dst_ops.entries) > init_net.ipv6.sysctl.ip6_rt_max_size); + return (atomic_read(&ip6_dst_ops->entries) > init_net.ipv6.sysctl.ip6_rt_max_size); } /* Clean host part of a prefix. Not necessary in radix tree, @@ -2408,7 +2407,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v) net->ipv6.rt6_stats->fib_rt_alloc, net->ipv6.rt6_stats->fib_rt_entries, net->ipv6.rt6_stats->fib_rt_cache, - atomic_read(&ip6_dst_ops.entries), + atomic_read(&ip6_dst_ops->entries), net->ipv6.rt6_stats->fib_discarded_routes); return 0; @@ -2464,7 +2463,7 @@ ctl_table ipv6_route_table_template[] = { { .ctl_name = NET_IPV6_ROUTE_GC_THRESH, .procname = "gc_thresh", - .data = &ip6_dst_ops.gc_thresh, + .data = &ip6_dst_ops_template.gc_thresh, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec, @@ -2553,8 +2552,7 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net) if (table) { table[0].data = &net->ipv6.sysctl.flush_delay; - /* table[1].data will be handled when we have - routes per namespace */ + table[1].data = &ip6_dst_ops_template.gc_thresh; table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout; @@ -2580,6 +2578,7 @@ static int ip6_route_net_init(struct net *net) goto out; net->ipv6.ip6_null_entry->u.dst.path = (struct dst_entry *)net->ipv6.ip6_null_entry; + net->ipv6.ip6_null_entry->u.dst.ops = ip6_dst_ops; #ifdef CONFIG_IPV6_MULTIPLE_TABLES net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, @@ -2591,6 +2590,7 @@ static int ip6_route_net_init(struct net *net) } net->ipv6.ip6_prohibit_entry->u.dst.path = (struct dst_entry *)net->ipv6.ip6_prohibit_entry; + net->ipv6.ip6_prohibit_entry->u.dst.ops = ip6_dst_ops; net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, sizeof(*net->ipv6.ip6_blk_hole_entry), @@ -2602,6 +2602,7 @@ static int ip6_route_net_init(struct net *net) } net->ipv6.ip6_blk_hole_entry->u.dst.path = (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; + net->ipv6.ip6_blk_hole_entry->u.dst.ops = ip6_dst_ops; #endif #ifdef CONFIG_PROC_FS @@ -2640,13 +2641,20 @@ int __init ip6_route_init(void) { int ret; - ip6_dst_ops.kmem_cachep = + ip6_dst_ops = kmemdup(&ip6_dst_ops_template, + sizeof(*ip6_dst_ops), GFP_KERNEL); + if (!ip6_dst_ops) + return -ENOMEM; + + ret = -ENOMEM; + ip6_dst_ops_template.kmem_cachep = kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, SLAB_HWCACHE_ALIGN, NULL); - if (!ip6_dst_ops.kmem_cachep) - return -ENOMEM; + if (!ip6_dst_ops_template.kmem_cachep) + goto out_ip6_dst_ops; - ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep; + ip6_dst_ops->kmem_cachep = ip6_dst_ops_template.kmem_cachep; + ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; ret = register_pernet_subsys(&ip6_route_net_ops); if (ret) @@ -2697,7 +2705,9 @@ out_fib6_init: out_register_subsys: unregister_pernet_subsys(&ip6_route_net_ops); out_kmem_cache: - kmem_cache_destroy(ip6_dst_ops.kmem_cachep); + kmem_cache_destroy(ip6_dst_ops->kmem_cachep); +out_ip6_dst_ops: + kfree(ip6_dst_ops); goto out; } @@ -2708,5 +2718,6 @@ void ip6_route_cleanup(void) xfrm6_fini(); fib6_gc_cleanup(); unregister_pernet_subsys(&ip6_route_net_ops); - kmem_cache_destroy(ip6_dst_ops.kmem_cachep); + kmem_cache_destroy(ip6_dst_ops->kmem_cachep); + kfree(ip6_dst_ops); } -- cgit v1.2.3-59-g8ed1b From f2fc6a54585a1be6669613a31fbaba2ecbadcd36 Mon Sep 17 00:00:00 2001 From: Benjamin Thery Date: Tue, 4 Mar 2008 13:49:23 -0800 Subject: [NETNS][IPV6] route6 - move ip6_dst_ops inside the network namespace The ip6_dst_ops is moved inside the network namespace structure. All references to this structure are now relative to the initial network namespace. Signed-off-by: Benjamin Thery Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/net/netns/ipv6.h | 1 + net/ipv6/route.c | 62 ++++++++++++++++++++++++------------------------ 2 files changed, 32 insertions(+), 31 deletions(-) (limited to 'net') diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 311a942f36e9..53b5a283a4b3 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -41,6 +41,7 @@ struct netns_ipv6 { struct timer_list *ip6_fib_timer; struct hlist_head *fib_table_hash; struct fib6_table *fib6_main_tbl; + struct dst_ops *ip6_dst_ops; #ifdef CONFIG_IPV6_MULTIPLE_TABLES struct rt6_info *ip6_prohibit_entry; struct rt6_info *ip6_blk_hole_entry; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index fa014d701c1a..d88b6ec3c5d1 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -113,8 +113,6 @@ static struct dst_ops ip6_dst_ops_template = { .entries = ATOMIC_INIT(0), }; -static struct dst_ops *ip6_dst_ops; - static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) { } @@ -188,9 +186,9 @@ static struct rt6_info ip6_blk_hole_entry_template = { #endif /* allocate dst with ip6_dst_ops */ -static __inline__ struct rt6_info *ip6_dst_alloc(void) +static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops) { - return (struct rt6_info *)dst_alloc(ip6_dst_ops); + return (struct rt6_info *)dst_alloc(ops); } static void ip6_dst_destroy(struct dst_entry *dst) @@ -925,7 +923,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, if (unlikely(idev == NULL)) return NULL; - rt = ip6_dst_alloc(); + rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); if (unlikely(rt == NULL)) { in6_dev_put(idev); goto out; @@ -999,18 +997,18 @@ static int ip6_dst_gc(struct dst_ops *ops) unsigned long now = jiffies; if (time_after(last_gc + init_net.ipv6.sysctl.ip6_rt_gc_min_interval, now) && - atomic_read(&ip6_dst_ops->entries) <= init_net.ipv6.sysctl.ip6_rt_max_size) + atomic_read(&init_net.ipv6.ip6_dst_ops->entries) <= init_net.ipv6.sysctl.ip6_rt_max_size) goto out; expire++; fib6_run_gc(expire, &init_net); last_gc = now; - if (atomic_read(&ip6_dst_ops->entries) < ip6_dst_ops->gc_thresh) + if (atomic_read(&init_net.ipv6.ip6_dst_ops->entries) < init_net.ipv6.ip6_dst_ops->gc_thresh) expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1; out: expire -= expire>>init_net.ipv6.sysctl.ip6_rt_gc_elasticity; - return (atomic_read(&ip6_dst_ops->entries) > init_net.ipv6.sysctl.ip6_rt_max_size); + return (atomic_read(&init_net.ipv6.ip6_dst_ops->entries) > init_net.ipv6.sysctl.ip6_rt_max_size); } /* Clean host part of a prefix. Not necessary in radix tree, @@ -1084,7 +1082,7 @@ int ip6_route_add(struct fib6_config *cfg) goto out; } - rt = ip6_dst_alloc(); + rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); if (rt == NULL) { err = -ENOMEM; @@ -1570,7 +1568,8 @@ out: static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) { - struct rt6_info *rt = ip6_dst_alloc(); + struct net *net = ort->rt6i_dev->nd_net; + struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); if (rt) { rt->u.dst.input = ort->u.dst.input; @@ -1849,7 +1848,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, int anycast) { struct net *net = idev->dev->nd_net; - struct rt6_info *rt = ip6_dst_alloc(); + struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); if (rt == NULL) return ERR_PTR(-ENOMEM); @@ -2407,7 +2406,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v) net->ipv6.rt6_stats->fib_rt_alloc, net->ipv6.rt6_stats->fib_rt_entries, net->ipv6.rt6_stats->fib_rt_cache, - atomic_read(&ip6_dst_ops->entries), + atomic_read(&net->ipv6.ip6_dst_ops->entries), net->ipv6.rt6_stats->fib_discarded_routes); return 0; @@ -2552,7 +2551,7 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net) if (table) { table[0].data = &net->ipv6.sysctl.flush_delay; - table[1].data = &ip6_dst_ops_template.gc_thresh; + table[1].data = &net->ipv6.ip6_dst_ops->gc_thresh; table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout; @@ -2571,14 +2570,21 @@ static int ip6_route_net_init(struct net *net) int ret = 0; ret = -ENOMEM; + net->ipv6.ip6_dst_ops = kmemdup(&ip6_dst_ops_template, + sizeof(*net->ipv6.ip6_dst_ops), + GFP_KERNEL); + if (!net->ipv6.ip6_dst_ops) + goto out; + net->ipv6.ip6_dst_ops->dst_net = net; + net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, sizeof(*net->ipv6.ip6_null_entry), GFP_KERNEL); if (!net->ipv6.ip6_null_entry) - goto out; + goto out_ip6_dst_ops; net->ipv6.ip6_null_entry->u.dst.path = (struct dst_entry *)net->ipv6.ip6_null_entry; - net->ipv6.ip6_null_entry->u.dst.ops = ip6_dst_ops; + net->ipv6.ip6_null_entry->u.dst.ops = net->ipv6.ip6_dst_ops; #ifdef CONFIG_IPV6_MULTIPLE_TABLES net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, @@ -2590,7 +2596,7 @@ static int ip6_route_net_init(struct net *net) } net->ipv6.ip6_prohibit_entry->u.dst.path = (struct dst_entry *)net->ipv6.ip6_prohibit_entry; - net->ipv6.ip6_prohibit_entry->u.dst.ops = ip6_dst_ops; + net->ipv6.ip6_prohibit_entry->u.dst.ops = net->ipv6.ip6_dst_ops; net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, sizeof(*net->ipv6.ip6_blk_hole_entry), @@ -2602,7 +2608,7 @@ static int ip6_route_net_init(struct net *net) } net->ipv6.ip6_blk_hole_entry->u.dst.path = (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; - net->ipv6.ip6_blk_hole_entry->u.dst.ops = ip6_dst_ops; + net->ipv6.ip6_blk_hole_entry->u.dst.ops = net->ipv6.ip6_dst_ops; #endif #ifdef CONFIG_PROC_FS @@ -2612,6 +2618,10 @@ static int ip6_route_net_init(struct net *net) ret = 0; out: return ret; + +out_ip6_dst_ops: + kfree(net->ipv6.ip6_dst_ops); + goto out; } static void ip6_route_net_exit(struct net *net) @@ -2625,6 +2635,7 @@ static void ip6_route_net_exit(struct net *net) kfree(net->ipv6.ip6_prohibit_entry); kfree(net->ipv6.ip6_blk_hole_entry); #endif + kfree(net->ipv6.ip6_dst_ops); } static struct pernet_operations ip6_route_net_ops = { @@ -2641,20 +2652,12 @@ int __init ip6_route_init(void) { int ret; - ip6_dst_ops = kmemdup(&ip6_dst_ops_template, - sizeof(*ip6_dst_ops), GFP_KERNEL); - if (!ip6_dst_ops) - return -ENOMEM; - ret = -ENOMEM; ip6_dst_ops_template.kmem_cachep = kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, SLAB_HWCACHE_ALIGN, NULL); if (!ip6_dst_ops_template.kmem_cachep) - goto out_ip6_dst_ops; - - ip6_dst_ops->kmem_cachep = ip6_dst_ops_template.kmem_cachep; - ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; + goto out;; ret = register_pernet_subsys(&ip6_route_net_ops); if (ret) @@ -2705,9 +2708,7 @@ out_fib6_init: out_register_subsys: unregister_pernet_subsys(&ip6_route_net_ops); out_kmem_cache: - kmem_cache_destroy(ip6_dst_ops->kmem_cachep); -out_ip6_dst_ops: - kfree(ip6_dst_ops); + kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); goto out; } @@ -2718,6 +2719,5 @@ void ip6_route_cleanup(void) xfrm6_fini(); fib6_gc_cleanup(); unregister_pernet_subsys(&ip6_route_net_ops); - kmem_cache_destroy(ip6_dst_ops->kmem_cachep); - kfree(ip6_dst_ops); + kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); } -- cgit v1.2.3-59-g8ed1b From 6891a346c387bd0a64afa50f4522f5fe8ba879d8 Mon Sep 17 00:00:00 2001 From: Benjamin Thery Date: Tue, 4 Mar 2008 13:49:47 -0800 Subject: [NETNS][IPV6] route6 - make garbage collection work with multiple network namespaces This patch makes the necessary changes to make IPv6 dst_entry garbage collection work with multiple network namespaces. In ip6_dst_gc(), static local variables are now declared per-namespace. Signed-off-by: Benjamin Thery Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/net/netns/ipv6.h | 2 ++ net/ipv6/route.c | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 53b5a283a4b3..90e6e24df858 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -42,6 +42,8 @@ struct netns_ipv6 { struct hlist_head *fib_table_hash; struct fib6_table *fib6_main_tbl; struct dst_ops *ip6_dst_ops; + unsigned int ip6_rt_gc_expire; + unsigned long ip6_rt_last_gc; #ifdef CONFIG_IPV6_MULTIPLE_TABLES struct rt6_info *ip6_prohibit_entry; struct rt6_info *ip6_blk_hole_entry; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index d88b6ec3c5d1..10a6cc0aca6c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -992,23 +992,22 @@ int icmp6_dst_gc(int *more) static int ip6_dst_gc(struct dst_ops *ops) { - static unsigned expire = 30*HZ; - static unsigned long last_gc; + struct net *net = ops->dst_net; unsigned long now = jiffies; - if (time_after(last_gc + init_net.ipv6.sysctl.ip6_rt_gc_min_interval, now) && - atomic_read(&init_net.ipv6.ip6_dst_ops->entries) <= init_net.ipv6.sysctl.ip6_rt_max_size) + if (time_after(net->ipv6.ip6_rt_last_gc + net->ipv6.sysctl.ip6_rt_gc_min_interval, now) && + atomic_read(&net->ipv6.ip6_dst_ops->entries) <= net->ipv6.sysctl.ip6_rt_max_size) goto out; - expire++; - fib6_run_gc(expire, &init_net); - last_gc = now; - if (atomic_read(&init_net.ipv6.ip6_dst_ops->entries) < init_net.ipv6.ip6_dst_ops->gc_thresh) - expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1; + net->ipv6.ip6_rt_gc_expire++; + fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net); + net->ipv6.ip6_rt_last_gc = now; + if (atomic_read(&net->ipv6.ip6_dst_ops->entries) < net->ipv6.ip6_dst_ops->gc_thresh) + net->ipv6.ip6_rt_gc_expire = net->ipv6.sysctl.ip6_rt_gc_timeout>>1; out: - expire -= expire>>init_net.ipv6.sysctl.ip6_rt_gc_elasticity; - return (atomic_read(&init_net.ipv6.ip6_dst_ops->entries) > init_net.ipv6.sysctl.ip6_rt_max_size); + net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>net->ipv6.sysctl.ip6_rt_gc_elasticity; + return (atomic_read(&net->ipv6.ip6_dst_ops->entries) > net->ipv6.sysctl.ip6_rt_max_size); } /* Clean host part of a prefix. Not necessary in radix tree, @@ -2615,6 +2614,8 @@ static int ip6_route_net_init(struct net *net) proc_net_fops_create(net, "ipv6_route", 0, &ipv6_route_proc_fops); proc_net_fops_create(net, "rt6_stats", S_IRUGO, &rt6_stats_seq_fops); #endif + net->ipv6.ip6_rt_gc_expire = 30*HZ; + ret = 0; out: return ret; -- cgit v1.2.3-59-g8ed1b From 7019b78e1483fa724dcba56e8465376b8fd03ea8 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 4 Mar 2008 13:50:14 -0800 Subject: [NETNS][IPV6] route6 - Make ip6_dst_gc simpler This patches improves the readibility of the ip6_dst_gc() routine. It simplifies long lines which grow a lot due to the introduction of network namespaces support. Signed-off-by: Daniel Lezcano Acked-by: Benjamin Thery Signed-off-by: David S. Miller --- net/ipv6/route.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 10a6cc0aca6c..ec1fedb339cc 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -992,22 +992,26 @@ int icmp6_dst_gc(int *more) static int ip6_dst_gc(struct dst_ops *ops) { - struct net *net = ops->dst_net; unsigned long now = jiffies; - - if (time_after(net->ipv6.ip6_rt_last_gc + net->ipv6.sysctl.ip6_rt_gc_min_interval, now) && - atomic_read(&net->ipv6.ip6_dst_ops->entries) <= net->ipv6.sysctl.ip6_rt_max_size) + struct net *net = ops->dst_net; + int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval; + int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size; + int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity; + int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout; + unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc; + + if (time_after(rt_last_gc + rt_min_interval, now) && + atomic_read(&ops->entries) <= rt_max_size) goto out; net->ipv6.ip6_rt_gc_expire++; fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net); net->ipv6.ip6_rt_last_gc = now; - if (atomic_read(&net->ipv6.ip6_dst_ops->entries) < net->ipv6.ip6_dst_ops->gc_thresh) - net->ipv6.ip6_rt_gc_expire = net->ipv6.sysctl.ip6_rt_gc_timeout>>1; - + if (atomic_read(&ops->entries) < ops->gc_thresh) + net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; out: - net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>net->ipv6.sysctl.ip6_rt_gc_elasticity; - return (atomic_read(&net->ipv6.ip6_dst_ops->entries) > net->ipv6.sysctl.ip6_rt_max_size); + net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity; + return (atomic_read(&ops->entries) > rt_max_size); } /* Clean host part of a prefix. Not necessary in radix tree, -- cgit v1.2.3-59-g8ed1b From 6b3d626321c1d4ce9138a86b047dfafc6a403016 Mon Sep 17 00:00:00 2001 From: Sangtae Ha Date: Tue, 4 Mar 2008 14:17:41 -0800 Subject: [TCP]: TCP cubic v2.2 We have updated CUBIC to fix some issues with slow increase in large BDP networks. We also improved its convergence speed. The fix is in fact very simple -- the window increase limit of smax during the window probing phase (i.e., convex growth phase) is removed. We found that this does not affect TCP friendliness, but only improves its scalability. We have run some tests in our lab and also over the Internet path from NCSU to Japan. These results can be seen from the following page: http://netsrv.csc.ncsu.edu/wiki/index.php/Intra_protocol_fairness_testing_with_linux-2.6.23.9 http://netsrv.csc.ncsu.edu/wiki/index.php/RTT_fairness_testing_with_linux-2.6.23.9 http://netsrv.csc.ncsu.edu/wiki/index.php/TCP_friendliness_testing_with_linux-2.6.23.9 Signed-off-by: Sangtae Ha Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/tcp_cubic.c | 35 ++++++++--------------------------- 1 file changed, 8 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 3aa0b23c1ea0..eb5b9854c8c7 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -1,12 +1,13 @@ /* - * TCP CUBIC: Binary Increase Congestion control for TCP v2.1 - * + * TCP CUBIC: Binary Increase Congestion control for TCP v2.2 + * Home page: + * http://netsrv.csc.ncsu.edu/twiki/bin/view/Main/BIC * This is from the implementation of CUBIC TCP in * Injong Rhee, Lisong Xu. * "CUBIC: A New TCP-Friendly High-Speed TCP Variant * in PFLDnet 2005 * Available from: - * http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/cubic-paper.pdf + * http://netsrv.csc.ncsu.edu/export/cubic-paper.pdf * * Unless CUBIC is enabled and congestion window is large * this behaves the same as the original Reno. @@ -20,15 +21,10 @@ #define BICTCP_BETA_SCALE 1024 /* Scale factor beta calculation * max_cwnd = snd_cwnd * beta */ -#define BICTCP_B 4 /* - * In binary search, - * go to point (max+min)/N - */ #define BICTCP_HZ 10 /* BIC HZ 2^10 = 1024 */ static int fast_convergence __read_mostly = 1; -static int max_increment __read_mostly = 16; -static int beta __read_mostly = 819; /* = 819/1024 (BICTCP_BETA_SCALE) */ +static int beta __read_mostly = 717; /* = 717/1024 (BICTCP_BETA_SCALE) */ static int initial_ssthresh __read_mostly; static int bic_scale __read_mostly = 41; static int tcp_friendliness __read_mostly = 1; @@ -40,9 +36,7 @@ static u64 cube_factor __read_mostly; /* Note parameters that are used for precomputing scale factors are read-only */ module_param(fast_convergence, int, 0644); MODULE_PARM_DESC(fast_convergence, "turn on/off fast convergence"); -module_param(max_increment, int, 0644); -MODULE_PARM_DESC(max_increment, "Limit on increment allowed during binary search"); -module_param(beta, int, 0444); +module_param(beta, int, 0644); MODULE_PARM_DESC(beta, "beta for multiplicative increase"); module_param(initial_ssthresh, int, 0644); MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold"); @@ -145,7 +139,7 @@ static u32 cubic_root(u64 a) static inline void bictcp_update(struct bictcp *ca, u32 cwnd) { u64 offs; - u32 delta, t, bic_target, min_cnt, max_cnt; + u32 delta, t, bic_target, max_cnt; ca->ack_cnt++; /* count the number of ACKs */ @@ -211,19 +205,6 @@ static inline void bictcp_update(struct bictcp *ca, u32 cwnd) ca->cnt = 100 * cwnd; /* very small increment*/ } - if (ca->delay_min > 0) { - /* max increment = Smax * rtt / 0.1 */ - min_cnt = (cwnd * HZ * 8)/(10 * max_increment * ca->delay_min); - - /* use concave growth when the target is above the origin */ - if (ca->cnt < min_cnt && t >= ca->bic_K) - ca->cnt = min_cnt; - } - - /* slow start and low utilization */ - if (ca->loss_cwnd == 0) /* could be aggressive in slow start */ - ca->cnt = 50; - /* TCP Friendly */ if (tcp_friendliness) { u32 scale = beta_scale; @@ -391,4 +372,4 @@ module_exit(cubictcp_unregister); MODULE_AUTHOR("Sangtae Ha, Stephen Hemminger"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("CUBIC TCP"); -MODULE_VERSION("2.1"); +MODULE_VERSION("2.2"); -- cgit v1.2.3-59-g8ed1b From 94911fe31710e355e9fcac8b1a7eb36c4953f36b Mon Sep 17 00:00:00 2001 From: Benjamin Thery Date: Wed, 5 Mar 2008 10:45:36 -0800 Subject: [NETNS][IPV6] Move sysctl initialization later on in the IPv6 init sequence This patch moves initialization of IPv6 sysctl stuff at the end of IPv6 initialization. This will be helpful for network namespaces where some sysctl entries depend on per-namespace variables, that need to be allocated and initialized before they are referenced by sysctl. Signed-off-by: Benjamin Thery Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 60b8a2254046..af5b30787662 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -934,12 +934,6 @@ static int __init inet6_init(void) err = register_pernet_subsys(&inet6_net_ops); if (err) goto register_pernet_fail; - -#ifdef CONFIG_SYSCTL - err = ipv6_sysctl_register(); - if (err) - goto sysctl_fail; -#endif err = icmpv6_init(); if (err) goto icmp_fail; @@ -1006,9 +1000,19 @@ static int __init inet6_init(void) err = ipv6_packet_init(); if (err) goto ipv6_packet_fail; + +#ifdef CONFIG_SYSCTL + err = ipv6_sysctl_register(); + if (err) + goto sysctl_fail; +#endif out: return err; +#ifdef CONFIG_SYSCTL +sysctl_fail: + ipv6_packet_cleanup(); +#endif ipv6_packet_fail: tcpv6_exit(); tcpv6_fail: @@ -1050,10 +1054,6 @@ igmp_fail: ndisc_fail: icmpv6_cleanup(); icmp_fail: -#ifdef CONFIG_SYSCTL - ipv6_sysctl_unregister(); -sysctl_fail: -#endif unregister_pernet_subsys(&inet6_net_ops); register_pernet_fail: cleanup_ipv6_mibs(); @@ -1083,6 +1083,9 @@ static void __exit inet6_exit(void) /* Disallow any further netlink messages */ rtnl_unregister_all(PF_INET6); +#ifdef CONFIG_SYSCTL + ipv6_sysctl_unregister(); +#endif udpv6_exit(); #ifdef CONFIG_IP_UDPLITE udplitev6_exit(); @@ -1112,9 +1115,7 @@ static void __exit inet6_exit(void) ndisc_cleanup(); icmpv6_cleanup(); rawv6_exit(); -#ifdef CONFIG_SYSCTL - ipv6_sysctl_unregister(); -#endif + unregister_pernet_subsys(&inet6_net_ops); cleanup_ipv6_mibs(); proto_unregister(&rawv6_prot); -- cgit v1.2.3-59-g8ed1b From 075de9395760d6d181078f863e676e81c06e1af2 Mon Sep 17 00:00:00 2001 From: Benjamin Thery Date: Wed, 5 Mar 2008 10:45:59 -0800 Subject: [NETNS][IPV6] af_inet6 - allow socket creation per namespace Allow creation of IPv6 raw and datagram sockets in network namespaces other than init_net. Signed-off-by: Benjamin Thery Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv6/af_inet6.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index af5b30787662..430bbd2139c1 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -92,9 +92,6 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol) int try_loading_module = 0; int err; - if (net != &init_net) - return -EAFNOSUPPORT; - if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM && !inet_ehash_secret) @@ -248,6 +245,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct sock *sk = sock->sk; struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); + struct net *net = sk->sk_net; __be32 v4addr = 0; unsigned short snum; int addr_type = 0; @@ -278,7 +276,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) /* Check if the address belongs to the host. */ if (addr_type == IPV6_ADDR_MAPPED) { v4addr = addr->sin6_addr.s6_addr32[3]; - if (inet_addr_type(&init_net, v4addr) != RTN_LOCAL) { + if (inet_addr_type(net, v4addr) != RTN_LOCAL) { err = -EADDRNOTAVAIL; goto out; } @@ -300,7 +298,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) err = -EINVAL; goto out; } - dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if); + dev = dev_get_by_index(net, sk->sk_bound_dev_if); if (!dev) { err = -ENODEV; goto out; @@ -312,7 +310,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) */ v4addr = LOOPBACK4_IPV6; if (!(addr_type & IPV6_ADDR_MULTICAST)) { - if (!ipv6_chk_addr(&init_net, &addr->sin6_addr, + if (!ipv6_chk_addr(net, &addr->sin6_addr, dev, 0)) { if (dev) dev_put(dev); -- cgit v1.2.3-59-g8ed1b From 300bf591deca8d108799e70e9300dc31765643e3 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 5 Mar 2008 10:46:31 -0800 Subject: [NETNS][IPV6] proc - protect snmp6 from non-init_net calls This patchset avoids creation of the /proc entry for snmp6 when the call is made from a network namespace different from the init_net. Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv6/proc.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 5ba7ae849d04..2453f2229ef7 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -220,6 +220,9 @@ int snmp6_register_dev(struct inet6_dev *idev) if (!idev || !idev->dev) return -EINVAL; + if (idev->dev->nd_net != &init_net) + return 0; + if (!proc_net_devsnmp6) return -ENOENT; -- cgit v1.2.3-59-g8ed1b From af2849377e7b70afa1274e475be50286cd0ef6eb Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 5 Mar 2008 10:46:57 -0800 Subject: [NETNS][IPV6] addrconf - Pass the proper network namespace parameters to addrconf This patch propagates the network namespace pointer to the address configuration routines which need it, which means adding a new parameter to these functions, and make them use it instead of using the initial network namespace. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/addrconf.h | 9 ++++--- net/ipv6/addrconf.c | 66 ++++++++++++++++++++++++++++++++++++-------------- net/ipv6/af_inet6.c | 6 ++--- 3 files changed, 57 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 89e3c53c8886..232da20e7171 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -55,9 +55,12 @@ struct prefix_info { extern int addrconf_init(void); extern void addrconf_cleanup(void); -extern int addrconf_add_ifaddr(void __user *arg); -extern int addrconf_del_ifaddr(void __user *arg); -extern int addrconf_set_dstaddr(void __user *arg); +extern int addrconf_add_ifaddr(struct net *net, + void __user *arg); +extern int addrconf_del_ifaddr(struct net *net, + void __user *arg); +extern int addrconf_set_dstaddr(struct net *net, + void __user *arg); extern int ipv6_chk_addr(struct net *net, struct in6_addr *addr, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 17b06d220e95..127021bdd180 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1866,7 +1866,7 @@ ok: * Special case for SIT interfaces where we create a new "virtual" * device. */ -int addrconf_set_dstaddr(void __user *arg) +int addrconf_set_dstaddr(struct net *net, void __user *arg) { struct in6_ifreq ireq; struct net_device *dev; @@ -1878,7 +1878,7 @@ int addrconf_set_dstaddr(void __user *arg) if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) goto err_exit; - dev = __dev_get_by_index(&init_net, ireq.ifr6_ifindex); + dev = __dev_get_by_index(net, ireq.ifr6_ifindex); err = -ENODEV; if (dev == NULL) @@ -1909,7 +1909,8 @@ int addrconf_set_dstaddr(void __user *arg) if (err == 0) { err = -ENOBUFS; - if ((dev = __dev_get_by_name(&init_net, p.name)) == NULL) + dev = __dev_get_by_name(net, p.name); + if (!dev) goto err_exit; err = dev_open(dev); } @@ -1924,8 +1925,9 @@ err_exit: /* * Manual configuration of address on an interface */ -static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, - __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft) +static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, + int plen, __u8 ifa_flags, __u32 prefered_lft, + __u32 valid_lft) { struct inet6_ifaddr *ifp; struct inet6_dev *idev; @@ -1939,7 +1941,8 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, if (!valid_lft || prefered_lft > valid_lft) return -EINVAL; - if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL) + dev = __dev_get_by_index(net, ifindex); + if (!dev) return -ENODEV; if ((idev = addrconf_add_dev(dev)) == NULL) @@ -1984,13 +1987,15 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen, return PTR_ERR(ifp); } -static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen) +static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx, + int plen) { struct inet6_ifaddr *ifp; struct inet6_dev *idev; struct net_device *dev; - if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL) + dev = __dev_get_by_index(net, ifindex); + if (!dev) return -ENODEV; if ((idev = __in6_dev_get(dev)) == NULL) @@ -2018,7 +2023,7 @@ static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen) } -int addrconf_add_ifaddr(void __user *arg) +int addrconf_add_ifaddr(struct net *net, void __user *arg) { struct in6_ifreq ireq; int err; @@ -2030,13 +2035,14 @@ int addrconf_add_ifaddr(void __user *arg) return -EFAULT; rtnl_lock(); - err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen, - IFA_F_PERMANENT, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); + err = inet6_addr_add(net, ireq.ifr6_ifindex, &ireq.ifr6_addr, + ireq.ifr6_prefixlen, IFA_F_PERMANENT, + INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); rtnl_unlock(); return err; } -int addrconf_del_ifaddr(void __user *arg) +int addrconf_del_ifaddr(struct net *net, void __user *arg) { struct in6_ifreq ireq; int err; @@ -2048,7 +2054,8 @@ int addrconf_del_ifaddr(void __user *arg) return -EFAULT; rtnl_lock(); - err = inet6_addr_del(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen); + err = inet6_addr_del(net, ireq.ifr6_ifindex, &ireq.ifr6_addr, + ireq.ifr6_prefixlen); rtnl_unlock(); return err; } @@ -3061,7 +3068,7 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) if (pfx == NULL) return -EINVAL; - return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen); + return inet6_addr_del(net, ifm->ifa_index, pfx, ifm->ifa_prefixlen); } static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, @@ -3137,7 +3144,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) valid_lft = INFINITY_LIFE_TIME; } - dev = __dev_get_by_index(&init_net, ifm->ifa_index); + dev = __dev_get_by_index(net, ifm->ifa_index); if (dev == NULL) return -ENODEV; @@ -3150,8 +3157,9 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) * It would be best to check for !NLM_F_CREATE here but * userspace alreay relies on not having to provide this. */ - return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen, - ifa_flags, preferred_lft, valid_lft); + return inet6_addr_add(net, ifm->ifa_index, pfx, + ifm->ifa_prefixlen, ifa_flags, + preferred_lft, valid_lft); } if (nlh->nlmsg_flags & NLM_F_EXCL || @@ -4260,6 +4268,22 @@ int unregister_inet6addr_notifier(struct notifier_block *nb) EXPORT_SYMBOL(unregister_inet6addr_notifier); + +static int addrconf_net_init(struct net *net) +{ + return 0; +} + +static void addrconf_net_exit(struct net *net) +{ + ; +} + +static struct pernet_operations addrconf_net_ops = { + .init = addrconf_net_init, + .exit = addrconf_net_exit, +}; + /* * Init / cleanup code */ @@ -4301,6 +4325,10 @@ int __init addrconf_init(void) if (err) goto errlo; + err = register_pernet_device(&addrconf_net_ops); + if (err) + return err; + register_netdevice_notifier(&ipv6_dev_notf); addrconf_verify(0); @@ -4334,6 +4362,7 @@ void addrconf_cleanup(void) int i; unregister_netdevice_notifier(&ipv6_dev_notf); + unregister_pernet_device(&addrconf_net_ops); unregister_pernet_subsys(&addrconf_ops); @@ -4370,6 +4399,7 @@ void addrconf_cleanup(void) write_unlock_bh(&addrconf_hash_lock); del_timer(&addr_chk_timer); - rtnl_unlock(); + + unregister_pernet_subsys(&addrconf_net_ops); } diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 430bbd2139c1..afe9276d0420 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -454,11 +454,11 @@ int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) return(ipv6_route_ioctl(net, cmd, (void __user *)arg)); case SIOCSIFADDR: - return addrconf_add_ifaddr((void __user *) arg); + return addrconf_add_ifaddr(net, (void __user *) arg); case SIOCDIFADDR: - return addrconf_del_ifaddr((void __user *) arg); + return addrconf_del_ifaddr(net, (void __user *) arg); case SIOCSIFDSTADDR: - return addrconf_set_dstaddr((void __user *) arg); + return addrconf_set_dstaddr(net, (void __user *) arg); default: if (!sk->sk_prot->ioctl) return -ENOIOCTLCMD; -- cgit v1.2.3-59-g8ed1b From 6fda73500581be531fd9bc232173332ec64f6435 Mon Sep 17 00:00:00 2001 From: Benjamin Thery Date: Wed, 5 Mar 2008 10:47:47 -0800 Subject: [NETNS][IPV6] addrconf - make addrconf per namespace All the infrastructure to propagate the network namespace information is ready. Make use of it. There is a special case here between the initial network namespace and the other namespaces: * When ipv6 is initialized at boot time (aka in the init_net), it registers to the notifier callback. So addrconf_notify will be called as many time as there are network devices setup on the system and the function will add ipv6 addresses to the network devices. But the first device which needs to have its ipv6 address setup is the loopback, unfortunatly this is not the case. So the loopback address is setup manually in the ipv6 init function. * With the network namespace, this ordering problem does not appears because notifier is already setup and active, so as soon as we register the loopback the ipv6 address is setup and it will be the first device. Signed-off-by: Benjamin Thery Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 113 +++++++++++++++++++++++----------------------------- 1 file changed, 50 insertions(+), 63 deletions(-) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 127021bdd180..c878fb681efb 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -561,7 +561,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, write_lock(&addrconf_hash_lock); /* Ignore adding duplicate addresses on an interface */ - if (ipv6_chk_same_addr(&init_net, addr, idev->dev)) { + if (ipv6_chk_same_addr(idev->dev->nd_net, addr, idev->dev)) { ADBG(("ipv6_add_addr: already assigned\n")); err = -EEXIST; goto out; @@ -751,9 +751,9 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) { struct in6_addr prefix; struct rt6_info *rt; - + struct net *net = ifp->idev->dev->nd_net; ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); - rt = rt6_lookup(&init_net, &prefix, NULL, ifp->idev->dev->ifindex, 1); + rt = rt6_lookup(net, &prefix, NULL, ifp->idev->dev->ifindex, 1); if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { if (onlink == 0) { @@ -905,6 +905,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, { struct ipv6_saddr_score hiscore; struct inet6_ifaddr *ifa_result = NULL; + struct net *net = daddr_dev->nd_net; int daddr_type = __ipv6_addr_type(daddr); int daddr_scope = __ipv6_addr_src_scope(daddr_type); int daddr_ifindex = daddr_dev ? daddr_dev->ifindex : 0; @@ -916,7 +917,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, read_lock(&dev_base_lock); rcu_read_lock(); - for_each_netdev(&init_net, dev) { + for_each_netdev(net, dev) { struct inet6_dev *idev; struct inet6_ifaddr *ifa; @@ -1555,7 +1556,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, .fc_expires = expires, .fc_dst_len = plen, .fc_flags = RTF_UP | flags, - .fc_nlinfo.nl_net = &init_net, + .fc_nlinfo.nl_net = dev->nd_net, }; ipv6_addr_copy(&cfg.fc_dst, pfx); @@ -1582,7 +1583,7 @@ static void addrconf_add_mroute(struct net_device *dev) .fc_ifindex = dev->ifindex, .fc_dst_len = 8, .fc_flags = RTF_UP, - .fc_nlinfo.nl_net = &init_net, + .fc_nlinfo.nl_net = dev->nd_net, }; ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0); @@ -1599,7 +1600,7 @@ static void sit_route_add(struct net_device *dev) .fc_ifindex = dev->ifindex, .fc_dst_len = 96, .fc_flags = RTF_UP | RTF_NONEXTHOP, - .fc_nlinfo.nl_net = &init_net, + .fc_nlinfo.nl_net = dev->nd_net, }; /* prefix length - 96 bits "::d.d.d.d" */ @@ -1700,7 +1701,8 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) if (pinfo->onlink) { struct rt6_info *rt; - rt = rt6_lookup(&init_net, &pinfo->prefix, NULL, dev->ifindex, 1); + rt = rt6_lookup(dev->nd_net, &pinfo->prefix, NULL, + dev->ifindex, 1); if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { if (rt->rt6i_flags&RTF_EXPIRES) { @@ -1743,7 +1745,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) ok: - ifp = ipv6_get_ifaddr(&init_net, &addr, dev, 1); + ifp = ipv6_get_ifaddr(dev->nd_net, &addr, dev, 1); if (ifp == NULL && valid_lft) { int max_addresses = in6_dev->cnf.max_addresses; @@ -2066,6 +2068,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) struct inet6_ifaddr * ifp; struct in6_addr addr; struct net_device *dev; + struct net *net = idev->dev->nd_net; int scope; ASSERT_RTNL(); @@ -2092,7 +2095,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) return; } - for_each_netdev(&init_net, dev) { + for_each_netdev(net, dev) { struct in_device * in_dev = __in_dev_get_rtnl(dev); if (in_dev && (dev->flags & IFF_UP)) { struct in_ifaddr * ifa; @@ -2255,15 +2258,16 @@ ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev) static void ip6_tnl_add_linklocal(struct inet6_dev *idev) { struct net_device *link_dev; + struct net *net = idev->dev->nd_net; /* first try to inherit the link-local address from the link device */ if (idev->dev->iflink && - (link_dev = __dev_get_by_index(&init_net, idev->dev->iflink))) { + (link_dev = __dev_get_by_index(net, idev->dev->iflink))) { if (!ipv6_inherit_linklocal(idev, link_dev)) return; } /* then try to inherit it from any device */ - for_each_netdev(&init_net, link_dev) { + for_each_netdev(net, link_dev) { if (!ipv6_inherit_linklocal(idev, link_dev)) return; } @@ -2296,9 +2300,6 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event, int run_pending = 0; int err; - if (dev->nd_net != &init_net) - return NOTIFY_DONE; - switch(event) { case NETDEV_REGISTER: if (!idev && dev->mtu >= IPV6_MIN_MTU) { @@ -3056,9 +3057,6 @@ inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) struct in6_addr *pfx; int err; - if (net != &init_net) - return -EINVAL; - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); if (err < 0) return err; @@ -3121,9 +3119,6 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) u8 ifa_flags; int err; - if (net != &init_net) - return -EINVAL; - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); if (err < 0) return err; @@ -3324,12 +3319,13 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, struct inet6_ifaddr *ifa; struct ifmcaddr6 *ifmca; struct ifacaddr6 *ifaca; + struct net *net = skb->sk->sk_net; s_idx = cb->args[0]; s_ip_idx = ip_idx = cb->args[1]; idx = 0; - for_each_netdev(&init_net, dev) { + for_each_netdev(net, dev) { if (idx < s_idx) goto cont; if (idx > s_idx) @@ -3396,35 +3392,23 @@ cont: static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; enum addr_type_t type = UNICAST_ADDR; - if (net != &init_net) - return 0; - return inet6_dump_addr(skb, cb, type); } static int inet6_dump_ifmcaddr(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; enum addr_type_t type = MULTICAST_ADDR; - if (net != &init_net) - return 0; - return inet6_dump_addr(skb, cb, type); } static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; enum addr_type_t type = ANYCAST_ADDR; - if (net != &init_net) - return 0; - return inet6_dump_addr(skb, cb, type); } @@ -3440,9 +3424,6 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, struct sk_buff *skb; int err; - if (net != &init_net) - return -EINVAL; - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); if (err < 0) goto errout; @@ -3455,7 +3436,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, ifm = nlmsg_data(nlh); if (ifm->ifa_index) - dev = __dev_get_by_index(&init_net, ifm->ifa_index); + dev = __dev_get_by_index(net, ifm->ifa_index); if ((ifa = ipv6_get_ifaddr(net, addr, dev, 1)) == NULL) { err = -EADDRNOTAVAIL; @@ -3475,7 +3456,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, kfree_skb(skb); goto errout_ifa; } - err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid); + err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid); errout_ifa: in6_ifa_put(ifa); errout: @@ -3485,6 +3466,7 @@ errout: static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) { struct sk_buff *skb; + struct net *net = ifa->idev->dev->nd_net; int err = -ENOBUFS; skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC); @@ -3498,10 +3480,10 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) kfree_skb(skb); goto errout; } - err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); + err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); errout: if (err < 0) - rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_IFADDR, err); + rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); } static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, @@ -3666,12 +3648,9 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) struct net_device *dev; struct inet6_dev *idev; - if (net != &init_net) - return 0; - read_lock(&dev_base_lock); idx = 0; - for_each_netdev(&init_net, dev) { + for_each_netdev(net, dev) { if (idx < s_idx) goto cont; if ((idev = in6_dev_get(dev)) == NULL) @@ -3693,6 +3672,7 @@ cont: void inet6_ifinfo_notify(int event, struct inet6_dev *idev) { struct sk_buff *skb; + struct net *net = idev->dev->nd_net; int err = -ENOBUFS; skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC); @@ -3706,10 +3686,10 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev) kfree_skb(skb); goto errout; } - err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); + err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); errout: if (err < 0) - rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_IFADDR, err); + rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); } static inline size_t inet6_prefix_nlmsg_size(void) @@ -3762,6 +3742,7 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, struct prefix_info *pinfo) { struct sk_buff *skb; + struct net *net = idev->dev->nd_net; int err = -ENOBUFS; skb = nlmsg_new(inet6_prefix_nlmsg_size(), GFP_ATOMIC); @@ -3775,10 +3756,10 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, kfree_skb(skb); goto errout; } - err = rtnl_notify(skb, &init_net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); + err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); errout: if (err < 0) - rtnl_set_sk_err(&init_net, RTNLGRP_IPV6_PREFIX, err); + rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err); } static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) @@ -4276,7 +4257,26 @@ static int addrconf_net_init(struct net *net) static void addrconf_net_exit(struct net *net) { - ; + struct net_device *dev; + + /* + * Remove loopback references from default routing entries + */ +/* in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev); */ +/* #ifdef CONFIG_IPV6_MULTIPLE_TABLES */ +/* in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev); */ +/* in6_dev_put(net->ipv6.ip6_blk_hole_entry->rt6i_idev); */ +/* #endif */ + + rtnl_lock(); + /* clean dev list */ + for_each_netdev(net, dev) { + if (__in6_dev_get(dev) == NULL) + continue; + addrconf_ifdown(dev, 1); + } + addrconf_ifdown(net->loopback_dev, 2); + rtnl_unlock(); } static struct pernet_operations addrconf_net_ops = { @@ -4357,7 +4357,6 @@ errlo: void addrconf_cleanup(void) { - struct net_device *dev; struct inet6_ifaddr *ifa; int i; @@ -4368,21 +4367,9 @@ void addrconf_cleanup(void) rtnl_lock(); - /* - * clean dev list. - */ - - for_each_netdev(&init_net, dev) { - if (__in6_dev_get(dev) == NULL) - continue; - addrconf_ifdown(dev, 1); - } - addrconf_ifdown(init_net.loopback_dev, 2); - /* * Check hash table. */ - write_lock_bh(&addrconf_hash_lock); for (i=0; i < IN6_ADDR_HSIZE; i++) { for (ifa=inet6_addr_lst[i]; ifa; ) { -- cgit v1.2.3-59-g8ed1b From 4591db4f37618f37a9f1f25d291c3c7a43a15a21 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 5 Mar 2008 10:48:10 -0800 Subject: [NETNS][IPV6] route6 - add netns parameter to ip6_route_output Add an netns parameter to ip6_route_output. That will allow to access to the right routing table for outgoing traffic. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/ip6_route.h | 3 ++- net/ipv6/icmp.c | 2 +- net/ipv6/ip6_output.c | 4 ++-- net/ipv6/ip6_tunnel.c | 2 +- net/ipv6/ndisc.c | 2 +- net/ipv6/netfilter.c | 4 ++-- net/ipv6/netfilter/ip6t_REJECT.c | 2 +- net/ipv6/route.c | 7 ++++--- net/ipv6/sit.c | 2 +- net/ipv6/xfrm6_policy.c | 2 +- net/sctp/ipv6.c | 2 +- 11 files changed, 17 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index e0caed25bfba..0e2895c8b270 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -43,7 +43,8 @@ extern struct rt6_info *ip6_blk_hole_entry; extern void ip6_route_input(struct sk_buff *skb); -extern struct dst_entry * ip6_route_output(struct sock *sk, +extern struct dst_entry * ip6_route_output(struct net *net, + struct sock *sk, struct flowi *fl); extern int ip6_route_init(void); diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index cff74127ea32..d4c4b50420d8 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -178,7 +178,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type, * XXX: perhaps the expire for routing entries cloned by * this lookup should be more aggressive (not longer than timeout). */ - dst = ip6_route_output(sk, fl); + dst = ip6_route_output(&init_net, sk, fl); if (dst->error) { IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index ff3971173e1e..161afd1142d0 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -913,7 +913,7 @@ static int ip6_dst_lookup_tail(struct sock *sk, int err; if (*dst == NULL) - *dst = ip6_route_output(sk, fl); + *dst = ip6_route_output(&init_net, sk, fl); if ((err = (*dst)->error)) goto out_err_release; @@ -954,7 +954,7 @@ static int ip6_dst_lookup_tail(struct sock *sk, dst_release(*dst); memcpy(&fl_gw, fl, sizeof(struct flowi)); memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr)); - *dst = ip6_route_output(sk, &fl_gw); + *dst = ip6_route_output(&init_net, sk, &fl_gw); if ((err = (*dst)->error)) goto out_err_release; } diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 4e1981660b3c..1e1ad1ed87e6 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -847,7 +847,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, if ((dst = ip6_tnl_dst_check(t)) != NULL) dst_hold(dst); else { - dst = ip6_route_output(NULL, fl); + dst = ip6_route_output(&init_net, NULL, fl); if (dst->error || xfrm_lookup(&dst, fl, NULL, 0) < 0) goto tx_err_link_failure; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index f1c95125100d..b5b4fd173e98 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1427,7 +1427,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, icmpv6_flow_init(ndisc_socket->sk, &fl, NDISC_REDIRECT, &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); - dst = ip6_route_output(NULL, &fl); + dst = ip6_route_output(&init_net, NULL, &fl); if (dst == NULL) return; diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 2e06724dc348..aed51bcc66b4 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -23,7 +23,7 @@ int ip6_route_me_harder(struct sk_buff *skb) .saddr = iph->saddr, } }, }; - dst = ip6_route_output(skb->sk, &fl); + dst = ip6_route_output(&init_net, skb->sk, &fl); #ifdef CONFIG_XFRM if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && @@ -86,7 +86,7 @@ static int nf_ip6_reroute(struct sk_buff *skb, static int nf_ip6_route(struct dst_entry **dst, struct flowi *fl) { - *dst = ip6_route_output(NULL, fl); + *dst = ip6_route_output(&init_net, NULL, fl); return (*dst)->error; } diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index b23baa635fe0..831708aeab37 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -93,7 +93,7 @@ static void send_reset(struct sk_buff *oldskb) fl.fl_ip_sport = otcph.dest; fl.fl_ip_dport = otcph.source; security_skb_classify_flow(oldskb, &fl); - dst = ip6_route_output(NULL, &fl); + dst = ip6_route_output(&init_net, NULL, &fl); if (dst == NULL) return; if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0)) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index ec1fedb339cc..f31d7dc11e72 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -772,7 +772,8 @@ static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table return ip6_pol_route(net, table, fl->oif, fl, flags); } -struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) +struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, + struct flowi *fl) { int flags = 0; @@ -782,7 +783,7 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) if (!ipv6_addr_any(&fl->fl6_src)) flags |= RT6_LOOKUP_F_HAS_SADDR; - return fib6_rule_lookup(&init_net, fl, flags, ip6_pol_route_output); + return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output); } EXPORT_SYMBOL(ip6_route_output); @@ -2260,7 +2261,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void skb_reset_mac_header(skb); skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); - rt = (struct rt6_info*) ip6_route_output(NULL, &fl); + rt = (struct rt6_info*) ip6_route_output(&init_net, NULL, &fl); skb->dst = &rt->u.dst; err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 68720aa63f96..1b8196c8d145 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -393,7 +393,7 @@ isatap_srcok(struct sk_buff *skb, struct iphdr *iph, struct net_device *dev) fl.oif = dev->ifindex; security_skb_classify_flow(skb, &fl); - dst = ip6_route_output(NULL, &fl); + dst = ip6_route_output(&init_net, NULL, &fl); if (!dst->error && (dst->dev == dev) && (neigh = dst->neighbour)) { addr6 = (struct in6_addr*)&neigh->primary_key; diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 6ef56303e69e..e96dafdc7032 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -38,7 +38,7 @@ static struct dst_entry *xfrm6_dst_lookup(int tos, xfrm_address_t *saddr, if (saddr) memcpy(&fl.fl6_src, saddr, sizeof(fl.fl6_src)); - dst = ip6_route_output(NULL, &fl); + dst = ip6_route_output(&init_net, NULL, &fl); err = dst->error; if (dst->error) { diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 3e4878800b36..4862835b0c39 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -257,7 +257,7 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, NIP6(fl.fl6_src)); } - dst = ip6_route_output(NULL, &fl); + dst = ip6_route_output(&init_net, NULL, &fl); if (!dst->error) { struct rt6_info *rt; rt = (struct rt6_info *)dst; -- cgit v1.2.3-59-g8ed1b From c20121ae87955cfc8b51f89072294fc6077f39ad Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 5 Mar 2008 10:48:35 -0800 Subject: [NETNS][IPV6] route6 - pass always a valid socket to ip6_dst_lookup The ip6_dst_lookup receive a socket as parameter. In some part of the code it is called with a NULL socket parameter. We want to rely on the socket to retrieve the network namespace, so we always pass a valid socket in all cases. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- net/ipv6/ip6_output.c | 4 ++-- net/ipv6/tcp_ipv6.c | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 161afd1142d0..937018529d18 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -913,7 +913,7 @@ static int ip6_dst_lookup_tail(struct sock *sk, int err; if (*dst == NULL) - *dst = ip6_route_output(&init_net, sk, fl); + *dst = ip6_route_output(sk->sk_net, sk, fl); if ((err = (*dst)->error)) goto out_err_release; @@ -954,7 +954,7 @@ static int ip6_dst_lookup_tail(struct sock *sk, dst_release(*dst); memcpy(&fl_gw, fl, sizeof(struct flowi)); memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr)); - *dst = ip6_route_output(&init_net, sk, &fl_gw); + *dst = ip6_route_output(sk->sk_net, sk, &fl_gw); if ((err = (*dst)->error)) goto out_err_release; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index fd773ac7531a..aacbb7688bf9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1071,8 +1071,11 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) fl.fl_ip_sport = t1->source; security_skb_classify_flow(skb, &fl); - /* sk = NULL, but it is safe for now. RST socket required. */ - if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { + /* Pass a socket to ip6_dst_lookup either it is for RST + * Underlying function will use this to retrieve the network + * namespace + */ + if (!ip6_dst_lookup(tcp6_socket->sk, &buff->dst, &fl)) { if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0); @@ -1172,7 +1175,7 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, fl.fl_ip_sport = t1->source; security_skb_classify_flow(skb, &fl); - if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) { + if (!ip6_dst_lookup(tcp6_socket->sk, &buff->dst, &fl)) { if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); -- cgit v1.2.3-59-g8ed1b From da6bb5c0c5c22e8289aa555afadfb69487fafbc3 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 5 Mar 2008 10:48:56 -0800 Subject: [NETNS][IPV6] ip6_input - enable ipv6_rcv to handle several network namespace The different subsystem of ipv6 are ready for namespaces, so let's activate it for ipv6_rcv. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- net/ipv6/ip6_input.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 178aebc0427a..7e36269826ba 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -61,11 +61,6 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt u32 pkt_len; struct inet6_dev *idev; - if (dev->nd_net != &init_net) { - kfree_skb(skb); - return 0; - } - if (skb->pkt_type == PACKET_OTHERHOST) { kfree_skb(skb); return 0; -- cgit v1.2.3-59-g8ed1b From 9a43b709a230705ca40a6f854a334a02334a3c1c Mon Sep 17 00:00:00 2001 From: Benjamin Thery Date: Wed, 5 Mar 2008 10:49:18 -0800 Subject: [NETNS][IPV6] icmp6 - make icmpv6_socket per namespace This patch make the changes necessary to support network namespaces in ICMPv6. Signed-off-by: Benjamin Thery Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv6/icmp.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index d4c4b50420d8..6b5391ab8346 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -163,6 +163,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type, struct flowi *fl) { struct dst_entry *dst; + struct net *net = sk->sk_net; int res = 0; /* Informational messages are not limited. */ @@ -178,7 +179,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type, * XXX: perhaps the expire for routing entries cloned by * this lookup should be more aggressive (not longer than timeout). */ - dst = ip6_route_output(&init_net, sk, fl); + dst = ip6_route_output(net, sk, fl); if (dst->error) { IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); @@ -186,7 +187,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type, res = 1; } else { struct rt6_info *rt = (struct rt6_info *)dst; - int tmo = init_net.ipv6.sysctl.icmpv6_time; + int tmo = net->ipv6.sysctl.icmpv6_time; /* Give more bandwidth to wider prefixes. */ if (rt->rt6i_dst.plen < 128) @@ -305,6 +306,7 @@ static inline void mip6_addr_swap(struct sk_buff *skb) {} void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, struct net_device *dev) { + struct net *net = skb->dev->nd_net; struct inet6_dev *idev = NULL; struct ipv6hdr *hdr = ipv6_hdr(skb); struct sock *sk; @@ -334,7 +336,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, */ addr_type = ipv6_addr_type(&hdr->daddr); - if (ipv6_chk_addr(&init_net, &hdr->daddr, skb->dev, 0)) + if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0)) saddr = &hdr->daddr; /* @@ -391,7 +393,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, fl.fl_icmp_code = code; security_skb_classify_flow(skb, &fl); - sk = icmpv6_sk(&init_net); + sk = icmpv6_sk(net); np = inet6_sk(sk); if (icmpv6_xmit_lock(sk)) @@ -507,6 +509,7 @@ EXPORT_SYMBOL(icmpv6_send); static void icmpv6_echo_reply(struct sk_buff *skb) { + struct net *net = skb->dev->nd_net; struct sock *sk; struct inet6_dev *idev; struct ipv6_pinfo *np; @@ -537,7 +540,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) fl.fl_icmp_type = ICMPV6_ECHO_REPLY; security_skb_classify_flow(skb, &fl); - sk = icmpv6_sk(&init_net); + sk = icmpv6_sk(net); np = inet6_sk(sk); if (icmpv6_xmit_lock(sk)) -- cgit v1.2.3-59-g8ed1b From a05c44f6d5fb6cd29da04f96bf5ffaa05f545ac5 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 5 Mar 2008 12:37:29 -0800 Subject: [IPV6]: Remove commented lines. Remove commented lines from netns patchset. Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index c878fb681efb..2ad07c7dc553 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4259,15 +4259,6 @@ static void addrconf_net_exit(struct net *net) { struct net_device *dev; - /* - * Remove loopback references from default routing entries - */ -/* in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev); */ -/* #ifdef CONFIG_IPV6_MULTIPLE_TABLES */ -/* in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev); */ -/* in6_dev_put(net->ipv6.ip6_blk_hole_entry->rt6i_idev); */ -/* #endif */ - rtnl_lock(); /* clean dev list */ for_each_netdev(net, dev) { -- cgit v1.2.3-59-g8ed1b From ee6b967301b4aa5d4a4b61e2f682f086266db9fb Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 5 Mar 2008 18:30:47 -0800 Subject: [IPV4]: Add 'rtable' field in struct sk_buff to alias 'dst' and avoid casts (Anonymous) unions can help us to avoid ugly casts. A common cast it the (struct rtable *)skb->dst one. Defining an union like : union { struct dst_entry *dst; struct rtable *rtable; }; permits to use skb->rtable in place. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/skbuff.h | 5 ++++- include/net/inet_sock.h | 2 +- net/bridge/br_netfilter.c | 14 +++++++------- net/dccp/ipv4.c | 7 +++---- net/ipv4/arp.c | 4 ++-- net/ipv4/icmp.c | 10 +++++----- net/ipv4/igmp.c | 2 +- net/ipv4/ip_forward.c | 2 +- net/ipv4/ip_gre.c | 4 ++-- net/ipv4/ip_input.c | 2 +- net/ipv4/ip_options.c | 16 ++++++++-------- net/ipv4/ip_output.c | 10 +++++----- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/ipip.c | 2 +- net/ipv4/ipmr.c | 6 +++--- net/ipv4/netfilter/ipt_MASQUERADE.c | 2 +- net/ipv4/netfilter/nf_nat_helper.c | 4 ++-- net/ipv4/route.c | 22 +++++++++++----------- net/ipv4/tcp_ipv4.c | 5 ++--- net/ipv4/udp_ipv4.c | 2 +- net/netfilter/nf_conntrack_netbios_ns.c | 2 +- net/sched/em_meta.c | 4 ++-- net/sctp/protocol.c | 8 ++++---- 23 files changed, 69 insertions(+), 68 deletions(-) (limited to 'net') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index bbd8d0027e2f..7beb239d2ee0 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -256,7 +256,10 @@ struct sk_buff { ktime_t tstamp; struct net_device *dev; - struct dst_entry *dst; + union { + struct dst_entry *dst; + struct rtable *rtable; + }; struct sec_path *sp; /* diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 89cd011edb99..8660cb0fa0dd 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -195,7 +195,7 @@ static inline int inet_sk_ehashfn(const struct sock *sk) static inline int inet_iif(const struct sk_buff *skb) { - return ((struct rtable *)skb->dst)->rt_iif; + return skb->rtable->rt_iif; } #endif /* _INET_SOCK_H */ diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 1c0efd8ad9f3..0278a069c6f1 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -223,8 +223,8 @@ static int br_nf_pre_routing_finish_ipv6(struct sk_buff *skb) } nf_bridge->mask ^= BRNF_NF_BRIDGE_PREROUTING; - skb->dst = (struct dst_entry *)&__fake_rtable; - dst_hold(skb->dst); + skb->rtable = &__fake_rtable; + dst_hold(&__fake_rtable.u.dst); skb->dev = nf_bridge->physindev; nf_bridge_push_encap_header(skb); @@ -388,8 +388,8 @@ bridged_dnat: skb->pkt_type = PACKET_HOST; } } else { - skb->dst = (struct dst_entry *)&__fake_rtable; - dst_hold(skb->dst); + skb->rtable = &__fake_rtable; + dst_hold(&__fake_rtable.u.dst); } skb->dev = nf_bridge->physindev; @@ -608,9 +608,9 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff *skb, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - if (skb->dst == (struct dst_entry *)&__fake_rtable) { - dst_release(skb->dst); - skb->dst = NULL; + if (skb->rtable == &__fake_rtable) { + dst_release(&__fake_rtable.u.dst); + skb->rtable = NULL; } return NF_ACCEPT; diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 514a40b7fc7f..17ad69e90e48 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -450,7 +450,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk, struct sk_buff *skb) { struct rtable *rt; - struct flowi fl = { .oif = ((struct rtable *)skb->dst)->rt_iif, + struct flowi fl = { .oif = skb->rtable->rt_iif, .nl_u = { .ip4_u = { .daddr = ip_hdr(skb)->saddr, .saddr = ip_hdr(skb)->daddr, @@ -511,7 +511,7 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) return; - if (((struct rtable *)rxskb->dst)->rt_type != RTN_LOCAL) + if (rxskb->rtable->rt_type != RTN_LOCAL) return; dst = dccp_v4_route_skb(dccp_v4_ctl_socket->sk, rxskb); @@ -563,8 +563,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ - if (((struct rtable *)skb->dst)->rt_flags & - (RTCF_BROADCAST | RTCF_MULTICAST)) + if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) return 0; /* discard, don't send a reset here */ if (dccp_bad_service_code(sk, service)) { diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 69e80bd9774a..efe01df8fc0e 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -475,7 +475,7 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb) return 1; } - paddr = ((struct rtable*)skb->dst)->rt_gateway; + paddr = skb->rtable->rt_gateway; if (arp_set_predefined(inet_addr_type(&init_net, paddr), haddr, paddr, dev)) return 0; @@ -814,7 +814,7 @@ static int arp_process(struct sk_buff *skb) if (arp->ar_op == htons(ARPOP_REQUEST) && ip_route_input(skb, tip, sip, 0, dev) == 0) { - rt = (struct rtable*)skb->dst; + rt = skb->rtable; addr_type = rt->rt_type; if (addr_type == RTN_LOCAL) { diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index cee77d606fbe..ff9a8e643fcc 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -381,7 +381,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) { struct ipcm_cookie ipc; - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; struct net *net = rt->u.dst.dev->nd_net; struct sock *sk = icmp_sk(net); struct inet_sock *inet = inet_sk(sk); @@ -438,7 +438,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) struct iphdr *iph; int room; struct icmp_bxm icmp_param; - struct rtable *rt = (struct rtable *)skb_in->dst; + struct rtable *rt = skb_in->rtable; struct ipcm_cookie ipc; __be32 saddr; u8 tos; @@ -616,7 +616,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) RT_TOS(tos), rt2->u.dst.dev); dst_release(&rt2->u.dst); - rt2 = (struct rtable *)skb_in->dst; + rt2 = skb_in->rtable; skb_in->dst = odst; } @@ -943,7 +943,7 @@ static void icmp_address(struct sk_buff *skb) static void icmp_address_reply(struct sk_buff *skb) { - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; struct net_device *dev = skb->dev; struct in_device *in_dev; struct in_ifaddr *ifa; @@ -988,7 +988,7 @@ static void icmp_discard(struct sk_buff *skb) int icmp_rcv(struct sk_buff *skb) { struct icmphdr *icmph; - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { int nh; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d3f34a772f3b..6a4ee8da6994 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -948,7 +948,7 @@ int igmp_rcv(struct sk_buff *skb) case IGMPV2_HOST_MEMBERSHIP_REPORT: case IGMPV3_HOST_MEMBERSHIP_REPORT: /* Is it our report looped back? */ - if (((struct rtable*)skb->dst)->fl.iif == 0) + if (skb->rtable->fl.iif == 0) break; /* don't rely on MC router hearing unicast reports */ if (skb->pkt_type == PACKET_MULTICAST || diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 0b3b328d82db..9d6d3befd854 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -80,7 +80,7 @@ int ip_forward(struct sk_buff *skb) if (!xfrm4_route_forward(skb)) goto drop; - rt = (struct rtable*)skb->dst; + rt = skb->rtable; if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway) goto sr_failed; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index e7821ba7a9a0..f9ee84420cb3 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -619,7 +619,7 @@ static int ipgre_rcv(struct sk_buff *skb) #ifdef CONFIG_NET_IPGRE_BROADCAST if (ipv4_is_multicast(iph->daddr)) { /* Looped back packet, drop it! */ - if (((struct rtable*)skb->dst)->fl.iif == 0) + if (skb->rtable->fl.iif == 0) goto drop; tunnel->stat.multicast++; skb->pkt_type = PACKET_BROADCAST; @@ -699,7 +699,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } if (skb->protocol == htons(ETH_P_IP)) { - rt = (struct rtable*)skb->dst; + rt = skb->rtable; if ((dst = rt->rt_gateway) == 0) goto tx_error_icmp; } diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 65631391d479..d36e310b314d 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -351,7 +351,7 @@ static int ip_rcv_finish(struct sk_buff *skb) if (iph->ihl > 5 && ip_rcv_options(skb)) goto drop; - rt = (struct rtable*)skb->dst; + rt = skb->rtable; if (rt->rt_type == RTN_MULTICAST) IP_INC_STATS_BH(IPSTATS_MIB_INMCASTPKTS); else if (rt->rt_type == RTN_BROADCAST) diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index baaedd9689a0..df93a9c2efda 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -107,7 +107,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) sptr = skb_network_header(skb); dptr = dopt->__data; - daddr = ((struct rtable*)skb->dst)->rt_spec_dst; + daddr = skb->rtable->rt_spec_dst; if (sopt->rr) { optlen = sptr[sopt->rr+1]; @@ -258,7 +258,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) unsigned char * optptr; int optlen; unsigned char * pp_ptr = NULL; - struct rtable *rt = skb ? (struct rtable*)skb->dst : NULL; + struct rtable *rt = skb ? skb->rtable : NULL; if (!opt) { opt = &(IPCB(skb)->opt); @@ -558,7 +558,7 @@ void ip_forward_options(struct sk_buff *skb) { struct ip_options * opt = &(IPCB(skb)->opt); unsigned char * optptr; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; unsigned char *raw = skb_network_header(skb); if (opt->rr_needaddr) { @@ -606,7 +606,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) __be32 nexthop; struct iphdr *iph = ip_hdr(skb); unsigned char *optptr = skb_network_header(skb) + opt->srr; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; struct rtable *rt2; int err; @@ -631,13 +631,13 @@ int ip_options_rcv_srr(struct sk_buff *skb) } memcpy(&nexthop, &optptr[srrptr-1], 4); - rt = (struct rtable*)skb->dst; - skb->dst = NULL; + rt = skb->rtable; + skb->rtable = NULL; err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev); - rt2 = (struct rtable*)skb->dst; + rt2 = skb->rtable; if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { ip_rt_put(rt2); - skb->dst = &rt->u.dst; + skb->rtable = rt; return -EINVAL; } ip_rt_put(rt); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 341779e685d9..dc494ea594a7 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -142,7 +142,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk, __be32 saddr, __be32 daddr, struct ip_options *opt) { struct inet_sock *inet = inet_sk(sk); - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; struct iphdr *iph; /* Build the IP header. */ @@ -240,7 +240,7 @@ static int ip_finish_output(struct sk_buff *skb) int ip_mc_output(struct sk_buff *skb) { struct sock *sk = skb->sk; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; struct net_device *dev = rt->u.dst.dev; /* @@ -321,7 +321,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) /* Skip all of this if the packet is already routed, * f.e. by something like SCTP. */ - rt = (struct rtable *) skb->dst; + rt = skb->rtable; if (rt != NULL) goto packet_routed; @@ -441,7 +441,7 @@ int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) unsigned int mtu, hlen, left, len, ll_rs, pad; int offset; __be16 not_last_frag; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; int err = 0; dev = rt->u.dst.dev; @@ -1357,7 +1357,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar } replyopts; struct ipcm_cookie ipc; __be32 daddr; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; if (ip_options_echo(&replyopts.opt, skb)) return; diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index de0572c88859..e7c9e4e72327 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -57,7 +57,7 @@ static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) { struct in_pktinfo info; - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; info.ipi_addr.s_addr = ip_hdr(skb)->daddr; if (rt) { diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index dbaed69de06a..894bce96284a 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -528,7 +528,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (!dst) { /* NBMA tunnel */ - if ((rt = (struct rtable*)skb->dst) == NULL) { + if ((rt = skb->rtable) == NULL) { tunnel->stat.tx_fifo_errors++; goto tx_error; } diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index a94f52c207a7..7d63d74ef62a 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1283,7 +1283,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local if (vif_table[vif].dev != skb->dev) { int true_vifi; - if (((struct rtable*)skb->dst)->fl.iif == 0) { + if (skb->rtable->fl.iif == 0) { /* It is our own packet, looped back. Very complicated situation... @@ -1357,7 +1357,7 @@ dont_forward: int ip_mr_input(struct sk_buff *skb) { struct mfc_cache *cache; - int local = ((struct rtable*)skb->dst)->rt_flags&RTCF_LOCAL; + int local = skb->rtable->rt_flags&RTCF_LOCAL; /* Packet is looped back after forward, it should not be forwarded second time, but still can be delivered locally. @@ -1594,7 +1594,7 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait) { int err; struct mfc_cache *cache; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; read_lock(&mrt_lock); cache = ipmr_cache_find(rt->rt_src, rt->rt_dst); diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 313b3fcf387e..c6817b18366a 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -77,7 +77,7 @@ masquerade_tg(struct sk_buff *skb, const struct net_device *in, return NF_ACCEPT; mr = targinfo; - rt = (struct rtable *)skb->dst; + rt = skb->rtable; newsrc = inet_select_addr(out, rt->rt_gateway, RT_SCOPE_UNIVERSE); if (!newsrc) { printk("MASQUERADE: %s ate my IP address\n", out->name); diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index ca57f47bbd25..2fca727aa8ba 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -139,7 +139,7 @@ nf_nat_mangle_tcp_packet(struct sk_buff *skb, const char *rep_buffer, unsigned int rep_len) { - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; struct iphdr *iph; struct tcphdr *tcph; int oldlen, datalen; @@ -217,7 +217,7 @@ nf_nat_mangle_udp_packet(struct sk_buff *skb, const char *rep_buffer, unsigned int rep_len) { - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; struct iphdr *iph; struct udphdr *udph; int datalen, oldlen; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 8c3e165f0034..1051326c36b2 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1289,7 +1289,7 @@ reject_redirect: static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) { - struct rtable *rt = (struct rtable*)dst; + struct rtable *rt = (struct rtable *)dst; struct dst_entry *ret = dst; if (rt) { @@ -1330,7 +1330,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) void ip_rt_send_redirect(struct sk_buff *skb) { - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; struct in_device *in_dev = in_dev_get(rt->u.dst.dev); if (!in_dev) @@ -1379,7 +1379,7 @@ out: static int ip_error(struct sk_buff *skb) { - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; unsigned long now; int code; @@ -1548,7 +1548,7 @@ static void ipv4_link_failure(struct sk_buff *skb) icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); - rt = (struct rtable *) skb->dst; + rt = skb->rtable; if (rt) dst_set_expires(&rt->u.dst, 0); } @@ -1708,7 +1708,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, in_dev_put(in_dev); hash = rt_hash(daddr, saddr, dev->ifindex); - return rt_intern_hash(hash, rth, (struct rtable**) &skb->dst); + return rt_intern_hash(hash, rth, &skb->rtable); e_nobufs: in_dev_put(in_dev); @@ -1869,7 +1869,7 @@ static inline int ip_mkroute_input(struct sk_buff *skb, /* put it into the cache */ hash = rt_hash(daddr, saddr, fl->iif); - return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst); + return rt_intern_hash(hash, rth, &skb->rtable); } /* @@ -2025,7 +2025,7 @@ local_input: } rth->rt_type = res.type; hash = rt_hash(daddr, saddr, fl.iif); - err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst); + err = rt_intern_hash(hash, rth, &skb->rtable); goto done; no_route: @@ -2091,7 +2091,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(in_hit); rcu_read_unlock(); - skb->dst = (struct dst_entry*)rth; + skb->rtable = rth; return 0; } RT_CACHE_STAT_INC(in_hlist_search); @@ -2598,7 +2598,7 @@ int ip_route_output_key(struct net *net, struct rtable **rp, struct flowi *flp) static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait, unsigned int flags) { - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; struct rtmsg *r; struct nlmsghdr *nlh; long expires; @@ -2742,7 +2742,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); local_bh_enable(); - rt = (struct rtable*) skb->dst; + rt = skb->rtable; if (err == 0 && rt->u.dst.error) err = -rt->u.dst.error; } else { @@ -2762,7 +2762,7 @@ static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void if (err) goto errout_free; - skb->dst = &rt->u.dst; + skb->rtable = rt; if (rtm->rtm_flags & RTM_F_NOTIFY) rt->rt_flags |= RTCF_NOTIFY; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 3873c4dbeaeb..a79e324638eb 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -552,7 +552,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) if (th->rst) return; - if (((struct rtable *)skb->dst)->rt_type != RTN_LOCAL) + if (skb->rtable->rt_type != RTN_LOCAL) return; /* Swap the send and the receive. */ @@ -1262,8 +1262,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) #endif /* Never answer to SYNs send to broadcast or multicast */ - if (((struct rtable *)skb->dst)->rt_flags & - (RTCF_BROADCAST | RTCF_MULTICAST)) + if (skb->rtable->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) goto drop; /* TW buckets are converted to open requests without diff --git a/net/ipv4/udp_ipv4.c b/net/ipv4/udp_ipv4.c index 40978de7fb51..fd14c2c50ed4 100644 --- a/net/ipv4/udp_ipv4.c +++ b/net/ipv4/udp_ipv4.c @@ -893,7 +893,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], struct sock *sk; struct udphdr *uh = udp_hdr(skb); unsigned short ulen; - struct rtable *rt = (struct rtable*)skb->dst; + struct rtable *rt = skb->rtable; __be32 saddr = ip_hdr(skb)->saddr; __be32 daddr = ip_hdr(skb)->daddr; diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c index 9810d81e2a06..60dedaded84e 100644 --- a/net/netfilter/nf_conntrack_netbios_ns.c +++ b/net/netfilter/nf_conntrack_netbios_ns.c @@ -47,7 +47,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, { struct nf_conntrack_expect *exp; struct iphdr *iph = ip_hdr(skb); - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; struct in_device *in_dev; __be32 mask = 0; diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index 3da4129b89d1..72cf86e3c090 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -256,10 +256,10 @@ META_COLLECTOR(int_rtclassid) META_COLLECTOR(int_rtiif) { - if (unlikely(skb->dst == NULL)) + if (unlikely(skb->rtable == NULL)) *err = -1; else - dst->value = ((struct rtable*) skb->dst)->fl.iif; + dst->value = skb->rtable->fl.iif; } /************************************************************************** diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 8d9d929f6cea..1afef08f6c1d 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -363,7 +363,7 @@ static int sctp_v4_addr_valid(union sctp_addr *addr, return 0; /* Is this a broadcast address? */ - if (skb && ((struct rtable *)skb->dst)->rt_flags & RTCF_BROADCAST) + if (skb && skb->rtable->rt_flags & RTCF_BROADCAST) return 0; return 1; @@ -539,7 +539,7 @@ static void sctp_v4_get_saddr(struct sctp_association *asoc, /* What interface did this skb arrive on? */ static int sctp_v4_skb_iif(const struct sk_buff *skb) { - return ((struct rtable *)skb->dst)->rt_iif; + return skb->rtable->rt_iif; } /* Was this packet marked by Explicit Congestion Notification? */ @@ -828,8 +828,8 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, " "src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n", __FUNCTION__, skb, skb->len, - NIPQUAD(((struct rtable *)skb->dst)->rt_src), - NIPQUAD(((struct rtable *)skb->dst)->rt_dst)); + NIPQUAD(skb->rtable->rt_src), + NIPQUAD(skb->rtable->rt_dst)); SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS); return ip_queue_xmit(skb, ipfragok); -- cgit v1.2.3-59-g8ed1b From 0dc47877a3de00ceadea0005189656ae8dc52669 Mon Sep 17 00:00:00 2001 From: Harvey Harrison Date: Wed, 5 Mar 2008 20:47:47 -0800 Subject: net: replace remaining __FUNCTION__ occurrences __FUNCTION__ is gcc-specific, use __func__ Signed-off-by: Harvey Harrison Signed-off-by: David S. Miller --- net/8021q/vlan_dev.c | 12 +- net/8021q/vlanproc.c | 2 +- net/9p/error.c | 2 +- net/bridge/br_sysfs_br.c | 6 +- net/core/sock.c | 2 +- net/dccp/dccp.h | 6 +- net/ieee80211/softmac/ieee80211softmac_priv.h | 2 +- net/ipv4/af_inet.c | 2 +- net/ipv4/ipvs/ip_vs_proto_tcp.c | 2 +- net/ipv4/ipvs/ip_vs_proto_udp.c | 2 +- net/ipv4/ipvs/ip_vs_sync.c | 4 +- net/ipv4/netfilter/arp_tables.c | 2 +- net/ipv4/netfilter/ip_tables.c | 2 +- net/ipv4/tcp_input.c | 2 +- net/ipv4/udplite_ipv4.c | 4 +- net/ipv6/addrconf.c | 4 +- net/ipv6/addrlabel.c | 14 +- net/ipv6/ip6_tunnel.c | 2 +- net/ipv6/mip6.c | 20 +-- net/ipv6/ndisc.c | 14 +- net/ipv6/netfilter/ip6_tables.c | 2 +- net/ipv6/netfilter/ip6t_REJECT.c | 2 +- net/ipv6/route.c | 4 +- net/ipv6/tcp_ipv6.c | 8 +- net/irda/af_irda.c | 178 +++++++++++++------------- net/irda/discovery.c | 4 +- net/irda/ircomm/ircomm_core.c | 46 +++---- net/irda/ircomm/ircomm_event.c | 12 +- net/irda/ircomm/ircomm_lmp.c | 30 ++--- net/irda/ircomm/ircomm_param.c | 32 ++--- net/irda/ircomm/ircomm_ttp.c | 26 ++-- net/irda/ircomm/ircomm_tty.c | 90 ++++++------- net/irda/ircomm/ircomm_tty_attach.c | 78 +++++------ net/irda/ircomm/ircomm_tty_ioctl.c | 18 +-- net/irda/irda_device.c | 18 +-- net/irda/iriap.c | 76 +++++------ net/irda/iriap_event.c | 38 +++--- net/irda/irias_object.c | 44 +++---- net/irda/irlan/irlan_client.c | 48 +++---- net/irda/irlan/irlan_client_event.c | 64 ++++----- net/irda/irlan/irlan_common.c | 72 +++++------ net/irda/irlan/irlan_eth.c | 18 +-- net/irda/irlan/irlan_event.c | 4 +- net/irda/irlan/irlan_filter.c | 4 +- net/irda/irlan/irlan_provider.c | 30 ++--- net/irda/irlan/irlan_provider_event.c | 16 +-- net/irda/irlap.c | 56 ++++---- net/irda/irlap_event.c | 122 +++++++++--------- net/irda/irlap_frame.c | 74 +++++------ net/irda/irlmp.c | 112 ++++++++-------- net/irda/irlmp_event.c | 94 +++++++------- net/irda/irlmp_frame.c | 36 +++--- net/irda/irmod.c | 2 +- net/irda/irnet/irnet.h | 10 +- net/irda/irnetlink.c | 4 +- net/irda/irqueue.c | 8 +- net/irda/irttp.c | 108 ++++++++-------- net/irda/parameters.c | 42 +++--- net/irda/qos.c | 24 ++-- net/irda/wrapper.c | 18 +-- net/llc/af_llc.c | 16 +-- net/llc/llc_c_ac.c | 2 +- net/llc/llc_c_ev.c | 8 +- net/llc/llc_conn.c | 24 ++-- net/llc/llc_input.c | 4 +- net/mac80211/ieee80211_iface.c | 2 +- net/rxrpc/ar-internal.h | 8 +- net/sctp/associola.c | 8 +- net/sctp/chunk.c | 2 +- net/sctp/input.c | 2 +- net/sctp/ipv6.c | 8 +- net/sctp/output.c | 14 +- net/sctp/outqueue.c | 14 +- net/sctp/protocol.c | 4 +- net/sctp/sm_sideeffect.c | 6 +- net/sctp/sm_statefuns.c | 10 +- net/sctp/socket.c | 14 +- net/sctp/transport.c | 10 +- net/sunrpc/auth_gss/auth_gss.c | 2 +- net/sunrpc/clnt.c | 44 +++---- net/sunrpc/rpc_pipe.c | 12 +- net/sunrpc/rpcb_clnt.c | 20 +-- net/sunrpc/xprtsock.c | 2 +- net/unix/af_unix.c | 2 +- 84 files changed, 1008 insertions(+), 1008 deletions(-) (limited to 'net') diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 77f04e49a1a0..556b2893b56b 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -171,7 +171,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, skb->dev = __find_vlan_dev(dev, vid); if (!skb->dev) { pr_debug("%s: ERROR: No net_device for VID: %u on dev: %s\n", - __FUNCTION__, (unsigned int)vid, dev->name); + __func__, (unsigned int)vid, dev->name); goto err_unlock; } @@ -187,7 +187,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, ntohs(vhdr->h_vlan_TCI)); pr_debug("%s: priority: %u for TCI: %hu\n", - __FUNCTION__, skb->priority, ntohs(vhdr->h_vlan_TCI)); + __func__, skb->priority, ntohs(vhdr->h_vlan_TCI)); switch (skb->pkt_type) { case PACKET_BROADCAST: /* Yeah, stats collect these together.. */ @@ -268,7 +268,7 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, struct net_device *vdev = dev; pr_debug("%s: skb: %p type: %hx len: %u vlan_id: %hx, daddr: %p\n", - __FUNCTION__, skb, type, len, vlan_dev_info(dev)->vlan_id, + __func__, skb, type, len, vlan_dev_info(dev)->vlan_id, daddr); /* build vlan header only if re_order_header flag is NOT set. This @@ -340,7 +340,7 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, return -ENOMEM; } vlan_dev_info(vdev)->cnt_inc_headroom_on_tx++; - pr_debug("%s: %s: had to grow skb\n", __FUNCTION__, vdev->name); + pr_debug("%s: %s: had to grow skb\n", __func__, vdev->name); } if (build_vlan_header) { @@ -382,7 +382,7 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) vlan_dev_info(dev)->cnt_encap_on_xmit++; pr_debug("%s: proto to encap: 0x%hx\n", - __FUNCTION__, htons(veth->h_vlan_proto)); + __func__, htons(veth->h_vlan_proto)); /* Construct the second two bytes. This field looks something * like: * usr_priority: 3 bits (high bits) @@ -403,7 +403,7 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) } pr_debug("%s: about to send skb: %p to dev: %s\n", - __FUNCTION__, skb, skb->dev->name); + __func__, skb, skb->dev->name); pr_debug(" " MAC_FMT " " MAC_FMT " %4hx %4hx %4hx\n", veth->h_dest[0], veth->h_dest[1], veth->h_dest[2], veth->h_dest[3], veth->h_dest[4], veth->h_dest[5], diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 146cfb0e9882..3b8657a0b837 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -168,7 +168,7 @@ int __init vlan_proc_init(void) return 0; err: - pr_err("%s: can't create entry in proc filesystem!\n", __FUNCTION__); + pr_err("%s: can't create entry in proc filesystem!\n", __func__); vlan_proc_cleanup(); return -ENOBUFS; } diff --git a/net/9p/error.c b/net/9p/error.c index ab2458b6c903..64104b9cb422 100644 --- a/net/9p/error.c +++ b/net/9p/error.c @@ -230,7 +230,7 @@ int p9_errstr2errno(char *errstr, int len) if (errno == 0) { /* TODO: if error isn't found, add it dynamically */ errstr[len] = 0; - printk(KERN_ERR "%s: errstr :%s: not found\n", __FUNCTION__, + printk(KERN_ERR "%s: errstr :%s: not found\n", __func__, errstr); errno = 1; } diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 9cf0538d1717..27d6a511c8c1 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -415,21 +415,21 @@ int br_sysfs_addbr(struct net_device *dev) err = sysfs_create_group(brobj, &bridge_group); if (err) { pr_info("%s: can't create group %s/%s\n", - __FUNCTION__, dev->name, bridge_group.name); + __func__, dev->name, bridge_group.name); goto out1; } err = sysfs_create_bin_file(brobj, &bridge_forward); if (err) { pr_info("%s: can't create attribute file %s/%s\n", - __FUNCTION__, dev->name, bridge_forward.attr.name); + __func__, dev->name, bridge_forward.attr.name); goto out2; } br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, brobj); if (!br->ifobj) { pr_info("%s: can't add kobject (directory) %s/%s\n", - __FUNCTION__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR); + __func__, dev->name, SYSFS_BRIDGE_PORT_SUBDIR); goto out3; } return 0; diff --git a/net/core/sock.c b/net/core/sock.c index 0ca069738021..bb5236aee643 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -981,7 +981,7 @@ void sk_free(struct sock *sk) if (atomic_read(&sk->sk_omem_alloc)) printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n", - __FUNCTION__, atomic_read(&sk->sk_omem_alloc)); + __func__, atomic_read(&sk->sk_omem_alloc)); put_net(sk->sk_net); sk_prot_free(sk->sk_prot_creator, sk); diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 287a62bc2e0f..e1b7c9c6a623 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -23,9 +23,9 @@ * DCCP - specific warning and debugging macros. */ #define DCCP_WARN(fmt, a...) LIMIT_NETDEBUG(KERN_WARNING "%s: " fmt, \ - __FUNCTION__, ##a) + __func__, ##a) #define DCCP_CRIT(fmt, a...) printk(KERN_CRIT fmt " at %s:%d/%s()\n", ##a, \ - __FILE__, __LINE__, __FUNCTION__) + __FILE__, __LINE__, __func__) #define DCCP_BUG(a...) do { DCCP_CRIT("BUG: " a); dump_stack(); } while(0) #define DCCP_BUG_ON(cond) do { if (unlikely((cond) != 0)) \ DCCP_BUG("\"%s\" holds (exception!)", \ @@ -36,7 +36,7 @@ printk(fmt, ##args); \ } while(0) #define DCCP_PR_DEBUG(enable, fmt, a...) DCCP_PRINTK(enable, KERN_DEBUG \ - "%s: " fmt, __FUNCTION__, ##a) + "%s: " fmt, __func__, ##a) #ifdef CONFIG_IP_DCCP_DEBUG extern int dccp_debug; diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h index c43b189634df..f9232c8f6bdc 100644 --- a/net/ieee80211/softmac/ieee80211softmac_priv.h +++ b/net/ieee80211/softmac/ieee80211softmac_priv.h @@ -43,7 +43,7 @@ do { \ if (unlikely(!(expr))) { \ printkl(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", #expr, \ - __FILE__, __LINE__, __FUNCTION__); \ + __FILE__, __LINE__, __func__); \ } \ } while (0) #else diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 67260c0eaaa8..25871c6c7444 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1060,7 +1060,7 @@ static int inet_sk_reselect_saddr(struct sock *sk) if (sysctl_ip_dynaddr > 1) { printk(KERN_INFO "%s(): shifting inet->" "saddr from %d.%d.%d.%d to %d.%d.%d.%d\n", - __FUNCTION__, + __func__, NIPQUAD(old_saddr), NIPQUAD(new_saddr)); } diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c index 12dc0d640b6d..620e40ff79a9 100644 --- a/net/ipv4/ipvs/ip_vs_proto_tcp.c +++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c @@ -550,7 +550,7 @@ tcp_app_conn_bind(struct ip_vs_conn *cp) IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->" "%u.%u.%u.%u:%u to app %s on port %u\n", - __FUNCTION__, + __func__, NIPQUAD(cp->caddr), ntohs(cp->cport), NIPQUAD(cp->vaddr), ntohs(cp->vport), inc->name, ntohs(inc->port)); diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c index 1fa7b330b9ac..1caa2908373f 100644 --- a/net/ipv4/ipvs/ip_vs_proto_udp.c +++ b/net/ipv4/ipvs/ip_vs_proto_udp.c @@ -344,7 +344,7 @@ static int udp_app_conn_bind(struct ip_vs_conn *cp) IP_VS_DBG(9, "%s: Binding conn %u.%u.%u.%u:%u->" "%u.%u.%u.%u:%u to app %s on port %u\n", - __FUNCTION__, + __func__, NIPQUAD(cp->caddr), ntohs(cp->cport), NIPQUAD(cp->vaddr), ntohs(cp->vport), inc->name, ntohs(inc->port)); diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c index 948378d0a755..69c56663cc9a 100644 --- a/net/ipv4/ipvs/ip_vs_sync.c +++ b/net/ipv4/ipvs/ip_vs_sync.c @@ -916,7 +916,7 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid) if (!tinfo) return -ENOMEM; - IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, task_pid_nr(current)); + IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current)); IP_VS_DBG(7, "Each ip_vs_sync_conn entry need %Zd bytes\n", sizeof(struct ip_vs_sync_conn)); @@ -956,7 +956,7 @@ int stop_sync_thread(int state) (state == IP_VS_STATE_BACKUP && !sync_backup_pid)) return -ESRCH; - IP_VS_DBG(7, "%s: pid %d\n", __FUNCTION__, task_pid_nr(current)); + IP_VS_DBG(7, "%s: pid %d\n", __func__, task_pid_nr(current)); IP_VS_INFO("stopping sync thread %d ...\n", (state == IP_VS_STATE_MASTER) ? sync_master_pid : sync_backup_pid); diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 9b5904486184..756bc0e1a7c6 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -52,7 +52,7 @@ MODULE_DESCRIPTION("arptables core"); do { \ if (!(x)) \ printk("ARP_NF_ASSERT: %s:%s:%u\n", \ - __FUNCTION__, __FILE__, __LINE__); \ + __func__, __FILE__, __LINE__); \ } while(0) #else #define ARP_NF_ASSERT(x) diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 600737f122d2..85a75e186b4b 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -53,7 +53,7 @@ MODULE_DESCRIPTION("IPv4 packet filter"); do { \ if (!(x)) \ printk("IP_NF_ASSERT: %s:%s:%u\n", \ - __FUNCTION__, __FILE__, __LINE__); \ + __func__, __FILE__, __LINE__); \ } while(0) #else #define IP_NF_ASSERT(x) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c4679f343675..9cf446427cc2 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3561,7 +3561,7 @@ static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th) * cases we should never reach this piece of code. */ printk(KERN_ERR "%s: Impossible, sk->sk_state=%d\n", - __FUNCTION__, sk->sk_state); + __func__, sk->sk_state); break; } diff --git a/net/ipv4/udplite_ipv4.c b/net/ipv4/udplite_ipv4.c index 001b881ca36f..d49c6d68c8a9 100644 --- a/net/ipv4/udplite_ipv4.c +++ b/net/ipv4/udplite_ipv4.c @@ -106,14 +106,14 @@ void __init udplite4_register(void) #ifdef CONFIG_PROC_FS if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ - printk(KERN_ERR "%s: Cannot register /proc!\n", __FUNCTION__); + printk(KERN_ERR "%s: Cannot register /proc!\n", __func__); #endif return; out_unregister_proto: proto_unregister(&udplite_prot); out_register_err: - printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __FUNCTION__); + printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __func__); } EXPORT_SYMBOL(udplite_hash); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 2ad07c7dc553..4b86d388bf63 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -349,7 +349,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) if (snmp6_alloc_dev(ndev) < 0) { ADBG((KERN_WARNING "%s(): cannot allocate memory for statistics; dev=%s.\n", - __FUNCTION__, dev->name)); + __func__, dev->name)); neigh_parms_release(&nd_tbl, ndev->nd_parms); ndev->dead = 1; in6_dev_finish_destroy(ndev); @@ -359,7 +359,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) if (snmp6_register_dev(ndev) < 0) { ADBG((KERN_WARNING "%s(): cannot create /proc/net/dev_snmp6/%s\n", - __FUNCTION__, dev->name)); + __func__, dev->name)); neigh_parms_release(&nd_tbl, ndev->nd_parms); ndev->dead = 1; in6_dev_finish_destroy(ndev); diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index 3a8b3f52da35..de371b5997fe 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c @@ -166,7 +166,7 @@ u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex) rcu_read_unlock(); ADDRLABEL(KERN_DEBUG "%s(addr=" NIP6_FMT ", type=%d, ifindex=%d) => %08x\n", - __FUNCTION__, + __func__, NIP6(*addr), type, ifindex, label); @@ -182,7 +182,7 @@ static struct ip6addrlbl_entry *ip6addrlbl_alloc(const struct in6_addr *prefix, int addrtype; ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d, label=%u)\n", - __FUNCTION__, + __func__, NIP6(*prefix), prefixlen, ifindex, (unsigned int)label); @@ -226,7 +226,7 @@ static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace) int ret = 0; ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n", - __FUNCTION__, + __func__, newp, replace); if (hlist_empty(&ip6addrlbl_table.head)) { @@ -268,7 +268,7 @@ static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen, int ret = 0; ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d, label=%u, replace=%d)\n", - __FUNCTION__, + __func__, NIP6(*prefix), prefixlen, ifindex, (unsigned int)label, @@ -294,7 +294,7 @@ static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen, int ret = -ESRCH; ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d)\n", - __FUNCTION__, + __func__, NIP6(*prefix), prefixlen, ifindex); @@ -318,7 +318,7 @@ static int ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen, int ret; ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d)\n", - __FUNCTION__, + __func__, NIP6(*prefix), prefixlen, ifindex); @@ -335,7 +335,7 @@ static __init int ip6addrlbl_init(void) int err = 0; int i; - ADDRLABEL(KERN_DEBUG "%s()\n", __FUNCTION__); + ADDRLABEL(KERN_DEBUG "%s()\n", __func__); for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) { int ret = ip6addrlbl_add(ip6addrlbl_init_table[i].prefix, diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 1e1ad1ed87e6..61517fe0c57c 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -60,7 +60,7 @@ MODULE_LICENSE("GPL"); #define IPV6_TLV_TEL_DST_SIZE 8 #ifdef IP6_TNL_DEBUG -#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __FUNCTION__) +#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __func__) #else #define IP6_TNL_TRACE(x...) do {;} while(0) #endif diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index cd8a5bda13cd..42403c626c27 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -304,13 +304,13 @@ static int mip6_destopt_offset(struct xfrm_state *x, struct sk_buff *skb, static int mip6_destopt_init_state(struct xfrm_state *x) { if (x->id.spi) { - printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__, + printk(KERN_INFO "%s: spi is not 0: %u\n", __func__, x->id.spi); return -EINVAL; } if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) { printk(KERN_INFO "%s: state's mode is not %u: %u\n", - __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode); + __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode); return -EINVAL; } @@ -439,13 +439,13 @@ static int mip6_rthdr_offset(struct xfrm_state *x, struct sk_buff *skb, static int mip6_rthdr_init_state(struct xfrm_state *x) { if (x->id.spi) { - printk(KERN_INFO "%s: spi is not 0: %u\n", __FUNCTION__, + printk(KERN_INFO "%s: spi is not 0: %u\n", __func__, x->id.spi); return -EINVAL; } if (x->props.mode != XFRM_MODE_ROUTEOPTIMIZATION) { printk(KERN_INFO "%s: state's mode is not %u: %u\n", - __FUNCTION__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode); + __func__, XFRM_MODE_ROUTEOPTIMIZATION, x->props.mode); return -EINVAL; } @@ -480,15 +480,15 @@ static int __init mip6_init(void) printk(KERN_INFO "Mobile IPv6\n"); if (xfrm_register_type(&mip6_destopt_type, AF_INET6) < 0) { - printk(KERN_INFO "%s: can't add xfrm type(destopt)\n", __FUNCTION__); + printk(KERN_INFO "%s: can't add xfrm type(destopt)\n", __func__); goto mip6_destopt_xfrm_fail; } if (xfrm_register_type(&mip6_rthdr_type, AF_INET6) < 0) { - printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __FUNCTION__); + printk(KERN_INFO "%s: can't add xfrm type(rthdr)\n", __func__); goto mip6_rthdr_xfrm_fail; } if (rawv6_mh_filter_register(mip6_mh_filter) < 0) { - printk(KERN_INFO "%s: can't add rawv6 mh filter\n", __FUNCTION__); + printk(KERN_INFO "%s: can't add rawv6 mh filter\n", __func__); goto mip6_rawv6_mh_fail; } @@ -506,11 +506,11 @@ static int __init mip6_init(void) static void __exit mip6_fini(void) { if (rawv6_mh_filter_unregister(mip6_mh_filter) < 0) - printk(KERN_INFO "%s: can't remove rawv6 mh filter\n", __FUNCTION__); + printk(KERN_INFO "%s: can't remove rawv6 mh filter\n", __func__); if (xfrm_unregister_type(&mip6_rthdr_type, AF_INET6) < 0) - printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __FUNCTION__); + printk(KERN_INFO "%s: can't remove xfrm type(rthdr)\n", __func__); if (xfrm_unregister_type(&mip6_destopt_type, AF_INET6) < 0) - printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __FUNCTION__); + printk(KERN_INFO "%s: can't remove xfrm type(destopt)\n", __func__); } module_init(mip6_init); diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index b5b4fd173e98..e0d023360a88 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -270,7 +270,7 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { ND_PRINTK2(KERN_WARNING "%s(): duplicated ND6 option found: type=%d\n", - __FUNCTION__, + __func__, nd_opt->nd_opt_type); } else { ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; @@ -301,7 +301,7 @@ static struct ndisc_options *ndisc_parse_options(u8 *opt, int opt_len, */ ND_PRINTK2(KERN_NOTICE "%s(): ignored unsupported option; type=%d, len=%d\n", - __FUNCTION__, + __func__, nd_opt->nd_opt_type, nd_opt->nd_opt_len); } } @@ -484,7 +484,7 @@ static void __ndisc_send(struct net_device *dev, if (!skb) { ND_PRINTK0(KERN_ERR "ICMPv6 ND: %s() failed to allocate an skb.\n", - __FUNCTION__); + __func__); dst_release(dst); return; } @@ -647,7 +647,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) ND_PRINTK1(KERN_DEBUG "%s(): trying to ucast probe in NUD_INVALID: " NIP6_FMT "\n", - __FUNCTION__, + __func__, NIP6(*target)); } ndisc_send_ns(dev, neigh, target, target, saddr); @@ -1149,7 +1149,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) if (rt == NULL) { ND_PRINTK0(KERN_ERR "ICMPv6 RA: %s() failed to add default route.\n", - __FUNCTION__); + __func__); in6_dev_put(in6_dev); return; } @@ -1158,7 +1158,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) if (neigh == NULL) { ND_PRINTK0(KERN_ERR "ICMPv6 RA: %s() got default router without neighbour.\n", - __FUNCTION__); + __func__); dst_release(&rt->u.dst); in6_dev_put(in6_dev); return; @@ -1471,7 +1471,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, if (buff == NULL) { ND_PRINTK0(KERN_ERR "ICMPv6 Redirect: %s() failed to allocate an skb.\n", - __FUNCTION__); + __func__); dst_release(dst); return; } diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index bf9bb6e55bb5..af1ec7ba757c 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -55,7 +55,7 @@ MODULE_DESCRIPTION("IPv6 packet filter"); do { \ if (!(x)) \ printk("IP_NF_ASSERT: %s:%s:%u\n", \ - __FUNCTION__, __FILE__, __LINE__); \ + __func__, __FILE__, __LINE__); \ } while(0) #else #define IP_NF_ASSERT(x) diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 831708aeab37..baf829075f6f 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -177,7 +177,7 @@ reject_tg6(struct sk_buff *skb, const struct net_device *in, { const struct ip6t_reject_info *reject = targinfo; - pr_debug("%s: medium point\n", __FUNCTION__); + pr_debug("%s: medium point\n", __func__); /* WARNING: This code causes reentry within ip6tables. This means that the ip6tables jump stack is now crap. We must return an absolute verdict. --RR */ diff --git a/net/ipv6/route.c b/net/ipv6/route.c index f31d7dc11e72..15e9a86f28c8 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -410,7 +410,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) struct net *net; RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n", - __FUNCTION__, fn->leaf, oif); + __func__, fn->leaf, oif); rt0 = fn->rr_ptr; if (!rt0) @@ -431,7 +431,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) } RT6_TRACE("%s() => %p\n", - __FUNCTION__, match); + __func__, match); net = rt0->rt6i_dev->nd_net; return (match ? match : net->ipv6.ip6_null_entry); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index aacbb7688bf9..b47cce8fea44 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -753,7 +753,7 @@ static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, hp = tcp_get_md5sig_pool(); if (!hp) { - printk(KERN_WARNING "%s(): hash pool not found...\n", __FUNCTION__); + printk(KERN_WARNING "%s(): hash pool not found...\n", __func__); goto clear_hash_noput; } bp = &hp->md5_blk.ip6; @@ -793,17 +793,17 @@ static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, /* Now store the hash into the packet */ err = crypto_hash_init(desc); if (err) { - printk(KERN_WARNING "%s(): hash_init failed\n", __FUNCTION__); + printk(KERN_WARNING "%s(): hash_init failed\n", __func__); goto clear_hash; } err = crypto_hash_update(desc, sg, nbytes); if (err) { - printk(KERN_WARNING "%s(): hash_update failed\n", __FUNCTION__); + printk(KERN_WARNING "%s(): hash_update failed\n", __func__); goto clear_hash; } err = crypto_hash_final(desc, md5_hash); if (err) { - printk(KERN_WARNING "%s(): hash_final failed\n", __FUNCTION__); + printk(KERN_WARNING "%s(): hash_final failed\n", __func__); goto clear_hash; } diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 240b0cbfb532..6f21a53cb3e7 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -85,14 +85,14 @@ static int irda_data_indication(void *instance, void *sap, struct sk_buff *skb) struct sock *sk; int err; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); self = instance; sk = instance; err = sock_queue_rcv_skb(sk, skb); if (err) { - IRDA_DEBUG(1, "%s(), error: no more mem!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), error: no more mem!\n", __func__); self->rx_flow = FLOW_STOP; /* When we return error, TTP will need to requeue the skb */ @@ -116,7 +116,7 @@ static void irda_disconnect_indication(void *instance, void *sap, self = instance; - IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); + IRDA_DEBUG(2, "%s(%p)\n", __func__, self); /* Don't care about it, but let's not leak it */ if(skb) @@ -125,7 +125,7 @@ static void irda_disconnect_indication(void *instance, void *sap, sk = instance; if (sk == NULL) { IRDA_DEBUG(0, "%s(%p) : BUG : sk is NULL\n", - __FUNCTION__, self); + __func__, self); return; } @@ -181,7 +181,7 @@ static void irda_connect_confirm(void *instance, void *sap, self = instance; - IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); + IRDA_DEBUG(2, "%s(%p)\n", __func__, self); sk = instance; if (sk == NULL) { @@ -203,7 +203,7 @@ static void irda_connect_confirm(void *instance, void *sap, case SOCK_STREAM: if (max_sdu_size != 0) { IRDA_ERROR("%s: max_sdu_size must be 0\n", - __FUNCTION__); + __func__); return; } self->max_data_size = irttp_get_max_seg_size(self->tsap); @@ -211,7 +211,7 @@ static void irda_connect_confirm(void *instance, void *sap, case SOCK_SEQPACKET: if (max_sdu_size == 0) { IRDA_ERROR("%s: max_sdu_size cannot be 0\n", - __FUNCTION__); + __func__); return; } self->max_data_size = max_sdu_size; @@ -220,7 +220,7 @@ static void irda_connect_confirm(void *instance, void *sap, self->max_data_size = irttp_get_max_seg_size(self->tsap); } - IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __func__, self->max_data_size); memcpy(&self->qos_tx, qos, sizeof(struct qos_info)); @@ -245,7 +245,7 @@ static void irda_connect_indication(void *instance, void *sap, self = instance; - IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); + IRDA_DEBUG(2, "%s(%p)\n", __func__, self); sk = instance; if (sk == NULL) { @@ -264,7 +264,7 @@ static void irda_connect_indication(void *instance, void *sap, case SOCK_STREAM: if (max_sdu_size != 0) { IRDA_ERROR("%s: max_sdu_size must be 0\n", - __FUNCTION__); + __func__); kfree_skb(skb); return; } @@ -273,7 +273,7 @@ static void irda_connect_indication(void *instance, void *sap, case SOCK_SEQPACKET: if (max_sdu_size == 0) { IRDA_ERROR("%s: max_sdu_size cannot be 0\n", - __FUNCTION__); + __func__); kfree_skb(skb); return; } @@ -283,7 +283,7 @@ static void irda_connect_indication(void *instance, void *sap, self->max_data_size = irttp_get_max_seg_size(self->tsap); } - IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), max_data_size=%d\n", __func__, self->max_data_size); memcpy(&self->qos_tx, qos, sizeof(struct qos_info)); @@ -302,13 +302,13 @@ static void irda_connect_response(struct irda_sock *self) { struct sk_buff *skb; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER, GFP_ATOMIC); if (skb == NULL) { IRDA_DEBUG(0, "%s() Unable to allocate sk_buff!\n", - __FUNCTION__); + __func__); return; } @@ -329,7 +329,7 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) struct irda_sock *self; struct sock *sk; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); self = instance; sk = instance; @@ -338,17 +338,17 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) switch (flow) { case FLOW_STOP: IRDA_DEBUG(1, "%s(), IrTTP wants us to slow down\n", - __FUNCTION__); + __func__); self->tx_flow = flow; break; case FLOW_START: self->tx_flow = flow; IRDA_DEBUG(1, "%s(), IrTTP wants us to start again\n", - __FUNCTION__); + __func__); wake_up_interruptible(sk->sk_sleep); break; default: - IRDA_DEBUG(0, "%s(), Unknown flow command!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Unknown flow command!\n", __func__); /* Unknown flow command, better stop */ self->tx_flow = flow; break; @@ -370,11 +370,11 @@ static void irda_getvalue_confirm(int result, __u16 obj_id, self = (struct irda_sock *) priv; if (!self) { - IRDA_WARNING("%s: lost myself!\n", __FUNCTION__); + IRDA_WARNING("%s: lost myself!\n", __func__); return; } - IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); + IRDA_DEBUG(2, "%s(%p)\n", __func__, self); /* We probably don't need to make any more queries */ iriap_close(self->iriap); @@ -382,7 +382,7 @@ static void irda_getvalue_confirm(int result, __u16 obj_id, /* Check if request succeeded */ if (result != IAS_SUCCESS) { - IRDA_DEBUG(1, "%s(), IAS query failed! (%d)\n", __FUNCTION__, + IRDA_DEBUG(1, "%s(), IAS query failed! (%d)\n", __func__, result); self->errno = result; /* We really need it later */ @@ -415,11 +415,11 @@ static void irda_selective_discovery_indication(discinfo_t *discovery, { struct irda_sock *self; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); self = (struct irda_sock *) priv; if (!self) { - IRDA_WARNING("%s: lost myself!\n", __FUNCTION__); + IRDA_WARNING("%s: lost myself!\n", __func__); return; } @@ -442,7 +442,7 @@ static void irda_discovery_timeout(u_long priv) { struct irda_sock *self; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); self = (struct irda_sock *) priv; BUG_ON(self == NULL); @@ -467,7 +467,7 @@ static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name) notify_t notify; if (self->tsap) { - IRDA_WARNING("%s: busy!\n", __FUNCTION__); + IRDA_WARNING("%s: busy!\n", __func__); return -EBUSY; } @@ -486,7 +486,7 @@ static int irda_open_tsap(struct irda_sock *self, __u8 tsap_sel, char *name) ¬ify); if (self->tsap == NULL) { IRDA_DEBUG(0, "%s(), Unable to allocate TSAP!\n", - __FUNCTION__); + __func__); return -ENOMEM; } /* Remember which TSAP selector we actually got */ @@ -507,7 +507,7 @@ static int irda_open_lsap(struct irda_sock *self, int pid) notify_t notify; if (self->lsap) { - IRDA_WARNING("%s(), busy!\n", __FUNCTION__); + IRDA_WARNING("%s(), busy!\n", __func__); return -EBUSY; } @@ -519,7 +519,7 @@ static int irda_open_lsap(struct irda_sock *self, int pid) self->lsap = irlmp_open_lsap(LSAP_CONNLESS, ¬ify, pid); if (self->lsap == NULL) { - IRDA_DEBUG( 0, "%s(), Unable to allocate LSAP!\n", __FUNCTION__); + IRDA_DEBUG( 0, "%s(), Unable to allocate LSAP!\n", __func__); return -ENOMEM; } @@ -540,11 +540,11 @@ static int irda_open_lsap(struct irda_sock *self, int pid) */ static int irda_find_lsap_sel(struct irda_sock *self, char *name) { - IRDA_DEBUG(2, "%s(%p, %s)\n", __FUNCTION__, self, name); + IRDA_DEBUG(2, "%s(%p, %s)\n", __func__, self, name); if (self->iriap) { IRDA_WARNING("%s(): busy with a previous query\n", - __FUNCTION__); + __func__); return -EBUSY; } @@ -580,7 +580,7 @@ static int irda_find_lsap_sel(struct irda_sock *self, char *name) switch (self->ias_result->type) { case IAS_INTEGER: IRDA_DEBUG(4, "%s() int=%d\n", - __FUNCTION__, self->ias_result->t.integer); + __func__, self->ias_result->t.integer); if (self->ias_result->t.integer != -1) self->dtsap_sel = self->ias_result->t.integer; @@ -589,7 +589,7 @@ static int irda_find_lsap_sel(struct irda_sock *self, char *name) break; default: self->dtsap_sel = 0; - IRDA_DEBUG(0, "%s(), bad type!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), bad type!\n", __func__); break; } if (self->ias_result) @@ -627,7 +627,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name) __u32 daddr = DEV_ADDR_ANY; /* Address we found the service on */ __u8 dtsap_sel = 0x0; /* TSAP associated with it */ - IRDA_DEBUG(2, "%s(), name=%s\n", __FUNCTION__, name); + IRDA_DEBUG(2, "%s(), name=%s\n", __func__, name); /* Ask lmp for the current discovery log * Note : we have to use irlmp_get_discoveries(), as opposed @@ -649,7 +649,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name) self->daddr = discoveries[i].daddr; self->saddr = 0x0; IRDA_DEBUG(1, "%s(), trying daddr = %08x\n", - __FUNCTION__, self->daddr); + __func__, self->daddr); /* Query remote LM-IAS for this service */ err = irda_find_lsap_sel(self, name); @@ -658,7 +658,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name) /* We found the requested service */ if(daddr != DEV_ADDR_ANY) { IRDA_DEBUG(1, "%s(), discovered service ''%s'' in two different devices !!!\n", - __FUNCTION__, name); + __func__, name); self->daddr = DEV_ADDR_ANY; kfree(discoveries); return(-ENOTUNIQ); @@ -672,7 +672,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name) break; default: /* Something bad did happen :-( */ - IRDA_DEBUG(0, "%s(), unexpected IAS query failure\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), unexpected IAS query failure\n", __func__); self->daddr = DEV_ADDR_ANY; kfree(discoveries); return(-EHOSTUNREACH); @@ -685,7 +685,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name) /* Check out what we found */ if(daddr == DEV_ADDR_ANY) { IRDA_DEBUG(1, "%s(), cannot discover service ''%s'' in any device !!!\n", - __FUNCTION__, name); + __func__, name); self->daddr = DEV_ADDR_ANY; return(-EADDRNOTAVAIL); } @@ -696,7 +696,7 @@ static int irda_discover_daddr_and_lsap_sel(struct irda_sock *self, char *name) self->dtsap_sel = dtsap_sel; IRDA_DEBUG(1, "%s(), discovered requested service ''%s'' at address %08x\n", - __FUNCTION__, name, self->daddr); + __func__, name, self->daddr); return 0; } @@ -727,8 +727,8 @@ static int irda_getname(struct socket *sock, struct sockaddr *uaddr, saddr.sir_addr = self->saddr; } - IRDA_DEBUG(1, "%s(), tsap_sel = %#x\n", __FUNCTION__, saddr.sir_lsap_sel); - IRDA_DEBUG(1, "%s(), addr = %08x\n", __FUNCTION__, saddr.sir_addr); + IRDA_DEBUG(1, "%s(), tsap_sel = %#x\n", __func__, saddr.sir_lsap_sel); + IRDA_DEBUG(1, "%s(), addr = %08x\n", __func__, saddr.sir_addr); /* uaddr_len come to us uninitialised */ *uaddr_len = sizeof (struct sockaddr_irda); @@ -747,7 +747,7 @@ static int irda_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) && (sk->sk_type != SOCK_DGRAM)) @@ -776,7 +776,7 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct irda_sock *self = irda_sk(sk); int err; - IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); + IRDA_DEBUG(2, "%s(%p)\n", __func__, self); if (addr_len != sizeof(struct sockaddr_irda)) return -EINVAL; @@ -787,7 +787,7 @@ static int irda_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) (sk->sk_protocol == IRDAPROTO_ULTRA)) { self->pid = addr->sir_lsap_sel; if (self->pid & 0x80) { - IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __func__); return -EOPNOTSUPP; } err = irda_open_lsap(self, self->pid); @@ -835,7 +835,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) struct sk_buff *skb; int err; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); err = irda_create(sk->sk_net, newsock, sk->sk_protocol); if (err) @@ -893,7 +893,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) /* Now attach up the new socket */ new->tsap = irttp_dup(self->tsap, new); if (!new->tsap) { - IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), dup failed!\n", __func__); kfree_skb(skb); return -1; } @@ -954,7 +954,7 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr, struct irda_sock *self = irda_sk(sk); int err; - IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); + IRDA_DEBUG(2, "%s(%p)\n", __func__, self); /* Don't allow connect for Ultra sockets */ if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA)) @@ -984,13 +984,13 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr, /* Try to find one suitable */ err = irda_discover_daddr_and_lsap_sel(self, addr->sir_name); if (err) { - IRDA_DEBUG(0, "%s(), auto-connect failed!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), auto-connect failed!\n", __func__); return err; } } else { /* Use the one provided by the user */ self->daddr = addr->sir_addr; - IRDA_DEBUG(1, "%s(), daddr = %08x\n", __FUNCTION__, self->daddr); + IRDA_DEBUG(1, "%s(), daddr = %08x\n", __func__, self->daddr); /* If we don't have a valid service name, we assume the * user want to connect on a specific LSAP. Prevent @@ -1000,7 +1000,7 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr, /* Query remote LM-IAS using service name */ err = irda_find_lsap_sel(self, addr->sir_name); if (err) { - IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), connect failed!\n", __func__); return err; } } else { @@ -1025,7 +1025,7 @@ static int irda_connect(struct socket *sock, struct sockaddr *uaddr, self->saddr, self->daddr, NULL, self->max_sdu_size_rx, NULL); if (err) { - IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), connect failed!\n", __func__); return err; } @@ -1068,7 +1068,7 @@ static int irda_create(struct net *net, struct socket *sock, int protocol) struct sock *sk; struct irda_sock *self; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); if (net != &init_net) return -EAFNOSUPPORT; @@ -1089,7 +1089,7 @@ static int irda_create(struct net *net, struct socket *sock, int protocol) return -ENOMEM; self = irda_sk(sk); - IRDA_DEBUG(2, "%s() : self is %p\n", __FUNCTION__, self); + IRDA_DEBUG(2, "%s() : self is %p\n", __func__, self); init_waitqueue_head(&self->query_wait); @@ -1149,7 +1149,7 @@ static int irda_create(struct net *net, struct socket *sock, int protocol) */ static void irda_destroy_socket(struct irda_sock *self) { - IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); + IRDA_DEBUG(2, "%s(%p)\n", __func__, self); /* Unregister with IrLMP */ irlmp_unregister_client(self->ckey); @@ -1186,7 +1186,7 @@ static int irda_release(struct socket *sock) { struct sock *sk = sock->sk; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); if (sk == NULL) return 0; @@ -1254,7 +1254,7 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb; int err = -EPIPE; - IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len); + IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len); /* Note : socket.c set MSG_EOR on SEQPACKET sockets */ if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR | MSG_CMSG_COMPAT | @@ -1282,7 +1282,7 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock, /* Check that we don't send out too big frames */ if (len > self->max_data_size) { IRDA_DEBUG(2, "%s(), Chopping frame from %zd to %d bytes!\n", - __FUNCTION__, len, self->max_data_size); + __func__, len, self->max_data_size); len = self->max_data_size; } @@ -1306,7 +1306,7 @@ static int irda_sendmsg(struct kiocb *iocb, struct socket *sock, */ err = irttp_data_request(self->tsap, skb); if (err) { - IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err); + IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err); goto out_err; } /* Tell client how much data we actually sent */ @@ -1332,7 +1332,7 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock, size_t copied; int err; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); if ((err = sock_error(sk)) < 0) return err; @@ -1347,7 +1347,7 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock, if (copied > size) { IRDA_DEBUG(2, "%s(), Received truncated frame (%zd < %zd)!\n", - __FUNCTION__, copied, size); + __func__, copied, size); copied = size; msg->msg_flags |= MSG_TRUNC; } @@ -1363,7 +1363,7 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock, */ if (self->rx_flow == FLOW_STOP) { if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) { - IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __func__); self->rx_flow = FLOW_START; irttp_flow_request(self->tsap, FLOW_START); } @@ -1385,7 +1385,7 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock, int target, err; long timeo; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); if ((err = sock_error(sk)) < 0) return err; @@ -1459,14 +1459,14 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock, /* put the skb back if we didn't use it up.. */ if (skb->len) { IRDA_DEBUG(1, "%s(), back on q!\n", - __FUNCTION__); + __func__); skb_queue_head(&sk->sk_receive_queue, skb); break; } kfree_skb(skb); } else { - IRDA_DEBUG(0, "%s() questionable!?\n", __FUNCTION__); + IRDA_DEBUG(0, "%s() questionable!?\n", __func__); /* put message back and return */ skb_queue_head(&sk->sk_receive_queue, skb); @@ -1482,7 +1482,7 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock, */ if (self->rx_flow == FLOW_STOP) { if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) { - IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __func__); self->rx_flow = FLOW_START; irttp_flow_request(self->tsap, FLOW_START); } @@ -1506,7 +1506,7 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb; int err; - IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len); + IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len); if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) return -EINVAL; @@ -1528,7 +1528,7 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock, if (len > self->max_data_size) { IRDA_DEBUG(0, "%s(), Warning to much data! " "Chopping frame from %zd to %d bytes!\n", - __FUNCTION__, len, self->max_data_size); + __func__, len, self->max_data_size); len = self->max_data_size; } @@ -1540,7 +1540,7 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock, skb_reserve(skb, self->max_header_size); skb_reset_transport_header(skb); - IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), appending user data\n", __func__); skb_put(skb, len); err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len); if (err) { @@ -1554,7 +1554,7 @@ static int irda_sendmsg_dgram(struct kiocb *iocb, struct socket *sock, */ err = irttp_udata_request(self->tsap, skb); if (err) { - IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err); + IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err); return err; } return len; @@ -1577,7 +1577,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, struct sk_buff *skb; int err; - IRDA_DEBUG(4, "%s(), len=%zd\n", __FUNCTION__, len); + IRDA_DEBUG(4, "%s(), len=%zd\n", __func__, len); if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_CMSG_COMPAT)) return -EINVAL; @@ -1600,7 +1600,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, pid = addr->sir_lsap_sel; if (pid & 0x80) { - IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __func__); return -EOPNOTSUPP; } } else { @@ -1609,7 +1609,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, if ((self->lsap == NULL) || (sk->sk_state != TCP_ESTABLISHED)) { IRDA_DEBUG(0, "%s(), socket not bound to Ultra PID.\n", - __FUNCTION__); + __func__); return -ENOTCONN; } /* Use PID from socket */ @@ -1623,7 +1623,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, if (len > self->max_data_size) { IRDA_DEBUG(0, "%s(), Warning to much data! " "Chopping frame from %zd to %d bytes!\n", - __FUNCTION__, len, self->max_data_size); + __func__, len, self->max_data_size); len = self->max_data_size; } @@ -1635,7 +1635,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, skb_reserve(skb, self->max_header_size); skb_reset_transport_header(skb); - IRDA_DEBUG(4, "%s(), appending user data\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), appending user data\n", __func__); skb_put(skb, len); err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len); if (err) { @@ -1646,7 +1646,7 @@ static int irda_sendmsg_ultra(struct kiocb *iocb, struct socket *sock, err = irlmp_connless_data_request((bound ? self->lsap : NULL), skb, pid); if (err) { - IRDA_DEBUG(0, "%s(), err=%d\n", __FUNCTION__, err); + IRDA_DEBUG(0, "%s(), err=%d\n", __func__, err); return err; } return len; @@ -1661,7 +1661,7 @@ static int irda_shutdown(struct socket *sock, int how) struct sock *sk = sock->sk; struct irda_sock *self = irda_sk(sk); - IRDA_DEBUG(1, "%s(%p)\n", __FUNCTION__, self); + IRDA_DEBUG(1, "%s(%p)\n", __func__, self); sk->sk_state = TCP_CLOSE; sk->sk_shutdown |= SEND_SHUTDOWN; @@ -1696,7 +1696,7 @@ static unsigned int irda_poll(struct file * file, struct socket *sock, struct irda_sock *self = irda_sk(sk); unsigned int mask; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); poll_wait(file, sk->sk_sleep, wait); mask = 0; @@ -1705,7 +1705,7 @@ static unsigned int irda_poll(struct file * file, struct socket *sock, if (sk->sk_err) mask |= POLLERR; if (sk->sk_shutdown & RCV_SHUTDOWN) { - IRDA_DEBUG(0, "%s(), POLLHUP\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), POLLHUP\n", __func__); mask |= POLLHUP; } @@ -1719,7 +1719,7 @@ static unsigned int irda_poll(struct file * file, struct socket *sock, switch (sk->sk_type) { case SOCK_STREAM: if (sk->sk_state == TCP_CLOSE) { - IRDA_DEBUG(0, "%s(), POLLHUP\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), POLLHUP\n", __func__); mask |= POLLHUP; } @@ -1755,7 +1755,7 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; - IRDA_DEBUG(4, "%s(), cmd=%#x\n", __FUNCTION__, cmd); + IRDA_DEBUG(4, "%s(), cmd=%#x\n", __func__, cmd); switch (cmd) { case TIOCOUTQ: { @@ -1796,7 +1796,7 @@ static int irda_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) case SIOCSIFMETRIC: return -EINVAL; default: - IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), doing device ioctl!\n", __func__); return -ENOIOCTLCMD; } @@ -1833,7 +1833,7 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, struct ias_attrib * ias_attr; /* Attribute in IAS object */ int opt, free_ias = 0; - IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); + IRDA_DEBUG(2, "%s(%p)\n", __func__, self); if (level != SOL_IRLMP) return -ENOPROTOOPT; @@ -2012,7 +2012,7 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, /* Check is the user space own the object */ if(ias_attr->value->owner != IAS_USER_ATTR) { - IRDA_DEBUG(1, "%s(), attempting to delete a kernel attribute\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), attempting to delete a kernel attribute\n", __func__); kfree(ias_opt); return -EPERM; } @@ -2031,11 +2031,11 @@ static int irda_setsockopt(struct socket *sock, int level, int optname, /* Only possible for a seqpacket service (TTP with SAR) */ if (sk->sk_type != SOCK_SEQPACKET) { IRDA_DEBUG(2, "%s(), setting max_sdu_size = %d\n", - __FUNCTION__, opt); + __func__, opt); self->max_sdu_size_rx = opt; } else { IRDA_WARNING("%s: not allowed to set MAXSDUSIZE for this socket type!\n", - __FUNCTION__); + __func__); return -ENOPROTOOPT; } break; @@ -2149,7 +2149,7 @@ static int irda_getsockopt(struct socket *sock, int level, int optname, int err; int offset, total; - IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); + IRDA_DEBUG(2, "%s(%p)\n", __func__, self); if (level != SOL_IRLMP) return -ENOPROTOOPT; @@ -2310,7 +2310,7 @@ bed: /* Check that we can proceed with IAP */ if (self->iriap) { IRDA_WARNING("%s: busy with a previous query\n", - __FUNCTION__); + __func__); kfree(ias_opt); return -EBUSY; } @@ -2406,7 +2406,7 @@ bed: if (!self->cachedaddr) { int ret = 0; - IRDA_DEBUG(1, "%s(), nothing discovered yet, going to sleep...\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), nothing discovered yet, going to sleep...\n", __func__); /* Set watchdog timer to expire in ms. */ self->errno = 0; @@ -2424,14 +2424,14 @@ bed: if(timer_pending(&(self->watchdog))) del_timer(&(self->watchdog)); - IRDA_DEBUG(1, "%s(), ...waking up !\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), ...waking up !\n", __func__); if (ret != 0) return ret; } else IRDA_DEBUG(1, "%s(), found immediately !\n", - __FUNCTION__); + __func__); /* Tell IrLMP that we have been notified */ irlmp_update_client(self->ckey, self->mask.word, diff --git a/net/irda/discovery.c b/net/irda/discovery.c index 80c33f408e3f..bfacef8b76f4 100644 --- a/net/irda/discovery.c +++ b/net/irda/discovery.c @@ -110,7 +110,7 @@ void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log) { discovery_t *discovery; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); /* * If log is missing this means that IrLAP was unable to perform the @@ -157,7 +157,7 @@ void irlmp_expire_discoveries(hashbin_t *log, __u32 saddr, int force) int i = 0; /* How many we expired */ IRDA_ASSERT(log != NULL, return;); - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); spin_lock_irqsave(&log->hb_spinlock, flags); diff --git a/net/irda/ircomm/ircomm_core.c b/net/irda/ircomm/ircomm_core.c index 6eef1f2a7553..018c92941aba 100644 --- a/net/irda/ircomm/ircomm_core.c +++ b/net/irda/ircomm/ircomm_core.c @@ -70,7 +70,7 @@ static int __init ircomm_init(void) { ircomm = hashbin_new(HB_LOCK); if (ircomm == NULL) { - IRDA_ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__); + IRDA_ERROR("%s(), can't allocate hashbin!\n", __func__); return -ENOMEM; } @@ -91,7 +91,7 @@ static int __init ircomm_init(void) static void __exit ircomm_cleanup(void) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); hashbin_delete(ircomm, (FREE_FUNC) __ircomm_close); @@ -111,7 +111,7 @@ struct ircomm_cb *ircomm_open(notify_t *notify, __u8 service_type, int line) struct ircomm_cb *self = NULL; int ret; - IRDA_DEBUG(2, "%s(), service_type=0x%02x\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s(), service_type=0x%02x\n", __func__ , service_type); IRDA_ASSERT(ircomm != NULL, return NULL;); @@ -155,7 +155,7 @@ EXPORT_SYMBOL(ircomm_open); */ static int __ircomm_close(struct ircomm_cb *self) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); /* Disconnect link if any */ ircomm_do_event(self, IRCOMM_DISCONNECT_REQUEST, NULL, NULL); @@ -191,7 +191,7 @@ int ircomm_close(struct ircomm_cb *self) IRDA_ASSERT(self != NULL, return -EIO;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EIO;); - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); entry = hashbin_remove(ircomm, self->line, NULL); @@ -216,7 +216,7 @@ int ircomm_connect_request(struct ircomm_cb *self, __u8 dlsap_sel, struct ircomm_info info; int ret; - IRDA_DEBUG(2 , "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2 , "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); @@ -245,7 +245,7 @@ void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb, { int clen = 0; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); /* Check if the packet contains data on the control channel */ if (skb->len > 0) @@ -261,7 +261,7 @@ void ircomm_connect_indication(struct ircomm_cb *self, struct sk_buff *skb, info->qos, info->max_data_size, info->max_header_size, skb); else { - IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), missing handler\n", __func__ ); } } @@ -278,7 +278,7 @@ int ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata) IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); ret = ircomm_do_event(self, IRCOMM_CONNECT_RESPONSE, userdata, NULL); @@ -296,7 +296,7 @@ EXPORT_SYMBOL(ircomm_connect_response); void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb, struct ircomm_info *info) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); if (self->notify.connect_confirm ) self->notify.connect_confirm(self->notify.instance, @@ -304,7 +304,7 @@ void ircomm_connect_confirm(struct ircomm_cb *self, struct sk_buff *skb, info->max_data_size, info->max_header_size, skb); else { - IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), missing handler\n", __func__ ); } } @@ -318,7 +318,7 @@ int ircomm_data_request(struct ircomm_cb *self, struct sk_buff *skb) { int ret; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -EFAULT;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;); @@ -339,14 +339,14 @@ EXPORT_SYMBOL(ircomm_data_request); */ void ircomm_data_indication(struct ircomm_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(skb->len > 0, return;); if (self->notify.data_indication) self->notify.data_indication(self->notify.instance, self, skb); else { - IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), missing handler\n", __func__ ); } } @@ -372,7 +372,7 @@ void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb) */ if (unlikely(skb->len < (clen + 1))) { IRDA_DEBUG(2, "%s() throwing away illegal frame\n", - __FUNCTION__ ); + __func__ ); return; } @@ -391,7 +391,7 @@ void ircomm_process_data(struct ircomm_cb *self, struct sk_buff *skb) ircomm_data_indication(self, skb); else { IRDA_DEBUG(4, "%s(), data was control info only!\n", - __FUNCTION__ ); + __func__ ); } } @@ -405,7 +405,7 @@ int ircomm_control_request(struct ircomm_cb *self, struct sk_buff *skb) { int ret; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -EFAULT;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -EFAULT;); @@ -427,7 +427,7 @@ EXPORT_SYMBOL(ircomm_control_request); static void ircomm_control_indication(struct ircomm_cb *self, struct sk_buff *skb, int clen) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); /* Use udata for delivering data on the control channel */ if (self->notify.udata_indication) { @@ -448,7 +448,7 @@ static void ircomm_control_indication(struct ircomm_cb *self, * see ircomm_tty_control_indication(). */ dev_kfree_skb(ctrl_skb); } else { - IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), missing handler\n", __func__ ); } } @@ -463,7 +463,7 @@ int ircomm_disconnect_request(struct ircomm_cb *self, struct sk_buff *userdata) struct ircomm_info info; int ret; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); @@ -484,7 +484,7 @@ EXPORT_SYMBOL(ircomm_disconnect_request); void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb, struct ircomm_info *info) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(info != NULL, return;); @@ -492,7 +492,7 @@ void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb, self->notify.disconnect_indication(self->notify.instance, self, info->reason, skb); } else { - IRDA_DEBUG(0, "%s(), missing handler\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), missing handler\n", __func__ ); } } @@ -504,7 +504,7 @@ void ircomm_disconnect_indication(struct ircomm_cb *self, struct sk_buff *skb, */ void ircomm_flow_request(struct ircomm_cb *self, LOCAL_FLOW flow) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); diff --git a/net/irda/ircomm/ircomm_event.c b/net/irda/ircomm/ircomm_event.c index 8ba4e59ece16..c35b3ef5c2f0 100644 --- a/net/irda/ircomm/ircomm_event.c +++ b/net/irda/ircomm/ircomm_event.c @@ -108,7 +108,7 @@ static int ircomm_state_idle(struct ircomm_cb *self, IRCOMM_EVENT event, ircomm_connect_indication(self, skb, info); break; default: - IRDA_DEBUG(4, "%s(), unknown event: %s\n", __FUNCTION__ , + IRDA_DEBUG(4, "%s(), unknown event: %s\n", __func__ , ircomm_event[event]); ret = -EINVAL; } @@ -138,7 +138,7 @@ static int ircomm_state_waiti(struct ircomm_cb *self, IRCOMM_EVENT event, ircomm_disconnect_indication(self, skb, info); break; default: - IRDA_DEBUG(0, "%s(), unknown event: %s\n", __FUNCTION__ , + IRDA_DEBUG(0, "%s(), unknown event: %s\n", __func__ , ircomm_event[event]); ret = -EINVAL; } @@ -171,7 +171,7 @@ static int ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, ircomm_disconnect_indication(self, skb, info); break; default: - IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ , + IRDA_DEBUG(0, "%s(), unknown event = %s\n", __func__ , ircomm_event[event]); ret = -EINVAL; } @@ -213,7 +213,7 @@ static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, ret = self->issue.disconnect_request(self, skb, info); break; default: - IRDA_DEBUG(0, "%s(), unknown event = %s\n", __FUNCTION__ , + IRDA_DEBUG(0, "%s(), unknown event = %s\n", __func__ , ircomm_event[event]); ret = -EINVAL; } @@ -229,7 +229,7 @@ static int ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, int ircomm_do_event(struct ircomm_cb *self, IRCOMM_EVENT event, struct sk_buff *skb, struct ircomm_info *info) { - IRDA_DEBUG(4, "%s: state=%s, event=%s\n", __FUNCTION__ , + IRDA_DEBUG(4, "%s: state=%s, event=%s\n", __func__ , ircomm_state[self->state], ircomm_event[event]); return (*state[self->state])(self, event, skb, info); @@ -245,6 +245,6 @@ void ircomm_next_state(struct ircomm_cb *self, IRCOMM_STATE state) { self->state = state; - IRDA_DEBUG(4, "%s: next state=%s, service type=%d\n", __FUNCTION__ , + IRDA_DEBUG(4, "%s: next state=%s, service type=%d\n", __func__ , ircomm_state[self->state], self->service_type); } diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c index 55860ee4e39e..67c99d20857f 100644 --- a/net/irda/ircomm/ircomm_lmp.c +++ b/net/irda/ircomm/ircomm_lmp.c @@ -53,7 +53,7 @@ static int ircomm_lmp_connect_request(struct ircomm_cb *self, { int ret = 0; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); /* Don't forget to refcount it - should be NULL anyway */ if(userdata) @@ -76,7 +76,7 @@ static int ircomm_lmp_connect_response(struct ircomm_cb *self, struct sk_buff *tx_skb; int ret; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); /* Any userdata supplied? */ if (userdata == NULL) { @@ -111,7 +111,7 @@ static int ircomm_lmp_disconnect_request(struct ircomm_cb *self, struct sk_buff *tx_skb; int ret; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); if (!userdata) { tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); @@ -148,13 +148,13 @@ static void ircomm_lmp_flow_control(struct sk_buff *skb) cb = (struct irda_skb_cb *) skb->cb; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); line = cb->line; self = (struct ircomm_cb *) hashbin_lock_find(ircomm, line, NULL); if (!self) { - IRDA_DEBUG(2, "%s(), didn't find myself\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), didn't find myself\n", __func__ ); return; } @@ -164,7 +164,7 @@ static void ircomm_lmp_flow_control(struct sk_buff *skb) self->pkt_count--; if ((self->pkt_count < 2) && (self->flow_status == FLOW_STOP)) { - IRDA_DEBUG(2, "%s(), asking TTY to start again!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), asking TTY to start again!\n", __func__ ); self->flow_status = FLOW_START; if (self->notify.flow_indication) self->notify.flow_indication(self->notify.instance, @@ -191,7 +191,7 @@ static int ircomm_lmp_data_request(struct ircomm_cb *self, cb->line = self->line; - IRDA_DEBUG(4, "%s(), sending frame\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s(), sending frame\n", __func__ ); /* Don't forget to refcount it - see ircomm_tty_do_softint() */ skb_get(skb); @@ -199,7 +199,7 @@ static int ircomm_lmp_data_request(struct ircomm_cb *self, skb->destructor = ircomm_lmp_flow_control; if ((self->pkt_count++ > 7) && (self->flow_status == FLOW_START)) { - IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), asking TTY to slow down!\n", __func__ ); self->flow_status = FLOW_STOP; if (self->notify.flow_indication) self->notify.flow_indication(self->notify.instance, @@ -207,7 +207,7 @@ static int ircomm_lmp_data_request(struct ircomm_cb *self, } ret = irlmp_data_request(self->lsap, skb); if (ret) { - IRDA_ERROR("%s(), failed\n", __FUNCTION__); + IRDA_ERROR("%s(), failed\n", __func__); /* irlmp_data_request already free the packet */ } @@ -225,7 +225,7 @@ static int ircomm_lmp_data_indication(void *instance, void *sap, { struct ircomm_cb *self = (struct ircomm_cb *) instance; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); @@ -255,7 +255,7 @@ static void ircomm_lmp_connect_confirm(void *instance, void *sap, struct ircomm_cb *self = (struct ircomm_cb *) instance; struct ircomm_info info; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); @@ -288,7 +288,7 @@ static void ircomm_lmp_connect_indication(void *instance, void *sap, struct ircomm_cb *self = (struct ircomm_cb *)instance; struct ircomm_info info; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); @@ -318,7 +318,7 @@ static void ircomm_lmp_disconnect_indication(void *instance, void *sap, struct ircomm_cb *self = (struct ircomm_cb *) instance; struct ircomm_info info; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); @@ -341,7 +341,7 @@ int ircomm_open_lsap(struct ircomm_cb *self) { notify_t notify; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); /* Register callbacks */ irda_notify_init(¬ify); @@ -354,7 +354,7 @@ int ircomm_open_lsap(struct ircomm_cb *self) self->lsap = irlmp_open_lsap(LSAP_ANY, ¬ify, 0); if (!self->lsap) { - IRDA_DEBUG(0,"%sfailed to allocate tsap\n", __FUNCTION__ ); + IRDA_DEBUG(0,"%sfailed to allocate tsap\n", __func__ ); return -1; } self->slsap_sel = self->lsap->slsap_sel; diff --git a/net/irda/ircomm/ircomm_param.c b/net/irda/ircomm/ircomm_param.c index 598dcbe4a501..d57aefd9fe77 100644 --- a/net/irda/ircomm/ircomm_param.c +++ b/net/irda/ircomm/ircomm_param.c @@ -103,7 +103,7 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush) struct sk_buff *skb; int count; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); @@ -136,7 +136,7 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush) count = irda_param_insert(self, pi, skb_tail_pointer(skb), skb_tailroom(skb), &ircomm_param_info); if (count < 0) { - IRDA_WARNING("%s(), no room for parameter!\n", __FUNCTION__); + IRDA_WARNING("%s(), no room for parameter!\n", __func__); spin_unlock_irqrestore(&self->spinlock, flags); return -1; } @@ -144,7 +144,7 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush) spin_unlock_irqrestore(&self->spinlock, flags); - IRDA_DEBUG(2, "%s(), skb->len=%d\n", __FUNCTION__ , skb->len); + IRDA_DEBUG(2, "%s(), skb->len=%d\n", __func__ , skb->len); if (flush) { /* ircomm_tty_do_softint will take care of the rest */ @@ -179,10 +179,10 @@ static int ircomm_param_service_type(void *instance, irda_param_t *param, service_type &= self->service_type; if (!service_type) { IRDA_DEBUG(2, - "%s(), No common service type to use!\n", __FUNCTION__ ); + "%s(), No common service type to use!\n", __func__ ); return -1; } - IRDA_DEBUG(0, "%s(), services in common=%02x\n", __FUNCTION__ , + IRDA_DEBUG(0, "%s(), services in common=%02x\n", __func__ , service_type); /* @@ -197,7 +197,7 @@ static int ircomm_param_service_type(void *instance, irda_param_t *param, else if (service_type & IRCOMM_3_WIRE_RAW) self->settings.service_type = IRCOMM_3_WIRE_RAW; - IRDA_DEBUG(0, "%s(), resulting service type=0x%02x\n", __FUNCTION__ , + IRDA_DEBUG(0, "%s(), resulting service type=0x%02x\n", __func__ , self->settings.service_type); /* @@ -240,7 +240,7 @@ static int ircomm_param_port_type(void *instance, irda_param_t *param, int get) else { self->settings.port_type = (__u8) param->pv.i; - IRDA_DEBUG(0, "%s(), port type=%d\n", __FUNCTION__ , + IRDA_DEBUG(0, "%s(), port type=%d\n", __func__ , self->settings.port_type); } return 0; @@ -260,9 +260,9 @@ static int ircomm_param_port_name(void *instance, irda_param_t *param, int get) IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); if (get) { - IRDA_DEBUG(0, "%s(), not imp!\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), not imp!\n", __func__ ); } else { - IRDA_DEBUG(0, "%s(), port-name=%s\n", __FUNCTION__ , param->pv.c); + IRDA_DEBUG(0, "%s(), port-name=%s\n", __func__ , param->pv.c); strncpy(self->settings.port_name, param->pv.c, 32); } @@ -287,7 +287,7 @@ static int ircomm_param_data_rate(void *instance, irda_param_t *param, int get) else self->settings.data_rate = param->pv.i; - IRDA_DEBUG(2, "%s(), data rate = %d\n", __FUNCTION__ , param->pv.i); + IRDA_DEBUG(2, "%s(), data rate = %d\n", __func__ , param->pv.i); return 0; } @@ -333,7 +333,7 @@ static int ircomm_param_flow_control(void *instance, irda_param_t *param, else self->settings.flow_control = (__u8) param->pv.i; - IRDA_DEBUG(1, "%s(), flow control = 0x%02x\n", __FUNCTION__ , (__u8) param->pv.i); + IRDA_DEBUG(1, "%s(), flow control = 0x%02x\n", __func__ , (__u8) param->pv.i); return 0; } @@ -359,7 +359,7 @@ static int ircomm_param_xon_xoff(void *instance, irda_param_t *param, int get) self->settings.xonxoff[1] = (__u16) param->pv.i >> 8; } - IRDA_DEBUG(0, "%s(), XON/XOFF = 0x%02x,0x%02x\n", __FUNCTION__ , + IRDA_DEBUG(0, "%s(), XON/XOFF = 0x%02x,0x%02x\n", __func__ , param->pv.i & 0xff, param->pv.i >> 8); return 0; @@ -386,7 +386,7 @@ static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get) self->settings.enqack[1] = (__u16) param->pv.i >> 8; } - IRDA_DEBUG(0, "%s(), ENQ/ACK = 0x%02x,0x%02x\n", __FUNCTION__ , + IRDA_DEBUG(0, "%s(), ENQ/ACK = 0x%02x,0x%02x\n", __func__ , param->pv.i & 0xff, param->pv.i >> 8); return 0; @@ -401,7 +401,7 @@ static int ircomm_param_enq_ack(void *instance, irda_param_t *param, int get) static int ircomm_param_line_status(void *instance, irda_param_t *param, int get) { - IRDA_DEBUG(2, "%s(), not impl.\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), not impl.\n", __func__ ); return 0; } @@ -462,7 +462,7 @@ static int ircomm_param_dce(void *instance, irda_param_t *param, int get) struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; __u8 dce; - IRDA_DEBUG(1, "%s(), dce = 0x%02x\n", __FUNCTION__ , (__u8) param->pv.i); + IRDA_DEBUG(1, "%s(), dce = 0x%02x\n", __func__ , (__u8) param->pv.i); dce = (__u8) param->pv.i; @@ -474,7 +474,7 @@ static int ircomm_param_dce(void *instance, irda_param_t *param, int get) /* Check if any of the settings have changed */ if (dce & 0x0f) { if (dce & IRCOMM_DELTA_CTS) { - IRDA_DEBUG(2, "%s(), CTS \n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), CTS \n", __func__ ); } } diff --git a/net/irda/ircomm/ircomm_ttp.c b/net/irda/ircomm/ircomm_ttp.c index 712eafd0cc76..6e6509f22f60 100644 --- a/net/irda/ircomm/ircomm_ttp.c +++ b/net/irda/ircomm/ircomm_ttp.c @@ -78,7 +78,7 @@ int ircomm_open_tsap(struct ircomm_cb *self) { notify_t notify; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); /* Register callbacks */ irda_notify_init(¬ify); @@ -93,7 +93,7 @@ int ircomm_open_tsap(struct ircomm_cb *self) self->tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify); if (!self->tsap) { - IRDA_DEBUG(0, "%sfailed to allocate tsap\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%sfailed to allocate tsap\n", __func__ ); return -1; } self->slsap_sel = self->tsap->stsap_sel; @@ -121,7 +121,7 @@ static int ircomm_ttp_connect_request(struct ircomm_cb *self, { int ret = 0; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); /* Don't forget to refcount it - should be NULL anyway */ if(userdata) @@ -145,7 +145,7 @@ static int ircomm_ttp_connect_response(struct ircomm_cb *self, { int ret; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); /* Don't forget to refcount it - should be NULL anyway */ if(userdata) @@ -173,7 +173,7 @@ static int ircomm_ttp_data_request(struct ircomm_cb *self, IRDA_ASSERT(skb != NULL, return -1;); - IRDA_DEBUG(2, "%s(), clen=%d\n", __FUNCTION__ , clen); + IRDA_DEBUG(2, "%s(), clen=%d\n", __func__ , clen); /* * Insert clen field, currently we either send data only, or control @@ -190,7 +190,7 @@ static int ircomm_ttp_data_request(struct ircomm_cb *self, ret = irttp_data_request(self->tsap, skb); if (ret) { - IRDA_ERROR("%s(), failed\n", __FUNCTION__); + IRDA_ERROR("%s(), failed\n", __func__); /* irttp_data_request already free the packet */ } @@ -208,7 +208,7 @@ static int ircomm_ttp_data_indication(void *instance, void *sap, { struct ircomm_cb *self = (struct ircomm_cb *) instance; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return -1;); @@ -231,7 +231,7 @@ static void ircomm_ttp_connect_confirm(void *instance, void *sap, struct ircomm_cb *self = (struct ircomm_cb *) instance; struct ircomm_info info; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); @@ -240,7 +240,7 @@ static void ircomm_ttp_connect_confirm(void *instance, void *sap, if (max_sdu_size != TTP_SAR_DISABLE) { IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n", - __FUNCTION__); + __func__); goto out; } @@ -272,7 +272,7 @@ static void ircomm_ttp_connect_indication(void *instance, void *sap, struct ircomm_cb *self = (struct ircomm_cb *)instance; struct ircomm_info info; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); @@ -281,7 +281,7 @@ static void ircomm_ttp_connect_indication(void *instance, void *sap, if (max_sdu_size != TTP_SAR_DISABLE) { IRDA_ERROR("%s(), SAR not allowed for IrCOMM!\n", - __FUNCTION__); + __func__); goto out; } @@ -331,7 +331,7 @@ static void ircomm_ttp_disconnect_indication(void *instance, void *sap, struct ircomm_cb *self = (struct ircomm_cb *) instance; struct ircomm_info info; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); @@ -356,7 +356,7 @@ static void ircomm_ttp_flow_indication(void *instance, void *sap, { struct ircomm_cb *self = (struct ircomm_cb *) instance; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_MAGIC, return;); diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c index be627e1f04d8..d2620410cb0a 100644 --- a/net/irda/ircomm/ircomm_tty.c +++ b/net/irda/ircomm/ircomm_tty.c @@ -115,7 +115,7 @@ static int __init ircomm_tty_init(void) return -ENOMEM; ircomm_tty = hashbin_new(HB_LOCK); if (ircomm_tty == NULL) { - IRDA_ERROR("%s(), can't allocate hashbin!\n", __FUNCTION__); + IRDA_ERROR("%s(), can't allocate hashbin!\n", __func__); put_tty_driver(driver); return -ENOMEM; } @@ -133,7 +133,7 @@ static int __init ircomm_tty_init(void) tty_set_operations(driver, &ops); if (tty_register_driver(driver)) { IRDA_ERROR("%s(): Couldn't register serial driver\n", - __FUNCTION__); + __func__); put_tty_driver(driver); return -1; } @@ -142,7 +142,7 @@ static int __init ircomm_tty_init(void) static void __exit __ircomm_tty_cleanup(struct ircomm_tty_cb *self) { - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -163,12 +163,12 @@ static void __exit ircomm_tty_cleanup(void) { int ret; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); ret = tty_unregister_driver(driver); if (ret) { IRDA_ERROR("%s(), failed to unregister driver\n", - __FUNCTION__); + __func__); return; } @@ -187,14 +187,14 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self) notify_t notify; int ret = -ENODEV; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); /* Check if already open */ if (test_and_set_bit(ASYNC_B_INITIALIZED, &self->flags)) { - IRDA_DEBUG(2, "%s(), already open so break out!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), already open so break out!\n", __func__ ); return 0; } @@ -224,7 +224,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self) /* Connect IrCOMM link with remote device */ ret = ircomm_tty_attach_cable(self); if (ret < 0) { - IRDA_ERROR("%s(), error attaching cable!\n", __FUNCTION__); + IRDA_ERROR("%s(), error attaching cable!\n", __func__); goto err; } @@ -249,7 +249,7 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, unsigned long flags; struct tty_struct *tty; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); tty = self->tty; @@ -260,12 +260,12 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self, if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ /* nonblock mode is set or port is not enabled */ self->flags |= ASYNC_NORMAL_ACTIVE; - IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __func__ ); return 0; } if (tty->termios->c_cflag & CLOCAL) { - IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __func__ ); do_clocal = 1; } @@ -368,7 +368,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) unsigned long flags; int ret; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); line = tty->index; if ((line < 0) || (line >= IRCOMM_TTY_PORTS)) { @@ -381,7 +381,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) /* No, so make new instance */ self = kzalloc(sizeof(struct ircomm_tty_cb), GFP_KERNEL); if (self == NULL) { - IRDA_ERROR("%s(), kmalloc failed!\n", __FUNCTION__); + IRDA_ERROR("%s(), kmalloc failed!\n", __func__); return -ENOMEM; } @@ -420,7 +420,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) self->tty = tty; spin_unlock_irqrestore(&self->spinlock, flags); - IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __FUNCTION__ , tty->driver->name, + IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __func__ , tty->driver->name, self->line, self->open_count); /* Not really used by us, but lets do it anyway */ @@ -442,7 +442,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) if (wait_event_interruptible(self->close_wait, !test_bit(ASYNC_B_CLOSING, &self->flags))) { IRDA_WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n", - __FUNCTION__); + __func__); return -ERESTARTSYS; } @@ -460,9 +460,9 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */ /* Jan Kiszka -> add DSR/RI -> Conform to IrCOMM spec */ self->settings.dce = IRCOMM_CTS | IRCOMM_CD | IRCOMM_DSR | IRCOMM_RI; /* Default line settings */ - IRDA_DEBUG(2, "%s(), IrCOMM device\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IrCOMM device\n", __func__ ); } else { - IRDA_DEBUG(2, "%s(), IrLPT device\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IrLPT device\n", __func__ ); self->service_type = IRCOMM_3_WIRE_RAW; self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */ } @@ -474,7 +474,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp) ret = ircomm_tty_block_til_ready(self, filp); if (ret) { IRDA_DEBUG(2, - "%s(), returning after block_til_ready with %d\n", __FUNCTION__ , + "%s(), returning after block_til_ready with %d\n", __func__ , ret); return ret; @@ -493,7 +493,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned long flags; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); if (!tty) return; @@ -506,7 +506,7 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) if (tty_hung_up_p(filp)) { spin_unlock_irqrestore(&self->spinlock, flags); - IRDA_DEBUG(0, "%s(), returning 1\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), returning 1\n", __func__ ); return; } @@ -519,20 +519,20 @@ static void ircomm_tty_close(struct tty_struct *tty, struct file *filp) * serial port won't be shutdown. */ IRDA_DEBUG(0, "%s(), bad serial port count; " - "tty->count is 1, state->count is %d\n", __FUNCTION__ , + "tty->count is 1, state->count is %d\n", __func__ , self->open_count); self->open_count = 1; } if (--self->open_count < 0) { IRDA_ERROR("%s(), bad serial port count for ttys%d: %d\n", - __FUNCTION__, self->line, self->open_count); + __func__, self->line, self->open_count); self->open_count = 0; } if (self->open_count) { spin_unlock_irqrestore(&self->spinlock, flags); - IRDA_DEBUG(0, "%s(), open count > 0\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), open count > 0\n", __func__ ); return; } @@ -608,7 +608,7 @@ static void ircomm_tty_do_softint(struct work_struct *work) unsigned long flags; struct sk_buff *skb, *ctrl_skb; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); if (!self || self->magic != IRCOMM_TTY_MAGIC) return; @@ -678,7 +678,7 @@ static int ircomm_tty_write(struct tty_struct *tty, int len = 0; int size; - IRDA_DEBUG(2, "%s(), count=%d, hw_stopped=%d\n", __FUNCTION__ , count, + IRDA_DEBUG(2, "%s(), count=%d, hw_stopped=%d\n", __func__ , count, tty->hw_stopped); IRDA_ASSERT(self != NULL, return -1;); @@ -701,7 +701,7 @@ static int ircomm_tty_write(struct tty_struct *tty, * we don't mess up the original "safe skb" (see tx_data_size). * Jean II */ if (self->max_header_size == IRCOMM_TTY_HDR_UNINITIALISED) { - IRDA_DEBUG(1, "%s() : not initialised\n", __FUNCTION__); + IRDA_DEBUG(1, "%s() : not initialised\n", __func__); #ifdef IRCOMM_NO_TX_BEFORE_INIT /* We didn't consume anything, TTY will retry */ return 0; @@ -830,7 +830,7 @@ static int ircomm_tty_write_room(struct tty_struct *tty) ret = self->max_data_size; spin_unlock_irqrestore(&self->spinlock, flags); } - IRDA_DEBUG(2, "%s(), ret=%d\n", __FUNCTION__ , ret); + IRDA_DEBUG(2, "%s(), ret=%d\n", __func__ , ret); return ret; } @@ -847,7 +847,7 @@ static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout) unsigned long orig_jiffies, poll_time; unsigned long flags; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -882,7 +882,7 @@ static void ircomm_tty_throttle(struct tty_struct *tty) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -913,7 +913,7 @@ static void ircomm_tty_unthrottle(struct tty_struct *tty) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -928,7 +928,7 @@ static void ircomm_tty_unthrottle(struct tty_struct *tty) self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS); ircomm_param_request(self, IRCOMM_DTE, TRUE); - IRDA_DEBUG(1, "%s(), FLOW_START\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), FLOW_START\n", __func__ ); } ircomm_flow_request(self->ircomm, FLOW_START); } @@ -965,7 +965,7 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self) IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); if (!test_and_clear_bit(ASYNC_B_INITIALIZED, &self->flags)) return; @@ -1008,7 +1008,7 @@ static void ircomm_tty_hangup(struct tty_struct *tty) struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned long flags; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -1037,7 +1037,7 @@ static void ircomm_tty_hangup(struct tty_struct *tty) */ static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch) { - IRDA_DEBUG(0, "%s(), not impl\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), not impl\n", __func__ ); } /* @@ -1081,7 +1081,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) struct tty_struct *tty; int status; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -1095,14 +1095,14 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) } if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) { IRDA_DEBUG(2, - "%s(), ircomm%d CD now %s...\n", __FUNCTION__ , self->line, + "%s(), ircomm%d CD now %s...\n", __func__ , self->line, (status & IRCOMM_CD) ? "on" : "off"); if (status & IRCOMM_CD) { wake_up_interruptible(&self->open_wait); } else { IRDA_DEBUG(2, - "%s(), Doing serial hangup..\n", __FUNCTION__ ); + "%s(), Doing serial hangup..\n", __func__ ); if (tty) tty_hangup(tty); @@ -1114,7 +1114,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) if (tty->hw_stopped) { if (status & IRCOMM_CTS) { IRDA_DEBUG(2, - "%s(), CTS tx start...\n", __FUNCTION__ ); + "%s(), CTS tx start...\n", __func__ ); tty->hw_stopped = 0; /* Wake up processes blocked on open */ @@ -1126,7 +1126,7 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self) } else { if (!(status & IRCOMM_CTS)) { IRDA_DEBUG(2, - "%s(), CTS tx stop...\n", __FUNCTION__ ); + "%s(), CTS tx stop...\n", __func__ ); tty->hw_stopped = 1; } } @@ -1144,14 +1144,14 @@ static int ircomm_tty_data_indication(void *instance, void *sap, { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); IRDA_ASSERT(skb != NULL, return -1;); if (!self->tty) { - IRDA_DEBUG(0, "%s(), no tty!\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), no tty!\n", __func__ ); return 0; } @@ -1162,7 +1162,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap, * params, we can just as well declare the hardware for running. */ if (self->tty->hw_stopped && (self->flow == FLOW_START)) { - IRDA_DEBUG(0, "%s(), polling for line settings!\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), polling for line settings!\n", __func__ ); ircomm_param_request(self, IRCOMM_POLL, TRUE); /* We can just as well declare the hardware for running */ @@ -1194,7 +1194,7 @@ static int ircomm_tty_control_indication(void *instance, void *sap, struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; int clen; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); @@ -1230,7 +1230,7 @@ static void ircomm_tty_flow_indication(void *instance, void *sap, switch (cmd) { case FLOW_START: - IRDA_DEBUG(2, "%s(), hw start!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), hw start!\n", __func__ ); tty->hw_stopped = 0; /* ircomm_tty_do_softint will take care of the rest */ @@ -1238,7 +1238,7 @@ static void ircomm_tty_flow_indication(void *instance, void *sap, break; default: /* If we get here, something is very wrong, better stop */ case FLOW_STOP: - IRDA_DEBUG(2, "%s(), hw stopped!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), hw stopped!\n", __func__ ); tty->hw_stopped = 1; break; } diff --git a/net/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c index b5a13882c927..9032a1d1190d 100644 --- a/net/irda/ircomm/ircomm_tty_attach.c +++ b/net/irda/ircomm/ircomm_tty_attach.c @@ -129,14 +129,14 @@ static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event, */ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self) { - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); /* Check if somebody has already connected to us */ if (ircomm_is_connected(self->ircomm)) { - IRDA_DEBUG(0, "%s(), already connected!\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), already connected!\n", __func__ ); return 0; } @@ -158,7 +158,7 @@ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self) */ void ircomm_tty_detach_cable(struct ircomm_tty_cb *self) { - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -207,7 +207,7 @@ static void ircomm_tty_ias_register(struct ircomm_tty_cb *self) __u8 oct_seq[6]; __u16 hints; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -308,16 +308,16 @@ int ircomm_tty_send_initial_parameters(struct ircomm_tty_cb *self) * Set default values, but only if the application for some reason * haven't set them already */ - IRDA_DEBUG(2, "%s(), data-rate = %d\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s(), data-rate = %d\n", __func__ , self->settings.data_rate); if (!self->settings.data_rate) self->settings.data_rate = 9600; - IRDA_DEBUG(2, "%s(), data-format = %d\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s(), data-format = %d\n", __func__ , self->settings.data_format); if (!self->settings.data_format) self->settings.data_format = IRCOMM_WSIZE_8; /* 8N1 */ - IRDA_DEBUG(2, "%s(), flow-control = %d\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s(), flow-control = %d\n", __func__ , self->settings.flow_control); /*self->settings.flow_control = IRCOMM_RTS_CTS_IN|IRCOMM_RTS_CTS_OUT;*/ @@ -362,7 +362,7 @@ static void ircomm_tty_discovery_indication(discinfo_t *discovery, struct ircomm_tty_cb *self; struct ircomm_tty_info info; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); /* Important note : * We need to drop all passive discoveries. @@ -398,7 +398,7 @@ void ircomm_tty_disconnect_indication(void *instance, void *sap, { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -428,7 +428,7 @@ static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) priv; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -439,13 +439,13 @@ static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, /* Check if request succeeded */ if (result != IAS_SUCCESS) { - IRDA_DEBUG(4, "%s(), got NULL value!\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s(), got NULL value!\n", __func__ ); return; } switch (value->type) { case IAS_OCT_SEQ: - IRDA_DEBUG(2, "%s(), got octet sequence\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), got octet sequence\n", __func__ ); irda_param_extract_all(self, value->t.oct_seq, value->len, &ircomm_param_info); @@ -455,21 +455,21 @@ static void ircomm_tty_getvalue_confirm(int result, __u16 obj_id, break; case IAS_INTEGER: /* Got LSAP selector */ - IRDA_DEBUG(2, "%s(), got lsapsel = %d\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s(), got lsapsel = %d\n", __func__ , value->t.integer); if (value->t.integer == -1) { - IRDA_DEBUG(0, "%s(), invalid value!\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), invalid value!\n", __func__ ); } else self->dlsap_sel = value->t.integer; ircomm_tty_do_event(self, IRCOMM_TTY_GOT_LSAPSEL, NULL, NULL); break; case IAS_MISSING: - IRDA_DEBUG(0, "%s(), got IAS_MISSING\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), got IAS_MISSING\n", __func__ ); break; default: - IRDA_DEBUG(0, "%s(), got unknown type!\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), got unknown type!\n", __func__ ); break; } irias_delete_value(value); @@ -489,7 +489,7 @@ void ircomm_tty_connect_confirm(void *instance, void *sap, { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -520,7 +520,7 @@ void ircomm_tty_connect_indication(void *instance, void *sap, struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; int clen; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -549,7 +549,7 @@ void ircomm_tty_connect_indication(void *instance, void *sap, */ void ircomm_tty_link_established(struct ircomm_tty_cb *self) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -566,10 +566,10 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self) * line. */ if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) { - IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ ); return; } else { - IRDA_DEBUG(1, "%s(), starting hardware!\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), starting hardware!\n", __func__ ); self->tty->hw_stopped = 0; @@ -607,7 +607,7 @@ static void ircomm_tty_watchdog_timer_expired(void *data) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) data; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); @@ -628,7 +628,7 @@ int ircomm_tty_do_event(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event, IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); - IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ , ircomm_tty_state[self->state], ircomm_tty_event[event]); return (*state[self->state])(self, event, skb, info); @@ -646,7 +646,7 @@ static inline void ircomm_tty_next_state(struct ircomm_tty_cb *self, IRCOMM_TTY_ IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); - IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s: next state=%s, service type=%d\n", __func__ , ircomm_tty_state[self->state], self->service_type); */ self->state = state; @@ -665,7 +665,7 @@ static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, { int ret = 0; - IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ , ircomm_tty_state[self->state], ircomm_tty_event[event]); switch (event) { case IRCOMM_TTY_ATTACH_CABLE: @@ -681,7 +681,7 @@ static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, if (self->iriap) { IRDA_WARNING("%s(), busy with a previous query\n", - __FUNCTION__); + __func__); return -EBUSY; } @@ -709,7 +709,7 @@ static int ircomm_tty_state_idle(struct ircomm_tty_cb *self, ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); break; default: - IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ , ircomm_tty_event[event]); ret = -EINVAL; } @@ -729,7 +729,7 @@ static int ircomm_tty_state_search(struct ircomm_tty_cb *self, { int ret = 0; - IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ , ircomm_tty_state[self->state], ircomm_tty_event[event]); switch (event) { @@ -739,7 +739,7 @@ static int ircomm_tty_state_search(struct ircomm_tty_cb *self, if (self->iriap) { IRDA_WARNING("%s(), busy with a previous query\n", - __FUNCTION__); + __func__); return -EBUSY; } @@ -782,7 +782,7 @@ static int ircomm_tty_state_search(struct ircomm_tty_cb *self, ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); break; default: - IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ , ircomm_tty_event[event]); ret = -EINVAL; } @@ -802,14 +802,14 @@ static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, { int ret = 0; - IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ , ircomm_tty_state[self->state], ircomm_tty_event[event]); switch (event) { case IRCOMM_TTY_GOT_PARAMETERS: if (self->iriap) { IRDA_WARNING("%s(), busy with a previous query\n", - __FUNCTION__); + __func__); return -EBUSY; } @@ -840,7 +840,7 @@ static int ircomm_tty_state_query_parameters(struct ircomm_tty_cb *self, ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); break; default: - IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ , ircomm_tty_event[event]); ret = -EINVAL; } @@ -860,7 +860,7 @@ static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, { int ret = 0; - IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ , ircomm_tty_state[self->state], ircomm_tty_event[event]); switch (event) { @@ -889,7 +889,7 @@ static int ircomm_tty_state_query_lsap_sel(struct ircomm_tty_cb *self, ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); break; default: - IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ , ircomm_tty_event[event]); ret = -EINVAL; } @@ -909,7 +909,7 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, { int ret = 0; - IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s: state=%s, event=%s\n", __func__ , ircomm_tty_state[self->state], ircomm_tty_event[event]); switch (event) { @@ -943,7 +943,7 @@ static int ircomm_tty_state_setup(struct ircomm_tty_cb *self, ircomm_tty_next_state(self, IRCOMM_TTY_IDLE); break; default: - IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ , ircomm_tty_event[event]); ret = -EINVAL; } @@ -981,13 +981,13 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self, self->settings.dce = IRCOMM_DELTA_CD; ircomm_tty_check_modem_status(self); } else { - IRDA_DEBUG(0, "%s(), hanging up!\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ ); if (self->tty) tty_hangup(self->tty); } break; default: - IRDA_DEBUG(2, "%s(), unknown event: %s\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s(), unknown event: %s\n", __func__ , ircomm_tty_event[event]); ret = -EINVAL; } diff --git a/net/irda/ircomm/ircomm_tty_ioctl.c b/net/irda/ircomm/ircomm_tty_ioctl.c index 6030947b6d93..24cb3aa2bbfb 100644 --- a/net/irda/ircomm/ircomm_tty_ioctl.c +++ b/net/irda/ircomm/ircomm_tty_ioctl.c @@ -57,7 +57,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self) unsigned cflag, cval; int baud; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); if (!self->tty || !self->tty->termios || !self->ircomm) return; @@ -94,7 +94,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self) self->settings.flow_control |= IRCOMM_RTS_CTS_IN; /* This got me. Bummer. Jean II */ if (self->service_type == IRCOMM_3_WIRE_RAW) - IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __FUNCTION__); + IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __func__); } else { self->flags &= ~ASYNC_CTS_FLOW; self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN; @@ -150,7 +150,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty, struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned int cflag = tty->termios->c_cflag; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); if ((cflag == old_termios->c_cflag) && (RELEVANT_IFLAG(tty->termios->c_iflag) == @@ -199,7 +199,7 @@ int ircomm_tty_tiocmget(struct tty_struct *tty, struct file *file) struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned int result; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; @@ -224,7 +224,7 @@ int ircomm_tty_tiocmset(struct tty_struct *tty, struct file *file, { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; @@ -266,7 +266,7 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self, if (!retinfo) return -EFAULT; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); memset(&info, 0, sizeof(info)); info.line = self->line; @@ -302,7 +302,7 @@ static int ircomm_tty_set_serial_info(struct ircomm_tty_cb *self, struct serial_struct new_serial; struct ircomm_tty_cb old_state, *state; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; @@ -376,7 +376,7 @@ int ircomm_tty_ioctl(struct tty_struct *tty, struct file *file, struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; int ret = 0; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && @@ -397,7 +397,7 @@ int ircomm_tty_ioctl(struct tty_struct *tty, struct file *file, break; case TIOCGICOUNT: - IRDA_DEBUG(0, "%s(), TIOCGICOUNT not impl!\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), TIOCGICOUNT not impl!\n", __func__ ); #if 0 save_flags(flags); cli(); cnow = driver->icount; diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c index 87185910d0ee..ea319e3ddc18 100644 --- a/net/irda/irda_device.c +++ b/net/irda/irda_device.c @@ -90,7 +90,7 @@ static void leftover_dongle(void *arg) void irda_device_cleanup(void) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); hashbin_delete(tasks, (FREE_FUNC) __irda_task_delete); @@ -107,7 +107,7 @@ void irda_device_set_media_busy(struct net_device *dev, int status) { struct irlap_cb *self; - IRDA_DEBUG(4, "%s(%s)\n", __FUNCTION__, status ? "TRUE" : "FALSE"); + IRDA_DEBUG(4, "%s(%s)\n", __func__, status ? "TRUE" : "FALSE"); self = (struct irlap_cb *) dev->atalk_ptr; @@ -147,11 +147,11 @@ int irda_device_is_receiving(struct net_device *dev) struct if_irda_req req; int ret; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); if (!dev->do_ioctl) { IRDA_ERROR("%s: do_ioctl not impl. by device driver\n", - __FUNCTION__); + __func__); return -1; } @@ -191,7 +191,7 @@ static int irda_task_kick(struct irda_task *task) int count = 0; int timeout; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); IRDA_ASSERT(task != NULL, return -1;); IRDA_ASSERT(task->magic == IRDA_TASK_MAGIC, return -1;); @@ -201,14 +201,14 @@ static int irda_task_kick(struct irda_task *task) timeout = task->function(task); if (count++ > 100) { IRDA_ERROR("%s: error in task handler!\n", - __FUNCTION__); + __func__); irda_task_delete(task); return TRUE; } } while ((timeout == 0) && (task->state != IRDA_TASK_DONE)); if (timeout < 0) { - IRDA_ERROR("%s: Error executing task!\n", __FUNCTION__); + IRDA_ERROR("%s: Error executing task!\n", __func__); irda_task_delete(task); return TRUE; } @@ -241,7 +241,7 @@ static int irda_task_kick(struct irda_task *task) finished = FALSE; } else { IRDA_DEBUG(0, "%s(), not finished, and no timeout!\n", - __FUNCTION__); + __func__); finished = FALSE; } @@ -258,7 +258,7 @@ static void irda_task_timer_expired(void *data) { struct irda_task *task; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); task = (struct irda_task *) data; diff --git a/net/irda/iriap.c b/net/irda/iriap.c index 390a790886eb..9e15c82960fe 100644 --- a/net/irda/iriap.c +++ b/net/irda/iriap.c @@ -108,7 +108,7 @@ int __init iriap_init(void) irias_objects = hashbin_new(HB_LOCK); if (!irias_objects) { IRDA_WARNING("%s: Can't allocate irias_objects hashbin!\n", - __FUNCTION__); + __func__); hashbin_delete(iriap, NULL); return -ENOMEM; } @@ -139,7 +139,7 @@ int __init iriap_init(void) */ server = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); if (!server) { - IRDA_DEBUG(0, "%s(), unable to open server\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), unable to open server\n", __func__); return -1; } iriap_register_lsap(server, LSAP_IAS, IAS_SERVER); @@ -171,11 +171,11 @@ struct iriap_cb *iriap_open(__u8 slsap_sel, int mode, void *priv, { struct iriap_cb *self; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); self = kzalloc(sizeof(*self), GFP_ATOMIC); if (!self) { - IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__); + IRDA_WARNING("%s: Unable to kmalloc!\n", __func__); return NULL; } @@ -217,7 +217,7 @@ EXPORT_SYMBOL(iriap_open); */ static void __iriap_close(struct iriap_cb *self) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); @@ -241,7 +241,7 @@ void iriap_close(struct iriap_cb *self) { struct iriap_cb *entry; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); @@ -262,7 +262,7 @@ static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode) { notify_t notify; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); irda_notify_init(¬ify); notify.connect_confirm = iriap_connect_confirm; @@ -277,7 +277,7 @@ static int iriap_register_lsap(struct iriap_cb *self, __u8 slsap_sel, int mode) self->lsap = irlmp_open_lsap(slsap_sel, ¬ify, 0); if (self->lsap == NULL) { - IRDA_ERROR("%s: Unable to allocated LSAP!\n", __FUNCTION__); + IRDA_ERROR("%s: Unable to allocated LSAP!\n", __func__); return -1; } self->slsap_sel = self->lsap->slsap_sel; @@ -297,7 +297,7 @@ static void iriap_disconnect_indication(void *instance, void *sap, { struct iriap_cb *self; - IRDA_DEBUG(4, "%s(), reason=%s\n", __FUNCTION__, irlmp_reasons[reason]); + IRDA_DEBUG(4, "%s(), reason=%s\n", __func__, irlmp_reasons[reason]); self = (struct iriap_cb *) instance; @@ -313,7 +313,7 @@ static void iriap_disconnect_indication(void *instance, void *sap, dev_kfree_skb(skb); if (self->mode == IAS_CLIENT) { - IRDA_DEBUG(4, "%s(), disconnect as client\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), disconnect as client\n", __func__); iriap_do_client_event(self, IAP_LM_DISCONNECT_INDICATION, @@ -326,7 +326,7 @@ static void iriap_disconnect_indication(void *instance, void *sap, if (self->confirm) self->confirm(IAS_DISCONNECT, 0, NULL, self->priv); } else { - IRDA_DEBUG(4, "%s(), disconnect as server\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), disconnect as server\n", __func__); iriap_do_server_event(self, IAP_LM_DISCONNECT_INDICATION, NULL); iriap_close(self); @@ -340,7 +340,7 @@ static void iriap_disconnect_request(struct iriap_cb *self) { struct sk_buff *tx_skb; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); @@ -349,7 +349,7 @@ static void iriap_disconnect_request(struct iriap_cb *self) if (tx_skb == NULL) { IRDA_DEBUG(0, "%s(), Could not allocate an sk_buff of length %d\n", - __FUNCTION__, LMP_MAX_HEADER); + __func__, LMP_MAX_HEADER); return; } @@ -453,13 +453,13 @@ static void iriap_getvaluebyclass_confirm(struct iriap_cb *self, /* Get length, MSB first */ len = be16_to_cpu(get_unaligned((__be16 *)(fp+n))); n += 2; - IRDA_DEBUG(4, "%s(), len=%d\n", __FUNCTION__, len); + IRDA_DEBUG(4, "%s(), len=%d\n", __func__, len); /* Get object ID, MSB first */ obj_id = be16_to_cpu(get_unaligned((__be16 *)(fp+n))); n += 2; type = fp[n++]; - IRDA_DEBUG(4, "%s(), Value type = %d\n", __FUNCTION__, type); + IRDA_DEBUG(4, "%s(), Value type = %d\n", __func__, type); switch (type) { case IAS_INTEGER: @@ -468,7 +468,7 @@ static void iriap_getvaluebyclass_confirm(struct iriap_cb *self, value = irias_new_integer_value(tmp_cpu32); /* Legal values restricted to 0x01-0x6f, page 15 irttp */ - IRDA_DEBUG(4, "%s(), lsap=%d\n", __FUNCTION__, value->t.integer); + IRDA_DEBUG(4, "%s(), lsap=%d\n", __func__, value->t.integer); break; case IAS_STRING: charset = fp[n++]; @@ -488,7 +488,7 @@ static void iriap_getvaluebyclass_confirm(struct iriap_cb *self, /* case CS_UNICODE: */ default: IRDA_DEBUG(0, "%s(), charset %s, not supported\n", - __FUNCTION__, ias_charset_types[charset]); + __func__, ias_charset_types[charset]); /* Aborting, close connection! */ iriap_disconnect_request(self); @@ -496,7 +496,7 @@ static void iriap_getvaluebyclass_confirm(struct iriap_cb *self, /* break; */ } value_len = fp[n++]; - IRDA_DEBUG(4, "%s(), strlen=%d\n", __FUNCTION__, value_len); + IRDA_DEBUG(4, "%s(), strlen=%d\n", __func__, value_len); /* Make sure the string is null-terminated */ fp[n+value_len] = 0x00; @@ -526,7 +526,7 @@ static void iriap_getvaluebyclass_confirm(struct iriap_cb *self, if (self->confirm) self->confirm(IAS_SUCCESS, obj_id, value, self->priv); else { - IRDA_DEBUG(0, "%s(), missing handler!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), missing handler!\n", __func__); irias_delete_value(value); } } @@ -548,7 +548,7 @@ static void iriap_getvaluebyclass_response(struct iriap_cb *self, __be16 tmp_be16; __u8 *fp; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); @@ -610,12 +610,12 @@ static void iriap_getvaluebyclass_response(struct iriap_cb *self, memcpy(fp+n, value->t.oct_seq, value->len); n+=value->len; break; case IAS_MISSING: - IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __FUNCTION__); + IRDA_DEBUG( 3, "%s: sending IAS_MISSING\n", __func__); skb_put(tx_skb, 1); fp[n++] = value->type; break; default: - IRDA_DEBUG(0, "%s(), type not implemented!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), type not implemented!\n", __func__); break; } iriap_do_r_connect_event(self, IAP_CALL_RESPONSE, tx_skb); @@ -642,7 +642,7 @@ static void iriap_getvaluebyclass_indication(struct iriap_cb *self, __u8 *fp; int n; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); @@ -697,7 +697,7 @@ void iriap_send_ack(struct iriap_cb *self) struct sk_buff *tx_skb; __u8 *frame; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); @@ -728,7 +728,7 @@ void iriap_connect_request(struct iriap_cb *self) self->saddr, self->daddr, NULL, NULL); if (ret < 0) { - IRDA_DEBUG(0, "%s(), connect failed!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), connect failed!\n", __func__); self->confirm(IAS_DISCONNECT, 0, NULL, self->priv); } } @@ -776,7 +776,7 @@ static void iriap_connect_indication(void *instance, void *sap, { struct iriap_cb *self, *new; - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); self = (struct iriap_cb *) instance; @@ -787,14 +787,14 @@ static void iriap_connect_indication(void *instance, void *sap, /* Start new server */ new = iriap_open(LSAP_IAS, IAS_SERVER, NULL, NULL); if (!new) { - IRDA_DEBUG(0, "%s(), open failed\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), open failed\n", __func__); goto out; } /* Now attach up the new "socket" */ new->lsap = irlmp_dup(self->lsap, new); if (!new->lsap) { - IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), dup failed!\n", __func__); goto out; } @@ -824,7 +824,7 @@ static int iriap_data_indication(void *instance, void *sap, __u8 *frame; __u8 opcode; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); self = (struct iriap_cb *) instance; @@ -836,7 +836,7 @@ static int iriap_data_indication(void *instance, void *sap, if (self->mode == IAS_SERVER) { /* Call server */ - IRDA_DEBUG(4, "%s(), Calling server!\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), Calling server!\n", __func__); iriap_do_r_connect_event(self, IAP_RECV_F_LST, skb); goto out; } @@ -844,13 +844,13 @@ static int iriap_data_indication(void *instance, void *sap, if (~opcode & IAP_LST) { IRDA_WARNING("%s:, IrIAS multiframe commands or " "results is not implemented yet!\n", - __FUNCTION__); + __func__); goto out; } /* Check for ack frames since they don't contain any data */ if (opcode & IAP_ACK) { - IRDA_DEBUG(0, "%s() Got ack frame!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s() Got ack frame!\n", __func__); goto out; } @@ -868,7 +868,7 @@ static int iriap_data_indication(void *instance, void *sap, iriap_getvaluebyclass_confirm(self, skb); break; case IAS_CLASS_UNKNOWN: - IRDA_DEBUG(1, "%s(), No such class!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), No such class!\n", __func__); /* Finished, close connection! */ iriap_disconnect_request(self); @@ -881,7 +881,7 @@ static int iriap_data_indication(void *instance, void *sap, self->priv); break; case IAS_ATTRIB_UNKNOWN: - IRDA_DEBUG(1, "%s(), No such attribute!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), No such attribute!\n", __func__); /* Finished, close connection! */ iriap_disconnect_request(self); @@ -896,7 +896,7 @@ static int iriap_data_indication(void *instance, void *sap, } break; default: - IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __FUNCTION__, + IRDA_DEBUG(0, "%s(), Unknown op-code: %02x\n", __func__, opcode); break; } @@ -918,7 +918,7 @@ void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb) __u8 *fp; __u8 opcode; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IAS_MAGIC, return;); @@ -929,7 +929,7 @@ void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb) opcode = fp[0]; if (~opcode & 0x80) { IRDA_WARNING("%s: IrIAS multiframe commands or results " - "is not implemented yet!\n", __FUNCTION__); + "is not implemented yet!\n", __func__); return; } opcode &= 0x7f; /* Mask away LST bit */ @@ -937,7 +937,7 @@ void iriap_call_indication(struct iriap_cb *self, struct sk_buff *skb) switch (opcode) { case GET_INFO_BASE: IRDA_WARNING("%s: GetInfoBaseDetails not implemented yet!\n", - __FUNCTION__); + __func__); break; case GET_VALUE_BY_CLASS: iriap_getvaluebyclass_indication(self, skb); diff --git a/net/irda/iriap_event.c b/net/irda/iriap_event.c index 8fb9d7277ca8..a301cbd93785 100644 --- a/net/irda/iriap_event.c +++ b/net/irda/iriap_event.c @@ -185,7 +185,7 @@ static void state_s_disconnect(struct iriap_cb *self, IRIAP_EVENT event, case IAP_LM_DISCONNECT_INDICATION: break; default: - IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); + IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event); break; } } @@ -217,7 +217,7 @@ static void state_s_connecting(struct iriap_cb *self, IRIAP_EVENT event, iriap_next_client_state(self, S_DISCONNECT); break; default: - IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); + IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event); break; } } @@ -269,7 +269,7 @@ static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event, iriap_next_call_state(self, S_OUTSTANDING); break; default: - IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); + IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event); break; } } @@ -283,7 +283,7 @@ static void state_s_make_call(struct iriap_cb *self, IRIAP_EVENT event, static void state_s_calling(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Not implemented\n", __func__); } /* @@ -305,7 +305,7 @@ static void state_s_outstanding(struct iriap_cb *self, IRIAP_EVENT event, iriap_next_call_state(self, S_WAIT_FOR_CALL); break; default: - IRDA_DEBUG(0, "%s(), Unknown event %d\n", __FUNCTION__, event); + IRDA_DEBUG(0, "%s(), Unknown event %d\n", __func__, event); break; } } @@ -318,7 +318,7 @@ static void state_s_outstanding(struct iriap_cb *self, IRIAP_EVENT event, static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Not implemented\n", __func__); } /* @@ -330,7 +330,7 @@ static void state_s_replying(struct iriap_cb *self, IRIAP_EVENT event, static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Not implemented\n", __func__); } @@ -343,7 +343,7 @@ static void state_s_wait_for_call(struct iriap_cb *self, IRIAP_EVENT event, static void state_s_wait_active(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Not implemented\n", __func__); } /************************************************************************** @@ -367,7 +367,7 @@ static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event, case IAP_LM_CONNECT_INDICATION: tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC); if (tx_skb == NULL) { - IRDA_WARNING("%s: unable to malloc!\n", __FUNCTION__); + IRDA_WARNING("%s: unable to malloc!\n", __func__); return; } @@ -386,7 +386,7 @@ static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event, iriap_next_r_connect_state(self, R_RECEIVING); break; default: - IRDA_DEBUG(0, "%s(), unknown event %d\n", __FUNCTION__, event); + IRDA_DEBUG(0, "%s(), unknown event %d\n", __func__, event); break; } } @@ -397,7 +397,7 @@ static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event, static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); switch (event) { case IAP_LM_DISCONNECT_INDICATION: @@ -406,7 +406,7 @@ static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event, iriap_next_r_connect_state(self, R_WAITING); break; default: - IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), unknown event!\n", __func__); break; } } @@ -421,13 +421,13 @@ static void state_r_call(struct iriap_cb *self, IRIAP_EVENT event, static void state_r_waiting(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Not implemented\n", __func__); } static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, "%s(), Not implemented\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Not implemented\n", __func__); } /* @@ -439,7 +439,7 @@ static void state_r_wait_active(struct iriap_cb *self, IRIAP_EVENT event, static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); switch (event) { case IAP_RECV_F_LST: @@ -448,7 +448,7 @@ static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event, iriap_call_indication(self, skb); break; default: - IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), unknown event!\n", __func__); break; } } @@ -462,7 +462,7 @@ static void state_r_receiving(struct iriap_cb *self, IRIAP_EVENT event, static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(skb != NULL, return;); IRDA_ASSERT(self != NULL, return;); @@ -483,7 +483,7 @@ static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, irlmp_data_request(self->lsap, skb); break; default: - IRDA_DEBUG(0, "%s(), unknown event!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), unknown event!\n", __func__); break; } } @@ -491,7 +491,7 @@ static void state_r_execute(struct iriap_cb *self, IRIAP_EVENT event, static void state_r_returning(struct iriap_cb *self, IRIAP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(0, "%s(), event=%d\n", __FUNCTION__, event); + IRDA_DEBUG(0, "%s(), event=%d\n", __func__, event); switch (event) { case IAP_RECV_F_LST: diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c index cbcf04380f3a..99ebb96f1386 100644 --- a/net/irda/irias_object.c +++ b/net/irda/irias_object.c @@ -47,12 +47,12 @@ struct ias_object *irias_new_object( char *name, int id) { struct ias_object *obj; - IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); + IRDA_DEBUG( 4, "%s()\n", __func__); obj = kzalloc(sizeof(struct ias_object), GFP_ATOMIC); if (obj == NULL) { IRDA_WARNING("%s(), Unable to allocate object!\n", - __FUNCTION__); + __func__); return NULL; } @@ -60,7 +60,7 @@ struct ias_object *irias_new_object( char *name, int id) obj->name = kstrndup(name, IAS_MAX_CLASSNAME, GFP_ATOMIC); if (!obj->name) { IRDA_WARNING("%s(), Unable to allocate name!\n", - __FUNCTION__); + __func__); kfree(obj); return NULL; } @@ -73,7 +73,7 @@ struct ias_object *irias_new_object( char *name, int id) if (obj->attribs == NULL) { IRDA_WARNING("%s(), Unable to allocate attribs!\n", - __FUNCTION__); + __func__); kfree(obj->name); kfree(obj); return NULL; @@ -134,7 +134,7 @@ int irias_delete_object(struct ias_object *obj) node = hashbin_remove_this(irias_objects, (irda_queue_t *) obj); if (!node) IRDA_DEBUG( 0, "%s(), object already removed!\n", - __FUNCTION__); + __func__); /* Destroy */ __irias_delete_object(obj); @@ -268,7 +268,7 @@ int irias_object_change_attribute(char *obj_name, char *attrib_name, /* Find object */ obj = hashbin_lock_find(irias_objects, 0, obj_name); if (obj == NULL) { - IRDA_WARNING("%s: Unable to find object: %s\n", __FUNCTION__, + IRDA_WARNING("%s: Unable to find object: %s\n", __func__, obj_name); return -1; } @@ -280,14 +280,14 @@ int irias_object_change_attribute(char *obj_name, char *attrib_name, attrib = hashbin_find(obj->attribs, 0, attrib_name); if (attrib == NULL) { IRDA_WARNING("%s: Unable to find attribute: %s\n", - __FUNCTION__, attrib_name); + __func__, attrib_name); spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); return -1; } if ( attrib->value->type != new_value->type) { IRDA_DEBUG( 0, "%s(), changing value type not allowed!\n", - __FUNCTION__); + __func__); spin_unlock_irqrestore(&obj->attribs->hb_spinlock, flags); return -1; } @@ -322,7 +322,7 @@ void irias_add_integer_attrib(struct ias_object *obj, char *name, int value, attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC); if (attrib == NULL) { IRDA_WARNING("%s: Unable to allocate attribute!\n", - __FUNCTION__); + __func__); return; } @@ -333,7 +333,7 @@ void irias_add_integer_attrib(struct ias_object *obj, char *name, int value, attrib->value = irias_new_integer_value(value); if (!attrib->name || !attrib->value) { IRDA_WARNING("%s: Unable to allocate attribute!\n", - __FUNCTION__); + __func__); if (attrib->value) irias_delete_value(attrib->value); kfree(attrib->name); @@ -366,7 +366,7 @@ void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets, attrib = kzalloc(sizeof(struct ias_attrib), GFP_ATOMIC); if (attrib == NULL) { IRDA_WARNING("%s: Unable to allocate attribute!\n", - __FUNCTION__); + __func__); return; } @@ -376,7 +376,7 @@ void irias_add_octseq_attrib(struct ias_object *obj, char *name, __u8 *octets, attrib->value = irias_new_octseq_value( octets, len); if (!attrib->name || !attrib->value) { IRDA_WARNING("%s: Unable to allocate attribute!\n", - __FUNCTION__); + __func__); if (attrib->value) irias_delete_value(attrib->value); kfree(attrib->name); @@ -408,7 +408,7 @@ void irias_add_string_attrib(struct ias_object *obj, char *name, char *value, attrib = kzalloc(sizeof( struct ias_attrib), GFP_ATOMIC); if (attrib == NULL) { IRDA_WARNING("%s: Unable to allocate attribute!\n", - __FUNCTION__); + __func__); return; } @@ -418,7 +418,7 @@ void irias_add_string_attrib(struct ias_object *obj, char *name, char *value, attrib->value = irias_new_string_value(value); if (!attrib->name || !attrib->value) { IRDA_WARNING("%s: Unable to allocate attribute!\n", - __FUNCTION__); + __func__); if (attrib->value) irias_delete_value(attrib->value); kfree(attrib->name); @@ -442,7 +442,7 @@ struct ias_value *irias_new_integer_value(int integer) value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); if (value == NULL) { - IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__); + IRDA_WARNING("%s: Unable to kmalloc!\n", __func__); return NULL; } @@ -467,7 +467,7 @@ struct ias_value *irias_new_string_value(char *string) value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); if (value == NULL) { - IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__); + IRDA_WARNING("%s: Unable to kmalloc!\n", __func__); return NULL; } @@ -475,7 +475,7 @@ struct ias_value *irias_new_string_value(char *string) value->charset = CS_ASCII; value->t.string = kstrndup(string, IAS_MAX_STRING, GFP_ATOMIC); if (!value->t.string) { - IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__); + IRDA_WARNING("%s: Unable to kmalloc!\n", __func__); kfree(value); return NULL; } @@ -498,7 +498,7 @@ struct ias_value *irias_new_octseq_value(__u8 *octseq , int len) value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); if (value == NULL) { - IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__); + IRDA_WARNING("%s: Unable to kmalloc!\n", __func__); return NULL; } @@ -510,7 +510,7 @@ struct ias_value *irias_new_octseq_value(__u8 *octseq , int len) value->t.oct_seq = kmemdup(octseq, len, GFP_ATOMIC); if (value->t.oct_seq == NULL){ - IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__); + IRDA_WARNING("%s: Unable to kmalloc!\n", __func__); kfree(value); return NULL; } @@ -523,7 +523,7 @@ struct ias_value *irias_new_missing_value(void) value = kzalloc(sizeof(struct ias_value), GFP_ATOMIC); if (value == NULL) { - IRDA_WARNING("%s: Unable to kmalloc!\n", __FUNCTION__); + IRDA_WARNING("%s: Unable to kmalloc!\n", __func__); return NULL; } @@ -540,7 +540,7 @@ struct ias_value *irias_new_missing_value(void) */ void irias_delete_value(struct ias_value *value) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(value != NULL, return;); @@ -558,7 +558,7 @@ void irias_delete_value(struct ias_value *value) kfree(value->t.oct_seq); break; default: - IRDA_DEBUG(0, "%s(), Unknown value type!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Unknown value type!\n", __func__); break; } kfree(value); diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c index fff52d57a200..6be1ec26b30c 100644 --- a/net/irda/irlan/irlan_client.c +++ b/net/irda/irlan/irlan_client.c @@ -72,7 +72,7 @@ static void irlan_client_kick_timer_expired(void *data) { struct irlan_cb *self = (struct irlan_cb *) data; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -91,7 +91,7 @@ static void irlan_client_kick_timer_expired(void *data) static void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); irda_start_timer(&self->client.kick_timer, timeout, (void *) self, irlan_client_kick_timer_expired); @@ -105,7 +105,7 @@ static void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout) */ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr) { - IRDA_DEBUG(1, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -117,7 +117,7 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr) if ((self->client.state != IRLAN_IDLE) || (self->provider.access_type == ACCESS_DIRECT)) { - IRDA_DEBUG(0, "%s(), already awake!\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), already awake!\n", __func__ ); return; } @@ -126,7 +126,7 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr) self->daddr = daddr; if (self->disconnect_reason == LM_USER_REQUEST) { - IRDA_DEBUG(0, "%s(), still stopped by user\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s(), still stopped by user\n", __func__ ); return; } @@ -153,7 +153,7 @@ void irlan_client_discovery_indication(discinfo_t *discovery, struct irlan_cb *self; __u32 saddr, daddr; - IRDA_DEBUG(1, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s()\n", __func__ ); IRDA_ASSERT(discovery != NULL, return;); @@ -175,7 +175,7 @@ void irlan_client_discovery_indication(discinfo_t *discovery, if (self) { IRDA_ASSERT(self->magic == IRLAN_MAGIC, goto out;); - IRDA_DEBUG(1, "%s(), Found instance (%08x)!\n", __FUNCTION__ , + IRDA_DEBUG(1, "%s(), Found instance (%08x)!\n", __func__ , daddr); irlan_client_wakeup(self, saddr, daddr); @@ -195,7 +195,7 @@ static int irlan_client_ctrl_data_indication(void *instance, void *sap, { struct irlan_cb *self; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); self = (struct irlan_cb *) instance; @@ -206,7 +206,7 @@ static int irlan_client_ctrl_data_indication(void *instance, void *sap, irlan_do_client_event(self, IRLAN_DATA_INDICATION, skb); /* Ready for a new command */ - IRDA_DEBUG(2, "%s(), clearing tx_busy\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), clearing tx_busy\n", __func__ ); self->client.tx_busy = FALSE; /* Check if we have some queued commands waiting to be sent */ @@ -223,7 +223,7 @@ static void irlan_client_ctrl_disconnect_indication(void *instance, void *sap, struct tsap_cb *tsap; struct sk_buff *skb; - IRDA_DEBUG(4, "%s(), reason=%d\n", __FUNCTION__ , reason); + IRDA_DEBUG(4, "%s(), reason=%d\n", __func__ , reason); self = (struct irlan_cb *) instance; tsap = (struct tsap_cb *) sap; @@ -255,7 +255,7 @@ static void irlan_client_open_ctrl_tsap(struct irlan_cb *self) struct tsap_cb *tsap; notify_t notify; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -275,7 +275,7 @@ static void irlan_client_open_ctrl_tsap(struct irlan_cb *self) tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify); if (!tsap) { - IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ ); return; } self->client.tsap_ctrl = tsap; @@ -295,7 +295,7 @@ static void irlan_client_ctrl_connect_confirm(void *instance, void *sap, { struct irlan_cb *self; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); self = (struct irlan_cb *) instance; @@ -374,13 +374,13 @@ void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb) IRDA_ASSERT(skb != NULL, return;); - IRDA_DEBUG(4, "%s() skb->len=%d\n", __FUNCTION__ , (int) skb->len); + IRDA_DEBUG(4, "%s() skb->len=%d\n", __func__ , (int) skb->len); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); if (!skb) { - IRDA_ERROR("%s(), Got NULL skb!\n", __FUNCTION__); + IRDA_ERROR("%s(), Got NULL skb!\n", __func__); return; } frame = skb->data; @@ -405,7 +405,7 @@ void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb) /* How many parameters? */ count = frame[1]; - IRDA_DEBUG(4, "%s(), got %d parameters\n", __FUNCTION__ , count); + IRDA_DEBUG(4, "%s(), got %d parameters\n", __func__ , count); ptr = frame+2; @@ -413,7 +413,7 @@ void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb) for (i=0; imagic == IRLAN_MAGIC, return;); @@ -476,7 +476,7 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param, else if (strcmp(value, "HOSTED") == 0) self->client.access_type = ACCESS_HOSTED; else { - IRDA_DEBUG(2, "%s(), unknown access type!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), unknown access type!\n", __func__ ); } } /* IRLAN version */ @@ -498,14 +498,14 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param, memcpy(&tmp_cpu, value, 2); /* Align value */ le16_to_cpus(&tmp_cpu); /* Convert to host order */ self->client.recv_arb_val = tmp_cpu; - IRDA_DEBUG(2, "%s(), receive arb val=%d\n", __FUNCTION__ , + IRDA_DEBUG(2, "%s(), receive arb val=%d\n", __func__ , self->client.recv_arb_val); } if (strcmp(param, "MAX_FRAME") == 0) { memcpy(&tmp_cpu, value, 2); /* Align value */ le16_to_cpus(&tmp_cpu); /* Convert to host order */ self->client.max_frame = tmp_cpu; - IRDA_DEBUG(4, "%s(), max frame=%d\n", __FUNCTION__ , + IRDA_DEBUG(4, "%s(), max frame=%d\n", __func__ , self->client.max_frame); } @@ -539,7 +539,7 @@ void irlan_client_get_value_confirm(int result, __u16 obj_id, { struct irlan_cb *self; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(priv != NULL, return;); @@ -552,7 +552,7 @@ void irlan_client_get_value_confirm(int result, __u16 obj_id, /* Check if request succeeded */ if (result != IAS_SUCCESS) { - IRDA_DEBUG(2, "%s(), got NULL value!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), got NULL value!\n", __func__ ); irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL); return; @@ -570,7 +570,7 @@ void irlan_client_get_value_confirm(int result, __u16 obj_id, irias_delete_value(value); break; default: - IRDA_DEBUG(2, "%s(), unknown type!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), unknown type!\n", __func__ ); break; } irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL); diff --git a/net/irda/irlan/irlan_client_event.c b/net/irda/irlan/irlan_client_event.c index 6afcee59e906..8d5a8ebc444f 100644 --- a/net/irda/irlan/irlan_client_event.c +++ b/net/irda/irlan/irlan_client_event.c @@ -92,7 +92,7 @@ void irlan_do_client_event(struct irlan_cb *self, IRLAN_EVENT event, static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); @@ -101,7 +101,7 @@ static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event, case IRLAN_DISCOVERY_INDICATION: if (self->client.iriap) { IRDA_WARNING("%s(), busy with a previous query\n", - __FUNCTION__); + __func__); return -EBUSY; } @@ -114,10 +114,10 @@ static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event, "IrLAN", "IrDA:TinyTP:LsapSel"); break; case IRLAN_WATCHDOG_TIMEOUT: - IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ ); break; default: - IRDA_DEBUG(4, "%s(), Unknown event %d\n", __FUNCTION__ , event); + IRDA_DEBUG(4, "%s(), Unknown event %d\n", __func__ , event); break; } if (skb) @@ -136,7 +136,7 @@ static int irlan_client_state_idle(struct irlan_cb *self, IRLAN_EVENT event, static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); @@ -154,7 +154,7 @@ static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_client_state(self, IRLAN_CONN); break; case IRLAN_IAS_PROVIDER_NOT_AVAIL: - IRDA_DEBUG(2, "%s(), IAS_PROVIDER_NOT_AVAIL\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IAS_PROVIDER_NOT_AVAIL\n", __func__ ); irlan_next_client_state(self, IRLAN_IDLE); /* Give the client a kick! */ @@ -167,10 +167,10 @@ static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_client_state(self, IRLAN_IDLE); break; case IRLAN_WATCHDOG_TIMEOUT: - IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ ); break; default: - IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); + IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event); break; } if (skb) @@ -189,7 +189,7 @@ static int irlan_client_state_query(struct irlan_cb *self, IRLAN_EVENT event, static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); @@ -204,10 +204,10 @@ static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_client_state(self, IRLAN_IDLE); break; case IRLAN_WATCHDOG_TIMEOUT: - IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ ); break; default: - IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); + IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event); break; } if (skb) @@ -224,7 +224,7 @@ static int irlan_client_state_conn(struct irlan_cb *self, IRLAN_EVENT event, static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); @@ -244,10 +244,10 @@ static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_client_state(self, IRLAN_IDLE); break; case IRLAN_WATCHDOG_TIMEOUT: - IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ ); break; default: - IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); + IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event); break; } if (skb) @@ -266,7 +266,7 @@ static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event, static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); @@ -281,10 +281,10 @@ static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_client_state(self, IRLAN_IDLE); break; case IRLAN_WATCHDOG_TIMEOUT: - IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ ); break; default: - IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); + IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event); break; } if (skb) @@ -305,7 +305,7 @@ static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event, { struct qos_info qos; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); @@ -344,7 +344,7 @@ static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_client_state(self, IRLAN_DATA); break; default: - IRDA_DEBUG(2, "%s(), unknown access type!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), unknown access type!\n", __func__ ); break; } break; @@ -353,10 +353,10 @@ static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_client_state(self, IRLAN_IDLE); break; case IRLAN_WATCHDOG_TIMEOUT: - IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ ); break; default: - IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); + IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event); break; } @@ -376,7 +376,7 @@ static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event, static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); @@ -390,10 +390,10 @@ static int irlan_client_state_wait(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_client_state(self, IRLAN_IDLE); break; case IRLAN_WATCHDOG_TIMEOUT: - IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ ); break; default: - IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); + IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event); break; } if (skb) @@ -407,7 +407,7 @@ static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event, { struct qos_info qos; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); @@ -429,7 +429,7 @@ static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event, } else if (self->client.recv_arb_val > self->provider.send_arb_val) { - IRDA_DEBUG(2, "%s(), lost the battle :-(\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), lost the battle :-(\n", __func__ ); } break; case IRLAN_DATA_CONNECT_INDICATION: @@ -440,10 +440,10 @@ static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_client_state(self, IRLAN_IDLE); break; case IRLAN_WATCHDOG_TIMEOUT: - IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IRLAN_WATCHDOG_TIMEOUT\n", __func__ ); break; default: - IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); + IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event); break; } if (skb) @@ -462,7 +462,7 @@ static int irlan_client_state_arb(struct irlan_cb *self, IRLAN_EVENT event, static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); @@ -476,7 +476,7 @@ static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_client_state(self, IRLAN_IDLE); break; default: - IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); + IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event); break; } if (skb) @@ -494,7 +494,7 @@ static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event, static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); if (skb) dev_kfree_skb(skb); @@ -511,7 +511,7 @@ static int irlan_client_state_close(struct irlan_cb *self, IRLAN_EVENT event, static int irlan_client_state_sync(struct irlan_cb *self, IRLAN_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); if (skb) dev_kfree_skb(skb); diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c index 1eb4bbcb1c9e..75bb6a9dcaaa 100644 --- a/net/irda/irlan/irlan_common.c +++ b/net/irda/irlan/irlan_common.c @@ -124,7 +124,7 @@ static int __init irlan_init(void) struct irlan_cb *new; __u16 hints; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); #ifdef CONFIG_PROC_FS { struct proc_dir_entry *proc; @@ -136,7 +136,7 @@ static int __init irlan_init(void) } #endif /* CONFIG_PROC_FS */ - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); hints = irlmp_service_to_hint(S_LAN); /* Register with IrLMP as a client */ @@ -179,7 +179,7 @@ static void __exit irlan_cleanup(void) { struct irlan_cb *self, *next; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); irlmp_unregister_client(ckey); irlmp_unregister_service(skey); @@ -207,7 +207,7 @@ static struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr) struct net_device *dev; struct irlan_cb *self; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); /* Create network device with irlan */ dev = alloc_irlandev(eth ? "eth%d" : "irlan%d"); @@ -252,7 +252,7 @@ static struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr) if (register_netdev(dev)) { IRDA_DEBUG(2, "%s(), register_netdev() failed!\n", - __FUNCTION__ ); + __func__ ); self = NULL; free_netdev(dev); } else { @@ -272,7 +272,7 @@ static struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr) */ static void __irlan_close(struct irlan_cb *self) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); ASSERT_RTNL(); IRDA_ASSERT(self != NULL, return;); @@ -320,7 +320,7 @@ static void irlan_connect_indication(void *instance, void *sap, struct irlan_cb *self; struct tsap_cb *tsap; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); self = (struct irlan_cb *) instance; tsap = (struct tsap_cb *) sap; @@ -332,7 +332,7 @@ static void irlan_connect_indication(void *instance, void *sap, self->max_sdu_size = max_sdu_size; self->max_header_size = max_header_size; - IRDA_DEBUG(0, "%s: We are now connected!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s: We are now connected!\n", __func__); del_timer(&self->watchdog_timer); @@ -376,7 +376,7 @@ static void irlan_connect_confirm(void *instance, void *sap, /* TODO: we could set the MTU depending on the max_sdu_size */ - IRDA_DEBUG(0, "%s: We are now connected!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s: We are now connected!\n", __func__); del_timer(&self->watchdog_timer); /* @@ -412,7 +412,7 @@ static void irlan_disconnect_indication(void *instance, struct irlan_cb *self; struct tsap_cb *tsap; - IRDA_DEBUG(0, "%s(), reason=%d\n", __FUNCTION__ , reason); + IRDA_DEBUG(0, "%s(), reason=%d\n", __func__ , reason); self = (struct irlan_cb *) instance; tsap = (struct tsap_cb *) sap; @@ -431,22 +431,22 @@ static void irlan_disconnect_indication(void *instance, switch (reason) { case LM_USER_REQUEST: /* User request */ - IRDA_DEBUG(2, "%s(), User requested\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), User requested\n", __func__ ); break; case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */ - IRDA_DEBUG(2, "%s(), Unexpected IrLAP disconnect\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), Unexpected IrLAP disconnect\n", __func__ ); break; case LM_CONNECT_FAILURE: /* Failed to establish IrLAP connection */ - IRDA_DEBUG(2, "%s(), IrLAP connect failed\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IrLAP connect failed\n", __func__ ); break; case LM_LAP_RESET: /* IrLAP reset */ - IRDA_DEBUG(2, "%s(), IrLAP reset\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IrLAP reset\n", __func__ ); break; case LM_INIT_DISCONNECT: - IRDA_DEBUG(2, "%s(), IrLMP connect failed\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IrLMP connect failed\n", __func__ ); break; default: - IRDA_ERROR("%s(), Unknown disconnect reason\n", __FUNCTION__); + IRDA_ERROR("%s(), Unknown disconnect reason\n", __func__); break; } @@ -468,7 +468,7 @@ void irlan_open_data_tsap(struct irlan_cb *self) struct tsap_cb *tsap; notify_t notify; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -490,7 +490,7 @@ void irlan_open_data_tsap(struct irlan_cb *self) tsap = irttp_open_tsap(LSAP_ANY, DEFAULT_INITIAL_CREDIT, ¬ify); if (!tsap) { - IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ ); return; } self->tsap_data = tsap; @@ -504,7 +504,7 @@ void irlan_open_data_tsap(struct irlan_cb *self) void irlan_close_tsaps(struct irlan_cb *self) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -594,7 +594,7 @@ int irlan_run_ctrl_tx_queue(struct irlan_cb *self) { struct sk_buff *skb; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); if (irda_lock(&self->client.tx_busy) == FALSE) return -EBUSY; @@ -613,7 +613,7 @@ int irlan_run_ctrl_tx_queue(struct irlan_cb *self) dev_kfree_skb(skb); return -1; } - IRDA_DEBUG(2, "%s(), sending ...\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), sending ...\n", __func__ ); return irttp_data_request(self->client.tsap_ctrl, skb); } @@ -626,7 +626,7 @@ int irlan_run_ctrl_tx_queue(struct irlan_cb *self) */ static void irlan_ctrl_data_request(struct irlan_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); /* Queue command */ skb_queue_tail(&self->client.txq, skb); @@ -646,7 +646,7 @@ void irlan_get_provider_info(struct irlan_cb *self) struct sk_buff *skb; __u8 *frame; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -679,7 +679,7 @@ void irlan_open_data_channel(struct irlan_cb *self) struct sk_buff *skb; __u8 *frame; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -714,7 +714,7 @@ void irlan_close_data_channel(struct irlan_cb *self) struct sk_buff *skb; __u8 *frame; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -755,7 +755,7 @@ static void irlan_open_unicast_addr(struct irlan_cb *self) struct sk_buff *skb; __u8 *frame; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -797,7 +797,7 @@ void irlan_set_broadcast_filter(struct irlan_cb *self, int status) struct sk_buff *skb; __u8 *frame; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -841,7 +841,7 @@ void irlan_set_multicast_filter(struct irlan_cb *self, int status) struct sk_buff *skb; __u8 *frame; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -886,7 +886,7 @@ static void irlan_get_unicast_addr(struct irlan_cb *self) struct sk_buff *skb; __u8 *frame; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -926,7 +926,7 @@ void irlan_get_media_char(struct irlan_cb *self) struct sk_buff *skb; __u8 *frame; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -1014,7 +1014,7 @@ static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, int n=0; if (skb == NULL) { - IRDA_DEBUG(2, "%s(), Got NULL skb\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), Got NULL skb\n", __func__ ); return 0; } @@ -1031,7 +1031,7 @@ static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, IRDA_ASSERT(value_len > 0, return 0;); break; default: - IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), Unknown parameter type!\n", __func__ ); return 0; break; } @@ -1041,7 +1041,7 @@ static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, /* Make space for data */ if (skb_tailroom(skb) < (param_len+value_len+3)) { - IRDA_DEBUG(2, "%s(), No more space at end of skb\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), No more space at end of skb\n", __func__ ); return 0; } skb_put(skb, param_len+value_len+3); @@ -1088,13 +1088,13 @@ int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len) __u16 val_len; int n=0; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); /* get length of parameter name (1 byte) */ name_len = buf[n++]; if (name_len > 254) { - IRDA_DEBUG(2, "%s(), name_len > 254\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), name_len > 254\n", __func__ ); return -RSP_INVALID_COMMAND_FORMAT; } @@ -1111,7 +1111,7 @@ int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len) le16_to_cpus(&val_len); n+=2; if (val_len > 1016) { - IRDA_DEBUG(2, "%s(), parameter length to long\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), parameter length to long\n", __func__ ); return -RSP_INVALID_COMMAND_FORMAT; } *len = val_len; diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index 1ab91f787cc1..7a6b14ab1e7f 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -103,7 +103,7 @@ static int irlan_eth_open(struct net_device *dev) { struct irlan_cb *self = netdev_priv(dev); - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); /* Ready to play! */ netif_stop_queue(dev); /* Wait until data link is ready */ @@ -130,7 +130,7 @@ static int irlan_eth_close(struct net_device *dev) { struct irlan_cb *self = netdev_priv(dev); - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); /* Stop device */ netif_stop_queue(dev); @@ -221,7 +221,7 @@ int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb) } if (skb->len < ETH_HLEN) { IRDA_DEBUG(0, "%s() : IrLAN frame too short (%d)\n", - __FUNCTION__, skb->len); + __func__, skb->len); ++self->stats.rx_dropped; dev_kfree_skb(skb); return 0; @@ -270,7 +270,7 @@ void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) IRDA_ASSERT(dev != NULL, return;); - IRDA_DEBUG(0, "%s() : flow %s ; running %d\n", __FUNCTION__, + IRDA_DEBUG(0, "%s() : flow %s ; running %d\n", __func__, flow == FLOW_STOP ? "FLOW_STOP" : "FLOW_START", netif_running(dev)); @@ -332,11 +332,11 @@ static void irlan_eth_set_multicast_list(struct net_device *dev) { struct irlan_cb *self = netdev_priv(dev); - IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s()\n", __func__ ); /* Check if data channel has been connected yet */ if (self->client.state != IRLAN_DATA) { - IRDA_DEBUG(1, "%s(), delaying!\n", __FUNCTION__ ); + IRDA_DEBUG(1, "%s(), delaying!\n", __func__ ); return; } @@ -346,20 +346,20 @@ static void irlan_eth_set_multicast_list(struct net_device *dev) } else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > HW_MAX_ADDRS) { /* Disable promiscuous mode, use normal mode. */ - IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ ); /* hardware_set_filter(NULL); */ irlan_set_multicast_filter(self, TRUE); } else if (dev->mc_count) { - IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s(), Setting multicast filter\n", __func__ ); /* Walk the address list, and load the filter */ /* hardware_set_filter(dev->mc_list); */ irlan_set_multicast_filter(self, TRUE); } else { - IRDA_DEBUG(4, "%s(), Clearing multicast filter\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s(), Clearing multicast filter\n", __func__ ); irlan_set_multicast_filter(self, FALSE); } diff --git a/net/irda/irlan/irlan_event.c b/net/irda/irlan/irlan_event.c index a9750a801388..cbcb4eb54037 100644 --- a/net/irda/irlan/irlan_event.c +++ b/net/irda/irlan/irlan_event.c @@ -40,7 +40,7 @@ char *irlan_state[] = { void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state) { - IRDA_DEBUG(2, "%s(), %s\n", __FUNCTION__ , irlan_state[state]); + IRDA_DEBUG(2, "%s(), %s\n", __func__ , irlan_state[state]); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -50,7 +50,7 @@ void irlan_next_client_state(struct irlan_cb *self, IRLAN_STATE state) void irlan_next_provider_state(struct irlan_cb *self, IRLAN_STATE state) { - IRDA_DEBUG(2, "%s(), %s\n", __FUNCTION__ , irlan_state[state]); + IRDA_DEBUG(2, "%s(), %s\n", __func__ , irlan_state[state]); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;); diff --git a/net/irda/irlan/irlan_filter.c b/net/irda/irlan/irlan_filter.c index 4384be9a6888..9ff7823abec7 100644 --- a/net/irda/irlan/irlan_filter.c +++ b/net/irda/irlan/irlan_filter.c @@ -145,7 +145,7 @@ void irlan_check_command_param(struct irlan_cb *self, char *param, char *value) { __u8 *bytes; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); bytes = value; @@ -158,7 +158,7 @@ void irlan_check_command_param(struct irlan_cb *self, char *param, char *value) * This is experimental!! DB. */ if (strcmp(param, "MODE") == 0) { - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); self->use_udata = TRUE; return; } diff --git a/net/irda/irlan/irlan_provider.c b/net/irda/irlan/irlan_provider.c index 13db942812e4..3f81f81b2dfa 100644 --- a/net/irda/irlan/irlan_provider.c +++ b/net/irda/irlan/irlan_provider.c @@ -70,7 +70,7 @@ static int irlan_provider_data_indication(void *instance, void *sap, struct irlan_cb *self; __u8 code; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); self = (struct irlan_cb *) instance; @@ -99,15 +99,15 @@ static int irlan_provider_data_indication(void *instance, void *sap, irlan_do_provider_event(self, IRLAN_FILTER_CONFIG_CMD, skb); break; case CMD_RECONNECT_DATA_CHAN: - IRDA_DEBUG(2, "%s(), Got RECONNECT_DATA_CHAN command\n", __FUNCTION__ ); - IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), Got RECONNECT_DATA_CHAN command\n", __func__ ); + IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __func__ ); break; case CMD_CLOSE_DATA_CHAN: IRDA_DEBUG(2, "Got CLOSE_DATA_CHAN command!\n"); - IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), NOT IMPLEMENTED\n", __func__ ); break; default: - IRDA_DEBUG(2, "%s(), Unknown command!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), Unknown command!\n", __func__ ); break; } return 0; @@ -129,7 +129,7 @@ static void irlan_provider_connect_indication(void *instance, void *sap, struct tsap_cb *tsap; __u32 saddr, daddr; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(0, "%s()\n", __func__ ); self = (struct irlan_cb *) instance; tsap = (struct tsap_cb *) sap; @@ -182,7 +182,7 @@ static void irlan_provider_disconnect_indication(void *instance, void *sap, struct irlan_cb *self; struct tsap_cb *tsap; - IRDA_DEBUG(4, "%s(), reason=%d\n", __FUNCTION__ , reason); + IRDA_DEBUG(4, "%s(), reason=%d\n", __func__ , reason); self = (struct irlan_cb *) instance; tsap = (struct tsap_cb *) sap; @@ -236,7 +236,7 @@ int irlan_provider_parse_command(struct irlan_cb *self, int cmd, IRDA_ASSERT(skb != NULL, return -RSP_PROTOCOL_ERROR;); - IRDA_DEBUG(4, "%s(), skb->len=%d\n", __FUNCTION__ , (int)skb->len); + IRDA_DEBUG(4, "%s(), skb->len=%d\n", __func__ , (int)skb->len); IRDA_ASSERT(self != NULL, return -RSP_PROTOCOL_ERROR;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -RSP_PROTOCOL_ERROR;); @@ -266,7 +266,7 @@ int irlan_provider_parse_command(struct irlan_cb *self, int cmd, for (i=0; imagic == IRLAN_MAGIC, return;); @@ -323,7 +323,7 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command, irlan_insert_string_param(skb, "MEDIA", "802.5"); break; default: - IRDA_DEBUG(2, "%s(), unknown media type!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), unknown media type!\n", __func__ ); break; } irlan_insert_short_param(skb, "IRLAN_VER", 0x0101); @@ -347,7 +347,7 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command, irlan_insert_string_param(skb, "ACCESS_TYPE", "HOSTED"); break; default: - IRDA_DEBUG(2, "%s(), Unknown access type\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), Unknown access type\n", __func__ ); break; } irlan_insert_short_param(skb, "MAX_FRAME", 0x05ee); @@ -367,7 +367,7 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command, irlan_filter_request(self, skb); break; default: - IRDA_DEBUG(2, "%s(), Unknown command!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), Unknown command!\n", __func__ ); break; } @@ -385,7 +385,7 @@ int irlan_provider_open_ctrl_tsap(struct irlan_cb *self) struct tsap_cb *tsap; notify_t notify; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); @@ -406,7 +406,7 @@ int irlan_provider_open_ctrl_tsap(struct irlan_cb *self) tsap = irttp_open_tsap(LSAP_ANY, 1, ¬ify); if (!tsap) { - IRDA_DEBUG(2, "%s(), Got no tsap!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), Got no tsap!\n", __func__ ); return -1; } self->provider.tsap_ctrl = tsap; diff --git a/net/irda/irlan/irlan_provider_event.c b/net/irda/irlan/irlan_provider_event.c index 10ece5a47522..01a9d7c993ee 100644 --- a/net/irda/irlan/irlan_provider_event.c +++ b/net/irda/irlan/irlan_provider_event.c @@ -72,7 +72,7 @@ void irlan_do_provider_event(struct irlan_cb *self, IRLAN_EVENT event, static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); @@ -82,7 +82,7 @@ static int irlan_provider_state_idle(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_provider_state( self, IRLAN_INFO); break; default: - IRDA_DEBUG(4, "%s(), Unknown event %d\n", __FUNCTION__ , event); + IRDA_DEBUG(4, "%s(), Unknown event %d\n", __func__ , event); break; } if (skb) @@ -101,7 +101,7 @@ static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event, { int ret; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); @@ -147,7 +147,7 @@ static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_provider_state(self, IRLAN_IDLE); break; default: - IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __FUNCTION__ , event); + IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __func__ , event); break; } if (skb) @@ -166,7 +166,7 @@ static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event, static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); @@ -186,7 +186,7 @@ static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_provider_state(self, IRLAN_IDLE); break; default: - IRDA_DEBUG(2, "%s(), Unknown event %d\n", __FUNCTION__ , event); + IRDA_DEBUG(2, "%s(), Unknown event %d\n", __func__ , event); break; } if (skb) @@ -205,7 +205,7 @@ static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event, static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); + IRDA_DEBUG(4, "%s()\n", __func__ ); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == IRLAN_MAGIC, return -1;); @@ -221,7 +221,7 @@ static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event, irlan_next_provider_state(self, IRLAN_IDLE); break; default: - IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __FUNCTION__ , event); + IRDA_DEBUG( 0, "%s(), Unknown event %d\n", __func__ , event); break; } if (skb) diff --git a/net/irda/irlap.c b/net/irda/irlap.c index f3236acc8d22..e4965b764b9b 100644 --- a/net/irda/irlap.c +++ b/net/irda/irlap.c @@ -88,7 +88,7 @@ int __init irlap_init(void) irlap = hashbin_new(HB_LOCK); if (irlap == NULL) { IRDA_ERROR("%s: can't allocate irlap hashbin!\n", - __FUNCTION__); + __func__); return -ENOMEM; } @@ -113,7 +113,7 @@ struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos, { struct irlap_cb *self; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); /* Initialize the irlap structure. */ self = kzalloc(sizeof(struct irlap_cb), GFP_KERNEL); @@ -215,7 +215,7 @@ void irlap_close(struct irlap_cb *self) { struct irlap_cb *lap; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -231,7 +231,7 @@ void irlap_close(struct irlap_cb *self) /* Be sure that we manage to remove ourself from the hash */ lap = hashbin_remove(irlap, self->saddr, NULL); if (!lap) { - IRDA_DEBUG(1, "%s(), Didn't find myself!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Didn't find myself!\n", __func__); return; } __irlap_close(lap); @@ -246,7 +246,7 @@ EXPORT_SYMBOL(irlap_close); */ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -265,7 +265,7 @@ void irlap_connect_indication(struct irlap_cb *self, struct sk_buff *skb) */ void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); irlap_do_event(self, CONNECT_RESPONSE, userdata, NULL); } @@ -280,7 +280,7 @@ void irlap_connect_response(struct irlap_cb *self, struct sk_buff *userdata) void irlap_connect_request(struct irlap_cb *self, __u32 daddr, struct qos_info *qos_user, int sniff) { - IRDA_DEBUG(3, "%s(), daddr=0x%08x\n", __FUNCTION__, daddr); + IRDA_DEBUG(3, "%s(), daddr=0x%08x\n", __func__, daddr); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -307,7 +307,7 @@ void irlap_connect_request(struct irlap_cb *self, __u32 daddr, */ void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -344,7 +344,7 @@ void irlap_data_request(struct irlap_cb *self, struct sk_buff *skb, IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), return;); @@ -391,7 +391,7 @@ void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb) IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(skb_headroom(skb) >= (LAP_ADDR_HEADER+LAP_CTRL_HEADER), return;); @@ -417,7 +417,7 @@ void irlap_unitdata_request(struct irlap_cb *self, struct sk_buff *skb) #ifdef CONFIG_IRDA_ULTRA void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -437,7 +437,7 @@ void irlap_unitdata_indication(struct irlap_cb *self, struct sk_buff *skb) */ void irlap_disconnect_request(struct irlap_cb *self) { - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -458,7 +458,7 @@ void irlap_disconnect_request(struct irlap_cb *self) irlap_do_event(self, DISCONNECT_REQUEST, NULL, NULL); break; default: - IRDA_DEBUG(2, "%s(), disconnect pending!\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), disconnect pending!\n", __func__); self->disconnect_pending = TRUE; break; } @@ -472,7 +472,7 @@ void irlap_disconnect_request(struct irlap_cb *self) */ void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason) { - IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, lap_reasons[reason]); + IRDA_DEBUG(1, "%s(), reason=%s\n", __func__, lap_reasons[reason]); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -482,7 +482,7 @@ void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason) switch (reason) { case LAP_RESET_INDICATION: - IRDA_DEBUG(1, "%s(), Sending reset request!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Sending reset request!\n", __func__); irlap_do_event(self, RESET_REQUEST, NULL, NULL); break; case LAP_NO_RESPONSE: /* FALLTROUGH */ @@ -493,7 +493,7 @@ void irlap_disconnect_indication(struct irlap_cb *self, LAP_REASON reason) reason, NULL); break; default: - IRDA_ERROR("%s: Unknown reason %d\n", __FUNCTION__, reason); + IRDA_ERROR("%s: Unknown reason %d\n", __func__, reason); } } @@ -511,7 +511,7 @@ void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery) IRDA_ASSERT(self->magic == LAP_MAGIC, return;); IRDA_ASSERT(discovery != NULL, return;); - IRDA_DEBUG(4, "%s(), nslots = %d\n", __FUNCTION__, discovery->nslots); + IRDA_DEBUG(4, "%s(), nslots = %d\n", __func__, discovery->nslots); IRDA_ASSERT((discovery->nslots == 1) || (discovery->nslots == 6) || (discovery->nslots == 8) || (discovery->nslots == 16), @@ -520,7 +520,7 @@ void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery) /* Discovery is only possible in NDM mode */ if (self->state != LAP_NDM) { IRDA_DEBUG(4, "%s(), discovery only possible in NDM mode\n", - __FUNCTION__); + __func__); irlap_discovery_confirm(self, NULL); /* Note : in theory, if we are not in NDM, we could postpone * the discovery like we do for connection request. @@ -543,7 +543,7 @@ void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery) if (self->discovery_log == NULL) { IRDA_WARNING("%s(), Unable to allocate discovery log!\n", - __FUNCTION__); + __func__); return; } @@ -598,7 +598,7 @@ void irlap_discovery_confirm(struct irlap_cb *self, hashbin_t *discovery_log) */ void irlap_discovery_indication(struct irlap_cb *self, discovery_t *discovery) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -644,7 +644,7 @@ void irlap_status_indication(struct irlap_cb *self, int quality_of_link) */ void irlap_reset_indication(struct irlap_cb *self) { - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -660,7 +660,7 @@ void irlap_reset_indication(struct irlap_cb *self) */ void irlap_reset_confirm(void) { - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); } /* @@ -760,7 +760,7 @@ int irlap_validate_nr_received(struct irlap_cb *self, int nr) { /* nr as expected? */ if (nr == self->vs) { - IRDA_DEBUG(4, "%s(), expected!\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), expected!\n", __func__); return NR_EXPECTED; } @@ -788,7 +788,7 @@ int irlap_validate_nr_received(struct irlap_cb *self, int nr) */ void irlap_initiate_connection_state(struct irlap_cb *self) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -871,7 +871,7 @@ static void irlap_change_speed(struct irlap_cb *self, __u32 speed, int now) { struct sk_buff *skb; - IRDA_DEBUG(0, "%s(), setting speed to %d\n", __FUNCTION__, speed); + IRDA_DEBUG(0, "%s(), setting speed to %d\n", __func__, speed); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -914,7 +914,7 @@ static void irlap_init_qos_capabilities(struct irlap_cb *self, * user may not have set all of them. */ if (qos_user) { - IRDA_DEBUG(1, "%s(), Found user specified QoS!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Found user specified QoS!\n", __func__); if (qos_user->baud_rate.bits) self->qos_rx.baud_rate.bits &= qos_user->baud_rate.bits; @@ -944,7 +944,7 @@ static void irlap_init_qos_capabilities(struct irlap_cb *self, */ void irlap_apply_default_connection_parameters(struct irlap_cb *self) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -1007,7 +1007,7 @@ void irlap_apply_default_connection_parameters(struct irlap_cb *self) */ void irlap_apply_connection_parameters(struct irlap_cb *self, int now) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c index 6af86eba7463..16c4ef0f5c1a 100644 --- a/net/irda/irlap_event.c +++ b/net/irda/irlap_event.c @@ -217,7 +217,7 @@ static void irlap_start_poll_timer(struct irlap_cb *self, int timeout) } else self->fast_RR = FALSE; - IRDA_DEBUG(3, "%s(), timeout=%d (%ld)\n", __FUNCTION__, timeout, jiffies); + IRDA_DEBUG(3, "%s(), timeout=%d (%ld)\n", __func__, timeout, jiffies); #endif /* CONFIG_IRDA_FAST_RR */ if (timeout == 0) @@ -241,7 +241,7 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, if (!self || self->magic != LAP_MAGIC) return; - IRDA_DEBUG(3, "%s(), event = %s, state = %s\n", __FUNCTION__, + IRDA_DEBUG(3, "%s(), event = %s, state = %s\n", __func__, irlap_event[event], irlap_state[self->state]); ret = (*state[self->state])(self, event, skb, info); @@ -259,7 +259,7 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event, * try to disconnect link if we send any data frames, since * that will change the state away form XMIT */ - IRDA_DEBUG(2, "%s() : queue len = %d\n", __FUNCTION__, + IRDA_DEBUG(2, "%s() : queue len = %d\n", __func__, skb_queue_len(&self->txq)); if (!skb_queue_empty(&self->txq)) { @@ -340,7 +340,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event, * media busy in irlap_connect_request() and * postpone the event... - Jean II */ IRDA_DEBUG(0, "%s(), CONNECT_REQUEST: media busy!\n", - __FUNCTION__); + __func__); /* Always switch state before calling upper layers */ irlap_next_state(self, LAP_NDM); @@ -367,7 +367,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event, irlap_connect_indication(self, skb); } else { IRDA_DEBUG(0, "%s(), SNRM frame does not " - "contain an I field!\n", __FUNCTION__); + "contain an I field!\n", __func__); } break; case DISCOVERY_REQUEST: @@ -375,7 +375,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event, if (self->media_busy) { IRDA_DEBUG(1, "%s(), DISCOVERY_REQUEST: media busy!\n", - __FUNCTION__); + __func__); /* irlap->log.condition = MEDIA_BUSY; */ /* This will make IrLMP try again */ @@ -441,7 +441,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event, * those cases... * Jean II */ - IRDA_DEBUG(1, "%s(), Receiving final discovery request, missed the discovery slots :-(\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Receiving final discovery request, missed the discovery slots :-(\n", __func__); /* Last discovery request -> in the log */ irlap_discovery_indication(self, info->discovery); @@ -520,7 +520,7 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event, /* Only accept broadcast frames in NDM mode */ if (info->caddr != CBROADCAST) { IRDA_DEBUG(0, "%s(), not a broadcast frame!\n", - __FUNCTION__); + __func__); } else irlap_unitdata_indication(self, skb); break; @@ -536,10 +536,10 @@ static int irlap_state_ndm(struct irlap_cb *self, IRLAP_EVENT event, irlap_send_test_frame(self, CBROADCAST, info->daddr, skb); break; case RECV_TEST_RSP: - IRDA_DEBUG(0, "%s() not implemented!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s() not implemented!\n", __func__); break; default: - IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__, irlap_event[event]); ret = -1; @@ -567,13 +567,13 @@ static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event, IRDA_ASSERT(info != NULL, return -1;); IRDA_ASSERT(info->discovery != NULL, return -1;); - IRDA_DEBUG(4, "%s(), daddr=%08x\n", __FUNCTION__, + IRDA_DEBUG(4, "%s(), daddr=%08x\n", __func__, info->discovery->data.daddr); if (!self->discovery_log) { IRDA_WARNING("%s: discovery log is gone! " "maybe the discovery timeout has been set" - " too short?\n", __FUNCTION__); + " too short?\n", __func__); break; } hashbin_insert(self->discovery_log, @@ -598,7 +598,7 @@ static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event, IRDA_ASSERT(info != NULL, return -1;); - IRDA_DEBUG(1, "%s(), Receiving discovery request (s = %d) while performing discovery :-(\n", __FUNCTION__, info->s); + IRDA_DEBUG(1, "%s(), Receiving discovery request (s = %d) while performing discovery :-(\n", __func__, info->s); /* Last discovery request ? */ if (info->s == 0xff) @@ -613,7 +613,7 @@ static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event, */ if (irda_device_is_receiving(self->netdev) && !self->add_wait) { IRDA_DEBUG(2, "%s(), device is slow to answer, " - "waiting some more!\n", __FUNCTION__); + "waiting some more!\n", __func__); irlap_start_slot_timer(self, msecs_to_jiffies(10)); self->add_wait = TRUE; return ret; @@ -649,7 +649,7 @@ static int irlap_state_query(struct irlap_cb *self, IRLAP_EVENT event, } break; default: - IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__, irlap_event[event]); ret = -1; @@ -671,7 +671,7 @@ static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event, discovery_t *discovery_rsp; int ret=0; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); @@ -679,7 +679,7 @@ static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event, switch (event) { case QUERY_TIMER_EXPIRED: IRDA_DEBUG(0, "%s(), QUERY_TIMER_EXPIRED <%ld>\n", - __FUNCTION__, jiffies); + __func__, jiffies); irlap_next_state(self, LAP_NDM); break; case RECV_DISCOVERY_XID_CMD: @@ -717,7 +717,7 @@ static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event, } break; default: - IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __FUNCTION__, + IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __func__, event, irlap_event[event]); ret = -1; @@ -738,7 +738,7 @@ static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event, { int ret = 0; - IRDA_DEBUG(4, "%s(), event=%s\n", __FUNCTION__, irlap_event[ event]); + IRDA_DEBUG(4, "%s(), event=%s\n", __func__, irlap_event[ event]); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); @@ -799,18 +799,18 @@ static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event, break; case RECV_DISCOVERY_XID_CMD: IRDA_DEBUG(3, "%s(), event RECV_DISCOVER_XID_CMD!\n", - __FUNCTION__); + __func__); irlap_next_state(self, LAP_NDM); break; case DISCONNECT_REQUEST: - IRDA_DEBUG(0, "%s(), Disconnect request!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), Disconnect request!\n", __func__); irlap_send_dm_frame(self); irlap_next_state( self, LAP_NDM); irlap_disconnect_indication(self, LAP_DISC_INDICATION); break; default: - IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __FUNCTION__, + IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __func__, event, irlap_event[event]); ret = -1; @@ -832,7 +832,7 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event, { int ret = 0; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); @@ -861,7 +861,7 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event, self->retry_count++; break; case RECV_SNRM_CMD: - IRDA_DEBUG(4, "%s(), SNRM battle!\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), SNRM battle!\n", __func__); IRDA_ASSERT(skb != NULL, return 0;); IRDA_ASSERT(info != NULL, return 0;); @@ -948,7 +948,7 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event, irlap_disconnect_indication(self, LAP_DISC_INDICATION); break; default: - IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __FUNCTION__, + IRDA_DEBUG(1, "%s(), Unknown event %d, %s\n", __func__, event, irlap_event[event]); ret = -1; @@ -966,7 +966,7 @@ static int irlap_state_setup(struct irlap_cb *self, IRLAP_EVENT event, static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event, struct sk_buff *skb, struct irlap_info *info) { - IRDA_DEBUG( 0, "%s(), Unknown event\n", __FUNCTION__); + IRDA_DEBUG( 0, "%s(), Unknown event\n", __func__); return -1; } @@ -1030,7 +1030,7 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event, */ if((!nextfit) && (skb->len > self->bytes_left)) { IRDA_DEBUG(0, "%s(), Not allowed to transmit" - " more bytes!\n", __FUNCTION__); + " more bytes!\n", __func__); /* Requeue the skb */ skb_queue_head(&self->txq, skb_get(skb)); /* @@ -1082,7 +1082,7 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event, #endif /* CONFIG_IRDA_FAST_RR */ } else { IRDA_DEBUG(4, "%s(), Unable to send! remote busy?\n", - __FUNCTION__); + __func__); skb_queue_head(&self->txq, skb_get(skb)); /* @@ -1094,7 +1094,7 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event, break; case POLL_TIMER_EXPIRED: IRDA_DEBUG(3, "%s(), POLL_TIMER_EXPIRED <%ld>\n", - __FUNCTION__, jiffies); + __func__, jiffies); irlap_send_rr_frame(self, CMD_FRAME); /* Return to NRM properly - Jean II */ self->window = self->window_size; @@ -1120,7 +1120,7 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event, break; default: IRDA_DEBUG(0, "%s(), Unknown event %s\n", - __FUNCTION__, irlap_event[event]); + __func__, irlap_event[event]); ret = -EINVAL; break; @@ -1138,7 +1138,7 @@ static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event, { int ret = 0; - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); @@ -1173,7 +1173,7 @@ static int irlap_state_pclose(struct irlap_cb *self, IRLAP_EVENT event, } break; default: - IRDA_DEBUG(1, "%s(), Unknown event %d\n", __FUNCTION__, event); + IRDA_DEBUG(1, "%s(), Unknown event %d\n", __func__, event); ret = -1; break; @@ -1297,7 +1297,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event, } else { IRDA_DEBUG(4, "%s(), missing or duplicate frame!\n", - __FUNCTION__); + __func__); /* Update Nr received */ irlap_update_nr_received(self, info->nr); @@ -1367,7 +1367,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event, (nr_status == NR_UNEXPECTED)) { IRDA_DEBUG(4, "%s(), unexpected nr and ns!\n", - __FUNCTION__); + __func__); if (info->pf) { /* Resend rejected frames */ irlap_resend_rejected_frames(self, CMD_FRAME); @@ -1407,9 +1407,9 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event, } break; } - IRDA_DEBUG(1, "%s(), Not implemented!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Not implemented!\n", __func__); IRDA_DEBUG(1, "%s(), event=%s, ns_status=%d, nr_status=%d\n", - __FUNCTION__, irlap_event[event], ns_status, nr_status); + __func__, irlap_event[event], ns_status, nr_status); break; case RECV_UI_FRAME: /* Poll bit cleared? */ @@ -1420,7 +1420,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event, del_timer(&self->final_timer); irlap_data_indication(self, skb, TRUE); irlap_next_state(self, LAP_XMIT_P); - IRDA_DEBUG(1, "%s: RECV_UI_FRAME: next state %s\n", __FUNCTION__, irlap_state[self->state]); + IRDA_DEBUG(1, "%s: RECV_UI_FRAME: next state %s\n", __func__, irlap_state[self->state]); irlap_start_poll_timer(self, self->poll_timeout); } break; @@ -1475,7 +1475,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event, irlap_next_state(self, LAP_NRM_P); } else if (ret == NR_INVALID) { IRDA_DEBUG(1, "%s(), Received RR with " - "invalid nr !\n", __FUNCTION__); + "invalid nr !\n", __func__); irlap_next_state(self, LAP_RESET_WAIT); @@ -1580,7 +1580,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event, irlap_start_final_timer(self, 2 * self->final_timeout); break; case RECV_RD_RSP: - IRDA_DEBUG(1, "%s(), RECV_RD_RSP\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), RECV_RD_RSP\n", __func__); irlap_flush_all_queues(self); irlap_next_state(self, LAP_XMIT_P); @@ -1589,7 +1589,7 @@ static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event, break; default: IRDA_DEBUG(1, "%s(), Unknown event %s\n", - __FUNCTION__, irlap_event[event]); + __func__, irlap_event[event]); ret = -1; break; @@ -1609,7 +1609,7 @@ static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, { int ret = 0; - IRDA_DEBUG(3, "%s(), event = %s\n", __FUNCTION__, irlap_event[event]); + IRDA_DEBUG(3, "%s(), event = %s\n", __func__, irlap_event[event]); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); @@ -1635,7 +1635,7 @@ static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, irlap_next_state( self, LAP_PCLOSE); break; default: - IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__, irlap_event[event]); ret = -1; @@ -1656,7 +1656,7 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event, { int ret = 0; - IRDA_DEBUG(3, "%s(), event = %s\n", __FUNCTION__, irlap_event[event]); + IRDA_DEBUG(3, "%s(), event = %s\n", __func__, irlap_event[event]); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); @@ -1714,7 +1714,7 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event, * state */ if (!info) { - IRDA_DEBUG(3, "%s(), RECV_SNRM_CMD\n", __FUNCTION__); + IRDA_DEBUG(3, "%s(), RECV_SNRM_CMD\n", __func__); irlap_initiate_connection_state(self); irlap_wait_min_turn_around(self, &self->qos_tx); irlap_send_ua_response_frame(self, &self->qos_rx); @@ -1724,12 +1724,12 @@ static int irlap_state_reset(struct irlap_cb *self, IRLAP_EVENT event, } else { IRDA_DEBUG(0, "%s(), SNRM frame contained an I field!\n", - __FUNCTION__); + __func__); } break; default: IRDA_DEBUG(1, "%s(), Unknown event %s\n", - __FUNCTION__, irlap_event[event]); + __func__, irlap_event[event]); ret = -1; break; @@ -1749,7 +1749,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event, { int ret = 0; - IRDA_DEBUG(4, "%s(), event=%s\n", __FUNCTION__, irlap_event[event]); + IRDA_DEBUG(4, "%s(), event=%s\n", __func__, irlap_event[event]); IRDA_ASSERT(self != NULL, return -ENODEV;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;); @@ -1786,7 +1786,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event, */ if((!nextfit) && (skb->len > self->bytes_left)) { IRDA_DEBUG(0, "%s(), Not allowed to transmit" - " more bytes!\n", __FUNCTION__); + " more bytes!\n", __func__); /* Requeue the skb */ skb_queue_head(&self->txq, skb_get(skb)); @@ -1832,7 +1832,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event, ret = -EPROTO; } } else { - IRDA_DEBUG(2, "%s(), Unable to send!\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), Unable to send!\n", __func__); skb_queue_head(&self->txq, skb_get(skb)); ret = -EPROTO; } @@ -1848,7 +1848,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event, * when we return... - Jean II */ break; default: - IRDA_DEBUG(2, "%s(), Unknown event %s\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), Unknown event %s\n", __func__, irlap_event[event]); ret = -EINVAL; @@ -1871,7 +1871,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event, int nr_status; int ret = 0; - IRDA_DEBUG(4, "%s(), event=%s\n", __FUNCTION__, irlap_event[ event]); + IRDA_DEBUG(4, "%s(), event=%s\n", __func__, irlap_event[ event]); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -1;); @@ -1880,7 +1880,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event, case RECV_I_CMD: /* Optimize for the common case */ /* FIXME: must check for remote_busy below */ IRDA_DEBUG(4, "%s(), event=%s nr=%d, vs=%d, ns=%d, " - "vr=%d, pf=%d\n", __FUNCTION__, + "vr=%d, pf=%d\n", __func__, irlap_event[event], info->nr, self->vs, info->ns, self->vr, info->pf); @@ -2112,21 +2112,21 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event, irlap_next_state(self, LAP_NRM_S); } else { IRDA_DEBUG(1, "%s(), invalid nr not implemented!\n", - __FUNCTION__); + __func__); } break; case RECV_SNRM_CMD: /* SNRM frame is not allowed to contain an I-field */ if (!info) { del_timer(&self->wd_timer); - IRDA_DEBUG(1, "%s(), received SNRM cmd\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), received SNRM cmd\n", __func__); irlap_next_state(self, LAP_RESET_CHECK); irlap_reset_indication(self); } else { IRDA_DEBUG(0, "%s(), SNRM frame contained an I-field!\n", - __FUNCTION__); + __func__); } break; @@ -2158,7 +2158,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event, * which explain why we use (self->N2 / 2) here !!! * Jean II */ - IRDA_DEBUG(1, "%s(), retry_count = %d\n", __FUNCTION__, + IRDA_DEBUG(1, "%s(), retry_count = %d\n", __func__, self->retry_count); if (self->retry_count < (self->N2 / 2)) { @@ -2211,7 +2211,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event, irlap_send_test_frame(self, self->caddr, info->daddr, skb); break; default: - IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __FUNCTION__, + IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__, event, irlap_event[event]); ret = -EINVAL; @@ -2228,7 +2228,7 @@ static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event, { int ret = 0; - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return -ENODEV;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;); @@ -2285,7 +2285,7 @@ static int irlap_state_sclose(struct irlap_cb *self, IRLAP_EVENT event, break; /* stay in SCLOSE */ } - IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __FUNCTION__, + IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__, event, irlap_event[event]); ret = -EINVAL; @@ -2301,7 +2301,7 @@ static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event, { int ret = 0; - IRDA_DEBUG(1, "%s(), event=%s\n", __FUNCTION__, irlap_event[event]); + IRDA_DEBUG(1, "%s(), event=%s\n", __func__, irlap_event[event]); IRDA_ASSERT(self != NULL, return -ENODEV;); IRDA_ASSERT(self->magic == LAP_MAGIC, return -EBADR;); @@ -2322,7 +2322,7 @@ static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event, irlap_next_state(self, LAP_SCLOSE); break; default: - IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __FUNCTION__, + IRDA_DEBUG(1, "%s(), Unknown event %d, (%s)\n", __func__, event, irlap_event[event]); ret = -EINVAL; diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c index 7c132d6342af..a38b231c8689 100644 --- a/net/irda/irlap_frame.c +++ b/net/irda/irlap_frame.c @@ -102,7 +102,7 @@ void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb) irlap_insert_info(self, skb); if (unlikely(self->mode & IRDA_MODE_MONITOR)) { - IRDA_DEBUG(3, "%s(): %s is in monitor mode\n", __FUNCTION__, + IRDA_DEBUG(3, "%s(): %s is in monitor mode\n", __func__, self->netdev->name); dev_kfree_skb(skb); return; @@ -182,7 +182,7 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb, /* Check if the new connection address is valid */ if ((info->caddr == 0x00) || (info->caddr == 0xfe)) { IRDA_DEBUG(3, "%s(), invalid connection address!\n", - __FUNCTION__); + __func__); return; } @@ -193,7 +193,7 @@ static void irlap_recv_snrm_cmd(struct irlap_cb *self, struct sk_buff *skb, /* Only accept if addressed directly to us */ if (info->saddr != self->saddr) { IRDA_DEBUG(2, "%s(), not addressed to us!\n", - __FUNCTION__); + __func__); return; } irlap_do_event(self, RECV_SNRM_CMD, skb, info); @@ -215,7 +215,7 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos) struct ua_frame *frame; int ret; - IRDA_DEBUG(2, "%s() <%ld>\n", __FUNCTION__, jiffies); + IRDA_DEBUG(2, "%s() <%ld>\n", __func__, jiffies); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -290,7 +290,7 @@ void irlap_send_disc_frame(struct irlap_cb *self) struct sk_buff *tx_skb = NULL; struct disc_frame *frame; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -321,7 +321,7 @@ void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s, __u32 bcast = BROADCAST; __u8 *info; - IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __FUNCTION__, + IRDA_DEBUG(4, "%s(), s=%d, S=%d, command=%d\n", __func__, s, S, command); IRDA_ASSERT(self != NULL, return;); @@ -414,13 +414,13 @@ static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self, __u8 *discovery_info; char *text; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); if (!pskb_may_pull(skb, sizeof(struct xid_frame))) { - IRDA_ERROR("%s: frame too short!\n", __FUNCTION__); + IRDA_ERROR("%s: frame too short!\n", __func__); return; } @@ -432,12 +432,12 @@ static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self, /* Make sure frame is addressed to us */ if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) { IRDA_DEBUG(0, "%s(), frame is not addressed to us!\n", - __FUNCTION__); + __func__); return; } if ((discovery = kzalloc(sizeof(discovery_t), GFP_ATOMIC)) == NULL) { - IRDA_WARNING("%s: kmalloc failed!\n", __FUNCTION__); + IRDA_WARNING("%s: kmalloc failed!\n", __func__); return; } @@ -445,7 +445,7 @@ static void irlap_recv_discovery_xid_rsp(struct irlap_cb *self, discovery->data.saddr = self->saddr; discovery->timestamp = jiffies; - IRDA_DEBUG(4, "%s(), daddr=%08x\n", __FUNCTION__, + IRDA_DEBUG(4, "%s(), daddr=%08x\n", __func__, discovery->data.daddr); discovery_info = skb_pull(skb, sizeof(struct xid_frame)); @@ -491,7 +491,7 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, char *text; if (!pskb_may_pull(skb, sizeof(struct xid_frame))) { - IRDA_ERROR("%s: frame too short!\n", __FUNCTION__); + IRDA_ERROR("%s: frame too short!\n", __func__); return; } @@ -503,7 +503,7 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, /* Make sure frame is addressed to us */ if ((info->saddr != self->saddr) && (info->saddr != BROADCAST)) { IRDA_DEBUG(0, "%s(), frame is not addressed to us!\n", - __FUNCTION__); + __func__); return; } @@ -536,7 +536,7 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, if((discovery_info == NULL) || !pskb_may_pull(skb, 3)) { IRDA_ERROR("%s: discovery frame too short!\n", - __FUNCTION__); + __func__); return; } @@ -545,7 +545,7 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self, */ discovery = kmalloc(sizeof(discovery_t), GFP_ATOMIC); if (!discovery) { - IRDA_WARNING("%s: unable to malloc!\n", __FUNCTION__); + IRDA_WARNING("%s: unable to malloc!\n", __func__); return; } @@ -657,7 +657,7 @@ static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb, { info->nr = skb->data[1] >> 5; - IRDA_DEBUG(4, "%s(), nr=%d, %ld\n", __FUNCTION__, info->nr, jiffies); + IRDA_DEBUG(4, "%s(), nr=%d, %ld\n", __func__, info->nr, jiffies); if (command) irlap_do_event(self, RECV_RNR_CMD, skb, info); @@ -668,7 +668,7 @@ static void irlap_recv_rnr_frame(struct irlap_cb *self, struct sk_buff *skb, static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb, struct irlap_info *info, int command) { - IRDA_DEBUG(0, "%s()\n", __FUNCTION__); + IRDA_DEBUG(0, "%s()\n", __func__); info->nr = skb->data[1] >> 5; @@ -682,7 +682,7 @@ static void irlap_recv_rej_frame(struct irlap_cb *self, struct sk_buff *skb, static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb, struct irlap_info *info, int command) { - IRDA_DEBUG(0, "%s()\n", __FUNCTION__); + IRDA_DEBUG(0, "%s()\n", __func__); info->nr = skb->data[1] >> 5; @@ -696,7 +696,7 @@ static void irlap_recv_srej_frame(struct irlap_cb *self, struct sk_buff *skb, static void irlap_recv_disc_frame(struct irlap_cb *self, struct sk_buff *skb, struct irlap_info *info, int command) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* Check if this is a command or a response frame */ if (command) @@ -755,7 +755,7 @@ void irlap_send_data_primary(struct irlap_cb *self, struct sk_buff *skb) irlap_send_i_frame( self, tx_skb, CMD_FRAME); } else { - IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __func__); irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME); self->window -= 1; } @@ -808,7 +808,7 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) irlap_next_state(self, LAP_NRM_P); irlap_send_i_frame(self, tx_skb, CMD_FRAME); } else { - IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), sending unreliable frame\n", __func__); if (self->ack_required) { irlap_send_ui_frame(self, skb_get(skb), self->caddr, CMD_FRAME); @@ -835,7 +835,7 @@ void irlap_send_data_primary_poll(struct irlap_cb *self, struct sk_buff *skb) * See max_line_capacities[][] in qos.c for details. Jean II */ transmission_time -= (self->final_timeout * self->bytes_left / self->line_capacity); - IRDA_DEBUG(4, "%s() adjusting transmission_time : ft=%d, bl=%d, lc=%d -> tt=%d\n", __FUNCTION__, self->final_timeout, self->bytes_left, self->line_capacity, transmission_time); + IRDA_DEBUG(4, "%s() adjusting transmission_time : ft=%d, bl=%d, lc=%d -> tt=%d\n", __func__, self->final_timeout, self->bytes_left, self->line_capacity, transmission_time); /* We are allowed to transmit a maximum number of bytes again. */ self->bytes_left = self->line_capacity; @@ -1001,7 +1001,7 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command) /* tx_skb = skb_clone( skb, GFP_ATOMIC); */ tx_skb = skb_copy(skb, GFP_ATOMIC); if (!tx_skb) { - IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), unable to copy\n", __func__); return; } @@ -1033,7 +1033,7 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command) */ while (!skb_queue_empty(&self->txq)) { - IRDA_DEBUG(0, "%s(), sending additional frames!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), sending additional frames!\n", __func__); if (self->window > 0) { skb = skb_dequeue( &self->txq); IRDA_ASSERT(skb != NULL, return;); @@ -1073,7 +1073,7 @@ void irlap_resend_rejected_frame(struct irlap_cb *self, int command) /* tx_skb = skb_clone( skb, GFP_ATOMIC); */ tx_skb = skb_copy(skb, GFP_ATOMIC); if (!tx_skb) { - IRDA_DEBUG(0, "%s(), unable to copy\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), unable to copy\n", __func__); return; } @@ -1096,7 +1096,7 @@ void irlap_resend_rejected_frame(struct irlap_cb *self, int command) void irlap_send_ui_frame(struct irlap_cb *self, struct sk_buff *skb, __u8 caddr, int command) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -1156,7 +1156,7 @@ static inline void irlap_recv_i_frame(struct irlap_cb *self, static void irlap_recv_ui_frame(struct irlap_cb *self, struct sk_buff *skb, struct irlap_info *info) { - IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); + IRDA_DEBUG( 4, "%s()\n", __func__); info->pf = skb->data[1] & PF_BIT; /* Final bit */ @@ -1175,7 +1175,7 @@ static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb, __u8 *frame; int w, x, y, z; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__); + IRDA_DEBUG(0, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LAP_MAGIC, return;); @@ -1183,7 +1183,7 @@ static void irlap_recv_frmr_frame(struct irlap_cb *self, struct sk_buff *skb, IRDA_ASSERT(info != NULL, return;); if (!pskb_may_pull(skb, 4)) { - IRDA_ERROR("%s: frame too short!\n", __FUNCTION__); + IRDA_ERROR("%s: frame too short!\n", __func__); return; } @@ -1269,10 +1269,10 @@ static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, { struct test_frame *frame; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); if (!pskb_may_pull(skb, sizeof(*frame))) { - IRDA_ERROR("%s: frame too short!\n", __FUNCTION__); + IRDA_ERROR("%s: frame too short!\n", __func__); return; } frame = (struct test_frame *) skb->data; @@ -1281,7 +1281,7 @@ static void irlap_recv_test_frame(struct irlap_cb *self, struct sk_buff *skb, if (info->caddr == CBROADCAST) { if (skb->len < sizeof(struct test_frame)) { IRDA_DEBUG(0, "%s() test frame too short!\n", - __FUNCTION__); + __func__); return; } @@ -1342,14 +1342,14 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, * share and non linear skbs. This should never happen, so * we don't need to be clever about it. Jean II */ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) { - IRDA_ERROR("%s: can't clone shared skb!\n", __FUNCTION__); + IRDA_ERROR("%s: can't clone shared skb!\n", __func__); dev_kfree_skb(skb); return -1; } /* Check if frame is large enough for parsing */ if (!pskb_may_pull(skb, 2)) { - IRDA_ERROR("%s: frame too short!\n", __FUNCTION__); + IRDA_ERROR("%s: frame too short!\n", __func__); dev_kfree_skb(skb); return -1; } @@ -1365,7 +1365,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, /* First we check if this frame has a valid connection address */ if ((info.caddr != self->caddr) && (info.caddr != CBROADCAST)) { IRDA_DEBUG(0, "%s(), wrong connection address!\n", - __FUNCTION__); + __func__); goto out; } /* @@ -1400,7 +1400,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, break; default: IRDA_WARNING("%s: Unknown S-frame %02x received!\n", - __FUNCTION__, info.control); + __func__, info.control); break; } goto out; @@ -1438,7 +1438,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, break; default: IRDA_WARNING("%s: Unknown frame %02x received!\n", - __FUNCTION__, info.control); + __func__, info.control); break; } out: diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c index 135ac6907bbf..1f81f8e7c61d 100644 --- a/net/irda/irlmp.c +++ b/net/irda/irlmp.c @@ -76,7 +76,7 @@ const char *irlmp_reasons[] = { */ int __init irlmp_init(void) { - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); /* Initialize the irlmp structure. */ irlmp = kzalloc( sizeof(struct irlmp_cb), GFP_KERNEL); if (irlmp == NULL) @@ -164,7 +164,7 @@ struct lsap_cb *irlmp_open_lsap(__u8 slsap_sel, notify_t *notify, __u8 pid) /* Allocate new instance of a LSAP connection */ self = kzalloc(sizeof(struct lsap_cb), GFP_ATOMIC); if (self == NULL) { - IRDA_ERROR("%s: can't allocate memory\n", __FUNCTION__); + IRDA_ERROR("%s: can't allocate memory\n", __func__); return NULL; } @@ -202,7 +202,7 @@ EXPORT_SYMBOL(irlmp_open_lsap); */ static void __irlmp_close_lsap(struct lsap_cb *self) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); @@ -264,7 +264,7 @@ void irlmp_close_lsap(struct lsap_cb *self) if (!lsap) { IRDA_DEBUG(0, "%s(), Looks like somebody has removed me already!\n", - __FUNCTION__); + __func__); return; } __irlmp_close_lsap(self); @@ -291,7 +291,7 @@ void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, notify_t *notify) */ lap = kzalloc(sizeof(struct lap_cb), GFP_KERNEL); if (lap == NULL) { - IRDA_ERROR("%s: unable to kmalloc\n", __FUNCTION__); + IRDA_ERROR("%s: unable to kmalloc\n", __func__); return; } @@ -304,7 +304,7 @@ void irlmp_register_link(struct irlap_cb *irlap, __u32 saddr, notify_t *notify) #endif lap->lsaps = hashbin_new(HB_LOCK); if (lap->lsaps == NULL) { - IRDA_WARNING("%s(), unable to kmalloc lsaps\n", __FUNCTION__); + IRDA_WARNING("%s(), unable to kmalloc lsaps\n", __func__); kfree(lap); return; } @@ -336,7 +336,7 @@ void irlmp_unregister_link(__u32 saddr) { struct lap_cb *link; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); /* We must remove ourselves from the hashbin *first*. This ensure * that no more LSAPs will be open on this link and no discovery @@ -381,7 +381,7 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x, saddr=%08x, daddr=%08x\n", - __FUNCTION__, self->slsap_sel, dlsap_sel, saddr, daddr); + __func__, self->slsap_sel, dlsap_sel, saddr, daddr); if (test_bit(0, &self->connected)) { ret = -EISCONN; @@ -425,7 +425,7 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, if (daddr != DEV_ADDR_ANY) discovery = hashbin_find(irlmp->cachelog, daddr, NULL); else { - IRDA_DEBUG(2, "%s(), no daddr\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), no daddr\n", __func__); discovery = (discovery_t *) hashbin_get_first(irlmp->cachelog); } @@ -438,7 +438,7 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, } lap = hashbin_lock_find(irlmp->links, saddr, NULL); if (lap == NULL) { - IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Unable to find a usable link!\n", __func__); ret = -EHOSTUNREACH; goto err; } @@ -453,14 +453,14 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel, * disconnected yet (waiting for timeout in LAP). * Maybe we could give LAP a bit of help in this case. */ - IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), sorry, but I'm waiting for LAP to timeout!\n", __func__); ret = -EAGAIN; goto err; } /* LAP is already connected to a different node, and LAP * can only talk to one node at a time */ - IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), sorry, but link is busy!\n", __func__); ret = -EBUSY; goto err; } @@ -522,7 +522,7 @@ void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb) IRDA_ASSERT(self->lap != NULL, return;); IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n", - __FUNCTION__, self->slsap_sel, self->dlsap_sel); + __func__, self->slsap_sel, self->dlsap_sel); /* Note : self->lap is set in irlmp_link_data_indication(), * (case CONNECT_CMD:) because we have no way to set it here. @@ -563,7 +563,7 @@ int irlmp_connect_response(struct lsap_cb *self, struct sk_buff *userdata) * in the state machine itself. Jean II */ IRDA_DEBUG(2, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n", - __FUNCTION__, self->slsap_sel, self->dlsap_sel); + __func__, self->slsap_sel, self->dlsap_sel); /* Make room for MUX control header (3 bytes) */ IRDA_ASSERT(skb_headroom(userdata) >= LMP_CONTROL_HEADER, return -1;); @@ -589,7 +589,7 @@ void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb) int lap_header_size; int max_seg_size; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(skb != NULL, return;); IRDA_ASSERT(self != NULL, return;); @@ -603,7 +603,7 @@ void irlmp_connect_confirm(struct lsap_cb *self, struct sk_buff *skb) max_header_size = LMP_HEADER + lap_header_size; IRDA_DEBUG(2, "%s(), max_header_size=%d\n", - __FUNCTION__, max_header_size); + __func__, max_header_size); /* Hide LMP_CONTROL_HEADER header from layer above */ skb_pull(skb, LMP_CONTROL_HEADER); @@ -629,7 +629,7 @@ struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance) struct lsap_cb *new; unsigned long flags; - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); spin_lock_irqsave(&irlmp->unconnected_lsaps->hb_spinlock, flags); @@ -638,7 +638,7 @@ struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance) if ((!hashbin_find(irlmp->unconnected_lsaps, (long) orig, NULL)) || (orig->lap == NULL)) { IRDA_DEBUG(0, "%s(), invalid LSAP (wrong state)\n", - __FUNCTION__); + __func__); spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); return NULL; @@ -647,7 +647,7 @@ struct lsap_cb *irlmp_dup(struct lsap_cb *orig, void *instance) /* Allocate a new instance */ new = kmemdup(orig, sizeof(*new), GFP_ATOMIC); if (!new) { - IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __func__); spin_unlock_irqrestore(&irlmp->unconnected_lsaps->hb_spinlock, flags); return NULL; @@ -693,7 +693,7 @@ int irlmp_disconnect_request(struct lsap_cb *self, struct sk_buff *userdata) * and us that might mess up the hashbins below. This fixes it. * Jean II */ if (! test_and_clear_bit(0, &self->connected)) { - IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), already disconnected!\n", __func__); dev_kfree_skb(userdata); return -1; } @@ -747,19 +747,19 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, { struct lsap_cb *lsap; - IRDA_DEBUG(1, "%s(), reason=%s\n", __FUNCTION__, irlmp_reasons[reason]); + IRDA_DEBUG(1, "%s(), reason=%s\n", __func__, irlmp_reasons[reason]); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); IRDA_DEBUG(3, "%s(), slsap_sel=%02x, dlsap_sel=%02x\n", - __FUNCTION__, self->slsap_sel, self->dlsap_sel); + __func__, self->slsap_sel, self->dlsap_sel); /* Already disconnected ? * There is a race condition between irlmp_disconnect_request() * and us that might mess up the hashbins below. This fixes it. * Jean II */ if (! test_and_clear_bit(0, &self->connected)) { - IRDA_DEBUG(0, "%s(), already disconnected!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), already disconnected!\n", __func__); return; } @@ -792,7 +792,7 @@ void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, self->notify.disconnect_indication(self->notify.instance, self, reason, skb); } else { - IRDA_DEBUG(0, "%s(), no handler\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), no handler\n", __func__); } } @@ -845,7 +845,7 @@ void irlmp_do_discovery(int nslots) /* Make sure the value is sane */ if ((nslots != 1) && (nslots != 6) && (nslots != 8) && (nslots != 16)){ IRDA_WARNING("%s: invalid value for number of slots!\n", - __FUNCTION__); + __func__); nslots = sysctl_discovery_slots = 8; } @@ -963,7 +963,7 @@ irlmp_notify_client(irlmp_client_t *client, int number; /* Number of nodes in the log */ int i; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); /* Check if client wants or not partial/selective log (optimisation) */ if (!client->disco_callback) @@ -1014,7 +1014,7 @@ void irlmp_discovery_confirm(hashbin_t *log, DISCOVERY_MODE mode) irlmp_client_t *client; irlmp_client_t *client_next; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(log != NULL, return;); @@ -1049,7 +1049,7 @@ void irlmp_discovery_expiry(discinfo_t *expiries, int number) irlmp_client_t *client_next; int i; - IRDA_DEBUG(3, "%s()\n", __FUNCTION__); + IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(expiries != NULL, return;); @@ -1082,7 +1082,7 @@ void irlmp_discovery_expiry(discinfo_t *expiries, int number) */ discovery_t *irlmp_get_discovery_response(void) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(irlmp != NULL, return NULL;); @@ -1160,7 +1160,7 @@ int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *userdata) { int ret; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(userdata != NULL, return -1;); @@ -1184,7 +1184,7 @@ int irlmp_udata_request(struct lsap_cb *self, struct sk_buff *userdata) */ void irlmp_udata_indication(struct lsap_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); @@ -1211,7 +1211,7 @@ int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *userdata, struct sk_buff *clone_skb; struct lap_cb *lap; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(userdata != NULL, return -1;); @@ -1262,7 +1262,7 @@ int irlmp_connless_data_request(struct lsap_cb *self, struct sk_buff *userdata, #ifdef CONFIG_IRDA_ULTRA void irlmp_connless_data_indication(struct lsap_cb *self, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); @@ -1305,7 +1305,7 @@ void irlmp_status_indication(struct lap_cb *self, curr->notify.status_indication(curr->notify.instance, link, lock); else - IRDA_DEBUG(2, "%s(), no handler\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), no handler\n", __func__); curr = next; } @@ -1333,7 +1333,7 @@ void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow) /* Get the number of lsap. That's the only safe way to know * that we have looped around... - Jean II */ lsap_todo = HASHBIN_GET_SIZE(self->lsaps); - IRDA_DEBUG(4, "%s() : %d lsaps to scan\n", __FUNCTION__, lsap_todo); + IRDA_DEBUG(4, "%s() : %d lsaps to scan\n", __func__, lsap_todo); /* Poll lsap in order until the queue is full or until we * tried them all. @@ -1352,14 +1352,14 @@ void irlmp_flow_indication(struct lap_cb *self, LOCAL_FLOW flow) /* Uh-oh... Paranoia */ if(curr == NULL) break; - IRDA_DEBUG(4, "%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", __FUNCTION__, curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap)); + IRDA_DEBUG(4, "%s() : curr is %p, next was %p and is now %p, still %d to go - queue len = %d\n", __func__, curr, next, self->flow_next, lsap_todo, IRLAP_GET_TX_QUEUE_LEN(self->irlap)); /* Inform lsap user that it can send one more packet. */ if (curr->notify.flow_indication != NULL) curr->notify.flow_indication(curr->notify.instance, curr, flow); else - IRDA_DEBUG(1, "%s(), no handler\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), no handler\n", __func__); } } @@ -1381,7 +1381,7 @@ __u8 *irlmp_hint_to_service(__u8 *hint) */ service = kmalloc(16, GFP_ATOMIC); if (!service) { - IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __func__); return NULL; } @@ -1482,12 +1482,12 @@ void *irlmp_register_service(__u16 hints) { irlmp_service_t *service; - IRDA_DEBUG(4, "%s(), hints = %04x\n", __FUNCTION__, hints); + IRDA_DEBUG(4, "%s(), hints = %04x\n", __func__, hints); /* Make a new registration */ service = kmalloc(sizeof(irlmp_service_t), GFP_ATOMIC); if (!service) { - IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Unable to kmalloc!\n", __func__); return NULL; } service->hints.word = hints; @@ -1512,7 +1512,7 @@ int irlmp_unregister_service(void *handle) irlmp_service_t *service; unsigned long flags; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); if (!handle) return -1; @@ -1520,7 +1520,7 @@ int irlmp_unregister_service(void *handle) /* Caller may call with invalid handle (it's legal) - Jean II */ service = hashbin_lock_find(irlmp->services, (long) handle, NULL); if (!service) { - IRDA_DEBUG(1, "%s(), Unknown service!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Unknown service!\n", __func__); return -1; } @@ -1557,13 +1557,13 @@ void *irlmp_register_client(__u16 hint_mask, DISCOVERY_CALLBACK1 disco_clb, { irlmp_client_t *client; - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); IRDA_ASSERT(irlmp != NULL, return NULL;); /* Make a new registration */ client = kmalloc(sizeof(irlmp_client_t), GFP_ATOMIC); if (!client) { - IRDA_DEBUG( 1, "%s(), Unable to kmalloc!\n", __FUNCTION__); + IRDA_DEBUG( 1, "%s(), Unable to kmalloc!\n", __func__); return NULL; } @@ -1599,7 +1599,7 @@ int irlmp_update_client(void *handle, __u16 hint_mask, client = hashbin_lock_find(irlmp->clients, (long) handle, NULL); if (!client) { - IRDA_DEBUG(1, "%s(), Unknown client!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Unknown client!\n", __func__); return -1; } @@ -1622,7 +1622,7 @@ int irlmp_unregister_client(void *handle) { struct irlmp_client *client; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); if (!handle) return -1; @@ -1630,11 +1630,11 @@ int irlmp_unregister_client(void *handle) /* Caller may call with invalid handle (it's legal) - Jean II */ client = hashbin_lock_find(irlmp->clients, (long) handle, NULL); if (!client) { - IRDA_DEBUG(1, "%s(), Unknown client!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Unknown client!\n", __func__); return -1; } - IRDA_DEBUG(4, "%s(), removing client!\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), removing client!\n", __func__); hashbin_remove_this(irlmp->clients, (irda_queue_t *) client); kfree(client); @@ -1663,7 +1663,7 @@ static int irlmp_slsap_inuse(__u8 slsap_sel) IRDA_ASSERT(irlmp->magic == LMP_MAGIC, return TRUE;); IRDA_ASSERT(slsap_sel != LSAP_ANY, return TRUE;); - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); #ifdef CONFIG_IRDA_ULTRA /* Accept all bindings to the connectionless LSAP */ @@ -1790,7 +1790,7 @@ static __u8 irlmp_find_free_slsap(void) /* Make sure we terminate the loop */ if (wrapped++) { IRDA_ERROR("%s: no more free LSAPs !\n", - __FUNCTION__); + __func__); return 0; } } @@ -1805,7 +1805,7 @@ static __u8 irlmp_find_free_slsap(void) /* Got it ! */ lsap_sel = irlmp->last_lsap_sel; IRDA_DEBUG(4, "%s(), found free lsap_sel=%02x\n", - __FUNCTION__, lsap_sel); + __func__, lsap_sel); return lsap_sel; } @@ -1823,26 +1823,26 @@ LM_REASON irlmp_convert_lap_reason( LAP_REASON lap_reason) switch (lap_reason) { case LAP_DISC_INDICATION: /* Received a disconnect request from peer */ - IRDA_DEBUG( 1, "%s(), LAP_DISC_INDICATION\n", __FUNCTION__); + IRDA_DEBUG( 1, "%s(), LAP_DISC_INDICATION\n", __func__); reason = LM_USER_REQUEST; break; case LAP_NO_RESPONSE: /* To many retransmits without response */ - IRDA_DEBUG( 1, "%s(), LAP_NO_RESPONSE\n", __FUNCTION__); + IRDA_DEBUG( 1, "%s(), LAP_NO_RESPONSE\n", __func__); reason = LM_LAP_DISCONNECT; break; case LAP_RESET_INDICATION: - IRDA_DEBUG( 1, "%s(), LAP_RESET_INDICATION\n", __FUNCTION__); + IRDA_DEBUG( 1, "%s(), LAP_RESET_INDICATION\n", __func__); reason = LM_LAP_RESET; break; case LAP_FOUND_NONE: case LAP_MEDIA_BUSY: case LAP_PRIMARY_CONFLICT: - IRDA_DEBUG(1, "%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), LAP_FOUND_NONE, LAP_MEDIA_BUSY or LAP_PRIMARY_CONFLICT\n", __func__); reason = LM_CONNECT_FAILURE; break; default: IRDA_DEBUG(1, "%s(), Unknow IrLAP disconnect reason %d!\n", - __FUNCTION__, lap_reason); + __func__, lap_reason); reason = LM_LAP_DISCONNECT; break; } diff --git a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c index 150cd3f1129a..78cce0cb073f 100644 --- a/net/irda/irlmp_event.c +++ b/net/irda/irlmp_event.c @@ -120,7 +120,7 @@ static inline void irlmp_next_lap_state(struct lap_cb *self, IRLMP_STATE state) { /* - IRDA_DEBUG(4, "%s(), LMP LAP = %s\n", __FUNCTION__, irlmp_state[state]); + IRDA_DEBUG(4, "%s(), LMP LAP = %s\n", __func__, irlmp_state[state]); */ self->lap_state = state; } @@ -130,7 +130,7 @@ static inline void irlmp_next_lsap_state(struct lsap_cb *self, { /* IRDA_ASSERT(self != NULL, return;); - IRDA_DEBUG(4, "%s(), LMP LSAP = %s\n", __FUNCTION__, irlsap_state[state]); + IRDA_DEBUG(4, "%s(), LMP LSAP = %s\n", __func__, irlsap_state[state]); */ self->lsap_state = state; } @@ -143,7 +143,7 @@ int irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", - __FUNCTION__, irlmp_event[event], irlsap_state[ self->lsap_state]); + __func__, irlmp_event[event], irlsap_state[ self->lsap_state]); return (*lsap_state[self->lsap_state]) (self, event, skb); } @@ -160,7 +160,7 @@ void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event, IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); - IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", __FUNCTION__, + IRDA_DEBUG(4, "%s(), EVENT = %s, STATE = %s\n", __func__, irlmp_event[event], irlmp_state[self->lap_state]); @@ -169,7 +169,7 @@ void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event, void irlmp_discovery_timer_expired(void *data) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); /* We always cleanup the log (active & passive discovery) */ irlmp_do_expiry(); @@ -184,7 +184,7 @@ void irlmp_watchdog_timer_expired(void *data) { struct lsap_cb *self = (struct lsap_cb *) data; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return;); @@ -196,7 +196,7 @@ void irlmp_idle_timer_expired(void *data) { struct lap_cb *self = (struct lap_cb *) data; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); @@ -256,7 +256,7 @@ irlmp_do_all_lsap_event(hashbin_t * lsap_hashbin, static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self->irlap != NULL, return;); switch (event) { @@ -276,7 +276,7 @@ static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event, irlap_connect_response(self->irlap, skb); break; case LM_LAP_CONNECT_REQUEST: - IRDA_DEBUG(4, "%s() LS_CONNECT_REQUEST\n", __FUNCTION__); + IRDA_DEBUG(4, "%s() LS_CONNECT_REQUEST\n", __func__); irlmp_next_lap_state(self, LAP_U_CONNECT); @@ -285,13 +285,13 @@ static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event, break; case LM_LAP_DISCONNECT_INDICATION: IRDA_DEBUG(4, "%s(), Error LM_LAP_DISCONNECT_INDICATION\n", - __FUNCTION__); + __func__); irlmp_next_lap_state(self, LAP_STANDBY); break; default: IRDA_DEBUG(0, "%s(), Unknown event %s\n", - __FUNCTION__, irlmp_event[event]); + __func__, irlmp_event[event]); break; } } @@ -306,7 +306,7 @@ static void irlmp_state_standby(struct lap_cb *self, IRLMP_EVENT event, static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(2, "%s(), event=%s\n", __FUNCTION__, irlmp_event[event]); + IRDA_DEBUG(2, "%s(), event=%s\n", __func__, irlmp_event[event]); switch (event) { case LM_LAP_CONNECT_INDICATION: @@ -326,7 +326,7 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event, * the lsaps may already have gone. This avoid getting stuck * forever in LAP_ACTIVE state - Jean II */ if (HASHBIN_GET_SIZE(self->lsaps) == 0) { - IRDA_DEBUG(0, "%s() NO LSAPs !\n", __FUNCTION__); + IRDA_DEBUG(0, "%s() NO LSAPs !\n", __func__); irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); } break; @@ -344,12 +344,12 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event, * the lsaps may already have gone. This avoid getting stuck * forever in LAP_ACTIVE state - Jean II */ if (HASHBIN_GET_SIZE(self->lsaps) == 0) { - IRDA_DEBUG(0, "%s() NO LSAPs !\n", __FUNCTION__); + IRDA_DEBUG(0, "%s() NO LSAPs !\n", __func__); irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT); } break; case LM_LAP_DISCONNECT_INDICATION: - IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_INDICATION\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_INDICATION\n", __func__); irlmp_next_lap_state(self, LAP_STANDBY); /* Send disconnect event to all LSAPs using this link */ @@ -357,7 +357,7 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event, LM_LAP_DISCONNECT_INDICATION); break; case LM_LAP_DISCONNECT_REQUEST: - IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_REQUEST\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), LM_LAP_DISCONNECT_REQUEST\n", __func__); /* One of the LSAP did timeout or was closed, if it was * the last one, try to get out of here - Jean II */ @@ -367,7 +367,7 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event, break; default: IRDA_DEBUG(0, "%s(), Unknown event %s\n", - __FUNCTION__, irlmp_event[event]); + __func__, irlmp_event[event]); break; } } @@ -381,11 +381,11 @@ static void irlmp_state_u_connect(struct lap_cb *self, IRLMP_EVENT event, static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); switch (event) { case LM_LAP_CONNECT_REQUEST: - IRDA_DEBUG(4, "%s(), LS_CONNECT_REQUEST\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), LS_CONNECT_REQUEST\n", __func__); /* * IrLAP may have a pending disconnect. We tried to close @@ -468,7 +468,7 @@ static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event, break; default: IRDA_DEBUG(0, "%s(), Unknown event %s\n", - __FUNCTION__, irlmp_event[event]); + __func__, irlmp_event[event]); break; } } @@ -490,7 +490,7 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, { int ret = 0; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); @@ -505,11 +505,11 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, break; #endif /* CONFIG_IRDA_ULTRA */ case LM_CONNECT_REQUEST: - IRDA_DEBUG(4, "%s(), LM_CONNECT_REQUEST\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), LM_CONNECT_REQUEST\n", __func__); if (self->conn_skb) { IRDA_WARNING("%s: busy with another request!\n", - __FUNCTION__); + __func__); return -EBUSY; } /* Don't forget to refcount it (see irlmp_connect_request()) */ @@ -526,7 +526,7 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, case LM_CONNECT_INDICATION: if (self->conn_skb) { IRDA_WARNING("%s: busy with another request!\n", - __FUNCTION__); + __func__); return -EBUSY; } /* Don't forget to refcount it (see irlap_driver_rcv()) */ @@ -552,7 +552,7 @@ static int irlmp_state_disconnected(struct lsap_cb *self, IRLMP_EVENT event, break; default: IRDA_DEBUG(1, "%s(), Unknown event %s on LSAP %#02x\n", - __FUNCTION__, irlmp_event[event], self->slsap_sel); + __func__, irlmp_event[event], self->slsap_sel); break; } return ret; @@ -570,7 +570,7 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event, struct lsap_cb *lsap; int ret = 0; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); @@ -603,7 +603,7 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event, case LM_WATCHDOG_TIMEOUT: /* May happen, who knows... * Jean II */ - IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__); /* Disconnect, get out... - Jean II */ self->lap = NULL; @@ -614,7 +614,7 @@ static int irlmp_state_connect(struct lsap_cb *self, IRLMP_EVENT event, /* LM_LAP_DISCONNECT_INDICATION : Should never happen, we * are *not* yet bound to the IrLAP link. Jean II */ IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", - __FUNCTION__, irlmp_event[event], self->slsap_sel); + __func__, irlmp_event[event], self->slsap_sel); break; } return ret; @@ -632,7 +632,7 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event, struct sk_buff *tx_skb; int ret = 0; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); @@ -643,16 +643,16 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event, break; case LM_CONNECT_RESPONSE: IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, " - "no indication issued yet\n", __FUNCTION__); + "no indication issued yet\n", __func__); /* Keep state */ break; case LM_DISCONNECT_REQUEST: IRDA_DEBUG(0, "%s(), LM_DISCONNECT_REQUEST, " - "not yet bound to IrLAP connection\n", __FUNCTION__); + "not yet bound to IrLAP connection\n", __func__); /* Keep state */ break; case LM_LAP_CONNECT_CONFIRM: - IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), LS_CONNECT_CONFIRM\n", __func__); irlmp_next_lsap_state(self, LSAP_CONNECT); tx_skb = self->conn_skb; @@ -666,7 +666,7 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event, /* Will happen in some rare cases because of a race condition. * Just make sure we don't stay there forever... * Jean II */ - IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__); /* Go back to disconnected mode, keep the socket waiting */ self->lap = NULL; @@ -680,7 +680,7 @@ static int irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event, /* LM_LAP_DISCONNECT_INDICATION : Should never happen, we * are *not* yet bound to the IrLAP link. Jean II */ IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", - __FUNCTION__, irlmp_event[event], self->slsap_sel); + __func__, irlmp_event[event], self->slsap_sel); break; } return ret; @@ -698,7 +698,7 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event, LM_REASON reason; int ret = 0; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); @@ -722,12 +722,12 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event, break; case LM_CONNECT_REQUEST: IRDA_DEBUG(0, "%s(), LM_CONNECT_REQUEST, " - "error, LSAP already connected\n", __FUNCTION__); + "error, LSAP already connected\n", __func__); /* Keep state */ break; case LM_CONNECT_RESPONSE: IRDA_DEBUG(0, "%s(), LM_CONNECT_RESPONSE, " - "error, LSAP already connected\n", __FUNCTION__); + "error, LSAP already connected\n", __func__); /* Keep state */ break; case LM_DISCONNECT_REQUEST: @@ -740,7 +740,7 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event, /* Try to close the LAP connection if its still there */ if (self->lap) { IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", - __FUNCTION__); + __func__); irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); @@ -764,14 +764,14 @@ static int irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event, reason = skb->data[3]; /* Try to close the LAP connection */ - IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __func__); irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); irlmp_disconnect_indication(self, reason, skb); break; default: IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", - __FUNCTION__, irlmp_event[event], self->slsap_sel); + __func__, irlmp_event[event], self->slsap_sel); break; } return ret; @@ -793,7 +793,7 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event, IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == LMP_LSAP_MAGIC, return -1;); - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); switch (event) { case LM_CONNECT_CONFIRM: @@ -814,7 +814,7 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event, reason = skb->data[3]; /* Try to close the LAP connection */ - IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), trying to close IrLAP\n", __func__); irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); irlmp_disconnect_indication(self, reason, skb); @@ -832,7 +832,7 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event, irlmp_disconnect_indication(self, reason, skb); break; case LM_WATCHDOG_TIMEOUT: - IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s() WATCHDOG_TIMEOUT!\n", __func__); IRDA_ASSERT(self->lap != NULL, return -1;); irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); @@ -842,7 +842,7 @@ static int irlmp_state_setup(struct lsap_cb *self, IRLMP_EVENT event, break; default: IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", - __FUNCTION__, irlmp_event[event], self->slsap_sel); + __func__, irlmp_event[event], self->slsap_sel); break; } return ret; @@ -863,7 +863,7 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event, LM_REASON reason; int ret = 0; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(irlmp != NULL, return -1;); @@ -883,7 +883,7 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event, irlmp_next_lsap_state(self, LSAP_SETUP); break; case LM_WATCHDOG_TIMEOUT: - IRDA_DEBUG(0, "%s() : WATCHDOG_TIMEOUT !\n", __FUNCTION__); + IRDA_DEBUG(0, "%s() : WATCHDOG_TIMEOUT !\n", __func__); IRDA_ASSERT(self->lap != NULL, return -1;); irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); @@ -902,7 +902,7 @@ static int irlmp_state_setup_pend(struct lsap_cb *self, IRLMP_EVENT event, break; default: IRDA_DEBUG(0, "%s(), Unknown event %s on LSAP %#02x\n", - __FUNCTION__, irlmp_event[event], self->slsap_sel); + __func__, irlmp_event[event], self->slsap_sel); break; } return ret; diff --git a/net/irda/irlmp_frame.c b/net/irda/irlmp_frame.c index 0a79d9aeb08c..3750884094da 100644 --- a/net/irda/irlmp_frame.c +++ b/net/irda/irlmp_frame.c @@ -44,7 +44,7 @@ inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, skb->data[1] = slsap; if (expedited) { - IRDA_DEBUG(4, "%s(), sending expedited data\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), sending expedited data\n", __func__); irlap_data_request(self->irlap, skb, TRUE); } else irlap_data_request(self->irlap, skb, FALSE); @@ -60,7 +60,7 @@ void irlmp_send_lcf_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, { __u8 *frame; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); @@ -95,7 +95,7 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb, __u8 dlsap_sel; /* Destination LSAP address */ __u8 *fp; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); @@ -117,7 +117,7 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb, if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) { IRDA_DEBUG(3, "%s(), incoming connection, " "source LSAP=%d, dest LSAP=%d\n", - __FUNCTION__, slsap_sel, dlsap_sel); + __func__, slsap_sel, dlsap_sel); /* Try to find LSAP among the unconnected LSAPs */ lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, CONNECT_CMD, @@ -125,7 +125,7 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb, /* Maybe LSAP was already connected, so try one more time */ if (!lsap) { - IRDA_DEBUG(1, "%s(), incoming connection for LSAP already connected\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), incoming connection for LSAP already connected\n", __func__); lsap = irlmp_find_lsap(self, dlsap_sel, slsap_sel, 0, self->lsaps); } @@ -136,12 +136,12 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb, if (lsap == NULL) { IRDA_DEBUG(2, "IrLMP, Sorry, no LSAP for received frame!\n"); IRDA_DEBUG(2, "%s(), slsap_sel = %02x, dlsap_sel = %02x\n", - __FUNCTION__, slsap_sel, dlsap_sel); + __func__, slsap_sel, dlsap_sel); if (fp[0] & CONTROL_BIT) { IRDA_DEBUG(2, "%s(), received control frame %02x\n", - __FUNCTION__, fp[2]); + __func__, fp[2]); } else { - IRDA_DEBUG(2, "%s(), received data frame\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), received data frame\n", __func__); } return; } @@ -160,7 +160,7 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb, break; case DISCONNECT: IRDA_DEBUG(4, "%s(), Disconnect indication!\n", - __FUNCTION__); + __func__); irlmp_do_lsap_event(lsap, LM_DISCONNECT_INDICATION, skb); break; @@ -172,7 +172,7 @@ void irlmp_link_data_indication(struct lap_cb *self, struct sk_buff *skb, break; default: IRDA_DEBUG(0, "%s(), Unknown control frame %02x\n", - __FUNCTION__, fp[2]); + __func__, fp[2]); break; } } else if (unreliable) { @@ -206,7 +206,7 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb) __u8 *fp; unsigned long flags; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); @@ -224,13 +224,13 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb) if (pid & 0x80) { IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", - __FUNCTION__); + __func__); return; } /* Check if frame is addressed to the connectionless LSAP */ if ((slsap_sel != LSAP_CONNLESS) || (dlsap_sel != LSAP_CONNLESS)) { - IRDA_DEBUG(0, "%s(), dropping frame!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), dropping frame!\n", __func__); return; } @@ -254,7 +254,7 @@ void irlmp_link_unitdata_indication(struct lap_cb *self, struct sk_buff *skb) if (lsap) irlmp_connless_data_indication(lsap, skb); else { - IRDA_DEBUG(0, "%s(), found no matching LSAP!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), found no matching LSAP!\n", __func__); } } #endif /* CONFIG_IRDA_ULTRA */ @@ -270,7 +270,7 @@ void irlmp_link_disconnect_indication(struct lap_cb *lap, LAP_REASON reason, struct sk_buff *skb) { - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); IRDA_ASSERT(lap != NULL, return;); IRDA_ASSERT(lap->magic == LMP_LAP_MAGIC, return;); @@ -296,7 +296,7 @@ void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr, __u32 daddr, struct qos_info *qos, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); /* Copy QoS settings for this session */ self->qos = qos; @@ -317,7 +317,7 @@ void irlmp_link_connect_indication(struct lap_cb *self, __u32 saddr, void irlmp_link_connect_confirm(struct lap_cb *self, struct qos_info *qos, struct sk_buff *skb) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); @@ -383,7 +383,7 @@ void irlmp_link_discovery_indication(struct lap_cb *self, */ void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log) { - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == LMP_LAP_MAGIC, return;); diff --git a/net/irda/irmod.c b/net/irda/irmod.c index 01554b996b9b..4c487a883725 100644 --- a/net/irda/irmod.c +++ b/net/irda/irmod.c @@ -90,7 +90,7 @@ static int __init irda_init(void) { int ret = 0; - IRDA_DEBUG(0, "%s()\n", __FUNCTION__); + IRDA_DEBUG(0, "%s()\n", __func__); /* Lower layer of the stack */ irlmp_init(); diff --git a/net/irda/irnet/irnet.h b/net/irda/irnet/irnet.h index bc2e15ce7004..a00e422c822e 100644 --- a/net/irda/irnet/irnet.h +++ b/net/irda/irnet/irnet.h @@ -337,27 +337,27 @@ /* All error messages (will show up in the normal logs) */ #define DERROR(dbg, format, args...) \ {if(DEBUG_##dbg) \ - printk(KERN_INFO "irnet: %s(): " format, __FUNCTION__ , ##args);} + printk(KERN_INFO "irnet: %s(): " format, __func__ , ##args);} /* Normal debug message (will show up in /var/log/debug) */ #define DEBUG(dbg, format, args...) \ {if(DEBUG_##dbg) \ - printk(KERN_DEBUG "irnet: %s(): " format, __FUNCTION__ , ##args);} + printk(KERN_DEBUG "irnet: %s(): " format, __func__ , ##args);} /* Entering a function (trace) */ #define DENTER(dbg, format, args...) \ {if(DEBUG_##dbg) \ - printk(KERN_DEBUG "irnet: -> %s" format, __FUNCTION__ , ##args);} + printk(KERN_DEBUG "irnet: -> %s" format, __func__ , ##args);} /* Entering and exiting a function in one go (trace) */ #define DPASS(dbg, format, args...) \ {if(DEBUG_##dbg) \ - printk(KERN_DEBUG "irnet: <>%s" format, __FUNCTION__ , ##args);} + printk(KERN_DEBUG "irnet: <>%s" format, __func__ , ##args);} /* Exiting a function (trace) */ #define DEXIT(dbg, format, args...) \ {if(DEBUG_##dbg) \ - printk(KERN_DEBUG "irnet: <-%s()" format, __FUNCTION__ , ##args);} + printk(KERN_DEBUG "irnet: <-%s()" format, __func__ , ##args);} /* Exit a function with debug */ #define DRETURN(ret, dbg, args...) \ diff --git a/net/irda/irnetlink.c b/net/irda/irnetlink.c index cd9ff176ecde..9e1fb82e3220 100644 --- a/net/irda/irnetlink.c +++ b/net/irda/irnetlink.c @@ -40,7 +40,7 @@ static struct net_device * ifname_to_netdev(struct net *net, struct genl_info *i ifname = nla_data(info->attrs[IRDA_NL_ATTR_IFNAME]); - IRDA_DEBUG(5, "%s(): Looking for %s\n", __FUNCTION__, ifname); + IRDA_DEBUG(5, "%s(): Looking for %s\n", __func__, ifname); return dev_get_by_name(net, ifname); } @@ -56,7 +56,7 @@ static int irda_nl_set_mode(struct sk_buff *skb, struct genl_info *info) mode = nla_get_u32(info->attrs[IRDA_NL_ATTR_MODE]); - IRDA_DEBUG(5, "%s(): Switching to mode: %d\n", __FUNCTION__, mode); + IRDA_DEBUG(5, "%s(): Switching to mode: %d\n", __func__, mode); dev = ifname_to_netdev(&init_net, info); if (!dev) diff --git a/net/irda/irqueue.c b/net/irda/irqueue.c index 40c28efaed95..ba01938becb5 100644 --- a/net/irda/irqueue.c +++ b/net/irda/irqueue.c @@ -232,7 +232,7 @@ static __u32 hash( const char* name) static void enqueue_first(irda_queue_t **queue, irda_queue_t* element) { - IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); + IRDA_DEBUG( 4, "%s()\n", __func__); /* * Check if queue is empty. @@ -451,7 +451,7 @@ void hashbin_insert(hashbin_t* hashbin, irda_queue_t* entry, long hashv, unsigned long flags = 0; int bin; - IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); + IRDA_DEBUG( 4, "%s()\n", __func__); IRDA_ASSERT( hashbin != NULL, return;); IRDA_ASSERT( hashbin->magic == HB_MAGIC, return;); @@ -564,7 +564,7 @@ void* hashbin_remove( hashbin_t* hashbin, long hashv, const char* name) unsigned long flags = 0; irda_queue_t* entry; - IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); + IRDA_DEBUG( 4, "%s()\n", __func__); IRDA_ASSERT( hashbin != NULL, return NULL;); IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;); @@ -657,7 +657,7 @@ void* hashbin_remove_this( hashbin_t* hashbin, irda_queue_t* entry) int bin; long hashv; - IRDA_DEBUG( 4, "%s()\n", __FUNCTION__); + IRDA_DEBUG( 4, "%s()\n", __func__); IRDA_ASSERT( hashbin != NULL, return NULL;); IRDA_ASSERT( hashbin->magic == HB_MAGIC, return NULL;); diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 97db158c9274..74e439e80823 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -95,7 +95,7 @@ int __init irttp_init(void) irttp->tsaps = hashbin_new(HB_LOCK); if (!irttp->tsaps) { IRDA_ERROR("%s: can't allocate IrTTP hashbin!\n", - __FUNCTION__); + __func__); kfree(irttp); return -ENOMEM; } @@ -164,7 +164,7 @@ static void irttp_todo_expired(unsigned long data) if (!self || self->magic != TTP_TSAP_MAGIC) return; - IRDA_DEBUG(4, "%s(instance=%p)\n", __FUNCTION__, self); + IRDA_DEBUG(4, "%s(instance=%p)\n", __func__, self); /* Try to make some progress, especially on Tx side - Jean II */ irttp_run_rx_queue(self); @@ -205,7 +205,7 @@ void irttp_flush_queues(struct tsap_cb *self) { struct sk_buff* skb; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); @@ -238,7 +238,7 @@ static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self) IRDA_ASSERT(self != NULL, return NULL;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return NULL;); - IRDA_DEBUG(2, "%s(), self->rx_sdu_size=%d\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), self->rx_sdu_size=%d\n", __func__, self->rx_sdu_size); skb = dev_alloc_skb(TTP_HEADER + self->rx_sdu_size); @@ -264,7 +264,7 @@ static struct sk_buff *irttp_reassemble_skb(struct tsap_cb *self) IRDA_DEBUG(2, "%s(), frame len=%d, rx_sdu_size=%d, rx_max_sdu_size=%d\n", - __FUNCTION__, n, self->rx_sdu_size, self->rx_max_sdu_size); + __func__, n, self->rx_sdu_size, self->rx_max_sdu_size); /* Note : irttp_run_rx_queue() calculate self->rx_sdu_size * by summing the size of all fragments, so we should always * have n == self->rx_sdu_size, except in cases where we @@ -293,7 +293,7 @@ static inline void irttp_fragment_skb(struct tsap_cb *self, struct sk_buff *frag; __u8 *frame; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); @@ -303,7 +303,7 @@ static inline void irttp_fragment_skb(struct tsap_cb *self, * Split frame into a number of segments */ while (skb->len > self->max_seg_size) { - IRDA_DEBUG(2, "%s(), fragmenting ...\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), fragmenting ...\n", __func__); /* Make new segment */ frag = alloc_skb(self->max_seg_size+self->max_header_size, @@ -328,7 +328,7 @@ static inline void irttp_fragment_skb(struct tsap_cb *self, skb_queue_tail(&self->tx_queue, frag); } /* Queue what is left of the original skb */ - IRDA_DEBUG(2, "%s(), queuing last segment\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), queuing last segment\n", __func__); frame = skb_push(skb, TTP_HEADER); frame[0] = 0x00; /* Clear more bit */ @@ -359,7 +359,7 @@ static int irttp_param_max_sdu_size(void *instance, irda_param_t *param, else self->tx_max_sdu_size = param->pv.i; - IRDA_DEBUG(1, "%s(), MaxSduSize=%d\n", __FUNCTION__, param->pv.i); + IRDA_DEBUG(1, "%s(), MaxSduSize=%d\n", __func__, param->pv.i); return 0; } @@ -400,13 +400,13 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify) * JeanII */ if((stsap_sel != LSAP_ANY) && ((stsap_sel < 0x01) || (stsap_sel >= 0x70))) { - IRDA_DEBUG(0, "%s(), invalid tsap!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), invalid tsap!\n", __func__); return NULL; } self = kzalloc(sizeof(struct tsap_cb), GFP_ATOMIC); if (self == NULL) { - IRDA_DEBUG(0, "%s(), unable to kmalloc!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), unable to kmalloc!\n", __func__); return NULL; } @@ -438,7 +438,7 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify) */ lsap = irlmp_open_lsap(stsap_sel, &ttp_notify, 0); if (lsap == NULL) { - IRDA_WARNING("%s: unable to allocate LSAP!!\n", __FUNCTION__); + IRDA_WARNING("%s: unable to allocate LSAP!!\n", __func__); return NULL; } @@ -448,7 +448,7 @@ struct tsap_cb *irttp_open_tsap(__u8 stsap_sel, int credit, notify_t *notify) * the stsap_sel we have might not be valid anymore */ self->stsap_sel = lsap->slsap_sel; - IRDA_DEBUG(4, "%s(), stsap_sel=%02x\n", __FUNCTION__, self->stsap_sel); + IRDA_DEBUG(4, "%s(), stsap_sel=%02x\n", __func__, self->stsap_sel); self->notify = *notify; self->lsap = lsap; @@ -506,7 +506,7 @@ int irttp_close_tsap(struct tsap_cb *self) { struct tsap_cb *tsap; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); @@ -516,7 +516,7 @@ int irttp_close_tsap(struct tsap_cb *self) /* Check if disconnect is not pending */ if (!test_bit(0, &self->disconnect_pend)) { IRDA_WARNING("%s: TSAP still connected!\n", - __FUNCTION__); + __func__); irttp_disconnect_request(self, NULL, P_NORMAL); } self->close_pend = TRUE; @@ -553,18 +553,18 @@ int irttp_udata_request(struct tsap_cb *self, struct sk_buff *skb) IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); IRDA_ASSERT(skb != NULL, return -1;); - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); /* Check that nothing bad happens */ if ((skb->len == 0) || (!self->connected)) { IRDA_DEBUG(1, "%s(), No data, or not connected\n", - __FUNCTION__); + __func__); goto err; } if (skb->len > self->max_seg_size) { IRDA_DEBUG(1, "%s(), UData is too large for IrLAP!\n", - __FUNCTION__); + __func__); goto err; } @@ -595,12 +595,12 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); IRDA_ASSERT(skb != NULL, return -1;); - IRDA_DEBUG(2, "%s() : queue len = %d\n", __FUNCTION__, + IRDA_DEBUG(2, "%s() : queue len = %d\n", __func__, skb_queue_len(&self->tx_queue)); /* Check that nothing bad happens */ if ((skb->len == 0) || (!self->connected)) { - IRDA_WARNING("%s: No data, or not connected\n", __FUNCTION__); + IRDA_WARNING("%s: No data, or not connected\n", __func__); ret = -ENOTCONN; goto err; } @@ -611,7 +611,7 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) */ if ((self->tx_max_sdu_size == 0) && (skb->len > self->max_seg_size)) { IRDA_ERROR("%s: SAR disabled, and data is too large for IrLAP!\n", - __FUNCTION__); + __func__); ret = -EMSGSIZE; goto err; } @@ -625,7 +625,7 @@ int irttp_data_request(struct tsap_cb *self, struct sk_buff *skb) (skb->len > self->tx_max_sdu_size)) { IRDA_ERROR("%s: SAR enabled, but data is larger than TxMaxSduSize!\n", - __FUNCTION__); + __func__); ret = -EMSGSIZE; goto err; } @@ -704,7 +704,7 @@ static void irttp_run_tx_queue(struct tsap_cb *self) int n; IRDA_DEBUG(2, "%s() : send_credit = %d, queue_len = %d\n", - __FUNCTION__, + __func__, self->send_credit, skb_queue_len(&self->tx_queue)); /* Get exclusive access to the tx queue, otherwise don't touch it */ @@ -813,7 +813,7 @@ static inline void irttp_give_credit(struct tsap_cb *self) IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n", - __FUNCTION__, + __func__, self->send_credit, self->avail_credit, self->remote_credit); /* Give credit to peer */ @@ -862,7 +862,7 @@ static int irttp_udata_indication(void *instance, void *sap, struct tsap_cb *self; int err; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); self = (struct tsap_cb *) instance; @@ -979,7 +979,7 @@ static void irttp_status_indication(void *instance, { struct tsap_cb *self; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); self = (struct tsap_cb *) instance; @@ -997,7 +997,7 @@ static void irttp_status_indication(void *instance, self->notify.status_indication(self->notify.instance, link, lock); else - IRDA_DEBUG(2, "%s(), no handler\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), no handler\n", __func__); } /* @@ -1015,7 +1015,7 @@ static void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); - IRDA_DEBUG(4, "%s(instance=%p)\n", __FUNCTION__, self); + IRDA_DEBUG(4, "%s(instance=%p)\n", __func__, self); /* We are "polled" directly from LAP, and the LAP want to fill * its Tx window. We want to do our best to send it data, so that @@ -1053,18 +1053,18 @@ static void irttp_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) */ void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow) { - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return;); switch (flow) { case FLOW_STOP: - IRDA_DEBUG(1, "%s(), flow stop\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), flow stop\n", __func__); self->rx_sdu_busy = TRUE; break; case FLOW_START: - IRDA_DEBUG(1, "%s(), flow start\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), flow start\n", __func__); self->rx_sdu_busy = FALSE; /* Client say he can accept more data, try to free our @@ -1073,7 +1073,7 @@ void irttp_flow_request(struct tsap_cb *self, LOCAL_FLOW flow) break; default: - IRDA_DEBUG(1, "%s(), Unknown flow command!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Unknown flow command!\n", __func__); } } EXPORT_SYMBOL(irttp_flow_request); @@ -1093,7 +1093,7 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, __u8 *frame; __u8 n; - IRDA_DEBUG(4, "%s(), max_sdu_size=%d\n", __FUNCTION__, max_sdu_size); + IRDA_DEBUG(4, "%s(), max_sdu_size=%d\n", __func__, max_sdu_size); IRDA_ASSERT(self != NULL, return -EBADR;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -EBADR;); @@ -1191,7 +1191,7 @@ static void irttp_connect_confirm(void *instance, void *sap, __u8 plen; __u8 n; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); self = (struct tsap_cb *) instance; @@ -1215,7 +1215,7 @@ static void irttp_connect_confirm(void *instance, void *sap, n = skb->data[0] & 0x7f; - IRDA_DEBUG(4, "%s(), Initial send_credit=%d\n", __FUNCTION__, n); + IRDA_DEBUG(4, "%s(), Initial send_credit=%d\n", __func__, n); self->send_credit = n; self->tx_max_sdu_size = 0; @@ -1236,7 +1236,7 @@ static void irttp_connect_confirm(void *instance, void *sap, /* Any errors in the parameter list? */ if (ret < 0) { IRDA_WARNING("%s: error extracting parameters\n", - __FUNCTION__); + __func__); dev_kfree_skb(skb); /* Do not accept this connection attempt */ @@ -1246,10 +1246,10 @@ static void irttp_connect_confirm(void *instance, void *sap, skb_pull(skb, IRDA_MIN(skb->len, plen+1)); } - IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n", __FUNCTION__, + IRDA_DEBUG(4, "%s() send=%d,avail=%d,remote=%d\n", __func__, self->send_credit, self->avail_credit, self->remote_credit); - IRDA_DEBUG(2, "%s(), MaxSduSize=%d\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), MaxSduSize=%d\n", __func__, self->tx_max_sdu_size); if (self->notify.connect_confirm) { @@ -1288,7 +1288,7 @@ void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos, self->max_seg_size = max_seg_size - TTP_HEADER; self->max_header_size = max_header_size+TTP_HEADER; - IRDA_DEBUG(4, "%s(), TSAP sel=%02x\n", __FUNCTION__, self->stsap_sel); + IRDA_DEBUG(4, "%s(), TSAP sel=%02x\n", __func__, self->stsap_sel); /* Need to update dtsap_sel if its equal to LSAP_ANY */ self->dtsap_sel = lsap->dlsap_sel; @@ -1313,7 +1313,7 @@ void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos, /* Any errors in the parameter list? */ if (ret < 0) { IRDA_WARNING("%s: error extracting parameters\n", - __FUNCTION__); + __func__); dev_kfree_skb(skb); /* Do not accept this connection attempt */ @@ -1350,7 +1350,7 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, IRDA_ASSERT(self != NULL, return -1;); IRDA_ASSERT(self->magic == TTP_TSAP_MAGIC, return -1;); - IRDA_DEBUG(4, "%s(), Source TSAP selector=%02x\n", __FUNCTION__, + IRDA_DEBUG(4, "%s(), Source TSAP selector=%02x\n", __func__, self->stsap_sel); /* Any userdata supplied? */ @@ -1432,14 +1432,14 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance) struct tsap_cb *new; unsigned long flags; - IRDA_DEBUG(1, "%s()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s()\n", __func__); /* Protect our access to the old tsap instance */ spin_lock_irqsave(&irttp->tsaps->hb_spinlock, flags); /* Find the old instance */ if (!hashbin_find(irttp->tsaps, (long) orig, NULL)) { - IRDA_DEBUG(0, "%s(), unable to find TSAP\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), unable to find TSAP\n", __func__); spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); return NULL; } @@ -1447,7 +1447,7 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance) /* Allocate a new instance */ new = kmalloc(sizeof(struct tsap_cb), GFP_ATOMIC); if (!new) { - IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), unable to kmalloc\n", __func__); spin_unlock_irqrestore(&irttp->tsaps->hb_spinlock, flags); return NULL; } @@ -1460,7 +1460,7 @@ struct tsap_cb *irttp_dup(struct tsap_cb *orig, void *instance) /* Try to dup the LSAP (may fail if we were too slow) */ new->lsap = irlmp_dup(orig->lsap, new); if (!new->lsap) { - IRDA_DEBUG(0, "%s(), dup failed!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), dup failed!\n", __func__); kfree(new); return NULL; } @@ -1495,7 +1495,7 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, /* Already disconnected? */ if (!self->connected) { - IRDA_DEBUG(4, "%s(), already disconnected!\n", __FUNCTION__); + IRDA_DEBUG(4, "%s(), already disconnected!\n", __func__); if (userdata) dev_kfree_skb(userdata); return -1; @@ -1508,7 +1508,7 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, * Jean II */ if(test_and_set_bit(0, &self->disconnect_pend)) { IRDA_DEBUG(0, "%s(), disconnect already pending\n", - __FUNCTION__); + __func__); if (userdata) dev_kfree_skb(userdata); @@ -1527,7 +1527,7 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, * disconnecting right now since the data will * not have any usable connection to be sent on */ - IRDA_DEBUG(1, "%s(): High priority!!()\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(): High priority!!()\n", __func__); irttp_flush_queues(self); } else if (priority == P_NORMAL) { /* @@ -1548,7 +1548,7 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata, * be sent at the LMP level (so even if the peer has its Tx queue * full of data). - Jean II */ - IRDA_DEBUG(1, "%s(), Disconnecting ...\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Disconnecting ...\n", __func__); self->connected = FALSE; if (!userdata) { @@ -1584,7 +1584,7 @@ void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason, { struct tsap_cb *self; - IRDA_DEBUG(4, "%s()\n", __FUNCTION__); + IRDA_DEBUG(4, "%s()\n", __func__); self = (struct tsap_cb *) instance; @@ -1644,7 +1644,7 @@ static void irttp_do_data_indication(struct tsap_cb *self, struct sk_buff *skb) * give an error back */ if (err) { - IRDA_DEBUG(0, "%s() requeueing skb!\n", __FUNCTION__); + IRDA_DEBUG(0, "%s() requeueing skb!\n", __func__); /* Make sure we take a break */ self->rx_sdu_busy = TRUE; @@ -1669,7 +1669,7 @@ void irttp_run_rx_queue(struct tsap_cb *self) struct sk_buff *skb; int more = 0; - IRDA_DEBUG(2, "%s() send=%d,avail=%d,remote=%d\n", __FUNCTION__, + IRDA_DEBUG(2, "%s() send=%d,avail=%d,remote=%d\n", __func__, self->send_credit, self->avail_credit, self->remote_credit); /* Get exclusive access to the rx queue, otherwise don't touch it */ @@ -1710,7 +1710,7 @@ void irttp_run_rx_queue(struct tsap_cb *self) */ if (self->rx_sdu_size <= self->rx_max_sdu_size) { IRDA_DEBUG(4, "%s(), queueing frag\n", - __FUNCTION__); + __func__); skb_queue_tail(&self->rx_fragments, skb); } else { /* Free the part of the SDU that is too big */ @@ -1740,7 +1740,7 @@ void irttp_run_rx_queue(struct tsap_cb *self) /* Now we can deliver the reassembled skb */ irttp_do_data_indication(self, skb); } else { - IRDA_DEBUG(1, "%s(), Truncated frame\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), Truncated frame\n", __func__); /* Free the part of the SDU that is too big */ dev_kfree_skb(skb); diff --git a/net/irda/parameters.c b/net/irda/parameters.c index 722bbe044d9c..fc1a20565e2d 100644 --- a/net/irda/parameters.c +++ b/net/irda/parameters.c @@ -148,23 +148,23 @@ static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi, */ if (p.pl == 0) { if (p.pv.i < 0xff) { - IRDA_DEBUG(2, "%s(), using 1 byte\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), using 1 byte\n", __func__); p.pl = 1; } else if (p.pv.i < 0xffff) { - IRDA_DEBUG(2, "%s(), using 2 bytes\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), using 2 bytes\n", __func__); p.pl = 2; } else { - IRDA_DEBUG(2, "%s(), using 4 bytes\n", __FUNCTION__); + IRDA_DEBUG(2, "%s(), using 4 bytes\n", __func__); p.pl = 4; /* Default length */ } } /* Check if buffer is long enough for insertion */ if (len < (2+p.pl)) { IRDA_WARNING("%s: buffer too short for insertion!\n", - __FUNCTION__); + __func__); return -1; } - IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __func__, p.pi, p.pl, p.pv.i); switch (p.pl) { case 1: @@ -187,7 +187,7 @@ static int irda_insert_integer(void *self, __u8 *buf, int len, __u8 pi, break; default: IRDA_WARNING("%s: length %d not supported\n", - __FUNCTION__, p.pl); + __func__, p.pl); /* Skip parameter */ return -1; } @@ -218,7 +218,7 @@ static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, if (len < (2+p.pl)) { IRDA_WARNING("%s: buffer too short for parsing! " "Need %d bytes, but len is only %d\n", - __FUNCTION__, p.pl, len); + __func__, p.pl, len); return -1; } @@ -230,7 +230,7 @@ static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, if (((type & PV_MASK) != PV_INTEGER) && ((type & PV_MASK) != p.pl)) { IRDA_ERROR("%s: invalid parameter length! " "Expected %d bytes, but value had %d bytes!\n", - __FUNCTION__, type & PV_MASK, p.pl); + __func__, type & PV_MASK, p.pl); /* Most parameters are bit/byte fields or little endian, * so it's ok to only extract a subset of it (the subset @@ -268,13 +268,13 @@ static int irda_extract_integer(void *self, __u8 *buf, int len, __u8 pi, break; default: IRDA_WARNING("%s: length %d not supported\n", - __FUNCTION__, p.pl); + __func__, p.pl); /* Skip parameter */ return p.pl+2; } - IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d, pi=%d\n", __func__, p.pi, p.pl, p.pv.i); /* Call handler for this parameter */ err = (*func)(self, &p, PV_PUT); @@ -294,19 +294,19 @@ static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi, irda_param_t p; int err; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); p.pi = pi; /* In case handler needs to know */ p.pl = buf[1]; /* Extract length of value */ - IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), pi=%#x, pl=%d\n", __func__, p.pi, p.pl); /* Check if buffer is long enough for parsing */ if (len < (2+p.pl)) { IRDA_WARNING("%s: buffer too short for parsing! " "Need %d bytes, but len is only %d\n", - __FUNCTION__, p.pl, len); + __func__, p.pl, len); return -1; } @@ -314,7 +314,7 @@ static int irda_extract_string(void *self, __u8 *buf, int len, __u8 pi, * checked that the buffer is long enough */ strncpy(str, buf+2, p.pl); - IRDA_DEBUG(2, "%s(), str=0x%02x 0x%02x\n", __FUNCTION__, + IRDA_DEBUG(2, "%s(), str=0x%02x 0x%02x\n", __func__, (__u8) str[0], (__u8) str[1]); /* Null terminate string */ @@ -345,11 +345,11 @@ static int irda_extract_octseq(void *self, __u8 *buf, int len, __u8 pi, if (len < (2+p.pl)) { IRDA_WARNING("%s: buffer too short for parsing! " "Need %d bytes, but len is only %d\n", - __FUNCTION__, p.pl, len); + __func__, p.pl, len); return -1; } - IRDA_DEBUG(0, "%s(), not impl\n", __FUNCTION__); + IRDA_DEBUG(0, "%s(), not impl\n", __func__); return p.pl+2; /* Extracted pl+2 bytes */ } @@ -473,7 +473,7 @@ int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len, (pi_minor > info->tables[pi_major].len-1)) { IRDA_DEBUG(0, "%s(), no handler for parameter=0x%02x\n", - __FUNCTION__, pi); + __func__, pi); /* Skip this parameter */ return -1; @@ -487,7 +487,7 @@ int irda_param_insert(void *self, __u8 pi, __u8 *buf, int len, /* Check if handler has been implemented */ if (!pi_minor_info->func) { - IRDA_MESSAGE("%s: no handler for pi=%#x\n", __FUNCTION__, pi); + IRDA_MESSAGE("%s: no handler for pi=%#x\n", __func__, pi); /* Skip this parameter */ return -1; } @@ -527,7 +527,7 @@ static int irda_param_extract(void *self, __u8 *buf, int len, (pi_minor > info->tables[pi_major].len-1)) { IRDA_DEBUG(0, "%s(), no handler for parameter=0x%02x\n", - __FUNCTION__, buf[0]); + __func__, buf[0]); /* Skip this parameter */ return 2 + buf[n + 1]; /* Continue */ @@ -539,13 +539,13 @@ static int irda_param_extract(void *self, __u8 *buf, int len, /* Find expected data type for this parameter identifier (pi)*/ type = pi_minor_info->type; - IRDA_DEBUG(3, "%s(), pi=[%d,%d], type=%d\n", __FUNCTION__, + IRDA_DEBUG(3, "%s(), pi=[%d,%d], type=%d\n", __func__, pi_major, pi_minor, type); /* Check if handler has been implemented */ if (!pi_minor_info->func) { IRDA_MESSAGE("%s: no handler for pi=%#x\n", - __FUNCTION__, buf[n]); + __func__, buf[n]); /* Skip this parameter */ return 2 + buf[n + 1]; /* Continue */ } diff --git a/net/irda/qos.c b/net/irda/qos.c index aeb18cf1dcae..2b00974e5bae 100644 --- a/net/irda/qos.c +++ b/net/irda/qos.c @@ -201,7 +201,7 @@ static int msb_index (__u16 word) * it's very likely the peer. - Jean II */ if (word == 0) { IRDA_WARNING("%s(), Detected buggy peer, adjust null PV to 0x1!\n", - __FUNCTION__); + __func__); /* The only safe choice (we don't know the array size) */ word = 0x1; } @@ -342,7 +342,7 @@ static void irlap_adjust_qos_settings(struct qos_info *qos) __u32 line_capacity; int index; - IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + IRDA_DEBUG(2, "%s()\n", __func__); /* * Make sure the mintt is sensible. @@ -352,7 +352,7 @@ static void irlap_adjust_qos_settings(struct qos_info *qos) int i; IRDA_WARNING("%s(), Detected buggy peer, adjust mtt to %dus!\n", - __FUNCTION__, sysctl_min_tx_turn_time); + __func__, sysctl_min_tx_turn_time); /* We don't really need bits, but easier this way */ i = value_highest_bit(sysctl_min_tx_turn_time, min_turn_times, @@ -370,7 +370,7 @@ static void irlap_adjust_qos_settings(struct qos_info *qos) { IRDA_DEBUG(0, "%s(), adjusting max turn time from %d to 500 ms\n", - __FUNCTION__, qos->max_turn_time.value); + __func__, qos->max_turn_time.value); qos->max_turn_time.value = 500; } @@ -386,7 +386,7 @@ static void irlap_adjust_qos_settings(struct qos_info *qos) while ((qos->data_size.value > line_capacity) && (index > 0)) { qos->data_size.value = data_sizes[index--]; IRDA_DEBUG(2, "%s(), reducing data size to %d\n", - __FUNCTION__, qos->data_size.value); + __func__, qos->data_size.value); } #else /* Use method described in section 6.6.11 of IrLAP */ while (irlap_requested_line_capacity(qos) > line_capacity) { @@ -396,14 +396,14 @@ static void irlap_adjust_qos_settings(struct qos_info *qos) if (qos->window_size.value > 1) { qos->window_size.value--; IRDA_DEBUG(2, "%s(), reducing window size to %d\n", - __FUNCTION__, qos->window_size.value); + __func__, qos->window_size.value); } else if (index > 1) { qos->data_size.value = data_sizes[index--]; IRDA_DEBUG(2, "%s(), reducing data size to %d\n", - __FUNCTION__, qos->data_size.value); + __func__, qos->data_size.value); } else { IRDA_WARNING("%s(), nothing more we can do!\n", - __FUNCTION__); + __func__); } } #endif /* CONFIG_IRDA_DYNAMIC_WINDOW */ @@ -538,7 +538,7 @@ static int irlap_param_baud_rate(void *instance, irda_param_t *param, int get) if (get) { param->pv.i = self->qos_rx.baud_rate.bits; IRDA_DEBUG(2, "%s(), baud rate = 0x%02x\n", - __FUNCTION__, param->pv.i); + __func__, param->pv.i); } else { /* * Stations must agree on baud rate, so calculate @@ -711,7 +711,7 @@ __u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time) int i,j; IRDA_DEBUG(2, "%s(), speed=%d, max_turn_time=%d\n", - __FUNCTION__, speed, max_turn_time); + __func__, speed, max_turn_time); i = value_index(speed, baud_rates, 10); j = value_index(max_turn_time, max_turn_times, 4); @@ -722,7 +722,7 @@ __u32 irlap_max_line_capacity(__u32 speed, __u32 max_turn_time) line_capacity = max_line_capacities[i][j]; IRDA_DEBUG(2, "%s(), line capacity=%d bytes\n", - __FUNCTION__, line_capacity); + __func__, line_capacity); return line_capacity; } @@ -738,7 +738,7 @@ static __u32 irlap_requested_line_capacity(struct qos_info *qos) qos->min_turn_time.value); IRDA_DEBUG(2, "%s(), requested line capacity=%d\n", - __FUNCTION__, line_capacity); + __func__, line_capacity); return line_capacity; } diff --git a/net/irda/wrapper.c b/net/irda/wrapper.c index c246983308b8..fd0995b1323a 100644 --- a/net/irda/wrapper.c +++ b/net/irda/wrapper.c @@ -106,16 +106,16 @@ int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize) * Nothing to worry about, but we set the default number of * BOF's */ - IRDA_DEBUG(1, "%s(), wrong magic in skb!\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), wrong magic in skb!\n", __func__); xbofs = 10; } else xbofs = cb->xbofs + cb->xbofs_delay; - IRDA_DEBUG(4, "%s(), xbofs=%d\n", __FUNCTION__, xbofs); + IRDA_DEBUG(4, "%s(), xbofs=%d\n", __func__, xbofs); /* Check that we never use more than 115 + 48 xbofs */ if (xbofs > 163) { - IRDA_DEBUG(0, "%s(), too many xbofs (%d)\n", __FUNCTION__, + IRDA_DEBUG(0, "%s(), too many xbofs (%d)\n", __func__, xbofs); xbofs = 163; } @@ -135,7 +135,7 @@ int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize) */ if(n >= (buffsize-5)) { IRDA_ERROR("%s(), tx buffer overflow (n=%d)\n", - __FUNCTION__, n); + __func__, n); return n; } @@ -287,7 +287,7 @@ async_unwrap_bof(struct net_device *dev, /* Not supposed to happen, the previous frame is not * finished - Jean II */ IRDA_DEBUG(1, "%s(), Discarding incomplete frame\n", - __FUNCTION__); + __func__); stats->rx_errors++; stats->rx_missed_errors++; irda_device_set_media_busy(dev, TRUE); @@ -360,7 +360,7 @@ async_unwrap_eof(struct net_device *dev, /* Wrong CRC, discard frame! */ irda_device_set_media_busy(dev, TRUE); - IRDA_DEBUG(1, "%s(), crc error\n", __FUNCTION__); + IRDA_DEBUG(1, "%s(), crc error\n", __func__); stats->rx_errors++; stats->rx_crc_errors++; } @@ -386,7 +386,7 @@ async_unwrap_ce(struct net_device *dev, break; case LINK_ESCAPE: - IRDA_WARNING("%s: state not defined\n", __FUNCTION__); + IRDA_WARNING("%s: state not defined\n", __func__); break; case BEGIN_FRAME: @@ -421,7 +421,7 @@ async_unwrap_other(struct net_device *dev, #endif } else { IRDA_DEBUG(1, "%s(), Rx buffer overflow, aborting\n", - __FUNCTION__); + __func__); rx_buff->state = OUTSIDE_FRAME; } break; @@ -440,7 +440,7 @@ async_unwrap_other(struct net_device *dev, rx_buff->state = INSIDE_FRAME; } else { IRDA_DEBUG(1, "%s(), Rx buffer overflow, aborting\n", - __FUNCTION__); + __func__); rx_buff->state = OUTSIDE_FRAME; } break; diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 46cf962f7f88..f93b57618582 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -185,7 +185,7 @@ static int llc_ui_release(struct socket *sock) sock_hold(sk); lock_sock(sk); llc = llc_sk(sk); - dprintk("%s: closing local(%02X) remote(%02X)\n", __FUNCTION__, + dprintk("%s: closing local(%02X) remote(%02X)\n", __func__, llc->laddr.lsap, llc->daddr.lsap); if (!llc_send_disc(sk)) llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); @@ -295,7 +295,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) struct llc_sap *sap; int rc = -EINVAL; - dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_sap); + dprintk("%s: binding %02X\n", __func__, addr->sllc_sap); if (unlikely(!sock_flag(sk, SOCK_ZAPPED) || addrlen != sizeof(*addr))) goto out; rc = -EAFNOSUPPORT; @@ -432,7 +432,7 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr, rc = llc_establish_connection(sk, llc->dev->dev_addr, addr->sllc_mac, addr->sllc_sap); if (rc) { - dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__); + dprintk("%s: llc_ui_send_conn failed :-(\n", __func__); sock->state = SS_UNCONNECTED; sk->sk_state = TCP_CLOSE; goto out; @@ -604,7 +604,7 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) struct sk_buff *skb; int rc = -EOPNOTSUPP; - dprintk("%s: accepting on %02X\n", __FUNCTION__, + dprintk("%s: accepting on %02X\n", __func__, llc_sk(sk)->laddr.lsap); lock_sock(sk); if (unlikely(sk->sk_type != SOCK_STREAM)) @@ -619,7 +619,7 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) if (rc) goto out; } - dprintk("%s: got a new connection on %02X\n", __FUNCTION__, + dprintk("%s: got a new connection on %02X\n", __func__, llc_sk(sk)->laddr.lsap); skb = skb_dequeue(&sk->sk_receive_queue); rc = -EINVAL; @@ -640,7 +640,7 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) /* put original socket back into a clean listen state. */ sk->sk_state = TCP_LISTEN; sk->sk_ack_backlog--; - dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__, + dprintk("%s: ok success on %02X, client on %02X\n", __func__, llc_sk(sk)->addr.sllc_sap, newllc->daddr.lsap); frees: kfree_skb(skb); @@ -833,7 +833,7 @@ static int llc_ui_sendmsg(struct kiocb *iocb, struct socket *sock, size_t size = 0; int rc = -EINVAL, copied = 0, hdrlen; - dprintk("%s: sending from %02X to %02X\n", __FUNCTION__, + dprintk("%s: sending from %02X to %02X\n", __func__, llc->laddr.lsap, llc->daddr.lsap); lock_sock(sk); if (addr) { @@ -891,7 +891,7 @@ out: kfree_skb(skb); release: dprintk("%s: failed sending from %02X to %02X: %d\n", - __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap, rc); + __func__, llc->laddr.lsap, llc->daddr.lsap, rc); } release_sock(sk); return rc ? : copied; diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c index 860140caa6e0..f728ffe288aa 100644 --- a/net/llc/llc_c_ac.c +++ b/net/llc/llc_c_ac.c @@ -1427,7 +1427,7 @@ static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb) { if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) { printk(KERN_WARNING "%s: timer called on closed connection\n", - __FUNCTION__); + __func__); kfree_skb(skb); } else { if (!sock_owned_by_user(sk)) diff --git a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c index c5deda246614..523fdd1cf781 100644 --- a/net/llc/llc_c_ev.c +++ b/net/llc/llc_c_ev.c @@ -228,7 +228,7 @@ int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk, llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; if (!rc) dprintk("%s: matched, state=%d, ns=%d, vr=%d\n", - __FUNCTION__, llc_sk(sk)->state, ns, vr); + __func__, llc_sk(sk)->state, ns, vr); return rc; } @@ -306,7 +306,7 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk, llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; if (!rc) dprintk("%s: matched, state=%d, ns=%d, vr=%d\n", - __FUNCTION__, llc_sk(sk)->state, ns, vr); + __func__, llc_sk(sk)->state, ns, vr); return rc; } @@ -511,7 +511,7 @@ int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk, (LLC_PDU_TYPE_IS_I(pdu) || LLC_PDU_TYPE_IS_S(pdu)) && nr != vs && llc_util_nr_inside_tx_window(sk, nr)) { dprintk("%s: matched, state=%d, vs=%d, nr=%d\n", - __FUNCTION__, llc_sk(sk)->state, vs, nr); + __func__, llc_sk(sk)->state, vs, nr); rc = 0; } return rc; @@ -530,7 +530,7 @@ int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk, nr != vs && llc_util_nr_inside_tx_window(sk, nr)) { rc = 0; dprintk("%s: matched, state=%d, vs=%d, nr=%d\n", - __FUNCTION__, llc_sk(sk)->state, vs, nr); + __func__, llc_sk(sk)->state, vs, nr); } return rc; } diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 441bc18f996d..5ebfd93ff5e7 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -73,7 +73,7 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) */ rc = llc_conn_service(skb->sk, skb); if (unlikely(rc != 0)) { - printk(KERN_ERR "%s: llc_conn_service failed\n", __FUNCTION__); + printk(KERN_ERR "%s: llc_conn_service failed\n", __func__); goto out_kfree_skb; } @@ -99,7 +99,7 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) * shouldn't happen */ printk(KERN_ERR "%s: sock_queue_rcv_skb failed!\n", - __FUNCTION__); + __func__); kfree_skb(skb); } break; @@ -132,13 +132,13 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) * FIXME: * RESET is not being notified to upper layers for now */ - printk(KERN_INFO "%s: received a reset ind!\n", __FUNCTION__); + printk(KERN_INFO "%s: received a reset ind!\n", __func__); kfree_skb(skb); break; default: if (ev->ind_prim) { printk(KERN_INFO "%s: received unknown %d prim!\n", - __FUNCTION__, ev->ind_prim); + __func__, ev->ind_prim); kfree_skb(skb); } /* No indication */ @@ -179,12 +179,12 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) * FIXME: * RESET is not being notified to upper layers for now */ - printk(KERN_INFO "%s: received a reset conf!\n", __FUNCTION__); + printk(KERN_INFO "%s: received a reset conf!\n", __func__); break; default: if (ev->cfm_prim) { printk(KERN_INFO "%s: received unknown %d prim!\n", - __FUNCTION__, ev->cfm_prim); + __func__, ev->cfm_prim); break; } goto out_skb_put; /* No confirmation */ @@ -759,7 +759,7 @@ void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb) if (!sock_owned_by_user(sk)) llc_conn_rcv(sk, skb); else { - dprintk("%s: adding to backlog...\n", __FUNCTION__); + dprintk("%s: adding to backlog...\n", __func__); llc_set_backlog_type(skb, LLC_PACKET); sk_add_backlog(sk, skb); } @@ -807,7 +807,7 @@ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb) else goto out_kfree_skb; } else { - printk(KERN_ERR "%s: invalid skb in backlog\n", __FUNCTION__); + printk(KERN_ERR "%s: invalid skb in backlog\n", __func__); goto out_kfree_skb; } out: @@ -874,7 +874,7 @@ struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct pr #ifdef LLC_REFCNT_DEBUG atomic_inc(&llc_sock_nr); printk(KERN_DEBUG "LLC socket %p created in %s, now we have %d alive\n", sk, - __FUNCTION__, atomic_read(&llc_sock_nr)); + __func__, atomic_read(&llc_sock_nr)); #endif out: return sk; @@ -894,7 +894,7 @@ void llc_sk_free(struct sock *sk) /* Stop all (possibly) running timers */ llc_conn_ac_stop_all_timers(sk, NULL); #ifdef DEBUG_LLC_CONN_ALLOC - printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__, + printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __func__, skb_queue_len(&llc->pdu_unack_q), skb_queue_len(&sk->sk_write_queue)); #endif @@ -904,13 +904,13 @@ void llc_sk_free(struct sock *sk) #ifdef LLC_REFCNT_DEBUG if (atomic_read(&sk->sk_refcnt) != 1) { printk(KERN_DEBUG "Destruction of LLC sock %p delayed in %s, cnt=%d\n", - sk, __FUNCTION__, atomic_read(&sk->sk_refcnt)); + sk, __func__, atomic_read(&sk->sk_refcnt)); printk(KERN_DEBUG "%d LLC sockets are still alive\n", atomic_read(&llc_sock_nr)); } else { atomic_dec(&llc_sock_nr); printk(KERN_DEBUG "LLC socket %p released in %s, %d are still alive\n", sk, - __FUNCTION__, atomic_read(&llc_sock_nr)); + __func__, atomic_read(&llc_sock_nr)); } #endif sock_put(sk); diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c index c40c9b2a345a..b9143d2a04e1 100644 --- a/net/llc/llc_input.c +++ b/net/llc/llc_input.c @@ -154,7 +154,7 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, * receives, do not try to analyse it. */ if (unlikely(skb->pkt_type == PACKET_OTHERHOST)) { - dprintk("%s: PACKET_OTHERHOST\n", __FUNCTION__); + dprintk("%s: PACKET_OTHERHOST\n", __func__); goto drop; } skb = skb_share_check(skb, GFP_ATOMIC); @@ -167,7 +167,7 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, goto handle_station; sap = llc_sap_find(pdu->dsap); if (unlikely(!sap)) {/* unknown SAP */ - dprintk("%s: llc_sap_find(%02X) failed!\n", __FUNCTION__, + dprintk("%s: llc_sap_find(%02X) failed!\n", __func__, pdu->dsap); goto drop; } diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 0d6824bca92b..677705046c6d 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -165,7 +165,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) break; default: printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x", - dev->name, __FUNCTION__, type); + dev->name, __func__, type); } ieee80211_debugfs_change_if_type(sdata, oldtype); } diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index 1aaa2e804b0d..e58cc65728b5 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -619,8 +619,8 @@ void _dbprintk(const char *fmt, ...) { } -#define kenter(FMT,...) dbgprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__) -#define kleave(FMT,...) dbgprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__) +#define kenter(FMT,...) dbgprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__) +#define kleave(FMT,...) dbgprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__) #define kdebug(FMT,...) dbgprintk(" "FMT ,##__VA_ARGS__) #define kproto(FMT,...) dbgprintk("### "FMT ,##__VA_ARGS__) #define knet(FMT,...) dbgprintk("@@@ "FMT ,##__VA_ARGS__) @@ -671,8 +671,8 @@ do { \ } while (0) #else -#define _enter(FMT,...) _dbprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__) -#define _leave(FMT,...) _dbprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__) +#define _enter(FMT,...) _dbprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__) +#define _leave(FMT,...) _dbprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__) #define _debug(FMT,...) _dbprintk(" "FMT ,##__VA_ARGS__) #define _proto(FMT,...) _dbprintk("### "FMT ,##__VA_ARGS__) #define _net(FMT,...) _dbprintk("@@@ "FMT ,##__VA_ARGS__) diff --git a/net/sctp/associola.c b/net/sctp/associola.c index d29f792e0529..422c98aa9d5c 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1330,7 +1330,7 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc) } SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n", - __FUNCTION__, asoc, asoc->pathmtu, asoc->frag_point); + __func__, asoc, asoc->pathmtu, asoc->frag_point); } /* Should we send a SACK to update our peer? */ @@ -1370,7 +1370,7 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len) } SCTP_DEBUG_PRINTK("%s: asoc %p rwnd increased by %d to (%u, %u) " - "- %u\n", __FUNCTION__, asoc, len, asoc->rwnd, + "- %u\n", __func__, asoc, len, asoc->rwnd, asoc->rwnd_over, asoc->a_rwnd); /* Send a window update SACK if the rwnd has increased by at least the @@ -1381,7 +1381,7 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned len) if (sctp_peer_needs_update(asoc)) { asoc->a_rwnd = asoc->rwnd; SCTP_DEBUG_PRINTK("%s: Sending window update SACK- asoc: %p " - "rwnd: %u a_rwnd: %u\n", __FUNCTION__, + "rwnd: %u a_rwnd: %u\n", __func__, asoc, asoc->rwnd, asoc->a_rwnd); sack = sctp_make_sack(asoc); if (!sack) @@ -1410,7 +1410,7 @@ void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len) asoc->rwnd = 0; } SCTP_DEBUG_PRINTK("%s: asoc %p rwnd decreased by %d to (%u, %u)\n", - __FUNCTION__, asoc, len, asoc->rwnd, + __func__, asoc, len, asoc->rwnd, asoc->rwnd_over); } diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index 4d3128f5ccc3..e1f355080026 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -189,7 +189,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc, msecs_to_jiffies(sinfo->sinfo_timetolive); msg->can_abandon = 1; SCTP_DEBUG_PRINTK("%s: msg:%p expires_at: %ld jiffies:%ld\n", - __FUNCTION__, msg, msg->expires_at, jiffies); + __func__, msg, msg->expires_at, jiffies); } max = asoc->frag_point; diff --git a/net/sctp/input.c b/net/sctp/input.c index 57fe2f81eca8..4db5a75e01ce 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -409,7 +409,7 @@ void sctp_icmp_proto_unreachable(struct sock *sk, struct sctp_association *asoc, struct sctp_transport *t) { - SCTP_DEBUG_PRINTK("%s\n", __FUNCTION__); + SCTP_DEBUG_PRINTK("%s\n", __func__); sctp_do_sm(SCTP_EVENT_T_OTHER, SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH), diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 4862835b0c39..2622215cd357 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -223,7 +223,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport, SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, " "src:" NIP6_FMT " dst:" NIP6_FMT "\n", - __FUNCTION__, skb, skb->len, + __func__, skb, skb->len, NIP6(fl.fl6_src), NIP6(fl.fl6_dst)); SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS); @@ -248,7 +248,7 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ", - __FUNCTION__, NIP6(fl.fl6_dst)); + __func__, NIP6(fl.fl6_dst)); if (saddr) { ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr); @@ -310,7 +310,7 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc, SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p " "daddr:" NIP6_FMT " ", - __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr)); + __func__, asoc, dst, NIP6(daddr->v6.sin6_addr)); if (!asoc) { ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, @@ -349,7 +349,7 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc, } else { printk(KERN_ERR "%s: asoc:%p Could not find a valid source " "address for the dest:" NIP6_FMT "\n", - __FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr)); + __func__, asoc, NIP6(daddr->v6.sin6_addr)); } rcu_read_unlock(); diff --git a/net/sctp/output.c b/net/sctp/output.c index aa700feea76c..cf4f9fb6819d 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -74,7 +74,7 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet, { struct sctp_chunk *chunk = NULL; - SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __FUNCTION__, + SCTP_DEBUG_PRINTK("%s: packet:%p vtag:0x%x\n", __func__, packet, vtag); packet->vtag = vtag; @@ -106,7 +106,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet, struct sctp_association *asoc = transport->asoc; size_t overhead; - SCTP_DEBUG_PRINTK("%s: packet:%p transport:%p\n", __FUNCTION__, + SCTP_DEBUG_PRINTK("%s: packet:%p transport:%p\n", __func__, packet, transport); packet->transport = transport; @@ -138,7 +138,7 @@ void sctp_packet_free(struct sctp_packet *packet) { struct sctp_chunk *chunk, *tmp; - SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet); + SCTP_DEBUG_PRINTK("%s: packet:%p\n", __func__, packet); list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) { list_del_init(&chunk->list); @@ -162,7 +162,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet, sctp_xmit_t retval; int error = 0; - SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__, + SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet, chunk); switch ((retval = (sctp_packet_append_chunk(packet, chunk)))) { @@ -264,7 +264,7 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, size_t pmtu; int too_big; - SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __FUNCTION__, packet, + SCTP_DEBUG_PRINTK("%s: packet:%p chunk:%p\n", __func__, packet, chunk); /* Try to bundle AUTH chunk */ @@ -372,7 +372,7 @@ int sctp_packet_transmit(struct sctp_packet *packet) unsigned char *auth = NULL; /* pointer to auth in skb data */ __u32 cksum_buf_len = sizeof(struct sctphdr); - SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet); + SCTP_DEBUG_PRINTK("%s: packet:%p\n", __func__, packet); /* Do NOT generate a chunkless packet. */ if (list_empty(&packet->chunk_list)) @@ -677,7 +677,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, "transport: %p, cwnd: %d, " "ssthresh: %d, flight_size: %d, " "pba: %d\n", - __FUNCTION__, transport, + __func__, transport, transport->cwnd, transport->ssthresh, transport->flight_size, diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index fd4deefab3cf..392012f5ab83 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -469,7 +469,7 @@ void sctp_retransmit_mark(struct sctp_outq *q, SCTP_DEBUG_PRINTK("%s: transport: %p, reason: %d, " "cwnd: %d, ssthresh: %d, flight_size: %d, " - "pba: %d\n", __FUNCTION__, + "pba: %d\n", __func__, transport, reason, transport->cwnd, transport->ssthresh, transport->flight_size, @@ -1206,10 +1206,10 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) sctp_generate_fwdtsn(q, sack_ctsn); SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n", - __FUNCTION__, sack_ctsn); + __func__, sack_ctsn); SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association, " "%p is 0x%x. Adv peer ack point: 0x%x\n", - __FUNCTION__, asoc, ctsn, asoc->adv_peer_ack_point); + __func__, asoc, ctsn, asoc->adv_peer_ack_point); /* See if all chunks are acked. * Make sure the empty queue handler will get run later. @@ -1444,7 +1444,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, if (tchunk->tsn_gap_acked) { SCTP_DEBUG_PRINTK("%s: Receiver reneged on " "data TSN: 0x%x\n", - __FUNCTION__, + __func__, tsn); tchunk->tsn_gap_acked = 0; @@ -1561,7 +1561,7 @@ static void sctp_check_transmitted(struct sctp_outq *q, (sack_ctsn+2 == q->asoc->next_tsn)) { SCTP_DEBUG_PRINTK("%s: SACK received for zero " "window probe: %u\n", - __FUNCTION__, sack_ctsn); + __func__, sack_ctsn); q->asoc->overall_error_count = 0; transport->error_count = 0; } @@ -1626,7 +1626,7 @@ static void sctp_mark_missing(struct sctp_outq *q, SCTP_DEBUG_PRINTK( "%s: TSN 0x%x missing counter: %d\n", - __FUNCTION__, tsn, + __func__, tsn, chunk->tsn_missing_report); } } @@ -1649,7 +1649,7 @@ static void sctp_mark_missing(struct sctp_outq *q, SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, " "ssthresh: %d, flight_size: %d, pba: %d\n", - __FUNCTION__, transport, transport->cwnd, + __func__, transport, transport->cwnd, transport->ssthresh, transport->flight_size, transport->partial_bytes_acked); } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 1afef08f6c1d..87512f14cf71 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -451,7 +451,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, fl.fl4_src = saddr->v4.sin_addr.s_addr; SCTP_DEBUG_PRINTK("%s: DST:%u.%u.%u.%u, SRC:%u.%u.%u.%u - ", - __FUNCTION__, NIPQUAD(fl.fl4_dst), + __func__, NIPQUAD(fl.fl4_dst), NIPQUAD(fl.fl4_src)); if (!ip_route_output_key(&init_net, &rt, &fl)) { @@ -827,7 +827,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, { SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, " "src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n", - __FUNCTION__, skb, skb->len, + __func__, skb, skb->len, NIPQUAD(skb->rtable->rt_src), NIPQUAD(skb->rtable->rt_dst)); diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 28eb38eb6083..02bf32c30263 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -243,7 +243,7 @@ void sctp_generate_t3_rtx_event(unsigned long peer) sctp_bh_lock_sock(asoc->base.sk); if (sock_owned_by_user(asoc->base.sk)) { - SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__); + SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__); /* Try again later. */ if (!mod_timer(&transport->T3_rtx_timer, jiffies + (HZ/20))) @@ -283,7 +283,7 @@ static void sctp_generate_timeout_event(struct sctp_association *asoc, sctp_bh_lock_sock(asoc->base.sk); if (sock_owned_by_user(asoc->base.sk)) { SCTP_DEBUG_PRINTK("%s:Sock is busy: timer %d\n", - __FUNCTION__, + __func__, timeout_type); /* Try again later. */ @@ -361,7 +361,7 @@ void sctp_generate_heartbeat_event(unsigned long data) sctp_bh_lock_sock(asoc->base.sk); if (sock_owned_by_user(asoc->base.sk)) { - SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __FUNCTION__); + SCTP_DEBUG_PRINTK("%s:Sock is busy.\n", __func__); /* Try again later. */ if (!mod_timer(&transport->hb_timer, jiffies + (HZ/20))) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index ade0cbd3a52b..c0c6bee77cf5 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -1124,7 +1124,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, printk(KERN_WARNING "%s association %p could not find address " NIP6_FMT "\n", - __FUNCTION__, + __func__, asoc, NIP6(from_addr.v6.sin6_addr)); } else { @@ -1132,7 +1132,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, printk(KERN_WARNING "%s association %p could not find address " NIPQUAD_FMT "\n", - __FUNCTION__, + __func__, asoc, NIPQUAD(from_addr.v4.sin_addr.s_addr)); } @@ -1150,7 +1150,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, time_after(jiffies, hbinfo->sent_at + max_interval)) { SCTP_DEBUG_PRINTK("%s: HEARTBEAT ACK with invalid timestamp " "received for transport: %p\n", - __FUNCTION__, link); + __func__, link); return SCTP_DISPOSITION_DISCARD; } @@ -3668,7 +3668,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep, skb_pull(chunk->skb, len); tsn = ntohl(fwdtsn_hdr->new_cum_tsn); - SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn); + SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __func__, tsn); /* The TSN is too high--silently discard the chunk and count on it * getting retransmitted later. @@ -3728,7 +3728,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast( skb_pull(chunk->skb, len); tsn = ntohl(fwdtsn_hdr->new_cum_tsn); - SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __FUNCTION__, tsn); + SCTP_DEBUG_PRINTK("%s: TSN 0x%x.\n", __func__, tsn); /* The TSN is too high--silently discard the chunk and count on it * getting retransmitted later. diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 939892691a26..1316694d0a21 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -525,7 +525,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk, ep = sp->ep; SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n", - __FUNCTION__, sk, addrs, addrcnt); + __func__, sk, addrs, addrcnt); list_for_each(pos, &ep->asocs) { asoc = list_entry(pos, struct sctp_association, asocs); @@ -711,7 +711,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk, ep = sp->ep; SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n", - __FUNCTION__, sk, addrs, addrcnt); + __func__, sk, addrs, addrcnt); list_for_each(pos, &ep->asocs) { asoc = list_entry(pos, struct sctp_association, asocs); @@ -1197,7 +1197,7 @@ SCTP_STATIC int sctp_setsockopt_connectx(struct sock* sk, struct sockaddr *kaddrs; SCTP_DEBUG_PRINTK("%s - sk %p addrs %p addrs_size %d\n", - __FUNCTION__, sk, addrs, addrs_size); + __func__, sk, addrs, addrs_size); if (unlikely(addrs_size <= 0)) return -EINVAL; @@ -3280,7 +3280,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *addr, sctp_lock_sock(sk); SCTP_DEBUG_PRINTK("%s - sk: %p, sockaddr: %p, addr_len: %d\n", - __FUNCTION__, sk, addr, addr_len); + __func__, sk, addr, addr_len); /* Validate addr_len before calling common connect/connectx routine. */ af = sctp_get_af_specific(addr->sa_family); @@ -3801,7 +3801,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval goto out; } - SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __FUNCTION__, sk, asoc); + SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __func__, sk, asoc); retval = sctp_do_peeloff(asoc, &newsock); if (retval < 0) @@ -3815,7 +3815,7 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char __user *optval } SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p newsk: %p sd: %d\n", - __FUNCTION__, sk, asoc, newsock->sk, retval); + __func__, sk, asoc, newsock->sk, retval); /* Return the fd mapped to the new socket. */ peeloff.sd = retval; @@ -6186,7 +6186,7 @@ static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p) long current_timeo = *timeo_p; DEFINE_WAIT(wait); - SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc, + SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __func__, asoc, (long)(*timeo_p)); /* Increment the association's refcnt. */ diff --git a/net/sctp/transport.c b/net/sctp/transport.c index d9f8af852b56..f4938f6c5abe 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -260,7 +260,7 @@ void sctp_transport_update_pmtu(struct sctp_transport *t, u32 pmtu) if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { printk(KERN_WARNING "%s: Reported pmtu %d too low, " "using default minimum of %d\n", - __FUNCTION__, pmtu, + __func__, pmtu, SCTP_DEFAULT_MINSEGMENT); /* Use default minimum segment size and disable * pmtu discovery on this transport. @@ -388,7 +388,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) tp->rto_pending = 0; SCTP_DEBUG_PRINTK("%s: transport: %p, rtt: %d, srtt: %d " - "rttvar: %d, rto: %ld\n", __FUNCTION__, + "rttvar: %d, rto: %ld\n", __func__, tp, rtt, tp->srtt, tp->rttvar, tp->rto); } @@ -434,7 +434,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport, SCTP_DEBUG_PRINTK("%s: SLOW START: transport: %p, " "bytes_acked: %d, cwnd: %d, ssthresh: %d, " "flight_size: %d, pba: %d\n", - __FUNCTION__, + __func__, transport, bytes_acked, cwnd, ssthresh, flight_size, pba); } else { @@ -460,7 +460,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport, SCTP_DEBUG_PRINTK("%s: CONGESTION AVOIDANCE: " "transport: %p, bytes_acked: %d, cwnd: %d, " "ssthresh: %d, flight_size: %d, pba: %d\n", - __FUNCTION__, + __func__, transport, bytes_acked, cwnd, ssthresh, flight_size, pba); } @@ -546,7 +546,7 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, transport->partial_bytes_acked = 0; SCTP_DEBUG_PRINTK("%s: transport: %p reason: %d cwnd: " - "%d ssthresh: %d\n", __FUNCTION__, + "%d ssthresh: %d\n", __func__, transport, reason, transport->cwnd, transport->ssthresh); } diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 6dac38792288..5828e5c060ca 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -625,7 +625,7 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor) gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor); if (!gss_auth->mech) { printk(KERN_WARNING "%s: Pseudoflavor %d not found!\n", - __FUNCTION__, flavor); + __func__, flavor); goto err_free; } gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 8c6a7f1a25e9..13a3718e7cc9 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -43,7 +43,7 @@ #define dprint_status(t) \ dprintk("RPC: %5u %s (status %d)\n", t->tk_pid, \ - __FUNCTION__, t->tk_status) + __func__, t->tk_status) /* * All RPC clients are linked into this list @@ -372,7 +372,7 @@ out_no_path: out_no_stats: kfree(new); out_no_clnt: - dprintk("RPC: %s: returned error %d\n", __FUNCTION__, err); + dprintk("RPC: %s: returned error %d\n", __func__, err); return ERR_PTR(err); } EXPORT_SYMBOL_GPL(rpc_clone_client); @@ -756,7 +756,7 @@ call_reserveresult(struct rpc_task *task) } printk(KERN_ERR "%s: status=%d, but no request slot, exiting\n", - __FUNCTION__, status); + __func__, status); rpc_exit(task, -EIO); return; } @@ -767,7 +767,7 @@ call_reserveresult(struct rpc_task *task) */ if (task->tk_rqstp) { printk(KERN_ERR "%s: status=%d, request allocated anyway\n", - __FUNCTION__, status); + __func__, status); xprt_release(task); } @@ -779,7 +779,7 @@ call_reserveresult(struct rpc_task *task) break; default: printk(KERN_ERR "%s: unrecognized error %d, exiting\n", - __FUNCTION__, status); + __func__, status); break; } rpc_exit(task, status); @@ -1327,7 +1327,7 @@ call_verify(struct rpc_task *task) * undefined results */ dprintk("RPC: %5u %s: XDR representation not a multiple of" - " 4 bytes: 0x%x\n", task->tk_pid, __FUNCTION__, + " 4 bytes: 0x%x\n", task->tk_pid, __func__, task->tk_rqstp->rq_rcv_buf.len); goto out_eio; } @@ -1337,7 +1337,7 @@ call_verify(struct rpc_task *task) if ((n = ntohl(*p++)) != RPC_REPLY) { dprintk("RPC: %5u %s: not an RPC reply: %x\n", - task->tk_pid, __FUNCTION__, n); + task->tk_pid, __func__, n); goto out_garbage; } if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) { @@ -1349,13 +1349,13 @@ call_verify(struct rpc_task *task) case RPC_MISMATCH: dprintk("RPC: %5u %s: RPC call version " "mismatch!\n", - task->tk_pid, __FUNCTION__); + task->tk_pid, __func__); error = -EPROTONOSUPPORT; goto out_err; default: dprintk("RPC: %5u %s: RPC call rejected, " "unknown error: %x\n", - task->tk_pid, __FUNCTION__, n); + task->tk_pid, __func__, n); goto out_eio; } if (--len < 0) @@ -1369,7 +1369,7 @@ call_verify(struct rpc_task *task) break; task->tk_cred_retry--; dprintk("RPC: %5u %s: retry stale creds\n", - task->tk_pid, __FUNCTION__); + task->tk_pid, __func__); rpcauth_invalcred(task); /* Ensure we obtain a new XID! */ xprt_release(task); @@ -1382,7 +1382,7 @@ call_verify(struct rpc_task *task) break; task->tk_garb_retry--; dprintk("RPC: %5u %s: retry garbled creds\n", - task->tk_pid, __FUNCTION__); + task->tk_pid, __func__); task->tk_action = call_bind; goto out_retry; case RPC_AUTH_TOOWEAK: @@ -1391,16 +1391,16 @@ call_verify(struct rpc_task *task) break; default: dprintk("RPC: %5u %s: unknown auth error: %x\n", - task->tk_pid, __FUNCTION__, n); + task->tk_pid, __func__, n); error = -EIO; } dprintk("RPC: %5u %s: call rejected %d\n", - task->tk_pid, __FUNCTION__, n); + task->tk_pid, __func__, n); goto out_err; } if (!(p = rpcauth_checkverf(task, p))) { dprintk("RPC: %5u %s: auth check failed\n", - task->tk_pid, __FUNCTION__); + task->tk_pid, __func__); goto out_garbage; /* bad verifier, retry */ } len = p - (__be32 *)iov->iov_base - 1; @@ -1411,14 +1411,14 @@ call_verify(struct rpc_task *task) return p; case RPC_PROG_UNAVAIL: dprintk("RPC: %5u %s: program %u is unsupported by server %s\n", - task->tk_pid, __FUNCTION__, + task->tk_pid, __func__, (unsigned int)task->tk_client->cl_prog, task->tk_client->cl_server); error = -EPFNOSUPPORT; goto out_err; case RPC_PROG_MISMATCH: dprintk("RPC: %5u %s: program %u, version %u unsupported by " - "server %s\n", task->tk_pid, __FUNCTION__, + "server %s\n", task->tk_pid, __func__, (unsigned int)task->tk_client->cl_prog, (unsigned int)task->tk_client->cl_vers, task->tk_client->cl_server); @@ -1427,7 +1427,7 @@ call_verify(struct rpc_task *task) case RPC_PROC_UNAVAIL: dprintk("RPC: %5u %s: proc %p unsupported by program %u, " "version %u on server %s\n", - task->tk_pid, __FUNCTION__, + task->tk_pid, __func__, task->tk_msg.rpc_proc, task->tk_client->cl_prog, task->tk_client->cl_vers, @@ -1436,11 +1436,11 @@ call_verify(struct rpc_task *task) goto out_err; case RPC_GARBAGE_ARGS: dprintk("RPC: %5u %s: server saw garbage\n", - task->tk_pid, __FUNCTION__); + task->tk_pid, __func__); break; /* retry */ default: dprintk("RPC: %5u %s: server accept status: %x\n", - task->tk_pid, __FUNCTION__, n); + task->tk_pid, __func__, n); /* Also retry */ } @@ -1449,7 +1449,7 @@ out_garbage: if (task->tk_garb_retry) { task->tk_garb_retry--; dprintk("RPC: %5u %s: retrying\n", - task->tk_pid, __FUNCTION__); + task->tk_pid, __func__); task->tk_action = call_bind; out_retry: return ERR_PTR(-EAGAIN); @@ -1459,11 +1459,11 @@ out_eio: out_err: rpc_exit(task, error); dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid, - __FUNCTION__, error); + __func__, error); return ERR_PTR(error); out_overflow: dprintk("RPC: %5u %s: server reply was truncated.\n", task->tk_pid, - __FUNCTION__); + __func__); goto out_garbage; } diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 1b395a41a8b2..5a9b0e7828cd 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -479,13 +479,13 @@ rpc_lookup_parent(char *path, struct nameidata *nd) mnt = rpc_get_mount(); if (IS_ERR(mnt)) { printk(KERN_WARNING "%s: %s failed to mount " - "pseudofilesystem \n", __FILE__, __FUNCTION__); + "pseudofilesystem \n", __FILE__, __func__); return PTR_ERR(mnt); } if (vfs_path_lookup(mnt->mnt_root, mnt, path, LOOKUP_PARENT, nd)) { printk(KERN_WARNING "%s: %s failed to find path %s\n", - __FILE__, __FUNCTION__, path); + __FILE__, __func__, path); rpc_put_mount(); return -ENOENT; } @@ -604,7 +604,7 @@ rpc_populate(struct dentry *parent, out_bad: mutex_unlock(&dir->i_mutex); printk(KERN_WARNING "%s: %s failed to populate directory %s\n", - __FILE__, __FUNCTION__, parent->d_name.name); + __FILE__, __func__, parent->d_name.name); return -ENOMEM; } @@ -623,7 +623,7 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry) return 0; out_err: printk(KERN_WARNING "%s: %s failed to allocate inode for dentry %s\n", - __FILE__, __FUNCTION__, dentry->d_name.name); + __FILE__, __func__, dentry->d_name.name); return -ENOMEM; } @@ -715,7 +715,7 @@ err_depopulate: err_dput: dput(dentry); printk(KERN_WARNING "%s: %s() failed to create directory %s (errno = %d)\n", - __FILE__, __FUNCTION__, path, error); + __FILE__, __func__, path, error); dentry = ERR_PTR(error); goto out; } @@ -804,7 +804,7 @@ err_dput: dput(dentry); dentry = ERR_PTR(-ENOMEM); printk(KERN_WARNING "%s: %s() failed to create pipe %s/%s (errno = %d)\n", - __FILE__, __FUNCTION__, parent->d_name.name, name, + __FILE__, __func__, parent->d_name.name, name, -ENOMEM); goto out; } diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 3164a0871cf0..56aa018dce3a 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -224,7 +224,7 @@ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot) int status; dprintk("RPC: %s(" NIPQUAD_FMT ", %u, %u, %d)\n", - __FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); + __func__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin, sizeof(*sin), prot, 2, 0); @@ -283,7 +283,7 @@ void rpcb_getport_async(struct rpc_task *task) struct rpcb_info *info; dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", - task->tk_pid, __FUNCTION__, + task->tk_pid, __func__, clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); /* Autobind on cloned rpc clients is discouraged */ @@ -292,7 +292,7 @@ void rpcb_getport_async(struct rpc_task *task) if (xprt_test_and_set_binding(xprt)) { status = -EAGAIN; /* tell caller to check again */ dprintk("RPC: %5u %s: waiting for another binder\n", - task->tk_pid, __FUNCTION__); + task->tk_pid, __func__); goto bailout_nowake; } @@ -304,7 +304,7 @@ void rpcb_getport_async(struct rpc_task *task) if (xprt_bound(xprt)) { status = 0; dprintk("RPC: %5u %s: already bound\n", - task->tk_pid, __FUNCTION__); + task->tk_pid, __func__); goto bailout_nofree; } @@ -321,27 +321,27 @@ void rpcb_getport_async(struct rpc_task *task) default: status = -EAFNOSUPPORT; dprintk("RPC: %5u %s: bad address family\n", - task->tk_pid, __FUNCTION__); + task->tk_pid, __func__); goto bailout_nofree; } if (info[xprt->bind_index].rpc_proc == NULL) { xprt->bind_index = 0; status = -EPFNOSUPPORT; dprintk("RPC: %5u %s: no more getport versions available\n", - task->tk_pid, __FUNCTION__); + task->tk_pid, __func__); goto bailout_nofree; } bind_version = info[xprt->bind_index].rpc_vers; dprintk("RPC: %5u %s: trying rpcbind version %u\n", - task->tk_pid, __FUNCTION__, bind_version); + task->tk_pid, __func__, bind_version); rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot, bind_version, 0); if (IS_ERR(rpcb_clnt)) { status = PTR_ERR(rpcb_clnt); dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n", - task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt)); + task->tk_pid, __func__, PTR_ERR(rpcb_clnt)); goto bailout_nofree; } @@ -349,7 +349,7 @@ void rpcb_getport_async(struct rpc_task *task) if (!map) { status = -ENOMEM; dprintk("RPC: %5u %s: no memory available\n", - task->tk_pid, __FUNCTION__); + task->tk_pid, __func__); goto bailout_nofree; } map->r_prog = clnt->cl_prog; @@ -366,7 +366,7 @@ void rpcb_getport_async(struct rpc_task *task) if (IS_ERR(child)) { status = -EIO; dprintk("RPC: %5u %s: rpc_run_task failed\n", - task->tk_pid, __FUNCTION__); + task->tk_pid, __func__); goto bailout; } rpc_put_task(child); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 30e7ac243a90..613daf8c1ff7 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1359,7 +1359,7 @@ static int xs_bind4(struct sock_xprt *transport, struct socket *sock) nloop++; } while (err == -EADDRINUSE && nloop != 2); dprintk("RPC: %s "NIPQUAD_FMT":%u: %s (%d)\n", - __FUNCTION__, NIPQUAD(myaddr.sin_addr), + __func__, NIPQUAD(myaddr.sin_addr), port, err ? "failed" : "ok", err); return err; } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index b8788fd5e3c6..ae584356852c 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2176,7 +2176,7 @@ static int __init af_unix_init(void) rc = proto_register(&unix_proto, 1); if (rc != 0) { printk(KERN_CRIT "%s: Cannot create unix_sock SLAB cache!\n", - __FUNCTION__); + __func__); goto out; } -- cgit v1.2.3-59-g8ed1b From 2ec600d672e74488f8d1acf67a0a2baed222564c Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:06 +0100 Subject: nl80211/cfg80211: support for mesh, sta dumping Added support for mesh id and mesh path operation as well as station structure dumping. Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 119 +++++++++++-- include/net/cfg80211.h | 139 +++++++++++++-- net/mac80211/cfg.c | 20 ++- net/wireless/nl80211.c | 438 +++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 650 insertions(+), 66 deletions(-) (limited to 'net') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index a9f0b93324a2..ea6517e58b04 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -78,6 +78,18 @@ * or, if no MAC address given, all stations, on the interface identified * by %NL80211_ATTR_IFINDEX. * + * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to + * destination %NL80211_ATTR_MAC on the interface identified by + * %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to + * destination %NL80211_ATTR_MAC on the interface identified by + * %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the + * the interface identified by %NL80211_ATTR_IFINDEX. + * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC + * or, if no MAC address given, all mesh paths, on the interface identified + * by %NL80211_ATTR_IFINDEX. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -112,6 +124,11 @@ enum nl80211_commands { /* add commands here */ + NL80211_CMD_GET_MPATH, + NL80211_CMD_SET_MPATH, + NL80211_CMD_NEW_MPATH, + NL80211_CMD_DEL_MPATH, + /* used to define NL80211_CMD_MAX below */ __NL80211_CMD_AFTER_LAST, NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1 @@ -157,13 +174,21 @@ enum nl80211_commands { * restriction (at most %NL80211_MAX_SUPP_RATES). * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station * to, or the AP interface the station was originally added to to. - * @NL80211_ATTR_STA_STATS: statistics for a station, part of station info + * @NL80211_ATTR_STA_INFO: information about a station, part of station info * given for %NL80211_CMD_GET_STATION, nested attribute containing - * info as possible, see &enum nl80211_sta_stats. + * info as possible, see &enum nl80211_sta_info. * * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands, * consisting of a nested array. * + * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes). + * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link. + * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path. + * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path + * info given for %NL80211_CMD_GET_MPATH, nested attribute described at + * &enum nl80211_mpath_info. + * + * * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of * &enum nl80211_mntr_flags. * @@ -199,7 +224,7 @@ enum nl80211_attrs { NL80211_ATTR_STA_LISTEN_INTERVAL, NL80211_ATTR_STA_SUPPORTED_RATES, NL80211_ATTR_STA_VLAN, - NL80211_ATTR_STA_STATS, + NL80211_ATTR_STA_INFO, NL80211_ATTR_WIPHY_BANDS, @@ -207,6 +232,11 @@ enum nl80211_attrs { /* add attributes here, update the policy in nl80211.c */ + NL80211_ATTR_MESH_ID, + NL80211_ATTR_STA_PLINK_ACTION, + NL80211_ATTR_MPATH_NEXT_HOP, + NL80211_ATTR_MPATH_INFO, + __NL80211_ATTR_AFTER_LAST, NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1 }; @@ -223,6 +253,7 @@ enum nl80211_attrs { * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points * @NL80211_IFTYPE_WDS: wireless distribution interface * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames + * @NL80211_IFTYPE_MESH_POINT: mesh point * @NL80211_IFTYPE_MAX: highest interface type number currently defined * @__NL80211_IFTYPE_AFTER_LAST: internal use * @@ -238,6 +269,7 @@ enum nl80211_iftype { NL80211_IFTYPE_AP_VLAN, NL80211_IFTYPE_WDS, NL80211_IFTYPE_MONITOR, + NL80211_IFTYPE_MESH_POINT, /* keep last */ __NL80211_IFTYPE_AFTER_LAST, @@ -267,27 +299,78 @@ enum nl80211_sta_flags { }; /** - * enum nl80211_sta_stats - station statistics + * enum nl80211_sta_info - station information * - * These attribute types are used with %NL80211_ATTR_STA_STATS + * These attribute types are used with %NL80211_ATTR_STA_INFO * when getting information about a station. * - * @__NL80211_STA_STAT_INVALID: attribute number 0 is reserved - * @NL80211_STA_STAT_INACTIVE_TIME: time since last activity (u32, msecs) - * @NL80211_STA_STAT_RX_BYTES: total received bytes (u32, from this station) - * @NL80211_STA_STAT_TX_BYTES: total transmitted bytes (u32, to this station) - * @__NL80211_STA_STAT_AFTER_LAST: internal - * @NL80211_STA_STAT_MAX: highest possible station stats attribute + * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved + * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs) + * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station) + * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station) + * @__NL80211_STA_INFO_AFTER_LAST: internal + * @NL80211_STA_INFO_MAX: highest possible station info attribute + */ +enum nl80211_sta_info { + __NL80211_STA_INFO_INVALID, + NL80211_STA_INFO_INACTIVE_TIME, + NL80211_STA_INFO_RX_BYTES, + NL80211_STA_INFO_TX_BYTES, + NL80211_STA_INFO_LLID, + NL80211_STA_INFO_PLID, + NL80211_STA_INFO_PLINK_STATE, + + /* keep last */ + __NL80211_STA_INFO_AFTER_LAST, + NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1 +}; + +/** + * enum nl80211_mpath_flags - nl80211 mesh path flags + * + * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active + * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running + * @NL80211_MPATH_FLAG_DSN_VALID: the mesh path contains a valid DSN + * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set + * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded + */ +enum nl80211_mpath_flags { + NL80211_MPATH_FLAG_ACTIVE = 1<<0, + NL80211_MPATH_FLAG_RESOLVING = 1<<1, + NL80211_MPATH_FLAG_DSN_VALID = 1<<2, + NL80211_MPATH_FLAG_FIXED = 1<<3, + NL80211_MPATH_FLAG_RESOLVED = 1<<4, +}; + +/** + * enum nl80211_mpath_info - mesh path information + * + * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting + * information about a mesh path. + * + * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved + * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination + * @NL80211_ATTR_MPATH_DSN: destination sequence number + * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path + * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now + * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in + * &enum nl80211_mpath_flags; + * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec + * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries */ -enum nl80211_sta_stats { - __NL80211_STA_STAT_INVALID, - NL80211_STA_STAT_INACTIVE_TIME, - NL80211_STA_STAT_RX_BYTES, - NL80211_STA_STAT_TX_BYTES, +enum nl80211_mpath_info { + __NL80211_MPATH_INFO_INVALID, + NL80211_MPATH_INFO_FRAME_QLEN, + NL80211_MPATH_INFO_DSN, + NL80211_MPATH_INFO_METRIC, + NL80211_MPATH_INFO_EXPTIME, + NL80211_MPATH_INFO_FLAGS, + NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, + NL80211_MPATH_INFO_DISCOVERY_RETRIES, /* keep last */ - __NL80211_STA_STAT_AFTER_LAST, - NL80211_STA_STAT_MAX = __NL80211_STA_STAT_AFTER_LAST - 1 + __NL80211_MPATH_INFO_AFTER_LAST, + NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 }; /** diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index ab4caf63954f..e00750836ba5 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -12,6 +12,16 @@ * Copyright 2006, 2007 Johannes Berg */ +/** + * struct vif_params - describes virtual interface parameters + * @mesh_id: mesh ID to use + * @mesh_id_len: length of the mesh ID + */ +struct vif_params { + u8 *mesh_id; + int mesh_id_len; +}; + /* Radiotap header iteration * implemented in net/wireless/radiotap.c * docs in Documentation/networking/radiotap-headers.txt @@ -108,6 +118,19 @@ enum station_flags { STATION_FLAG_WME = 1<ieee80211_ptr); struct sta_info *sta; @@ -307,13 +309,13 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, /* XXX: verify sta->dev == dev */ - stats->filled = STATION_STAT_INACTIVE_TIME | - STATION_STAT_RX_BYTES | - STATION_STAT_TX_BYTES; + sinfo->filled = STATION_INFO_INACTIVE_TIME | + STATION_INFO_RX_BYTES | + STATION_INFO_TX_BYTES; - stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); - stats->rx_bytes = sta->rx_bytes; - stats->tx_bytes = sta->tx_bytes; + sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); + sinfo->rx_bytes = sta->rx_bytes; + sinfo->tx_bytes = sta->tx_bytes; sta_info_put(sta); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 5b3474798b8d..64a7460af734 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -81,8 +81,12 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_STA_LISTEN_INTERVAL] = { .type = NLA_U16 }, [NL80211_ATTR_STA_SUPPORTED_RATES] = { .type = NLA_BINARY, .len = NL80211_MAX_SUPP_RATES }, + [NL80211_ATTR_STA_PLINK_ACTION] = { .type = NLA_U8 }, [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, [NL80211_ATTR_MNTR_FLAGS] = { .type = NLA_NESTED }, + [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, + .len = IEEE80211_MAX_MESH_ID_LEN }, + [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, }; /* message building helper */ @@ -369,11 +373,14 @@ static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; + struct vif_params params; int err, ifindex; enum nl80211_iftype type; struct net_device *dev; u32 flags; + memset(¶ms, 0, sizeof(params)); + if (info->attrs[NL80211_ATTR_IFTYPE]) { type = nla_get_u32(info->attrs[NL80211_ATTR_IFTYPE]); if (type > NL80211_IFTYPE_MAX) @@ -392,12 +399,18 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) goto unlock; } + if (type == NL80211_IFTYPE_MESH_POINT && + info->attrs[NL80211_ATTR_MESH_ID]) { + params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); + params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); + } + rtnl_lock(); err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, &flags); err = drv->ops->change_virtual_intf(&drv->wiphy, ifindex, - type, err ? NULL : &flags); + type, err ? NULL : &flags, ¶ms); rtnl_unlock(); unlock: @@ -408,10 +421,13 @@ static int nl80211_set_interface(struct sk_buff *skb, struct genl_info *info) static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; + struct vif_params params; int err; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; u32 flags; + memset(¶ms, 0, sizeof(params)); + if (!info->attrs[NL80211_ATTR_IFNAME]) return -EINVAL; @@ -430,15 +446,22 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) goto unlock; } + if (type == NL80211_IFTYPE_MESH_POINT && + info->attrs[NL80211_ATTR_MESH_ID]) { + params.mesh_id = nla_data(info->attrs[NL80211_ATTR_MESH_ID]); + params.mesh_id_len = nla_len(info->attrs[NL80211_ATTR_MESH_ID]); + } + rtnl_lock(); err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, &flags); err = drv->ops->add_virtual_intf(&drv->wiphy, nla_data(info->attrs[NL80211_ATTR_IFNAME]), - type, err ? NULL : &flags); + type, err ? NULL : &flags, ¶ms); rtnl_unlock(); + unlock: cfg80211_put_dev(drv); return err; @@ -866,10 +889,10 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags) static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct net_device *dev, - u8 *mac_addr, struct station_stats *stats) + u8 *mac_addr, struct station_info *sinfo) { void *hdr; - struct nlattr *statsattr; + struct nlattr *sinfoattr; hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); if (!hdr) @@ -878,20 +901,29 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr); - statsattr = nla_nest_start(msg, NL80211_ATTR_STA_STATS); - if (!statsattr) + sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO); + if (!sinfoattr) goto nla_put_failure; - if (stats->filled & STATION_STAT_INACTIVE_TIME) - NLA_PUT_U32(msg, NL80211_STA_STAT_INACTIVE_TIME, - stats->inactive_time); - if (stats->filled & STATION_STAT_RX_BYTES) - NLA_PUT_U32(msg, NL80211_STA_STAT_RX_BYTES, - stats->rx_bytes); - if (stats->filled & STATION_STAT_TX_BYTES) - NLA_PUT_U32(msg, NL80211_STA_STAT_TX_BYTES, - stats->tx_bytes); - - nla_nest_end(msg, statsattr); + if (sinfo->filled & STATION_INFO_INACTIVE_TIME) + NLA_PUT_U32(msg, NL80211_STA_INFO_INACTIVE_TIME, + sinfo->inactive_time); + if (sinfo->filled & STATION_INFO_RX_BYTES) + NLA_PUT_U32(msg, NL80211_STA_INFO_RX_BYTES, + sinfo->rx_bytes); + if (sinfo->filled & STATION_INFO_TX_BYTES) + NLA_PUT_U32(msg, NL80211_STA_INFO_TX_BYTES, + sinfo->tx_bytes); + if (sinfo->filled & STATION_INFO_LLID) + NLA_PUT_U16(msg, NL80211_STA_INFO_LLID, + sinfo->llid); + if (sinfo->filled & STATION_INFO_PLID) + NLA_PUT_U16(msg, NL80211_STA_INFO_PLID, + sinfo->plid); + if (sinfo->filled & STATION_INFO_PLINK_STATE) + NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, + sinfo->plink_state); + + nla_nest_end(msg, sinfoattr); return genlmsg_end(msg, hdr); @@ -899,17 +931,80 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, return genlmsg_cancel(msg, hdr); } +static int nl80211_dump_station(struct sk_buff *skb, + struct netlink_callback *cb) +{ + int wp_idx = 0; + int if_idx = 0; + int sta_idx = cb->args[2]; + int wp_start = cb->args[0]; + int if_start = cb->args[1]; + struct station_info sinfo; + struct cfg80211_registered_device *dev; + struct wireless_dev *wdev; + u8 mac_addr[ETH_ALEN]; + int err; + int exit = 0; + + /* TODO: filter by device */ + mutex_lock(&cfg80211_drv_mutex); + list_for_each_entry(dev, &cfg80211_drv_list, list) { + if (exit) + break; + if (++wp_idx < wp_start) + continue; + if_idx = 0; + + mutex_lock(&dev->devlist_mtx); + list_for_each_entry(wdev, &dev->netdev_list, list) { + if (exit) + break; + if (++if_idx < if_start) + continue; + if (!dev->ops->dump_station) + continue; + + for (;; ++sta_idx) { + rtnl_lock(); + err = dev->ops->dump_station(&dev->wiphy, + wdev->netdev, sta_idx, mac_addr, + &sinfo); + rtnl_unlock(); + if (err) { + sta_idx = 0; + break; + } + if (nl80211_send_station(skb, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + wdev->netdev, mac_addr, + &sinfo) < 0) { + exit = 1; + break; + } + } + } + mutex_unlock(&dev->devlist_mtx); + } + mutex_unlock(&cfg80211_drv_mutex); + + cb->args[0] = wp_idx; + cb->args[1] = if_idx; + cb->args[2] = sta_idx; + + return skb->len; +} static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *drv; int err; struct net_device *dev; - struct station_stats stats; + struct station_info sinfo; struct sk_buff *msg; u8 *mac_addr = NULL; - memset(&stats, 0, sizeof(stats)); + memset(&sinfo, 0, sizeof(sinfo)); if (!info->attrs[NL80211_ATTR_MAC]) return -EINVAL; @@ -926,15 +1021,18 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info) } rtnl_lock(); - err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &stats); + err = drv->ops->get_station(&drv->wiphy, dev, mac_addr, &sinfo); rtnl_unlock(); + if (err) + goto out; + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (!msg) goto out; if (nl80211_send_station(msg, info->snd_pid, info->snd_seq, 0, - dev, mac_addr, &stats) < 0) + dev, mac_addr, &sinfo) < 0) goto out_free; err = genlmsg_unicast(msg, info->snd_pid); @@ -1005,6 +1103,10 @@ static int nl80211_set_station(struct sk_buff *skb, struct genl_info *info) ¶ms.station_flags)) return -EINVAL; + if (info->attrs[NL80211_ATTR_STA_PLINK_ACTION]) + params.plink_action = + nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]); + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); if (err) return err; @@ -1119,6 +1221,273 @@ static int nl80211_del_station(struct sk_buff *skb, struct genl_info *info) return err; } +static int nl80211_send_mpath(struct sk_buff *msg, u32 pid, u32 seq, + int flags, struct net_device *dev, + u8 *dst, u8 *next_hop, + struct mpath_info *pinfo) +{ + void *hdr; + struct nlattr *pinfoattr; + + hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); + if (!hdr) + return -1; + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst); + NLA_PUT(msg, NL80211_ATTR_MPATH_NEXT_HOP, ETH_ALEN, next_hop); + + pinfoattr = nla_nest_start(msg, NL80211_ATTR_MPATH_INFO); + if (!pinfoattr) + goto nla_put_failure; + if (pinfo->filled & MPATH_INFO_FRAME_QLEN) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_FRAME_QLEN, + pinfo->frame_qlen); + if (pinfo->filled & MPATH_INFO_DSN) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_DSN, + pinfo->dsn); + if (pinfo->filled & MPATH_INFO_METRIC) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_METRIC, + pinfo->metric); + if (pinfo->filled & MPATH_INFO_EXPTIME) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_EXPTIME, + pinfo->exptime); + if (pinfo->filled & MPATH_INFO_FLAGS) + NLA_PUT_U8(msg, NL80211_MPATH_INFO_FLAGS, + pinfo->flags); + if (pinfo->filled & MPATH_INFO_DISCOVERY_TIMEOUT) + NLA_PUT_U32(msg, NL80211_MPATH_INFO_DISCOVERY_TIMEOUT, + pinfo->discovery_timeout); + if (pinfo->filled & MPATH_INFO_DISCOVERY_RETRIES) + NLA_PUT_U8(msg, NL80211_MPATH_INFO_DISCOVERY_RETRIES, + pinfo->discovery_retries); + + nla_nest_end(msg, pinfoattr); + + return genlmsg_end(msg, hdr); + + nla_put_failure: + return genlmsg_cancel(msg, hdr); +} + +static int nl80211_dump_mpath(struct sk_buff *skb, + struct netlink_callback *cb) +{ + int wp_idx = 0; + int if_idx = 0; + int sta_idx = cb->args[2]; + int wp_start = cb->args[0]; + int if_start = cb->args[1]; + struct mpath_info pinfo; + struct cfg80211_registered_device *dev; + struct wireless_dev *wdev; + u8 dst[ETH_ALEN]; + u8 next_hop[ETH_ALEN]; + int err; + int exit = 0; + + /* TODO: filter by device */ + mutex_lock(&cfg80211_drv_mutex); + list_for_each_entry(dev, &cfg80211_drv_list, list) { + if (exit) + break; + if (++wp_idx < wp_start) + continue; + if_idx = 0; + + mutex_lock(&dev->devlist_mtx); + list_for_each_entry(wdev, &dev->netdev_list, list) { + if (exit) + break; + if (++if_idx < if_start) + continue; + if (!dev->ops->dump_mpath) + continue; + + for (;; ++sta_idx) { + rtnl_lock(); + err = dev->ops->dump_mpath(&dev->wiphy, + wdev->netdev, sta_idx, dst, + next_hop, &pinfo); + rtnl_unlock(); + if (err) { + sta_idx = 0; + break; + } + if (nl80211_send_mpath(skb, + NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + wdev->netdev, dst, next_hop, + &pinfo) < 0) { + exit = 1; + break; + } + } + } + mutex_unlock(&dev->devlist_mtx); + } + mutex_unlock(&cfg80211_drv_mutex); + + cb->args[0] = wp_idx; + cb->args[1] = if_idx; + cb->args[2] = sta_idx; + + return skb->len; +} + +static int nl80211_get_mpath(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + struct mpath_info pinfo; + struct sk_buff *msg; + u8 *dst = NULL; + u8 next_hop[ETH_ALEN]; + + memset(&pinfo, 0, sizeof(pinfo)); + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + + if (!drv->ops->get_mpath) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->get_mpath(&drv->wiphy, dev, dst, next_hop, &pinfo); + rtnl_unlock(); + + if (err) + goto out; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) + goto out; + + if (nl80211_send_mpath(msg, info->snd_pid, info->snd_seq, 0, + dev, dst, next_hop, &pinfo) < 0) + goto out_free; + + err = genlmsg_unicast(msg, info->snd_pid); + goto out; + + out_free: + nlmsg_free(msg); + + out: + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + +static int nl80211_set_mpath(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + u8 *dst = NULL; + u8 *next_hop = NULL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) + return -EINVAL; + + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); + next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + + if (!drv->ops->change_mpath) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->change_mpath(&drv->wiphy, dev, dst, next_hop); + rtnl_unlock(); + + out: + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} +static int nl80211_new_mpath(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + u8 *dst = NULL; + u8 *next_hop = NULL; + + if (!info->attrs[NL80211_ATTR_MAC]) + return -EINVAL; + + if (!info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]) + return -EINVAL; + + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); + next_hop = nla_data(info->attrs[NL80211_ATTR_MPATH_NEXT_HOP]); + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + + if (!drv->ops->add_mpath) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->add_mpath(&drv->wiphy, dev, dst, next_hop); + rtnl_unlock(); + + out: + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + +static int nl80211_del_mpath(struct sk_buff *skb, struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + int err; + struct net_device *dev; + u8 *dst = NULL; + + if (info->attrs[NL80211_ATTR_MAC]) + dst = nla_data(info->attrs[NL80211_ATTR_MAC]); + + err = get_drv_dev_by_info_ifindex(info, &drv, &dev); + if (err) + return err; + + if (!drv->ops->del_mpath) { + err = -EOPNOTSUPP; + goto out; + } + + rtnl_lock(); + err = drv->ops->del_mpath(&drv->wiphy, dev, dst); + rtnl_unlock(); + + out: + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_WIPHY, @@ -1203,7 +1572,7 @@ static struct genl_ops nl80211_ops[] = { { .cmd = NL80211_CMD_GET_STATION, .doit = nl80211_get_station, - /* TODO: implement dumpit */ + .dumpit = nl80211_dump_station, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, @@ -1225,6 +1594,31 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_GET_MPATH, + .doit = nl80211_get_mpath, + .dumpit = nl80211_dump_mpath, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_SET_MPATH, + .doit = nl80211_set_mpath, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_NEW_MPATH, + .doit = nl80211_new_mpath, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = NL80211_CMD_DEL_MPATH, + .doit = nl80211_del_mpath, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; /* multicast groups */ -- cgit v1.2.3-59-g8ed1b From 6032f934c818e5c3435c9f17274fe1983f53c6b4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 23 Feb 2008 15:17:07 +0100 Subject: mac80211: add mesh interface type This adds the mesh interface type. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 1 + net/mac80211/ieee80211.c | 1 + net/mac80211/ieee80211_iface.c | 1 + net/mac80211/rx.c | 10 ++++++++++ net/mac80211/util.c | 1 + 5 files changed, 14 insertions(+) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7a80c3981237..934cc25f757a 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -443,6 +443,7 @@ enum ieee80211_if_types { IEEE80211_IF_TYPE_AP, IEEE80211_IF_TYPE_STA, IEEE80211_IF_TYPE_IBSS, + IEEE80211_IF_TYPE_MESH_POINT, IEEE80211_IF_TYPE_MNTR, IEEE80211_IF_TYPE_WDS, IEEE80211_IF_TYPE_VLAN, diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 2133c9fd27a4..1ddb8e1b6ab6 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -258,6 +258,7 @@ static int ieee80211_open(struct net_device *dev) case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_MNTR: case IEEE80211_IF_TYPE_IBSS: + case IEEE80211_IF_TYPE_MESH_POINT: /* no special treatment */ break; case IEEE80211_IF_TYPE_INVALID: diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 677705046c6d..9523aeb71032 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -235,6 +235,7 @@ void ieee80211_if_reinit(struct net_device *dev) #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ } break; + case IEEE80211_IF_TYPE_MESH_POINT: case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: kfree(sdata->u.sta.extra_ie); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 48574f6c0e74..b7eeae0d3956 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1713,6 +1713,16 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb, bssid, hdr->addr2); break; + case IEEE80211_IF_TYPE_MESH_POINT: + if (!multicast && + compare_ether_addr(sdata->dev->dev_addr, + hdr->addr1) != 0) { + if (!(sdata->dev->flags & IFF_PROMISC)) + return 0; + + rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; + } + break; case IEEE80211_IF_TYPE_VLAN: case IEEE80211_IF_TYPE_AP: if (!bssid) { diff --git a/net/mac80211/util.c b/net/mac80211/util.c index f64804fed0a9..790c32f894c0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -382,6 +382,7 @@ void ieee80211_iterate_active_interfaces( case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: case IEEE80211_IF_TYPE_WDS: + case IEEE80211_IF_TYPE_MESH_POINT: break; } if (sdata->dev == local->mdev) -- cgit v1.2.3-59-g8ed1b From ccf80ddfe4923ae75cd3536723880277d285e779 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:08 +0100 Subject: mac80211: mesh function and data structures definitions Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh.h | 283 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 net/mac80211/mesh.h (limited to 'net') diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h new file mode 100644 index 000000000000..ac8923793908 --- /dev/null +++ b/net/mac80211/mesh.h @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2008 open80211s Ltd. + * Authors: Luis Carlos Cobo + * Javier Cardona + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef IEEE80211S_H +#define IEEE80211S_H + +#include "ieee80211_i.h" +#include + +extern int mesh_allocated; + +/* Data structures */ + +/** + * enum mesh_path_flags - mac80211 mesh path flags + * + * + * + * @MESH_PATH_ACTIVE: the mesh path is can be used for forwarding + * @MESH_PATH_RESOLVED: the discovery process is running for this mesh path + * @MESH_PATH_DSN_VALID: the mesh path contains a valid destination sequence + * number + * @MESH_PATH_FIXED: the mesh path has been manually set and should not be + * modified + * @MESH_PATH_RESOLVED: the mesh path can has been resolved + * @MESH_PATH_DELETE: the mesh path is scheduled to be deleted + * + * MESH_PATH_RESOLVED and MESH_PATH_DELETE are used by the mesh path timer to + * decide when to stop or cancel the mesh path discovery. + */ +enum mesh_path_flags { + MESH_PATH_ACTIVE = BIT(0), + MESH_PATH_RESOLVING = BIT(1), + MESH_PATH_DSN_VALID = BIT(2), + MESH_PATH_FIXED = BIT(3), + MESH_PATH_RESOLVED = BIT(4), + MESH_PATH_DELETE = BIT(5), +}; + +/** + * struct mesh_path - mac80211 mesh path structure + * + * @dst: mesh path destination mac address + * @dev: mesh path device + * @next_hop: mesh neighbor to which frames for this destination will be + * forwarded + * @timer: mesh path discovery timer + * @frame_queue: pending queue for frames sent to this destination while the + * path is unresolved + * @dsn: destination sequence number of the destination + * @metric: current metric to this destination + * @hop_count: hops to destination + * @exp_time: in jiffies, when the path will expire or when it expired + * @discovery_timeout: timeout (lapse in jiffies) used for the last discovery + * retry + * @discovery_retries: number of discovery retries + * @flags: mesh path flags, as specified on &enum mesh_path_flags + * @state_lock: mesh pat state lock + * + * + * The combination of dst and dev is unique in the mesh path table. A reference + * to the next_hop sta will be kept and in case this sta is removed, the + * mesh_path structure must be also removed or substitued in a rcu safe way + */ +struct mesh_path { + u8 dst[ETH_ALEN]; + struct net_device *dev; + struct sta_info *next_hop; + struct timer_list timer; + struct sk_buff_head frame_queue; + struct rcu_head rcu; + u32 dsn; + u32 metric; + u8 hop_count; + unsigned long exp_time; + u32 discovery_timeout; + u8 discovery_retries; + enum mesh_path_flags flags; + spinlock_t state_lock; +}; + +/** + * struct mesh_table + * + * @hash_buckets: array of hash buckets of the table + * @hashwlock: array of locks to protect write operations, one per bucket + * @hash_mask: 2^size_order - 1, used to compute hash idx + * @hash_rnd: random value used for hash computations + * @entries: number of entries in the table + * @free_node: function to free nodes of the table + * @copy_node: fuction to copy nodes of the table + * @size_order: determines size of the table, there will be 2^size_order hash + * buckets + * @mean_chain_len: maximum average length for the hash buckets' list, if it is + * reached, the table will grow + */ +struct mesh_table { + /* Number of buckets will be 2^N */ + struct hlist_head *hash_buckets; + spinlock_t *hashwlock; /* One per bucket, for add/del */ + unsigned int hash_mask; /* (2^size_order) - 1 */ + __u32 hash_rnd; /* Used for hash generation */ + atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */ + void (*free_node) (struct hlist_node *p, bool free_leafs); + void (*copy_node) (struct hlist_node *p, struct mesh_table *newtbl); + int size_order; + int mean_chain_len; +}; + +/* Recent multicast cache */ +/* RMC_BUCKETS must be a power of 2, maximum 256 */ +#define RMC_BUCKETS 256 +#define RMC_QUEUE_MAX_LEN 4 +#define RMC_TIMEOUT (3 * HZ) + +/** + * struct rmc_entry - entry in the Recent Multicast Cache + * + * @seqnum: mesh sequence number of the frame + * @exp_time: expiration time of the entry, in jiffies + * @sa: source address of the frame + * + * The Recent Multicast Cache keeps track of the latest multicast frames that + * have been received by a mesh interface and discards received multicast frames + * that are found in the cache. + */ +struct rmc_entry { + struct list_head list; + u32 seqnum; + unsigned long exp_time; + u8 sa[ETH_ALEN]; +}; + +struct mesh_rmc { + struct rmc_entry bucket[RMC_BUCKETS]; + u8 idx_mask; +}; + + +/* Mesh IEs constants */ +#define MESH_CFG_LEN 19 + +/* + * MESH_CFG_COMP_LEN Includes: + * - Active path selection protocol ID. + * - Active path selection metric ID. + * - Congestion control mode identifier. + * - Channel precedence. + * Does not include mesh capabilities, which may vary across nodes in the same + * mesh + */ +#define MESH_CFG_CMP_LEN 17 + +/* Default values, timeouts in ms */ +#define MESH_TTL 5 +#define MESH_MAX_RETR 3 +#define MESH_RET_T 100 +#define MESH_CONF_T 100 +#define MESH_HOLD_T 100 + +#define MESH_PATH_TIMEOUT 5000 +/* Minimum interval between two consecutive PREQs originated by the same + * interface + */ +#define MESH_PREQ_MIN_INT 10 +#define MESH_DIAM_TRAVERSAL_TIME 50 +/* Paths will be refreshed if they are closer than PATH_REFRESH_TIME to their + * expiration + */ +#define MESH_PATH_REFRESH_TIME 1000 +#define MESH_MIN_DISCOVERY_TIMEOUT (2 * MESH_DIAM_TRAVERSAL_TIME) + +#define MESH_MAX_PREQ_RETRIES 4 +#define MESH_PATH_EXPIRE (600 * HZ) + +/* Default maximum number of established plinks per interface */ +#define MESH_MAX_ESTAB_PLINKS 32 + +/* Default maximum number of plinks per interface */ +#define MESH_MAX_PLINKS 256 + +/* Maximum number of paths per interface */ +#define MESH_MAX_MPATHS 1024 + +/* Pending ANA approval */ +#define PLINK_CATEGORY 30 +#define MESH_PATH_SEL_CATEGORY 32 + +/* Mesh Header Flags */ +#define IEEE80211S_FLAGS_AE 0x3 + +/* Public interfaces */ +/* Various */ +u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len); +int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr); +int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, + struct ieee80211_sub_if_data *sdata); +int mesh_rmc_check(u8 *addr, struct ieee80211s_hdr *mesh_hdr, + struct net_device *dev); +bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev); +void mesh_ids_set_default(struct ieee80211_if_sta *sta); +void mesh_mgmt_ies_add(struct sk_buff *skb, struct net_device *dev); +void mesh_rmc_free(struct net_device *dev); +int mesh_rmc_init(struct net_device *dev); +void ieee80211s_init(void); +void ieee80211s_stop(void); +/* Mesh paths */ +int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb, + struct net_device *dev); +void mesh_path_start_discovery(struct net_device *dev); +struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev); +struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev); +void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); +void mesh_path_expire(struct net_device *dev); +void mesh_path_flush(struct net_device *dev); +void mesh_rx_path_sel_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, + size_t len); +int mesh_path_add(u8 *dst, struct net_device *dev); +/* Mesh plinks */ +void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, + bool add); +bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie, + struct net_device *dev); +void mesh_accept_plinks_update(struct net_device *dev); +struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev); +void mesh_plink_broken(struct sta_info *sta); +void mesh_plink_deactivate(struct sta_info *sta); +int mesh_plink_open(struct sta_info *sta); +int mesh_plink_close(struct sta_info *sta); +void mesh_plink_block(struct sta_info *sta); +void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, + size_t len, struct ieee80211_rx_status *rx_status); + +/* Private interfaces */ +/* Mesh tables */ +struct mesh_table *mesh_table_alloc(int size_order); +void mesh_table_free(struct mesh_table *tbl, bool free_leafs); +struct mesh_table *mesh_table_grow(struct mesh_table *tbl); +u32 mesh_table_hash(u8 *addr, struct net_device *dev, struct mesh_table *tbl); +/* Mesh paths */ +int mesh_path_error_tx(u8 *dest, __le32 dest_dsn, u8 *ra, + struct net_device *dev); +void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta); +void mesh_path_flush_pending(struct mesh_path *mpath); +void mesh_path_tx_pending(struct mesh_path *mpath); +int mesh_pathtbl_init(void); +void mesh_pathtbl_unregister(void); +int mesh_path_del(u8 *addr, struct net_device *dev); +void mesh_path_timer(unsigned long data); +void mesh_path_flush_by_nexthop(struct sta_info *sta); +void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev); + +static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata) +{ + return sdata->u.sta.mshcfg.dot11MeshMaxPeerLinks - + atomic_read(&sdata->u.sta.mshstats.estab_plinks); +} + +static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata) +{ + return (min(mesh_plink_free_count(sdata), + MESH_MAX_PLINKS - sdata->local->num_sta)) > 0; +} + +static inline void mesh_path_activate(struct mesh_path *mpath) +{ + mpath->flags |= MESH_PATH_ACTIVE | MESH_PATH_RESOLVED; +} + +#define for_each_mesh_entry(x, p, node, i) \ + for (i = 0; i <= x->hash_mask; i++) \ + hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list) + +#define MESH_PREQ(skb) (skb->cb + 30) + +#endif /* IEEE80211S_H */ -- cgit v1.2.3-59-g8ed1b From 2e3c8736820bf72a8ad10721c7e31d36d4fa7790 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:09 +0100 Subject: mac80211: support functions for mesh The two important features coded in mesh.c are: Recently Multicast Cache: in on-demand HWMP, multicast traffic is retransmitted by every receiving node. Even though a mesh TTL counter avoids infinite loops, it is also necessary to avoid traffic explosion by keeping a cache of multicast mesh frame that have been received recently. With this feature, maximum number of retransmissions of a multicast frame for the case of N nodes within the range of each other would be N. Without it, the maximum number of retransmissions would be in the order of N^(MESH_TTL - 1). Code to support mesh tables. Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 383 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 net/mac80211/mesh.c (limited to 'net') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c new file mode 100644 index 000000000000..8ff533005d92 --- /dev/null +++ b/net/mac80211/mesh.c @@ -0,0 +1,383 @@ +/* + * Copyright (c) 2008 open80211s Ltd. + * Authors: Luis Carlos Cobo + * Javier Cardona + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "ieee80211_i.h" +#include "mesh.h" + +#define PP_OFFSET 1 /* Path Selection Protocol */ +#define PM_OFFSET 5 /* Path Selection Metric */ +#define CC_OFFSET 9 /* Congestion Control Mode */ +#define CAPAB_OFFSET 17 +#define ACCEPT_PLINKS 0x80 + +int mesh_allocated; +static struct kmem_cache *rm_cache; + +void ieee80211s_init(void) +{ + mesh_pathtbl_init(); + mesh_allocated = 1; + rm_cache = kmem_cache_create("mesh_rmc", sizeof(struct rmc_entry), + 0, 0, NULL); +} + +void ieee80211s_stop(void) +{ + mesh_pathtbl_unregister(); + kmem_cache_destroy(rm_cache); +} + +/** + * mesh_matches_local - check if the config of a mesh point matches ours + * + * @ie: information elements of a management frame from the mesh peer + * @dev: local mesh interface + * + * This function checks if the mesh configuration of a mesh point matches the + * local mesh configuration, i.e. if both nodes belong to the same mesh network. + */ +bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *sta = &sdata->u.sta; + + if (sta->mesh_id_len == ie->mesh_id_len && + memcmp(sta->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && + memcmp(sta->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 && + memcmp(sta->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 && + memcmp(sta->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0) + /* + * As support for each feature is added, check for matching + * - On mesh config capabilities + * - Power Save Support En + * - Sync support enabled + * - Sync support active + * - Sync support required from peer + * - MDA enabled + * - Power management control on fc + */ + return true; + + return false; +} + +/** + * mesh_peer_accepts_plinks - check if an mp is willing to establish peer links + * + * @ie: information elements of a management frame from the mesh peer + * @dev: local mesh interface + */ +bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie, + struct net_device *dev) +{ + return (*(ie->mesh_config + CAPAB_OFFSET) & ACCEPT_PLINKS) != 0; +} + +/** + * mesh_accept_plinks_update: update accepting_plink in local mesh beacons + * + * @dev: mesh interface in which mesh beacons are going to be updated + */ +void mesh_accept_plinks_update(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + bool free_plinks; + + /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0, + * the mesh interface might be able to establish plinks with peers that + * are already on the table but are not on ESTAB state. However, in + * general the mesh interface is not accepting peer link requests from + * new peers, and that must be reflected in the beacon + */ + free_plinks = mesh_plink_availables(sdata); + + if (free_plinks != sdata->u.sta.accepting_plinks) + ieee80211_sta_timer((unsigned long) sdata); +} + +void mesh_ids_set_default(struct ieee80211_if_sta *sta) +{ + u8 def_id[4] = {0x00, 0x0F, 0xAC, 0xff}; + + memcpy(sta->mesh_pp_id, def_id, 4); + memcpy(sta->mesh_pm_id, def_id, 4); + memcpy(sta->mesh_cc_id, def_id, 4); +} + +int mesh_rmc_init(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int i; + + sdata->u.sta.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL); + if (!sdata->u.sta.rmc) + return -ENOMEM; + sdata->u.sta.rmc->idx_mask = RMC_BUCKETS - 1; + for (i = 0; i < RMC_BUCKETS; i++) + INIT_LIST_HEAD(&sdata->u.sta.rmc->bucket[i].list); + return 0; +} + +void mesh_rmc_free(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct mesh_rmc *rmc = sdata->u.sta.rmc; + struct rmc_entry *p, *n; + int i; + + if (!sdata->u.sta.rmc) + return; + + for (i = 0; i < RMC_BUCKETS; i++) + list_for_each_entry_safe(p, n, &rmc->bucket[i].list, list) { + list_del(&p->list); + kmem_cache_free(rm_cache, p); + } + + kfree(rmc); + sdata->u.sta.rmc = NULL; +} + +/** + * mesh_rmc_check - Check frame in recent multicast cache and add if absent. + * + * @sa: source address + * @mesh_hdr: mesh_header + * + * Returns: 0 if the frame is not in the cache, nonzero otherwise. + * + * Checks using the source address and the mesh sequence number if we have + * received this frame lately. If the frame is not in the cache, it is added to + * it. + */ +int mesh_rmc_check(u8 *sa, struct ieee80211s_hdr *mesh_hdr, + struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct mesh_rmc *rmc = sdata->u.sta.rmc; + u32 seqnum = 0; + int entries = 0; + u8 idx; + struct rmc_entry *p, *n; + + /* Don't care about endianness since only match matters */ + memcpy(&seqnum, mesh_hdr->seqnum, sizeof(mesh_hdr->seqnum)); + idx = mesh_hdr->seqnum[0] & rmc->idx_mask; + list_for_each_entry_safe(p, n, &rmc->bucket[idx].list, list) { + ++entries; + if (time_after(jiffies, p->exp_time) || + (entries == RMC_QUEUE_MAX_LEN)) { + list_del(&p->list); + kmem_cache_free(rm_cache, p); + --entries; + } else if ((seqnum == p->seqnum) + && (memcmp(sa, p->sa, ETH_ALEN) == 0)) + return -1; + } + + p = kmem_cache_alloc(rm_cache, GFP_ATOMIC); + if (!p) { + printk(KERN_DEBUG "o11s: could not allocate RMC entry\n"); + return 0; + } + p->seqnum = seqnum; + p->exp_time = jiffies + RMC_TIMEOUT; + memcpy(p->sa, sa, ETH_ALEN); + list_add(&p->list, &rmc->bucket[idx].list); + return 0; +} + +void mesh_mgmt_ies_add(struct sk_buff *skb, struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_supported_band *sband; + u8 *pos; + int len, i, rate; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + len = sband->n_bitrates; + if (len > 8) + len = 8; + pos = skb_put(skb, len + 2); + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = len; + for (i = 0; i < len; i++) { + rate = sband->bitrates[i].bitrate; + *pos++ = (u8) (rate / 5); + } + + if (sband->n_bitrates > len) { + pos = skb_put(skb, sband->n_bitrates - len + 2); + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos++ = sband->n_bitrates - len; + for (i = len; i < sband->n_bitrates; i++) { + rate = sband->bitrates[i].bitrate; + *pos++ = (u8) (rate / 5); + } + } + + pos = skb_put(skb, 2 + sdata->u.sta.mesh_id_len); + *pos++ = WLAN_EID_MESH_ID; + *pos++ = sdata->u.sta.mesh_id_len; + if (sdata->u.sta.mesh_id_len) + memcpy(pos, sdata->u.sta.mesh_id, sdata->u.sta.mesh_id_len); + + pos = skb_put(skb, 21); + *pos++ = WLAN_EID_MESH_CONFIG; + *pos++ = MESH_CFG_LEN; + /* Version */ + *pos++ = 1; + + /* Active path selection protocol ID */ + memcpy(pos, sdata->u.sta.mesh_pp_id, 4); + pos += 4; + + /* Active path selection metric ID */ + memcpy(pos, sdata->u.sta.mesh_pm_id, 4); + pos += 4; + + /* Congestion control mode identifier */ + memcpy(pos, sdata->u.sta.mesh_cc_id, 4); + pos += 4; + + /* Channel precedence: + * Not running simple channel unification protocol + */ + memset(pos, 0x00, 4); + pos += 4; + + /* Mesh capability */ + sdata->u.sta.accepting_plinks = mesh_plink_availables(sdata); + *pos++ = sdata->u.sta.accepting_plinks ? ACCEPT_PLINKS : 0x00; + *pos++ = 0x00; + + return; +} + +u32 mesh_table_hash(u8 *addr, struct net_device *dev, struct mesh_table *tbl) +{ + /* Use last four bytes of hw addr and interface index as hash index */ + return jhash_2words(*(u32 *)(addr+2), dev->ifindex, tbl->hash_rnd) + & tbl->hash_mask; +} + +u8 mesh_id_hash(u8 *mesh_id, int mesh_id_len) +{ + if (!mesh_id_len) + return 1; + else if (mesh_id_len == 1) + return (u8) mesh_id[0]; + else + return (u8) (mesh_id[0] + 2 * mesh_id[1]); +} + +struct mesh_table *mesh_table_alloc(int size_order) +{ + int i; + struct mesh_table *newtbl; + + newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL); + if (!newtbl) + return NULL; + + newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) * + (1 << size_order), GFP_KERNEL); + + if (!newtbl->hash_buckets) { + kfree(newtbl); + return NULL; + } + + newtbl->hashwlock = kmalloc(sizeof(spinlock_t) * + (1 << size_order), GFP_KERNEL); + if (!newtbl->hashwlock) { + kfree(newtbl->hash_buckets); + kfree(newtbl); + return NULL; + } + + newtbl->size_order = size_order; + newtbl->hash_mask = (1 << size_order) - 1; + atomic_set(&newtbl->entries, 0); + get_random_bytes(&newtbl->hash_rnd, + sizeof(newtbl->hash_rnd)); + for (i = 0; i <= newtbl->hash_mask; i++) + spin_lock_init(&newtbl->hashwlock[i]); + + return newtbl; +} + +void mesh_table_free(struct mesh_table *tbl, bool free_leafs) +{ + struct hlist_head *mesh_hash; + struct hlist_node *p, *q; + int i; + + mesh_hash = tbl->hash_buckets; + for (i = 0; i <= tbl->hash_mask; i++) { + spin_lock(&tbl->hashwlock[i]); + hlist_for_each_safe(p, q, &mesh_hash[i]) { + tbl->free_node(p, free_leafs); + atomic_dec(&tbl->entries); + } + spin_unlock(&tbl->hashwlock[i]); + } + kfree(tbl->hash_buckets); + kfree(tbl->hashwlock); + kfree(tbl); +} + +static void ieee80211_mesh_path_timer(unsigned long data) +{ + struct ieee80211_sub_if_data *sdata = + (struct ieee80211_sub_if_data *) data; + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct ieee80211_local *local = wdev_priv(&sdata->wdev); + + queue_work(local->hw.workqueue, &ifsta->work); +} + +struct mesh_table *mesh_table_grow(struct mesh_table *tbl) +{ + struct mesh_table *newtbl; + struct hlist_head *oldhash; + struct hlist_node *p; + int err = 0; + int i; + + if (atomic_read(&tbl->entries) + < tbl->mean_chain_len * (tbl->hash_mask + 1)) { + err = -EPERM; + goto endgrow; + } + + newtbl = mesh_table_alloc(tbl->size_order + 1); + if (!newtbl) { + err = -ENOMEM; + goto endgrow; + } + + newtbl->free_node = tbl->free_node; + newtbl->mean_chain_len = tbl->mean_chain_len; + newtbl->copy_node = tbl->copy_node; + atomic_set(&newtbl->entries, atomic_read(&tbl->entries)); + + oldhash = tbl->hash_buckets; + for (i = 0; i <= tbl->hash_mask; i++) + hlist_for_each(p, &oldhash[i]) + tbl->copy_node(p, newtbl); + +endgrow: + if (err) + return NULL; + else + return newtbl; +} -- cgit v1.2.3-59-g8ed1b From 33b64eb2b1b1759cbdafbe5c59df652f1e7c746e Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:10 +0100 Subject: mac80211: support for mesh interfaces in mac80211 data path This changes the TX/RX paths in mac80211 to support mesh interfaces. This code will be cleaned up later again before being enabled. Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/rx.c | 121 +++++++++++++++++++++++++++++++++++++++-- net/mac80211/tx.c | 158 ++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 246 insertions(+), 33 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index b7eeae0d3956..cc4a896c617f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -20,6 +20,9 @@ #include "ieee80211_i.h" #include "ieee80211_led.h" +#ifdef CONFIG_MAC80211_MESH +#include "mesh.h" +#endif #include "wep.h" #include "wpa.h" #include "tkip.h" @@ -390,10 +393,60 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) return RX_CONTINUE; } +#ifdef CONFIG_MAC80211_MESH +#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l)) +static ieee80211_rx_result +ieee80211_rx_mesh_check(struct ieee80211_txrx_data *rx) +{ + int hdrlen = ieee80211_get_hdrlen(rx->fc); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; + if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { + if (!((rx->fc & IEEE80211_FCTL_FROMDS) && + (rx->fc & IEEE80211_FCTL_TODS))) + return RX_DROP_MONITOR; + if (memcmp(hdr->addr4, rx->dev->dev_addr, ETH_ALEN) == 0) + return RX_DROP_MONITOR; + } + + /* If there is not an established peer link and this is not a peer link + * establisment frame, beacon or probe, drop the frame. + */ + + if (!rx->sta || rx->sta->plink_state != ESTAB) { + struct ieee80211_mgmt *mgmt; + if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) + return RX_DROP_MONITOR; + + switch (rx->fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_ACTION: + mgmt = (struct ieee80211_mgmt *)hdr; + if (mgmt->u.action.category != PLINK_CATEGORY) + return RX_DROP_MONITOR; + /* fall through on else */ + case IEEE80211_STYPE_PROBE_REQ: + case IEEE80211_STYPE_PROBE_RESP: + case IEEE80211_STYPE_BEACON: + return RX_CONTINUE; + break; + default: + return RX_DROP_MONITOR; + } + + } else if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && + is_broadcast_ether_addr(hdr->addr1) && + mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev)) + return RX_DROP_MONITOR; + else + return RX_CONTINUE; +} +#endif + + static ieee80211_rx_result ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) { struct ieee80211_hdr *hdr; + hdr = (struct ieee80211_hdr *) rx->skb->data; /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ @@ -423,6 +476,12 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) * deauth/disassoc frames when needed. In addition, hostapd is * responsible for filtering on both auth and assoc states. */ + +#ifdef CONFIG_MAC80211_MESH + if (rx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + return ieee80211_rx_mesh_check(rx); +#endif + if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA || ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PSPOLL)) && @@ -657,6 +716,8 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) /* Update last_rx only for unicast frames in order to prevent * the Probe Request frames (the only broadcast frames from a * STA in infrastructure mode) from keeping a connection alive. + * Mesh beacons will update last_rx when if they are found to + * match the current local configuration when processed. */ sta->last_rx = jiffies; } @@ -1050,6 +1111,23 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) hdrlen = ieee80211_get_hdrlen(fc); +#ifdef CONFIG_MAC80211_MESH + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { + int meshhdrlen = ieee80211_get_mesh_hdrlen( + (struct ieee80211s_hdr *) (skb->data + hdrlen)); + /* Copy on cb: + * - mesh header: to be used for mesh forwarding + * decision. It will also be used as mesh header template at + * tx.c:ieee80211_subif_start_xmit() if interface + * type is mesh and skb->pkt_type == PACKET_OTHERHOST + * - ta: to be used if a RERR needs to be sent. + */ + memcpy(skb->cb, skb->data + hdrlen, meshhdrlen); + memcpy(MESH_PREQ(skb), hdr->addr2, ETH_ALEN); + hdrlen += meshhdrlen; + } +#endif + /* convert IEEE 802.11 header + possible LLC headers into Ethernet * header * IEEE 802.11 address fields: @@ -1083,9 +1161,10 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) memcpy(dst, hdr->addr3, ETH_ALEN); memcpy(src, hdr->addr4, ETH_ALEN); - if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS)) { - if (net_ratelimit()) - printk(KERN_DEBUG "%s: dropped FromDS&ToDS " + if (unlikely(sdata->vif.type != IEEE80211_IF_TYPE_WDS && + sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT)) { + if (net_ratelimit()) + printk(KERN_DEBUG "%s: dropped FromDS&ToDS " "frame (RA=%s TA=%s DA=%s SA=%s)\n", rx->dev->name, print_mac(mac, hdr->addr1), @@ -1227,6 +1306,39 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) } } +#ifdef CONFIG_MAC80211_MESH + /* Mesh forwarding */ + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { + u8 *mesh_ttl = &((struct ieee80211s_hdr *)skb->cb)->ttl; + (*mesh_ttl)--; + + if (is_multicast_ether_addr(skb->data)) { + if (*mesh_ttl > 0) { + xmit_skb = skb_copy(skb, GFP_ATOMIC); + if (!xmit_skb && net_ratelimit()) + printk(KERN_DEBUG "%s: failed to clone " + "multicast frame\n", dev->name); + else + xmit_skb->pkt_type = PACKET_OTHERHOST; + } else + sdata->u.sta.mshstats.dropped_frames_ttl++; + + } else if (skb->pkt_type != PACKET_OTHERHOST && + compare_ether_addr(dev->dev_addr, skb->data) != 0) { + if (*mesh_ttl == 0) { + sdata->u.sta.mshstats.dropped_frames_ttl++; + dev_kfree_skb(skb); + skb = NULL; + } else { + xmit_skb = skb; + xmit_skb->pkt_type = PACKET_OTHERHOST; + if (!(dev->flags & IFF_PROMISC)) + skb = NULL; + } + } + } +#endif + if (skb) { /* deliver to local stack */ skb->protocol = eth_type_trans(skb, dev); @@ -1444,7 +1556,8 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) && + sdata->vif.type == IEEE80211_IF_TYPE_IBSS || + sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) && !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); else diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1cd58e01f1ee..fc1ffb55ed5c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -26,6 +26,9 @@ #include "ieee80211_i.h" #include "ieee80211_led.h" +#ifdef CONFIG_MAC80211_MESH +#include "mesh.h" +#endif #include "wep.h" #include "wpa.h" #include "wme.h" @@ -249,6 +252,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) (tx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PROBE_REQ)) return TX_DROP; + if (tx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + return TX_CONTINUE; + if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED) return TX_CONTINUE; @@ -1384,8 +1390,9 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, struct ieee80211_tx_packet_data *pkt_data; struct ieee80211_sub_if_data *sdata; int ret = 1, head_need; - u16 ethertype, hdrlen, fc; + u16 ethertype, hdrlen, meshhdrlen = 0, fc; struct ieee80211_hdr hdr; + struct ieee80211s_hdr mesh_hdr; const u8 *encaps_data; int encaps_len, skip_header_bytes; int nh_pos, h_pos; @@ -1427,6 +1434,37 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); hdrlen = 30; break; +#ifdef CONFIG_MAC80211_MESH + case IEEE80211_IF_TYPE_MESH_POINT: + fc |= IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS; + /* RA TA DA SA */ + if (is_multicast_ether_addr(skb->data)) + memcpy(hdr.addr1, skb->data, ETH_ALEN); + else if (mesh_nexthop_lookup(hdr.addr1, skb, dev)) + return 0; + memcpy(hdr.addr2, dev->dev_addr, ETH_ALEN); + memcpy(hdr.addr3, skb->data, ETH_ALEN); + memcpy(hdr.addr4, skb->data + ETH_ALEN, ETH_ALEN); + if (skb->pkt_type == PACKET_OTHERHOST) { + /* Forwarded frame, keep mesh ttl and seqnum */ + struct ieee80211s_hdr *prev_meshhdr; + prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb); + meshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr); + memcpy(&mesh_hdr, prev_meshhdr, meshhdrlen); + sdata->u.sta.mshstats.fwded_frames++; + } else { + if (!sdata->u.sta.mshcfg.dot11MeshTTL) { + /* Do not send frames with mesh_ttl == 0 */ + sdata->u.sta.mshstats.dropped_frames_ttl++; + ret = 0; + goto fail; + } + meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, + sdata); + } + hdrlen = 30; + break; +#endif case IEEE80211_IF_TYPE_STA: fc |= IEEE80211_FCTL_TODS; /* BSSID SA DA */ @@ -1471,8 +1509,8 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, * EAPOL frames from the local station. */ if (unlikely(!is_multicast_ether_addr(hdr.addr1) && - !(sta_flags & WLAN_STA_AUTHORIZED) && - !(ethertype == ETH_P_PAE && + !(sta_flags & WLAN_STA_AUTHORIZED) && + !(ethertype == ETH_P_PAE && compare_ether_addr(dev->dev_addr, skb->data + ETH_ALEN) == 0))) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG @@ -1525,7 +1563,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, * build in headroom in __dev_alloc_skb() (linux/skbuff.h) and * alloc_skb() (net/core/skbuff.c) */ - head_need = hdrlen + encaps_len + local->tx_headroom; + head_need = hdrlen + encaps_len + meshhdrlen + local->tx_headroom; head_need -= skb_headroom(skb); /* We are going to modify skb data, so make a copy of it if happens to @@ -1559,6 +1597,12 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, h_pos += encaps_len; } + if (meshhdrlen > 0) { + memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen); + nh_pos += meshhdrlen; + h_pos += meshhdrlen; + } + if (fc & IEEE80211_STYPE_QOS_DATA) { __le16 *qos_control; @@ -1734,6 +1778,40 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, read_unlock_bh(&local->sta_lock); } +#ifdef CONFIG_MAC80211_MESH +static struct sk_buff *ieee80211_mesh_beacon_get(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); + struct ieee80211_mgmt *mgmt; + u8 *pos; + + if (!skb) + return NULL; + skb_reserve(skb, local->hw.extra_tx_headroom); + mgmt = (struct ieee80211_mgmt *) + skb_put(skb, 24 + sizeof(mgmt->u.beacon)); + memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_BEACON); + memset(mgmt->da, 0xff, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + /* BSSID is left zeroed, wildcard value */ + mgmt->u.beacon.beacon_int = + cpu_to_le16(local->hw.conf.beacon_int); + mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ + + pos = skb_put(skb, 2); + *pos++ = WLAN_EID_SSID; + *pos++ = 0x0; + + mesh_mgmt_ies_add(skb, dev); + + return skb; +} +#endif + + struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_tx_control *control) @@ -1746,6 +1824,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct rate_selection rsel; struct beacon_data *beacon; struct ieee80211_supported_band *sband; + int *num_beacons; + int err = 0; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; @@ -1753,11 +1833,51 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, sdata = vif_to_sdata(vif); bdev = sdata->dev; - ap = &sdata->u.ap; - beacon = rcu_dereference(ap->beacon); + switch (sdata->vif.type) { + case IEEE80211_IF_TYPE_AP: + ap = &sdata->u.ap; + beacon = rcu_dereference(ap->beacon); + if (!ap || !beacon) { + err = -1; + break; + } + + /* headroom, head length, tail length and maximum TIM length */ + skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + + beacon->tail_len + 256); + if (!skb) + goto out; + + skb_reserve(skb, local->tx_headroom); + memcpy(skb_put(skb, beacon->head_len), beacon->head, + beacon->head_len); - if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon) { + ieee80211_include_sequence(sdata, + (struct ieee80211_hdr *)skb->data); + + ieee80211_beacon_add_tim(local, ap, skb, beacon); + + if (beacon->tail) + memcpy(skb_put(skb, beacon->tail_len), beacon->tail, + beacon->tail_len); + + num_beacons = &ap->num_beacons; + break; + +#ifdef CONFIG_MAC80211_MESH + case IEEE80211_IF_TYPE_MESH_POINT: + skb = ieee80211_mesh_beacon_get(bdev); + num_beacons = &sdata->u.sta.num_beacons; + break; +#endif + + default: + err = -1; + break; + } + + if (err) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "no beacon data avail for %s\n", @@ -1767,24 +1887,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, goto out; } - /* headroom, head length, tail length and maximum TIM length */ - skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + - beacon->tail_len + 256); - if (!skb) - goto out; - - skb_reserve(skb, local->tx_headroom); - memcpy(skb_put(skb, beacon->head_len), beacon->head, - beacon->head_len); - - ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); - - ieee80211_beacon_add_tim(local, ap, skb, beacon); - - if (beacon->tail) - memcpy(skb_put(skb, beacon->tail_len), beacon->tail, - beacon->tail_len); - if (control) { rate_control_get_rate(local->mdev, sband, skb, &rsel); if (!rsel.rate) { @@ -1808,10 +1910,8 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, control->retry_limit = 1; control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; } - - ap->num_beacons++; - - out: + (*num_beacons)++; +out: rcu_read_unlock(); return skb; } -- cgit v1.2.3-59-g8ed1b From ee3858551ae6d044578f598f8001db5f1a9fd52e Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:11 +0100 Subject: mac80211: mesh data structures and first mesh changes Includes integration in struct sta_info of mesh peer link elements, previously on their own mesh peer link table. Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 2 +- net/mac80211/ieee80211.c | 2 +- net/mac80211/ieee80211_i.h | 170 +++++++++++++++++++++++++++++++++++++++- net/mac80211/ieee80211_iface.c | 62 ++++++++++++++- net/mac80211/ieee80211_ioctl.c | 1 + net/mac80211/ieee80211_sta.c | 70 +++++++---------- net/mac80211/rc80211_pid_algo.c | 14 ++++ net/mac80211/sta_info.c | 42 +++++++++- net/mac80211/sta_info.h | 30 +++++++ net/mac80211/util.c | 51 ++++++++++++ 10 files changed, 394 insertions(+), 50 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 006da6a2e71b..0e97ceee640c 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -50,7 +50,7 @@ static int ieee80211_add_iface(struct wiphy *wiphy, char *name, if (itype == IEEE80211_IF_TYPE_INVALID) return -EINVAL; - err = ieee80211_if_add(local->mdev, name, &dev, itype); + err = ieee80211_if_add(local->mdev, name, &dev, itype, params); if (err || itype != IEEE80211_IF_TYPE_MNTR || !flags) return err; diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 1ddb8e1b6ab6..190917a74c3e 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -1663,7 +1663,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) /* add one default STA interface */ result = ieee80211_if_add(local->mdev, "wlan%d", NULL, - IEEE80211_IF_TYPE_STA); + IEEE80211_IF_TYPE_STA, NULL); if (result) printk(KERN_WARNING "%s: Failed to add default virtual iface\n", wiphy_name(local->hw.wiphy)); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b07b3cbfd039..49466b6996d1 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -90,6 +90,12 @@ struct ieee80211_sta_bss { size_t wmm_ie_len; u8 *ht_ie; size_t ht_ie_len; +#ifdef CONFIG_MAC80211_MESH + u8 *mesh_id; + size_t mesh_id_len; +#endif + /* mesh_cfg left out the ifdef to reduce clutter on bss handling */ + u8 *mesh_cfg; #define IEEE80211_MAX_SUPP_RATES 32 u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; size_t supp_rates_len; @@ -227,6 +233,43 @@ struct ieee80211_if_vlan { struct list_head list; }; +#ifdef CONFIG_MAC80211_MESH +struct mesh_stats { + __u32 fwded_frames; /* Mesh forwarded frames */ + __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ + __u32 dropped_frames_no_route; /* Not transmitted, no route found */ + atomic_t estab_plinks; +}; + +#define PREQ_Q_F_START 0x1 +#define PREQ_Q_F_REFRESH 0x2 +struct mesh_preq_queue { + struct list_head list; + u8 dst[ETH_ALEN]; + u8 flags; +}; + + +struct mesh_config { + /* Timeouts in ms */ + /* Mesh plink management parameters */ + u16 dot11MeshRetryTimeout; + u16 dot11MeshConfirmTimeout; + u16 dot11MeshHoldingTimeout; + u16 dot11MeshMaxPeerLinks; + u8 dot11MeshMaxRetries; + u8 dot11MeshTTL; + bool auto_open_plinks; + /* HWMP parameters */ + u32 dot11MeshHWMPactivePathTimeout; + u16 dot11MeshHWMPpreqMinInterval; + u16 dot11MeshHWMPnetDiameterTraversalTime; + u8 dot11MeshHWMPmaxPREQretries; + u32 path_refresh_time; + u16 min_discovery_timeout; +}; +#endif + /* flags used in struct ieee80211_if_sta.flags */ #define IEEE80211_STA_SSID_SET BIT(0) #define IEEE80211_STA_BSSID_SET BIT(1) @@ -245,7 +288,8 @@ struct ieee80211_if_sta { enum { IEEE80211_DISABLED, IEEE80211_AUTHENTICATE, IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED, - IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED + IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED, + IEEE80211_MESH_UP } state; struct timer_list timer; struct work_struct work; @@ -254,6 +298,34 @@ struct ieee80211_if_sta { size_t ssid_len; u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; size_t scan_ssid_len; +#ifdef CONFIG_MAC80211_MESH + struct timer_list mesh_path_timer; + u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; + bool accepting_plinks; + size_t mesh_id_len; + /* Active Path Selection Protocol Identifier */ + u8 mesh_pp_id[4]; + /* Active Path Selection Metric Identifier */ + u8 mesh_pm_id[4]; + /* Congestion Control Mode Identifier */ + u8 mesh_cc_id[4]; + /* Local mesh Destination Sequence Number */ + u32 dsn; + /* Last used PREQ ID */ + u32 preq_id; + atomic_t mpaths; + /* Timestamp of last DSN update */ + unsigned long last_dsn_update; + /* Timestamp of last DSN sent */ + unsigned long last_preq; + struct mesh_rmc *rmc; + spinlock_t mesh_preq_queue_lock; + struct mesh_preq_queue preq_queue; + int preq_queue_len; + struct mesh_stats mshstats; + struct mesh_config mshcfg; + u8 mesh_seqnum[3]; +#endif u16 aid; u16 ap_capab, capab; u8 *extra_ie; /* to be added to the end of AssocReq */ @@ -286,6 +358,7 @@ struct ieee80211_if_sta { u32 supp_rates_bits[IEEE80211_NUM_BANDS]; int wmm_last_param_set; + int num_beacons; /* number of TXed beacon frames by this STA */ }; @@ -365,6 +438,7 @@ struct ieee80211_sub_if_data { struct dentry *auth_alg; struct dentry *auth_transaction; struct dentry *flags; + struct dentry *num_beacons_sta; } sta; struct { struct dentry *channel_use; @@ -390,6 +464,35 @@ struct ieee80211_sub_if_data { } monitor; struct dentry *default_key; } debugfs; + +#ifdef CONFIG_MAC80211_MESH + struct dentry *mesh_stats_dir; + struct { + struct dentry *fwded_frames; + struct dentry *dropped_frames_ttl; + struct dentry *dropped_frames_no_route; + struct dentry *estab_plinks; + struct timer_list mesh_path_timer; + } mesh_stats; + + struct dentry *mesh_config_dir; + struct { + struct dentry *dot11MeshRetryTimeout; + struct dentry *dot11MeshConfirmTimeout; + struct dentry *dot11MeshHoldingTimeout; + struct dentry *dot11MeshMaxRetries; + struct dentry *dot11MeshTTL; + struct dentry *auto_open_plinks; + struct dentry *dot11MeshMaxPeerLinks; + struct dentry *dot11MeshHWMPactivePathTimeout; + struct dentry *dot11MeshHWMPpreqMinInterval; + struct dentry *dot11MeshHWMPnetDiameterTraversalTime; + struct dentry *dot11MeshHWMPmaxPREQretries; + struct dentry *path_refresh_time; + struct dentry *min_discovery_timeout; + } mesh_config; +#endif + #endif /* must be last, dynamically sized area in this! */ struct ieee80211_vif vif; @@ -617,6 +720,57 @@ struct ieee80211_ra_tid { u16 tid; }; +/* Parsed Information Elements */ +struct ieee802_11_elems { + /* pointers to IEs */ + u8 *ssid; + u8 *supp_rates; + u8 *fh_params; + u8 *ds_params; + u8 *cf_params; + u8 *tim; + u8 *ibss_params; + u8 *challenge; + u8 *wpa; + u8 *rsn; + u8 *erp_info; + u8 *ext_supp_rates; + u8 *wmm_info; + u8 *wmm_param; + u8 *ht_cap_elem; + u8 *ht_info_elem; + u8 *mesh_config; + u8 *mesh_id; + u8 *peer_link; + u8 *preq; + u8 *prep; + u8 *perr; + + /* length of them, respectively */ + u8 ssid_len; + u8 supp_rates_len; + u8 fh_params_len; + u8 ds_params_len; + u8 cf_params_len; + u8 tim_len; + u8 ibss_params_len; + u8 challenge_len; + u8 wpa_len; + u8 rsn_len; + u8 erp_info_len; + u8 ext_supp_rates_len; + u8 wmm_info_len; + u8 wmm_param_len; + u8 ht_cap_elem_len; + u8 ht_info_elem_len; + u8 mesh_config_len; + u8 mesh_id_len; + u8 peer_link_len; + u8 preq_len; + u8 prep_len; + u8 perr_len; +}; + static inline struct ieee80211_local *hw_to_local( struct ieee80211_hw *hw) { @@ -686,6 +840,7 @@ int ieee80211_set_compression(struct ieee80211_local *local, struct net_device *dev, struct sta_info *sta); int ieee80211_set_freq(struct ieee80211_local *local, int freq); /* ieee80211_sta.c */ +#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype) void ieee80211_sta_timer(unsigned long data); void ieee80211_sta_work(struct work_struct *work); void ieee80211_sta_scan_work(struct work_struct *work); @@ -726,9 +881,20 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da, u16 tid, u16 initiator, u16 reason); void sta_rx_agg_session_timer_expired(unsigned long data); void sta_addba_resp_timer_expired(unsigned long data); +u64 ieee80211_sta_get_rates(struct ieee80211_local *local, + struct ieee802_11_elems *elems, + enum ieee80211_band band); +void ieee80211_start_mesh(struct net_device *dev); +void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, + int encrypt); +void ieee802_11_parse_elems(u8 *start, size_t len, + struct ieee802_11_elems *elems); + + /* ieee80211_iface.c */ int ieee80211_if_add(struct net_device *dev, const char *name, - struct net_device **new_dev, int type); + struct net_device **new_dev, int type, + struct vif_params *params); void ieee80211_if_set_type(struct net_device *dev, int type); void ieee80211_if_reinit(struct net_device *dev); void __ieee80211_if_del(struct ieee80211_local *local, diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 9523aeb71032..c2f92b78bfc9 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -15,6 +15,9 @@ #include "ieee80211_i.h" #include "sta_info.h" #include "debugfs_netdev.h" +#ifdef CONFIG_MAC80211_MESH +#include "mesh.h" +#endif void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) { @@ -39,7 +42,8 @@ static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) /* Must be called with rtnl lock held. */ int ieee80211_if_add(struct net_device *dev, const char *name, - struct net_device **new_dev, int type) + struct net_device **new_dev, int type, + struct vif_params *params) { struct net_device *ndev; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); @@ -78,6 +82,15 @@ int ieee80211_if_add(struct net_device *dev, const char *name, ieee80211_debugfs_add_netdev(sdata); ieee80211_if_set_type(ndev, type); +#ifdef CONFIG_MAC80211_MESH + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && + params && params->mesh_id_len) { + sdata->u.sta.mesh_id_len = params->mesh_id_len; + memcpy(sdata->u.sta.mesh_id, params->mesh_id, + params->mesh_id_len); + } +#endif + /* we're under RTNL so all this is fine */ if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) { __ieee80211_if_del(local, sdata); @@ -134,6 +147,7 @@ void ieee80211_if_set_type(struct net_device *dev, int type) sdata->bss = &sdata->u.ap; INIT_LIST_HEAD(&sdata->u.ap.vlans); break; + case IEEE80211_IF_TYPE_MESH_POINT: case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: { struct ieee80211_sub_if_data *msdata; @@ -155,6 +169,48 @@ void ieee80211_if_set_type(struct net_device *dev, int type) msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); sdata->bss = &msdata->u.ap; + +#ifdef CONFIG_MAC80211_MESH + if (type == IEEE80211_IF_TYPE_MESH_POINT) { + ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T; + ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T; + ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T; + ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR; + ifsta->mshcfg.dot11MeshTTL = MESH_TTL; + ifsta->mshcfg.auto_open_plinks = true; + ifsta->mshcfg.dot11MeshMaxPeerLinks = + MESH_MAX_ESTAB_PLINKS; + ifsta->mshcfg.dot11MeshHWMPactivePathTimeout = + MESH_PATH_TIMEOUT; + ifsta->mshcfg.dot11MeshHWMPpreqMinInterval = + MESH_PREQ_MIN_INT; + ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime = + MESH_DIAM_TRAVERSAL_TIME; + ifsta->mshcfg.dot11MeshHWMPmaxPREQretries = + MESH_MAX_PREQ_RETRIES; + ifsta->mshcfg.path_refresh_time = + MESH_PATH_REFRESH_TIME; + ifsta->mshcfg.min_discovery_timeout = + MESH_MIN_DISCOVERY_TIMEOUT; + ifsta->accepting_plinks = true; + ifsta->preq_id = 0; + ifsta->dsn = 0; + atomic_set(&ifsta->mpaths, 0); + mesh_rmc_init(dev); + ifsta->last_preq = jiffies; + /* Allocate all mesh structures when creating the first + * mesh interface. + */ + if (!mesh_allocated) + ieee80211s_init(); + mesh_ids_set_default(ifsta); + setup_timer(&ifsta->mesh_path_timer, + ieee80211_mesh_path_timer, + (unsigned long) sdata); + INIT_LIST_HEAD(&ifsta->preq_queue.list); + spin_lock_init(&ifsta->mesh_preq_queue_lock); + } +#endif break; } case IEEE80211_IF_TYPE_MNTR: @@ -236,6 +292,10 @@ void ieee80211_if_reinit(struct net_device *dev) } break; case IEEE80211_IF_TYPE_MESH_POINT: +#ifdef CONFIG_MAC80211_MESH + mesh_rmc_free(dev); +#endif + /* fall through */ case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: kfree(sdata->u.sta.extra_ie); diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 7551db3f3abc..38e2d83e15f4 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -525,6 +525,7 @@ static int ieee80211_ioctl_siwscan(struct net_device *dev, if (sdata->vif.type != IEEE80211_IF_TYPE_STA && sdata->vif.type != IEEE80211_IF_TYPE_IBSS && + sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT && sdata->vif.type != IEEE80211_IF_TYPE_AP) return -EOPNOTSUPP; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index ddb5832f37cb..b4b498ae60f2 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -87,46 +87,8 @@ static int ieee80211_sta_config_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta); -/* Parsed Information Elements */ -struct ieee802_11_elems { - /* pointers to IEs */ - u8 *ssid; - u8 *supp_rates; - u8 *fh_params; - u8 *ds_params; - u8 *cf_params; - u8 *tim; - u8 *ibss_params; - u8 *challenge; - u8 *wpa; - u8 *rsn; - u8 *erp_info; - u8 *ext_supp_rates; - u8 *wmm_info; - u8 *wmm_param; - u8 *ht_cap_elem; - u8 *ht_info_elem; - /* length of them, respectively */ - u8 ssid_len; - u8 supp_rates_len; - u8 fh_params_len; - u8 ds_params_len; - u8 cf_params_len; - u8 tim_len; - u8 ibss_params_len; - u8 challenge_len; - u8 wpa_len; - u8 rsn_len; - u8 erp_info_len; - u8 ext_supp_rates_len; - u8 wmm_info_len; - u8 wmm_param_len; - u8 ht_cap_elem_len; - u8 ht_info_elem_len; -}; - -static void ieee802_11_parse_elems(u8 *start, size_t len, - struct ieee802_11_elems *elems) +void ieee802_11_parse_elems(u8 *start, size_t len, + struct ieee802_11_elems *elems) { size_t left = len; u8 *pos = start; @@ -215,6 +177,30 @@ static void ieee802_11_parse_elems(u8 *start, size_t len, elems->ht_info_elem = pos; elems->ht_info_elem_len = elen; break; + case WLAN_EID_MESH_ID: + elems->mesh_id = pos; + elems->mesh_id_len = elen; + break; + case WLAN_EID_MESH_CONFIG: + elems->mesh_config = pos; + elems->mesh_config_len = elen; + break; + case WLAN_EID_PEER_LINK: + elems->peer_link = pos; + elems->peer_link_len = elen; + break; + case WLAN_EID_PREQ: + elems->preq = pos; + elems->preq_len = elen; + break; + case WLAN_EID_PREP: + elems->prep = pos; + elems->prep_len = elen; + break; + case WLAN_EID_PERR: + elems->perr = pos; + elems->perr_len = elen; + break; default: break; } @@ -501,8 +487,8 @@ static void ieee80211_set_disassoc(struct net_device *dev, ieee80211_set_associated(dev, ifsta, 0); } -static void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, - int encrypt) +void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, + int encrypt) { struct ieee80211_sub_if_data *sdata; struct ieee80211_tx_packet_data *pkt_data; diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 9762803e4876..4a51647a41af 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -15,6 +15,9 @@ #include #include #include "ieee80211_rate.h" +#ifdef CONFIG_MAC80211_MESH +#include "mesh.h" +#endif #include "rc80211_pid.h" @@ -148,6 +151,9 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, struct ieee80211_local *local, struct sta_info *sta) { +#ifdef CONFIG_MAC80211_MESH + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); +#endif struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; struct rc_pid_rateinfo *rinfo = pinfo->rinfo; struct ieee80211_supported_band *sband; @@ -178,7 +184,14 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, pf = spinfo->last_pf; else { pf = spinfo->tx_num_failed * 100 / spinfo->tx_num_xmit; +#ifdef CONFIG_MAC80211_MESH + if (pf == 100 && + sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + mesh_plink_broken(sta); +#endif pf <<= RC_PID_ARITH_SHIFT; + sta->fail_avg = ((pf + (spinfo->last_pf << 3)) / 9) + >> RC_PID_ARITH_SHIFT; } spinfo->tx_num_xmit = 0; @@ -357,6 +370,7 @@ static void rate_control_pid_rate_init(void *priv, void *priv_sta, sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; sta->txrate_idx = rate_lowest_index(local, sband, sta); + sta->fail_avg = 0; } static void *rate_control_pid_alloc(struct ieee80211_local *local) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index e384e6632d97..1f3c9eb98500 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -21,6 +21,9 @@ #include "ieee80211_rate.h" #include "sta_info.h" #include "debugfs_sta.h" +#ifdef CONFIG_MAC80211_MESH +#include "mesh.h" +#endif /* Caller must hold local->sta_lock */ static void sta_info_hash_add(struct ieee80211_local *local, @@ -84,6 +87,27 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) } EXPORT_SYMBOL(sta_info_get); +struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, + struct net_device *dev) +{ + struct sta_info *sta; + int i = 0; + + read_lock_bh(&local->sta_lock); + list_for_each_entry(sta, &local->sta_list, list) { + if (i < idx) { + ++i; + continue; + } else if (!dev || dev == sta->dev) { + __sta_info_get(sta); + read_unlock_bh(&local->sta_lock); + return sta; + } + } + read_unlock_bh(&local->sta_lock); + + return NULL; +} static void sta_info_release(struct kref *kref) { @@ -284,12 +308,19 @@ void sta_info_remove(struct sta_info *sta) __sta_info_clear_tim_bit(sdata->bss, sta); } local->num_sta--; + +#ifdef CONFIG_MAC80211_MESH + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + mesh_accept_plinks_update(sdata->dev); +#endif } void sta_info_free(struct sta_info *sta) { struct sk_buff *skb; struct ieee80211_local *local = sta->local; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + DECLARE_MAC_BUF(mac); might_sleep(); @@ -298,6 +329,14 @@ void sta_info_free(struct sta_info *sta) sta_info_remove(sta); write_unlock_bh(&local->sta_lock); +#ifdef CONFIG_MAC80211_MESH + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { + spin_lock_bh(&sta->plink_lock); + mesh_plink_deactivate(sta); + spin_unlock_bh(&sta->plink_lock); + } +#endif + while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { local->total_ps_buffered--; dev_kfree_skb(skb); @@ -315,9 +354,6 @@ void sta_info_free(struct sta_info *sta) WARN_ON(sta->key); if (local->ops->sta_notify) { - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) sdata = sdata->u.vlan.ap; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 86eed40ada78..9d1d7a0e3114 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -107,6 +107,18 @@ struct tid_ampdu_rx { struct timer_list session_timer; }; +#ifdef CONFIG_MAC80211_MESH +enum plink_state { + LISTEN, + OPN_SNT, + OPN_RCVD, + CNF_RCVD, + ESTAB, + HOLDING, + BLOCKED +}; +#endif + /** * struct sta_ampdu_mlme - STA aggregation information. * @@ -144,6 +156,8 @@ struct sta_info { unsigned long rx_bytes, tx_bytes; unsigned long tx_retry_failed, tx_retry_count; unsigned long tx_filtered_count; + /* moving percentage of failed MSDUs */ + unsigned int fail_avg; unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */ @@ -192,6 +206,20 @@ struct sta_info { struct sta_ampdu_mlme ampdu_mlme; u8 timer_to_tid[STA_TID_NUM]; /* convert timer id to tid */ u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */ +#ifdef CONFIG_MAC80211_MESH + /* mesh peer link attributes */ + __le16 llid; /* Local link ID */ + __le16 plid; /* Peer link ID */ + __le16 reason; /* Buffer for cancel reason on HOLDING state */ + enum plink_state plink_state; + u32 plink_timeout; + struct timer_list plink_timer; + u8 plink_retries; /* Retries in establishment */ + bool ignore_plink_timer; + spinlock_t plink_lock; /* For peer_state reads / updates and other + updates in the structure. Ensures robust + transitions for the peerlink FSM */ +#endif #ifdef CONFIG_MAC80211_DEBUGFS struct sta_info_debugfsdentries { @@ -234,6 +262,8 @@ static inline void __sta_info_get(struct sta_info *sta) } struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); +struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, + struct net_device *dev); void sta_info_put(struct sta_info *sta); struct sta_info *sta_info_add(struct ieee80211_local *local, struct net_device *dev, u8 *addr, gfp_t gfp); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 790c32f894c0..6b50b6c12da3 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -26,6 +26,9 @@ #include "ieee80211_i.h" #include "ieee80211_rate.h" +#ifdef CONFIG_MAC80211_MESH +#include "mesh.h" +#endif #include "wme.h" /* privid for wiphys to determine whether they belong to us or not */ @@ -146,6 +149,26 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) } EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); +#ifdef CONFIG_MAC80211_MESH +int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) +{ + int ae = meshhdr->flags & IEEE80211S_FLAGS_AE; + /* 7.1.3.5a.2 */ + switch (ae) { + case 0: + return 5; + case 1: + return 11; + case 2: + return 17; + case 3: + return 23; + default: + return 5; + } +} +#endif + void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; @@ -395,3 +418,31 @@ void ieee80211_iterate_active_interfaces( rcu_read_unlock(); } EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); + +#ifdef CONFIG_MAC80211_MESH +/** + * ieee80211_new_mesh_header - create a new mesh header + * @meshhdr: uninitialized mesh header + * @sdata: mesh interface to be used + * + * Return the header length. + */ +int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, + struct ieee80211_sub_if_data *sdata) +{ + meshhdr->flags = 0; + meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL; + + meshhdr->seqnum[0] = sdata->u.sta.mesh_seqnum[0]++; + meshhdr->seqnum[1] = sdata->u.sta.mesh_seqnum[1]; + meshhdr->seqnum[2] = sdata->u.sta.mesh_seqnum[2]; + + if (sdata->u.sta.mesh_seqnum[0] == 0) { + sdata->u.sta.mesh_seqnum[1]++; + if (sdata->u.sta.mesh_seqnum[1] == 0) + sdata->u.sta.mesh_seqnum[2]++; + } + + return 5; +} +#endif -- cgit v1.2.3-59-g8ed1b From f709fc696d72d31273a77b82aa32cb6d19857011 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:12 +0100 Subject: mac80211: mesh changes to the MLME This includes support for mesh network scanning. The ugly code in ieee80211_sta_scan_result() is my approach to work around wext. This has been tested with wireless tools version 29 and works as expected (the new interface mode is just not shown). Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 322 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 263 insertions(+), 59 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index b4b498ae60f2..d2dedcb5a954 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -31,12 +31,16 @@ #include "ieee80211_i.h" #include "ieee80211_rate.h" #include "ieee80211_led.h" +#ifdef CONFIG_MAC80211_MESH +#include "mesh.h" +#endif #define IEEE80211_AUTH_TIMEOUT (HZ / 5) #define IEEE80211_AUTH_MAX_TRIES 3 #define IEEE80211_ASSOC_TIMEOUT (HZ / 5) #define IEEE80211_ASSOC_MAX_TRIES 3 #define IEEE80211_MONITORING_INTERVAL (2 * HZ) +#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) #define IEEE80211_PROBE_INTERVAL (60 * HZ) #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) #define IEEE80211_SCAN_INTERVAL (2 * HZ) @@ -49,6 +53,7 @@ #define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) #define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) #define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) +#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 @@ -1891,8 +1896,15 @@ static void __ieee80211_rx_bss_hash_add(struct net_device *dev, struct ieee80211_sta_bss *bss) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - bss->hnext = local->sta_bss_hash[STA_HASH(bss->bssid)]; - local->sta_bss_hash[STA_HASH(bss->bssid)] = bss; + u8 hash_idx; +#ifdef CONFIG_MAC80211_MESH + if (bss->mesh_cfg) + hash_idx = mesh_id_hash(bss->mesh_id, bss->mesh_id_len); + else +#endif + hash_idx = STA_HASH(bss->bssid); + bss->hnext = local->sta_bss_hash[hash_idx]; + local->sta_bss_hash[hash_idx] = bss; } @@ -1945,7 +1957,6 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int freq, return bss; } - static struct ieee80211_sta_bss * ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, u8 *ssid, u8 ssid_len) @@ -1956,7 +1967,7 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, spin_lock_bh(&local->sta_bss_lock); bss = local->sta_bss_hash[STA_HASH(bssid)]; while (bss) { - if (!memcmp(bss->bssid, bssid, ETH_ALEN) && + if (!bss->mesh_cfg && !memcmp(bss->bssid, bssid, ETH_ALEN) && bss->freq == freq && bss->ssid_len == ssid_len && (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { @@ -1969,6 +1980,72 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, return bss; } +#ifdef CONFIG_MAC80211_MESH +static struct ieee80211_sta_bss * +ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len, + u8 *mesh_cfg, int freq) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sta_bss *bss; + + spin_lock_bh(&local->sta_bss_lock); + bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)]; + while (bss) { + if (bss->mesh_cfg && + !memcmp(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN) && + bss->freq == freq && + mesh_id_len == bss->mesh_id_len && + (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id, + mesh_id_len))) { + atomic_inc(&bss->users); + break; + } + bss = bss->hnext; + } + spin_unlock_bh(&local->sta_bss_lock); + return bss; +} + +static struct ieee80211_sta_bss * +ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len, + u8 *mesh_cfg, int freq) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sta_bss *bss; + + bss = kzalloc(sizeof(*bss), GFP_ATOMIC); + if (!bss) + return NULL; + + bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC); + if (!bss->mesh_cfg) { + kfree(bss); + return NULL; + } + + if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) { + bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC); + if (!bss->mesh_id) { + kfree(bss->mesh_cfg); + kfree(bss); + return NULL; + } + memcpy(bss->mesh_id, mesh_id, mesh_id_len); + } + + atomic_inc(&bss->users); + atomic_inc(&bss->users); + memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN); + bss->mesh_id_len = mesh_id_len; + bss->freq = freq; + spin_lock_bh(&local->sta_bss_lock); + /* TODO: order by RSSI? */ + list_add_tail(&bss->list, &local->sta_bss_list); + __ieee80211_rx_bss_hash_add(dev, bss); + spin_unlock_bh(&local->sta_bss_lock); + return bss; +} +#endif static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) { @@ -1976,6 +2053,10 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) kfree(bss->rsn_ie); kfree(bss->wmm_ie); kfree(bss->ht_ie); +#ifdef CONFIG_MAC80211_MESH + kfree(bss->mesh_id); + kfree(bss->mesh_cfg); +#endif kfree(bss); } @@ -2171,6 +2252,42 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, return res; } +u64 ieee80211_sta_get_rates(struct ieee80211_local *local, + struct ieee802_11_elems *elems, + enum ieee80211_band band) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_rate *bitrates; + size_t num_rates; + u64 supp_rates; + int i, j; + sband = local->hw.wiphy->bands[band]; + + if (!sband) { + WARN_ON(1); + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + } + + bitrates = sband->bitrates; + num_rates = sband->n_bitrates; + supp_rates = 0; + for (i = 0; i < elems->supp_rates_len + + elems->ext_supp_rates_len; i++) { + u8 rate = 0; + int own_rate; + if (i < elems->supp_rates_len) + rate = elems->supp_rates[i]; + else if (elems->ext_supp_rates) + rate = elems->ext_supp_rates + [i - elems->supp_rates_len]; + own_rate = 5 * (rate & 0x7f); + for (j = 0; j < num_rates; j++) + if (bitrates[j].bitrate == own_rate) + supp_rates |= BIT(j); + } + return supp_rates; +} + static void ieee80211_rx_bss_info(struct net_device *dev, struct ieee80211_mgmt *mgmt, @@ -2205,41 +2322,23 @@ static void ieee80211_rx_bss_info(struct net_device *dev, beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); +#ifdef CONFIG_MAC80211_MESH + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && elems.mesh_id + && elems.mesh_config) + if (mesh_matches_local(&elems, dev)) { + u64 rates = ieee80211_sta_get_rates(local, &elems, + rx_status->band); + mesh_neighbour_update(mgmt->sa, rates, dev, + mesh_peer_accepts_plinks(&elems, dev)); + } +#endif + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && (sta = sta_info_get(local, mgmt->sa))) { - struct ieee80211_supported_band *sband; - struct ieee80211_rate *bitrates; - size_t num_rates; - u64 supp_rates, prev_rates; - int i, j; - - sband = local->hw.wiphy->bands[rx_status->band]; - - if (!sband) { - WARN_ON(1); - sband = local->hw.wiphy->bands[ - local->hw.conf.channel->band]; - } - - bitrates = sband->bitrates; - num_rates = sband->n_bitrates; - - supp_rates = 0; - for (i = 0; i < elems.supp_rates_len + - elems.ext_supp_rates_len; i++) { - u8 rate = 0; - int own_rate; - if (i < elems.supp_rates_len) - rate = elems.supp_rates[i]; - else if (elems.ext_supp_rates) - rate = elems.ext_supp_rates - [i - elems.supp_rates_len]; - own_rate = 5 * (rate & 0x7f); - for (j = 0; j < num_rates; j++) - if (bitrates[j].bitrate == own_rate) - supp_rates |= BIT(j); - } + u64 prev_rates; + u64 supp_rates = ieee80211_sta_get_rates(local, &elems, + rx_status->band); prev_rates = sta->supp_rates[rx_status->band]; sta->supp_rates[rx_status->band] &= supp_rates; @@ -2262,19 +2361,28 @@ static void ieee80211_rx_bss_info(struct net_device *dev, sta_info_put(sta); } - if (!elems.ssid) - return; - if (elems.ds_params && elems.ds_params_len == 1) freq = ieee80211_channel_to_frequency(elems.ds_params[0]); else freq = rx_status->freq; - bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq, - elems.ssid, elems.ssid_len); - if (!bss) { - bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, +#ifdef CONFIG_MAC80211_MESH + if (elems.mesh_config) + bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id, + elems.mesh_id_len, elems.mesh_config, freq); + else +#endif + bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq, elems.ssid, elems.ssid_len); + if (!bss) { +#ifdef CONFIG_MAC80211_MESH + if (elems.mesh_config) + bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id, + elems.mesh_id_len, elems.mesh_config, freq); + else +#endif + bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, + elems.ssid, elems.ssid_len); if (!bss) return; } else { @@ -2601,8 +2709,13 @@ static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, static void ieee80211_rx_mgmt_action(struct net_device *dev, struct ieee80211_if_sta *ifsta, struct ieee80211_mgmt *mgmt, - size_t len) + size_t len, + struct ieee80211_rx_status *rx_status) { +#ifdef CONFIG_MAC80211_MESH + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); +#endif + if (len < IEEE80211_MIN_ACTION_SIZE) return; @@ -2634,7 +2747,21 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev, break; } break; +#ifdef CONFIG_MAC80211_MESH + case PLINK_CATEGORY: + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + mesh_rx_plink_frame(dev, mgmt, len, rx_status); + break; + + case MESH_PATH_SEL_CATEGORY: + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + mesh_rx_path_sel_frame(dev, mgmt, len); + break; +#endif default: + if (net_ratelimit()) + printk(KERN_DEBUG "%s: Rx unknown action frame - " + "category=%d\n", dev->name, mgmt->u.action.category); break; } } @@ -2661,13 +2788,13 @@ void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb, case IEEE80211_STYPE_PROBE_REQ: case IEEE80211_STYPE_PROBE_RESP: case IEEE80211_STYPE_BEACON: + case IEEE80211_STYPE_ACTION: memcpy(skb->cb, rx_status, sizeof(*rx_status)); case IEEE80211_STYPE_AUTH: case IEEE80211_STYPE_ASSOC_RESP: case IEEE80211_STYPE_REASSOC_RESP: case IEEE80211_STYPE_DEAUTH: case IEEE80211_STYPE_DISASSOC: - case IEEE80211_STYPE_ACTION: skb_queue_tail(&ifsta->skb_queue, skb); queue_work(local->hw.workqueue, &ifsta->work); return; @@ -2726,7 +2853,7 @@ static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev, ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len); break; case IEEE80211_STYPE_ACTION: - ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len); + ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len, rx_status); break; } @@ -2791,7 +2918,7 @@ static int ieee80211_sta_active_ibss(struct net_device *dev) } -static void ieee80211_sta_expire(struct net_device *dev) +static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta, *tmp; @@ -2800,8 +2927,7 @@ static void ieee80211_sta_expire(struct net_device *dev) write_lock_bh(&local->sta_lock); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) - if (time_after(jiffies, sta->last_rx + - IEEE80211_IBSS_INACTIVITY_LIMIT)) { + if (time_after(jiffies, sta->last_rx + exp_time)) { printk(KERN_DEBUG "%s: expiring inactive STA %s\n", dev->name, print_mac(mac, sta->addr)); __sta_info_get(sta); @@ -2822,7 +2948,7 @@ static void ieee80211_sta_merge_ibss(struct net_device *dev, { mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); - ieee80211_sta_expire(dev); + ieee80211_sta_expire(dev, IEEE80211_IBSS_INACTIVITY_LIMIT); if (ieee80211_sta_active_ibss(dev)) return; @@ -2832,6 +2958,36 @@ static void ieee80211_sta_merge_ibss(struct net_device *dev, } +#ifdef CONFIG_MAC80211_MESH +static void ieee80211_mesh_housekeeping(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + bool free_plinks; + + ieee80211_sta_expire(dev, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); + mesh_path_expire(dev); + + free_plinks = mesh_plink_availables(sdata); + if (free_plinks != sdata->u.sta.accepting_plinks) + ieee80211_if_config_beacon(dev); + + mod_timer(&ifsta->timer, jiffies + + IEEE80211_MESH_HOUSEKEEPING_INTERVAL); +} + + +void ieee80211_start_mesh(struct net_device *dev) +{ + struct ieee80211_if_sta *ifsta; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + ifsta = &sdata->u.sta; + ifsta->state = IEEE80211_MESH_UP; + ieee80211_sta_timer((unsigned long)sdata); +} +#endif + + void ieee80211_sta_timer(unsigned long data) { struct ieee80211_sub_if_data *sdata = @@ -2843,7 +2999,6 @@ void ieee80211_sta_timer(unsigned long data) queue_work(local->hw.workqueue, &ifsta->work); } - void ieee80211_sta_work(struct work_struct *work) { struct ieee80211_sub_if_data *sdata = @@ -2860,7 +3015,8 @@ void ieee80211_sta_work(struct work_struct *work) return; if (sdata->vif.type != IEEE80211_IF_TYPE_STA && - sdata->vif.type != IEEE80211_IF_TYPE_IBSS) { + sdata->vif.type != IEEE80211_IF_TYPE_IBSS && + sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) { printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface " "(type=%d)\n", dev->name, sdata->vif.type); return; @@ -2870,6 +3026,12 @@ void ieee80211_sta_work(struct work_struct *work) while ((skb = skb_dequeue(&ifsta->skb_queue))) ieee80211_sta_rx_queued_mgmt(dev, skb); +#ifdef CONFIG_MAC80211_MESH + if (ifsta->preq_queue_len && time_after(jiffies, ifsta->last_preq + + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval))) + mesh_path_start_discovery(dev); +#endif + if (ifsta->state != IEEE80211_AUTHENTICATE && ifsta->state != IEEE80211_ASSOCIATE && test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { @@ -2905,6 +3067,11 @@ void ieee80211_sta_work(struct work_struct *work) case IEEE80211_IBSS_JOINED: ieee80211_sta_merge_ibss(dev, ifsta); break; +#ifdef CONFIG_MAC80211_MESH + case IEEE80211_MESH_UP: + ieee80211_mesh_housekeeping(dev, ifsta); + break; +#endif default: printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n", ifsta->state); @@ -3109,7 +3276,7 @@ static int ieee80211_sta_create_ibss(struct net_device *dev, sband = local->hw.wiphy->bands[bss->band]; if (local->hw.conf.beacon_int == 0) - local->hw.conf.beacon_int = 100; + local->hw.conf.beacon_int = 10000; bss->beacon_int = local->hw.conf.beacon_int; bss->last_update = jiffies; bss->capability = WLAN_CAPABILITY_IBSS; @@ -3398,6 +3565,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) ieee80211_sta_timer((unsigned long)sdata); } + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + ieee80211_sta_timer((unsigned long)sdata); + netif_wake_queue(sdata->dev); } rcu_read_unlock(); @@ -3640,15 +3810,27 @@ ieee80211_sta_scan_result(struct net_device *dev, memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWESSID; - iwe.u.data.length = bss->ssid_len; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - bss->ssid); + if (bss->mesh_cfg) { +#ifdef CONFIG_MAC80211_MESH + iwe.u.data.length = bss->mesh_id_len; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + bss->mesh_id); +#endif + } else { + iwe.u.data.length = bss->ssid_len; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + bss->ssid); + } - if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { + if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS + || bss->mesh_cfg)) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWMODE; - if (bss->capability & WLAN_CAPABILITY_ESS) + if (bss->mesh_cfg) + iwe.u.mode = IW_MODE_MESH; + else if (bss->capability & WLAN_CAPABILITY_ESS) iwe.u.mode = IW_MODE_MASTER; else iwe.u.mode = IW_MODE_ADHOC; @@ -3737,6 +3919,28 @@ ieee80211_sta_scan_result(struct net_device *dev, } } + if (bss->mesh_cfg) { + char *buf; + u8 *cfg = bss->mesh_cfg; + buf = kmalloc(200, GFP_ATOMIC); + if (buf) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "Mesh network (version %d)\n" + "\t\t\tPath Selection Protocol ID: 0x%02X%02X%02X%02X\n" + "\t\t\tPath Selection Metric ID: 0x%02X%02X%02X%02X\n" + "\t\t\tCongestion Control Mode ID: 0x%02X%02X%02X%02X\n" + "\t\t\tChannel Precedence: 0x%02X%02X%02X%02X", + cfg[0], cfg[1], cfg[2], cfg[3], cfg[4], cfg[5], cfg[6], + cfg[7], cfg[8], cfg[9], cfg[10], cfg[11], cfg[12], + cfg[13], cfg[14], cfg[15], cfg[16]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + kfree(buf); + } + } + return current_ev; } -- cgit v1.2.3-59-g8ed1b From c3896d2ca4dd97be290f000cb1079ed759d28574 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:13 +0100 Subject: mac80211: mesh peer link implementation This file implements mesh discovery and peer link establishment support using the mesh peer link table provided in mesh_plinktbl.c. Secure peer links have not been implemented yet. Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh_plink.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 755 insertions(+) create mode 100644 net/mac80211/mesh_plink.c (limited to 'net') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c new file mode 100644 index 000000000000..5cd97e99be62 --- /dev/null +++ b/net/mac80211/mesh_plink.c @@ -0,0 +1,755 @@ +/* + * Copyright (c) 2008 open80211s Ltd. + * Author: Luis Carlos Cobo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "ieee80211_i.h" +#include "ieee80211_rate.h" +#include "mesh.h" +#include + +#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG +#define mpl_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args) +#else +#define mpl_dbg(fmt, args...) do { (void)(0); } while (0) +#endif + +#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype) +#define PLINK_GET_FRAME_SUBTYPE(p) (p) +#define PLINK_GET_LLID(p) (p + 1) +#define PLINK_GET_PLID(p) (p + 3) + +#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ + jiffies + HZ * t / 1000)) + +/* Peer link cancel reasons, all subject to ANA approval */ +#define MESH_LINK_CANCELLED 2 +#define MESH_MAX_NEIGHBORS 3 +#define MESH_CAPABILITY_POLICY_VIOLATION 4 +#define MESH_CLOSE_RCVD 5 +#define MESH_MAX_RETRIES 6 +#define MESH_CONFIRM_TIMEOUT 7 +#define MESH_SECURITY_ROLE_NEGOTIATION_DIFFERS 8 +#define MESH_SECURITY_AUTHENTICATION_IMPOSSIBLE 9 +#define MESH_SECURITY_FAILED_VERIFICATION 10 + +#define dot11MeshMaxRetries(s) (s->u.sta.mshcfg.dot11MeshMaxRetries) +#define dot11MeshRetryTimeout(s) (s->u.sta.mshcfg.dot11MeshRetryTimeout) +#define dot11MeshConfirmTimeout(s) (s->u.sta.mshcfg.dot11MeshConfirmTimeout) +#define dot11MeshHoldingTimeout(s) (s->u.sta.mshcfg.dot11MeshHoldingTimeout) +#define dot11MeshMaxPeerLinks(s) (s->u.sta.mshcfg.dot11MeshMaxPeerLinks) + +enum plink_frame_type { + PLINK_OPEN = 0, + PLINK_CONFIRM, + PLINK_CLOSE +}; + +enum plink_event { + PLINK_UNDEFINED, + OPN_ACPT, + OPN_RJCT, + OPN_IGNR, + CNF_ACPT, + CNF_RJCT, + CNF_IGNR, + CLS_ACPT, + CLS_IGNR +}; + +static inline +void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) +{ + atomic_inc(&sdata->u.sta.mshstats.estab_plinks); + mesh_accept_plinks_update(sdata->dev); +} + +static inline +void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) +{ + atomic_dec(&sdata->u.sta.mshstats.estab_plinks); + mesh_accept_plinks_update(sdata->dev); +} + +/** + * mesh_plink_fsm_restart - restart a mesh peer link finite state machine + * + * @sta: mes peer link to restart + * + * Locking: this function must be called holding sta->plink_lock + */ +static inline void mesh_plink_fsm_restart(struct sta_info *sta) +{ + sta->plink_state = LISTEN; + sta->llid = sta->plid = sta->reason = sta->plink_retries = 0; +} + +/** + * mesh_plink_add - allocate and add a new mesh peer link + * + * @hw_addr: hardware address (ETH_ALEN length) + * @rates: rates the mesh peer supports + * @dev: local mesh interface + * + * The initial state of the new plink is set to LISTEN + * + * Returns: non-NULL on success, ERR_PTR() on error. + */ +struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta; + + if (memcmp(hw_addr, dev->dev_addr, ETH_ALEN) == 0) + /* never add ourselves as neighbours */ + return ERR_PTR(-EINVAL); + + if (is_multicast_ether_addr(hw_addr)) + return ERR_PTR(-EINVAL); + + if (local->num_sta >= MESH_MAX_PLINKS) + return ERR_PTR(-ENOSPC); + + sta = sta_info_add(local, dev, hw_addr, GFP_KERNEL); + if (IS_ERR(sta)) + return sta; + + sta->plink_state = LISTEN; + spin_lock_init(&sta->plink_lock); + init_timer(&sta->plink_timer); + sta->flags |= WLAN_STA_AUTHORIZED; + sta->supp_rates[local->hw.conf.channel->band] = rates; + rate_control_rate_init(sta, local); + + mesh_accept_plinks_update(dev); + + return sta; +} + +/** + * mesh_plink_deactivate - deactivate mesh peer link + * + * @sta: mesh peer link to deactivate + * + * All mesh paths with this peer as next hop will be flushed + * + * Locking: the caller must hold sta->plink_lock + */ +void mesh_plink_deactivate(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + if (sta->plink_state == ESTAB) + mesh_plink_dec_estab_count(sdata); + sta->plink_state = BLOCKED; + mesh_path_flush_by_nexthop(sta); +} + +static int mesh_plink_frame_tx(struct net_device *dev, + enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid, + __le16 reason) { + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); + struct ieee80211_mgmt *mgmt; + bool include_plid = false; + u8 *pos; + int ie_len; + + if (!skb) + return -1; + skb_reserve(skb, local->hw.extra_tx_headroom); + /* 25 is the size of the common mgmt part (24) plus the size of the + * common action part (1) + */ + mgmt = (struct ieee80211_mgmt *) + skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action)); + memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action)); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_ACTION); + memcpy(mgmt->da, da, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + /* BSSID is left zeroed, wildcard value */ + mgmt->u.action.category = PLINK_CATEGORY; + mgmt->u.action.u.plink_action.action_code = action; + + if (action == PLINK_CLOSE) + mgmt->u.action.u.plink_action.aux = reason; + else { + mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0); + if (action == PLINK_CONFIRM) { + pos = skb_put(skb, 4); + /* two-byte status code followed by two-byte AID */ + memset(pos, 0, 4); + } + mesh_mgmt_ies_add(skb, dev); + } + + /* Add Peer Link Management element */ + switch (action) { + case PLINK_OPEN: + ie_len = 3; + break; + case PLINK_CONFIRM: + ie_len = 5; + include_plid = true; + break; + case PLINK_CLOSE: + default: + if (!plid) + ie_len = 5; + else { + ie_len = 7; + include_plid = true; + } + break; + } + + pos = skb_put(skb, 2 + ie_len); + *pos++ = WLAN_EID_PEER_LINK; + *pos++ = ie_len; + *pos++ = action; + memcpy(pos, &llid, 2); + if (include_plid) { + pos += 2; + memcpy(pos, &plid, 2); + } + if (action == PLINK_CLOSE) { + pos += 2; + memcpy(pos, &reason, 2); + } + + ieee80211_sta_tx(dev, skb, 0); + return 0; +} + +void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, + bool peer_accepting_plinks) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta; + + sta = sta_info_get(local, hw_addr); + if (!sta) { + sta = mesh_plink_add(hw_addr, rates, dev); + if (IS_ERR(sta)) + return; + } + + sta->last_rx = jiffies; + sta->supp_rates[local->hw.conf.channel->band] = rates; + if (peer_accepting_plinks && sta->plink_state == LISTEN && + sdata->u.sta.accepting_plinks && + sdata->u.sta.mshcfg.auto_open_plinks) + mesh_plink_open(sta); + + sta_info_put(sta); +} + +static void mesh_plink_timer(unsigned long data) +{ + struct sta_info *sta; + __le16 llid, plid, reason; + struct net_device *dev = NULL; + struct ieee80211_sub_if_data *sdata; +#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG + DECLARE_MAC_BUF(mac); +#endif + + sta = (struct sta_info *) data; + + spin_lock_bh(&sta->plink_lock); + if (sta->ignore_plink_timer) { + sta->ignore_plink_timer = false; + spin_unlock_bh(&sta->plink_lock); + return; + } + mpl_dbg("Mesh plink timer for %s fired on state %d\n", + print_mac(mac, sta->addr), sta->plink_state); + reason = 0; + llid = sta->llid; + plid = sta->plid; + dev = sta->dev; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + switch (sta->plink_state) { + case OPN_RCVD: + case OPN_SNT: + /* retry timer */ + if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { + u32 rand; + mpl_dbg("Mesh plink for %s (retry, timeout): %d %d\n", + print_mac(mac, sta->addr), + sta->plink_retries, sta->plink_timeout); + get_random_bytes(&rand, sizeof(u32)); + sta->plink_timeout = sta->plink_timeout + + rand % sta->plink_timeout; + ++sta->plink_retries; + if (!mod_plink_timer(sta, sta->plink_timeout)) + __sta_info_get(sta); + spin_unlock_bh(&sta->plink_lock); + mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, + 0, 0); + break; + } + reason = cpu_to_le16(MESH_MAX_RETRIES); + /* fall through on else */ + case CNF_RCVD: + /* confirm timer */ + if (!reason) + reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); + sta->plink_state = HOLDING; + if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) + __sta_info_get(sta); + spin_unlock_bh(&sta->plink_lock); + mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, + reason); + break; + case HOLDING: + /* holding timer */ + if (del_timer(&sta->plink_timer)) + sta_info_put(sta); + mesh_plink_fsm_restart(sta); + spin_unlock_bh(&sta->plink_lock); + break; + default: + spin_unlock_bh(&sta->plink_lock); + break; + } + + sta_info_put(sta); +} + +static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) +{ + sta->plink_timer.expires = jiffies + (HZ * timeout / 1000); + sta->plink_timer.data = (unsigned long) sta; + sta->plink_timer.function = mesh_plink_timer; + sta->plink_timeout = timeout; + __sta_info_get(sta); + add_timer(&sta->plink_timer); +} + +int mesh_plink_open(struct sta_info *sta) +{ + __le16 llid; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); +#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG + DECLARE_MAC_BUF(mac); +#endif + + spin_lock_bh(&sta->plink_lock); + get_random_bytes(&llid, 2); + sta->llid = llid; + if (sta->plink_state != LISTEN) { + spin_unlock_bh(&sta->plink_lock); + sta_info_put(sta); + return -EBUSY; + } + sta->plink_state = OPN_SNT; + mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); + spin_unlock_bh(&sta->plink_lock); + mpl_dbg("Mesh plink: starting establishment with %s\n", + print_mac(mac, sta->addr)); + + return mesh_plink_frame_tx(sta->dev, PLINK_OPEN, sta->addr, llid, 0, 0); +} + +void mesh_plink_block(struct sta_info *sta) +{ +#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG + DECLARE_MAC_BUF(mac); +#endif + + spin_lock_bh(&sta->plink_lock); + mesh_plink_deactivate(sta); + sta->plink_state = BLOCKED; + spin_unlock_bh(&sta->plink_lock); +} + +int mesh_plink_close(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + int llid, plid, reason; +#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG + DECLARE_MAC_BUF(mac); +#endif + + mpl_dbg("Mesh plink: closing link with %s\n", + print_mac(mac, sta->addr)); + spin_lock_bh(&sta->plink_lock); + sta->reason = cpu_to_le16(MESH_LINK_CANCELLED); + reason = sta->reason; + + if (sta->plink_state == LISTEN || sta->plink_state == BLOCKED) { + mesh_plink_fsm_restart(sta); + spin_unlock_bh(&sta->plink_lock); + sta_info_put(sta); + return 0; + } else if (sta->plink_state == ESTAB) { + mesh_plink_deactivate(sta); + /* The timer should not be running */ + if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) + __sta_info_get(sta); + } else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) + sta->ignore_plink_timer = true; + + sta->plink_state = HOLDING; + llid = sta->llid; + plid = sta->plid; + spin_unlock_bh(&sta->plink_lock); + mesh_plink_frame_tx(sta->dev, PLINK_CLOSE, sta->addr, llid, plid, + reason); + return 0; +} + +void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, + size_t len, struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee802_11_elems elems; + struct sta_info *sta; + enum plink_event event; + enum plink_frame_type ftype; + size_t baselen; + u8 ie_len; + u8 *baseaddr; + __le16 plid, llid, reason; +#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG + DECLARE_MAC_BUF(mac); +#endif + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (is_multicast_ether_addr(mgmt->da)) { + mpl_dbg("Mesh plink: ignore frame from multicast address"); + return; + } + + baseaddr = mgmt->u.action.u.plink_action.variable; + baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt; + if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) { + baseaddr += 4; + baselen -= 4; + } + ieee802_11_parse_elems(baseaddr, len - baselen, &elems); + if (!elems.peer_link) { + mpl_dbg("Mesh plink: missing necessary peer link ie\n"); + return; + } + + ftype = *((u8 *)PLINK_GET_FRAME_SUBTYPE(elems.peer_link)); + ie_len = elems.peer_link_len; + if ((ftype == PLINK_OPEN && ie_len != 3) || + (ftype == PLINK_CONFIRM && ie_len != 5) || + (ftype == PLINK_CLOSE && ie_len != 5 && ie_len != 7)) { + mpl_dbg("Mesh plink: incorrect plink ie length\n"); + return; + } + + if (ftype != PLINK_CLOSE && (!elems.mesh_id || !elems.mesh_config)) { + mpl_dbg("Mesh plink: missing necessary ie\n"); + return; + } + /* Note the lines below are correct, the llid in the frame is the plid + * from the point of view of this host. + */ + memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2); + if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7)) + memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); + + sta = sta_info_get(local, mgmt->sa); + if (!sta && ftype != PLINK_OPEN) { + mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); + return; + } + + if (sta && sta->plink_state == BLOCKED) { + sta_info_put(sta); + return; + } + + /* Now we will figure out the appropriate event... */ + event = PLINK_UNDEFINED; + if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, dev))) { + switch (ftype) { + case PLINK_OPEN: + event = OPN_RJCT; + break; + case PLINK_CONFIRM: + event = CNF_RJCT; + break; + case PLINK_CLOSE: + /* avoid warning */ + break; + } + spin_lock_bh(&sta->plink_lock); + } else if (!sta) { + /* ftype == PLINK_OPEN */ + u64 rates; + if (!mesh_plink_free_count(sdata)) { + mpl_dbg("Mesh plink error: no more free plinks\n"); + return; + } + + rates = ieee80211_sta_get_rates(local, &elems, rx_status->band); + sta = mesh_plink_add(mgmt->sa, rates, dev); + if (IS_ERR(sta)) { + mpl_dbg("Mesh plink error: plink table full\n"); + return; + } + event = OPN_ACPT; + spin_lock_bh(&sta->plink_lock); + } else { + spin_lock_bh(&sta->plink_lock); + switch (ftype) { + case PLINK_OPEN: + if (!mesh_plink_free_count(sdata) || + (sta->plid && sta->plid != plid)) + event = OPN_IGNR; + else + event = OPN_ACPT; + break; + case PLINK_CONFIRM: + if (!mesh_plink_free_count(sdata) || + (sta->llid != llid || sta->plid != plid)) + event = CNF_IGNR; + else + event = CNF_ACPT; + break; + case PLINK_CLOSE: + if (sta->plink_state == ESTAB) + /* Do not check for llid or plid. This does not + * follow the standard but since multiple plinks + * per sta are not supported, it is necessary in + * order to avoid a livelock when MP A sees an + * establish peer link to MP B but MP B does not + * see it. This can be caused by a timeout in + * B's peer link establishment or B beign + * restarted. + */ + event = CLS_ACPT; + else if (sta->plid != plid) + event = CLS_IGNR; + else if (ie_len == 7 && sta->llid != llid) + event = CLS_IGNR; + else + event = CLS_ACPT; + break; + default: + mpl_dbg("Mesh plink: unknown frame subtype\n"); + spin_unlock_bh(&sta->plink_lock); + sta_info_put(sta); + return; + } + } + + mpl_dbg("Mesh plink (peer, state, llid, plid, event): %s %d %d %d %d\n", + print_mac(mac, mgmt->sa), sta->plink_state, + __le16_to_cpu(sta->llid), __le16_to_cpu(sta->plid), + event); + reason = 0; + switch (sta->plink_state) { + /* spin_unlock as soon as state is updated at each case */ + case LISTEN: + switch (event) { + case CLS_ACPT: + mesh_plink_fsm_restart(sta); + spin_unlock_bh(&sta->plink_lock); + break; + case OPN_ACPT: + sta->plink_state = OPN_RCVD; + sta->plid = plid; + get_random_bytes(&llid, 2); + sta->llid = llid; + mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); + spin_unlock_bh(&sta->plink_lock); + mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, + 0, 0); + mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, + llid, plid, 0); + break; + default: + spin_unlock_bh(&sta->plink_lock); + break; + } + break; + + case OPN_SNT: + switch (event) { + case OPN_RJCT: + case CNF_RJCT: + reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION); + case CLS_ACPT: + if (!reason) + reason = cpu_to_le16(MESH_CLOSE_RCVD); + sta->reason = reason; + sta->plink_state = HOLDING; + if (!mod_plink_timer(sta, + dot11MeshHoldingTimeout(sdata))) + sta->ignore_plink_timer = true; + + llid = sta->llid; + spin_unlock_bh(&sta->plink_lock); + mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, + plid, reason); + break; + case OPN_ACPT: + /* retry timer is left untouched */ + sta->plink_state = OPN_RCVD; + sta->plid = plid; + llid = sta->llid; + spin_unlock_bh(&sta->plink_lock); + mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, + plid, 0); + break; + case CNF_ACPT: + sta->plink_state = CNF_RCVD; + if (!mod_plink_timer(sta, + dot11MeshConfirmTimeout(sdata))) + sta->ignore_plink_timer = true; + + spin_unlock_bh(&sta->plink_lock); + break; + default: + spin_unlock_bh(&sta->plink_lock); + break; + } + break; + + case OPN_RCVD: + switch (event) { + case OPN_RJCT: + case CNF_RJCT: + reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION); + case CLS_ACPT: + if (!reason) + reason = cpu_to_le16(MESH_CLOSE_RCVD); + sta->reason = reason; + sta->plink_state = HOLDING; + if (!mod_plink_timer(sta, + dot11MeshHoldingTimeout(sdata))) + sta->ignore_plink_timer = true; + + llid = sta->llid; + spin_unlock_bh(&sta->plink_lock); + mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, + plid, reason); + break; + case OPN_ACPT: + llid = sta->llid; + spin_unlock_bh(&sta->plink_lock); + mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, + plid, 0); + break; + case CNF_ACPT: + if (del_timer(&sta->plink_timer)) + sta_info_put(sta); + sta->plink_state = ESTAB; + mesh_plink_inc_estab_count(sdata); + spin_unlock_bh(&sta->plink_lock); + mpl_dbg("Mesh plink with %s ESTABLISHED\n", + print_mac(mac, sta->addr)); + break; + default: + spin_unlock_bh(&sta->plink_lock); + break; + } + break; + + case CNF_RCVD: + switch (event) { + case OPN_RJCT: + case CNF_RJCT: + reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION); + case CLS_ACPT: + if (!reason) + reason = cpu_to_le16(MESH_CLOSE_RCVD); + sta->reason = reason; + sta->plink_state = HOLDING; + if (!mod_plink_timer(sta, + dot11MeshHoldingTimeout(sdata))) + sta->ignore_plink_timer = true; + + llid = sta->llid; + spin_unlock_bh(&sta->plink_lock); + mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, + plid, reason); + case OPN_ACPT: + if (del_timer(&sta->plink_timer)) + sta_info_put(sta); + sta->plink_state = ESTAB; + mesh_plink_inc_estab_count(sdata); + spin_unlock_bh(&sta->plink_lock); + mpl_dbg("Mesh plink with %s ESTABLISHED\n", + print_mac(mac, sta->addr)); + mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, + plid, 0); + break; + default: + spin_unlock_bh(&sta->plink_lock); + break; + } + break; + + case ESTAB: + switch (event) { + case CLS_ACPT: + reason = cpu_to_le16(MESH_CLOSE_RCVD); + sta->reason = reason; + mesh_plink_deactivate(sta); + sta->plink_state = HOLDING; + llid = sta->llid; + if (!mod_plink_timer(sta, + dot11MeshHoldingTimeout(sdata))) + __sta_info_get(sta); + spin_unlock_bh(&sta->plink_lock); + mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, + plid, reason); + break; + case OPN_ACPT: + llid = sta->llid; + spin_unlock_bh(&sta->plink_lock); + mesh_plink_frame_tx(dev, PLINK_CONFIRM, sta->addr, llid, + plid, 0); + break; + default: + spin_unlock_bh(&sta->plink_lock); + break; + } + break; + case HOLDING: + switch (event) { + case CLS_ACPT: + if (del_timer(&sta->plink_timer)) { + sta->ignore_plink_timer = 1; + sta_info_put(sta); + } + mesh_plink_fsm_restart(sta); + spin_unlock_bh(&sta->plink_lock); + break; + case OPN_ACPT: + case CNF_ACPT: + case OPN_RJCT: + case CNF_RJCT: + llid = sta->llid; + reason = sta->reason; + spin_unlock_bh(&sta->plink_lock); + mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, + plid, reason); + break; + default: + spin_unlock_bh(&sta->plink_lock); + } + break; + default: + /* should not get here, BLOCKED is dealt with at the beggining + * of the function + */ + spin_unlock_bh(&sta->plink_lock); + break; + } + sta_info_put(sta); +} -- cgit v1.2.3-59-g8ed1b From eb2b9311fd00a868e9bf85ab66e86b7dee1643e1 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:14 +0100 Subject: mac80211: mesh path table implementation The mesh path table associates destinations with the next hop to reach them. The table is a hash of linked lists protected by rcu mechanisms. Every mesh path contains a lock to protect the mesh path state. Each outgoing mesh frame requires a look up into this table. Therefore, the table it has been designed so it is not necessary to hold any lock to find the appropriate next hop. If the path is determined to be active within a rcu context we can safely dereference mpath->next_hop->addr, since it holds a reference to the sta next_hop. After a mesh path has been set active for the first time it next_hop must always point to a valid sta. If this is not possible the mpath must be deleted or replaced in a RCU safe fashion. Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh_pathtbl.c | 522 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 522 insertions(+) create mode 100644 net/mac80211/mesh_pathtbl.c (limited to 'net') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c new file mode 100644 index 000000000000..37094942e728 --- /dev/null +++ b/net/mac80211/mesh_pathtbl.c @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2008 open80211s Ltd. + * Author: Luis Carlos Cobo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ieee80211_i.h" +#include "mesh.h" + +/* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */ +#define INIT_PATHS_SIZE_ORDER 2 + +/* Keep the mean chain length below this constant */ +#define MEAN_CHAIN_LEN 2 + +#define MPATH_EXPIRED(mpath) ((mpath->flags & MESH_PATH_ACTIVE) && \ + time_after(jiffies, mpath->exp_time) && \ + !(mpath->flags & MESH_PATH_FIXED)) + +struct mpath_node { + struct hlist_node list; + struct rcu_head rcu; + /* This indirection allows two different tables to point to the same + * mesh_path structure, useful when resizing + */ + struct mesh_path *mpath; +}; + +static struct mesh_table *mesh_paths; + +/* This lock will have the grow table function as writer and add / delete nodes + * as readers. When reading the table (i.e. doing lookups) we are well protected + * by RCU + */ +static DEFINE_RWLOCK(pathtbl_resize_lock); + +/** + * + * mesh_path_assign_nexthop - update mesh path next hop + * + * @mpath: mesh path to update + * @sta: next hop to assign + * + * Locking: mpath->state_lock must be held when calling this function + */ +void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) +{ + __sta_info_get(sta); + if (mpath->next_hop) + sta_info_put(mpath->next_hop); + mpath->next_hop = sta; +} + + +/** + * mesh_path_lookup - look up a path in the mesh path table + * @dst: hardware address (ETH_ALEN length) of destination + * @dev: local interface + * + * Returns: pointer to the mesh path structure, or NULL if not found + * + * Locking: must be called within a read rcu section. + */ +struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev) +{ + struct mesh_path *mpath; + struct hlist_node *n; + struct hlist_head *bucket; + struct mesh_table *tbl; + struct mpath_node *node; + + tbl = rcu_dereference(mesh_paths); + + bucket = &tbl->hash_buckets[mesh_table_hash(dst, dev, tbl)]; + hlist_for_each_entry_rcu(node, n, bucket, list) { + mpath = node->mpath; + if (mpath->dev == dev && + memcmp(dst, mpath->dst, ETH_ALEN) == 0) { + if (MPATH_EXPIRED(mpath)) { + spin_lock_bh(&mpath->state_lock); + if (MPATH_EXPIRED(mpath)) + mpath->flags &= ~MESH_PATH_ACTIVE; + spin_unlock_bh(&mpath->state_lock); + } + return mpath; + } + } + return NULL; +} + +/** + * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index + * @idx: index + * @dev: local interface + * + * Returns: pointer to the mesh path structure, or NULL if not found. + * + * Locking: must be called within a read rcu section. + */ +struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev) +{ + struct mpath_node *node; + struct hlist_node *p; + int i; + int j = 0; + + for_each_mesh_entry(mesh_paths, p, node, i) + if (j++ == idx) { + if (MPATH_EXPIRED(node->mpath)) { + spin_lock_bh(&node->mpath->state_lock); + if (MPATH_EXPIRED(node->mpath)) + node->mpath->flags &= ~MESH_PATH_ACTIVE; + spin_unlock_bh(&node->mpath->state_lock); + } + return node->mpath; + } + + return NULL; +} + +/** + * mesh_path_add - allocate and add a new path to the mesh path table + * @addr: destination address of the path (ETH_ALEN length) + * @dev: local interface + * + * Returns: 0 on sucess + * + * State: the initial state of the new path is set to 0 + */ +int mesh_path_add(u8 *dst, struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct mesh_path *mpath, *new_mpath; + struct mpath_node *node, *new_node; + struct hlist_head *bucket; + struct hlist_node *n; + int grow = 0; + int err = 0; + u32 hash_idx; + + if (memcmp(dst, dev->dev_addr, ETH_ALEN) == 0) + /* never add ourselves as neighbours */ + return -ENOTSUPP; + + if (is_multicast_ether_addr(dst)) + return -ENOTSUPP; + + if (atomic_add_unless(&sdata->u.sta.mpaths, 1, MESH_MAX_MPATHS) == 0) + return -ENOSPC; + + read_lock(&pathtbl_resize_lock); + + new_mpath = kzalloc(sizeof(struct mesh_path), GFP_KERNEL); + if (!new_mpath) { + atomic_dec(&sdata->u.sta.mpaths); + err = -ENOMEM; + goto endadd2; + } + memcpy(new_mpath->dst, dst, ETH_ALEN); + new_mpath->dev = dev; + new_mpath->flags = 0; + skb_queue_head_init(&new_mpath->frame_queue); + new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); + new_node->mpath = new_mpath; + new_mpath->timer.data = (unsigned long) new_mpath; + new_mpath->timer.function = mesh_path_timer; + new_mpath->exp_time = jiffies; + spin_lock_init(&new_mpath->state_lock); + init_timer(&new_mpath->timer); + + hash_idx = mesh_table_hash(dst, dev, mesh_paths); + bucket = &mesh_paths->hash_buckets[hash_idx]; + + spin_lock(&mesh_paths->hashwlock[hash_idx]); + + hlist_for_each_entry(node, n, bucket, list) { + mpath = node->mpath; + if (mpath->dev == dev && memcmp(dst, mpath->dst, ETH_ALEN) + == 0) { + err = -EEXIST; + atomic_dec(&sdata->u.sta.mpaths); + kfree(new_node); + kfree(new_mpath); + goto endadd; + } + } + + hlist_add_head_rcu(&new_node->list, bucket); + if (atomic_inc_return(&mesh_paths->entries) >= + mesh_paths->mean_chain_len * (mesh_paths->hash_mask + 1)) + grow = 1; + +endadd: + spin_unlock(&mesh_paths->hashwlock[hash_idx]); +endadd2: + read_unlock(&pathtbl_resize_lock); + if (!err && grow) { + struct mesh_table *oldtbl, *newtbl; + + write_lock(&pathtbl_resize_lock); + oldtbl = mesh_paths; + newtbl = mesh_table_grow(mesh_paths); + if (!newtbl) { + write_unlock(&pathtbl_resize_lock); + return -ENOMEM; + } + rcu_assign_pointer(mesh_paths, newtbl); + synchronize_rcu(); + mesh_table_free(oldtbl, false); + write_unlock(&pathtbl_resize_lock); + } + return err; +} + + +/** + * mesh_plink_broken - deactivates paths and sends perr when a link breaks + * + * @sta: broken peer link + * + * This function must be called from the rate control algorithm if enough + * delivery errors suggest that a peer link is no longer usable. + */ +void mesh_plink_broken(struct sta_info *sta) +{ + struct mesh_path *mpath; + struct mpath_node *node; + struct hlist_node *p; + struct net_device *dev = sta->dev; + int i; + + rcu_read_lock(); + for_each_mesh_entry(mesh_paths, p, node, i) { + mpath = node->mpath; + spin_lock_bh(&mpath->state_lock); + if (mpath->next_hop == sta && + mpath->flags & MESH_PATH_ACTIVE && + !(mpath->flags & MESH_PATH_FIXED)) { + mpath->flags &= ~MESH_PATH_ACTIVE; + ++mpath->dsn; + spin_unlock_bh(&mpath->state_lock); + mesh_path_error_tx(mpath->dst, + cpu_to_le32(mpath->dsn), + dev->broadcast, dev); + } else + spin_unlock_bh(&mpath->state_lock); + } + rcu_read_unlock(); +} + +/** + * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches + * + * @sta - mesh peer to match + * + * RCU notes: this function is called when a mesh plink transitions from ESTAB + * to any other state, since ESTAB state is the only one that allows path + * creation. This will happen before the sta can be freed (since we hold + * a reference to it) so any reader in a rcu read block will be protected + * against the plink dissapearing. + */ +void mesh_path_flush_by_nexthop(struct sta_info *sta) +{ + struct mesh_path *mpath; + struct mpath_node *node; + struct hlist_node *p; + int i; + + for_each_mesh_entry(mesh_paths, p, node, i) { + mpath = node->mpath; + if (mpath->next_hop == sta) + mesh_path_del(mpath->dst, mpath->dev); + } +} + +void mesh_path_flush(struct net_device *dev) +{ + struct mesh_path *mpath; + struct mpath_node *node; + struct hlist_node *p; + int i; + + for_each_mesh_entry(mesh_paths, p, node, i) { + mpath = node->mpath; + if (mpath->dev == dev) + mesh_path_del(mpath->dst, mpath->dev); + } +} + +static void mesh_path_node_reclaim(struct rcu_head *rp) +{ + struct mpath_node *node = container_of(rp, struct mpath_node, rcu); + struct ieee80211_sub_if_data *sdata = + IEEE80211_DEV_TO_SUB_IF(node->mpath->dev); + if (node->mpath->next_hop) + sta_info_put(node->mpath->next_hop); + atomic_dec(&sdata->u.sta.mpaths); + kfree(node->mpath); + kfree(node); +} + +/** + * mesh_path_del - delete a mesh path from the table + * + * @addr: dst address (ETH_ALEN length) + * @dev: local interface + * + * Returns: 0 if succesful + * + * State: if the path is being resolved, the deletion will be postponed until + * the path resolution completes or times out. + */ +int mesh_path_del(u8 *addr, struct net_device *dev) +{ + struct mesh_path *mpath; + struct mpath_node *node; + struct hlist_head *bucket; + struct hlist_node *n; + int hash_idx; + int err = 0; + + read_lock(&pathtbl_resize_lock); + hash_idx = mesh_table_hash(addr, dev, mesh_paths); + bucket = &mesh_paths->hash_buckets[hash_idx]; + + spin_lock(&mesh_paths->hashwlock[hash_idx]); + hlist_for_each_entry(node, n, bucket, list) { + mpath = node->mpath; + if (mpath->dev == dev && + memcmp(addr, mpath->dst, ETH_ALEN) == 0) { + spin_lock_bh(&mpath->state_lock); + if (mpath->flags & MESH_PATH_RESOLVING) { + mpath->flags |= MESH_PATH_DELETE; + } else { + mpath->flags |= MESH_PATH_RESOLVING; + hlist_del_rcu(&node->list); + call_rcu(&node->rcu, mesh_path_node_reclaim); + atomic_dec(&mesh_paths->entries); + } + spin_unlock_bh(&mpath->state_lock); + goto enddel; + } + } + + err = -ENXIO; +enddel: + spin_unlock(&mesh_paths->hashwlock[hash_idx]); + read_unlock(&pathtbl_resize_lock); + return err; +} + +/** + * mesh_path_tx_pending - sends pending frames in a mesh path queue + * + * @mpath: mesh path to activate + * + * Locking: the state_lock of the mpath structure must NOT be held when calling + * this function. + */ +void mesh_path_tx_pending(struct mesh_path *mpath) +{ + struct sk_buff *skb; + + while ((skb = skb_dequeue(&mpath->frame_queue)) && + (mpath->flags & MESH_PATH_ACTIVE)) + dev_queue_xmit(skb); +} + +/** + * mesh_path_discard_frame - discard a frame whose path could not be resolved + * + * @skb: frame to discard + * @dev: network device the frame was to be sent through + * + * If the frame was beign forwarded from another MP, a PERR frame will be sent + * to the precursor. + * + * Locking: the function must me called within a rcu_read_lock region + */ +void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct mesh_path *mpath; + u32 dsn = 0; + + if (skb->pkt_type == PACKET_OTHERHOST) { + struct ieee80211s_hdr *prev_meshhdr; + int mshhdrlen; + u8 *ra, *da; + + prev_meshhdr = ((struct ieee80211s_hdr *)skb->cb); + mshhdrlen = ieee80211_get_mesh_hdrlen(prev_meshhdr); + da = skb->data; + ra = MESH_PREQ(skb); + mpath = mesh_path_lookup(da, dev); + if (mpath) + dsn = ++mpath->dsn; + mesh_path_error_tx(skb->data, cpu_to_le32(dsn), ra, dev); + } + + kfree_skb(skb); + sdata->u.sta.mshstats.dropped_frames_no_route++; +} + +/** + * mesh_path_flush_pending - free the pending queue of a mesh path + * + * @mpath: mesh path whose queue has to be freed + * + * Locking: the function must me called withing a rcu_read_lock region + */ +void mesh_path_flush_pending(struct mesh_path *mpath) +{ + struct ieee80211_sub_if_data *sdata; + struct sk_buff *skb; + + sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev); + + while ((skb = skb_dequeue(&mpath->frame_queue)) && + (mpath->flags & MESH_PATH_ACTIVE)) + mesh_path_discard_frame(skb, mpath->dev); +} + +/** + * mesh_path_fix_nexthop - force a specific next hop for a mesh path + * + * @mpath: the mesh path to modify + * @next_hop: the next hop to force + * + * Locking: this function must be called holding mpath->state_lock + */ +void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop) +{ + spin_lock_bh(&mpath->state_lock); + mesh_path_assign_nexthop(mpath, next_hop); + mpath->dsn = 0xffff; + mpath->metric = 0; + mpath->hop_count = 0; + mpath->exp_time = 0; + mpath->flags |= MESH_PATH_FIXED; + mesh_path_activate(mpath); + spin_unlock_bh(&mpath->state_lock); + mesh_path_tx_pending(mpath); +} + +static void mesh_path_node_free(struct hlist_node *p, bool free_leafs) +{ + struct mesh_path *mpath; + struct mpath_node *node = hlist_entry(p, struct mpath_node, list); + mpath = node->mpath; + hlist_del_rcu(p); + synchronize_rcu(); + if (free_leafs) + kfree(mpath); + kfree(node); +} + +static void mesh_path_node_copy(struct hlist_node *p, struct mesh_table *newtbl) +{ + struct mesh_path *mpath; + struct mpath_node *node, *new_node; + u32 hash_idx; + + node = hlist_entry(p, struct mpath_node, list); + mpath = node->mpath; + new_node = kmalloc(sizeof(struct mpath_node), GFP_KERNEL); + new_node->mpath = mpath; + hash_idx = mesh_table_hash(mpath->dst, mpath->dev, newtbl); + hlist_add_head(&new_node->list, + &newtbl->hash_buckets[hash_idx]); +} + +int mesh_pathtbl_init(void) +{ + mesh_paths = mesh_table_alloc(INIT_PATHS_SIZE_ORDER); + mesh_paths->free_node = &mesh_path_node_free; + mesh_paths->copy_node = &mesh_path_node_copy; + mesh_paths->mean_chain_len = MEAN_CHAIN_LEN; + if (!mesh_paths) + return -ENOMEM; + return 0; +} + +void mesh_path_expire(struct net_device *dev) +{ + struct mesh_path *mpath; + struct mpath_node *node; + struct hlist_node *p; + int i; + + read_lock(&pathtbl_resize_lock); + for_each_mesh_entry(mesh_paths, p, node, i) { + if (node->mpath->dev != dev) + continue; + mpath = node->mpath; + spin_lock_bh(&mpath->state_lock); + if ((!(mpath->flags & MESH_PATH_RESOLVING)) && + (!(mpath->flags & MESH_PATH_FIXED)) && + time_after(jiffies, + mpath->exp_time + MESH_PATH_EXPIRE)) { + spin_unlock_bh(&mpath->state_lock); + mesh_path_del(mpath->dst, mpath->dev); + } else + spin_unlock_bh(&mpath->state_lock); + } + read_unlock(&pathtbl_resize_lock); +} + +void mesh_pathtbl_unregister(void) +{ + mesh_table_free(mesh_paths, true); +} -- cgit v1.2.3-59-g8ed1b From 050ac52cbe1f3de2fb0d06f02c7919ae1f691c9e Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:15 +0100 Subject: mac80211: code for on-demand Hybrid Wireless Mesh Protocol This file implements the on-demand Hybrid Wireless Mesh Protocol, at this moment using hop-count as the metric. When no mesh path exists for a given destination or the mesh path is not active, frames addressed to that destination will be queued and a Path Request frame will be sent. Queued frames will be sent when the path is resolved (usually after reception of a Path Response) or discarded if discovery times out. Path Requests will also be sent to refresh paths that are being used and are close to expiring. Path Errors are sent when a path discovery process triggered by the attempt to forward a frame originated in a different mesh point times out. Path Errors are also sent when a peer link is determined to be unreachable because of high error rates. Multiple destination support in Path Requests and Path Errors and precursors have not been implemented yet. Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 862 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 862 insertions(+) create mode 100644 net/mac80211/mesh_hwmp.c (limited to 'net') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c new file mode 100644 index 000000000000..9a501aae48eb --- /dev/null +++ b/net/mac80211/mesh_hwmp.c @@ -0,0 +1,862 @@ +/* + * Copyright (c) 2008 open80211s Ltd. + * Author: Luis Carlos Cobo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "mesh.h" + +#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype) + +#define TEST_FRAME_LEN 8192 +#define MAX_METRIC 0xffffffff +#define ARITH_SHIFT 8 + +/* Number of frames buffered per destination for unresolved destinations */ +#define MESH_FRAME_QUEUE_LEN 10 +#define MAX_PREQ_QUEUE_LEN 64 + +/* Destination only */ +#define MP_F_DO 0x1 +/* Reply and forward */ +#define MP_F_RF 0x2 + +/* HWMP IE processing macros */ +#define AE_F (1<<6) +#define AE_F_SET(x) (*x & AE_F) +#define PREQ_IE_FLAGS(x) (*(x)) +#define PREQ_IE_HOPCOUNT(x) (*(x + 1)) +#define PREQ_IE_TTL(x) (*(x + 2)) +#define PREQ_IE_PREQ_ID(x) le32_to_cpu(*((u32 *) (x + 3))) +#define PREQ_IE_ORIG_ADDR(x) (x + 7) +#define PREQ_IE_ORIG_DSN(x) le32_to_cpu(*((u32 *) (x + 13))) +#define PREQ_IE_LIFETIME(x) le32_to_cpu(*((u32 *) \ + (AE_F_SET(x) ? x + 23 : x + 17))) +#define PREQ_IE_METRIC(x) le32_to_cpu(*((u32 *) \ + (AE_F_SET(x) ? x + 27 : x + 21))) +#define PREQ_IE_DST_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) +#define PREQ_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) +#define PREQ_IE_DST_DSN(x) le32_to_cpu(*((u32 *) \ + (AE_F_SET(x) ? x + 39 : x + 33))) + + +#define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x) +#define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) +#define PREP_IE_TTL(x) PREQ_IE_TTL(x) +#define PREP_IE_ORIG_ADDR(x) (x + 3) +#define PREP_IE_ORIG_DSN(x) le32_to_cpu(*((u32 *) (x + 9))) +#define PREP_IE_LIFETIME(x) le32_to_cpu(*((u32 *) \ + (AE_F_SET(x) ? x + 19 : x + 13))) +#define PREP_IE_METRIC(x) le32_to_cpu(*((u32 *) \ + (AE_F_SET(x) ? x + 23 : x + 17))) +#define PREP_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) +#define PREP_IE_DST_DSN(x) le32_to_cpu(*((u32 *) \ + (AE_F_SET(x) ? x + 33 : x + 27))) + +#define PERR_IE_DST_ADDR(x) (x + 2) +#define PERR_IE_DST_DSN(x) le32_to_cpu(*((u32 *) (x + 8))) + +#define TU_TO_EXP_TIME(x) (jiffies + msecs_to_jiffies(x * 1024 / 1000)) +#define MSEC_TO_TU(x) (x*1000/1024) +#define DSN_GT(x, y) ((long) (y) - (long) (x) < 0) +#define DSN_LT(x, y) ((long) (x) - (long) (y) < 0) + +#define net_traversal_jiffies(s) \ + msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime) +#define default_lifetime(s) \ + MSEC_TO_TU(s->u.sta.mshcfg.dot11MeshHWMPactivePathTimeout) +#define min_preq_int_jiff(s) \ + (msecs_to_jiffies(s->u.sta.mshcfg.dot11MeshHWMPpreqMinInterval)) +#define max_preq_retries(s) (s->u.sta.mshcfg.dot11MeshHWMPmaxPREQretries) +#define disc_timeout_jiff(s) \ + msecs_to_jiffies(sdata->u.sta.mshcfg.min_discovery_timeout) + +enum mpath_frame_type { + MPATH_PREQ = 0, + MPATH_PREP, + MPATH_PERR +}; + +static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, + u8 *orig_addr, __le32 orig_dsn, u8 dst_flags, u8 *dst, + __le32 dst_dsn, u8 *da, u8 hop_count, u8 ttl, __le32 lifetime, + __le32 metric, __le32 preq_id, struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); + struct ieee80211_mgmt *mgmt; + u8 *pos; + int ie_len; + + if (!skb) + return -1; + skb_reserve(skb, local->hw.extra_tx_headroom); + /* 25 is the size of the common mgmt part (24) plus the size of the + * common action part (1) + */ + mgmt = (struct ieee80211_mgmt *) + skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action)); + memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action)); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_ACTION); + + memcpy(mgmt->da, da, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + /* BSSID is left zeroed, wildcard value */ + mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; + mgmt->u.action.u.mesh_action.action_code = action; + + switch (action) { + case MPATH_PREQ: + ie_len = 37; + pos = skb_put(skb, 2 + ie_len); + *pos++ = WLAN_EID_PREQ; + break; + case MPATH_PREP: + ie_len = 31; + pos = skb_put(skb, 2 + ie_len); + *pos++ = WLAN_EID_PREP; + break; + default: + kfree(skb); + return -ENOTSUPP; + break; + } + *pos++ = ie_len; + *pos++ = flags; + *pos++ = hop_count; + *pos++ = ttl; + if (action == MPATH_PREQ) { + memcpy(pos, &preq_id, 4); + pos += 4; + } + memcpy(pos, orig_addr, ETH_ALEN); + pos += ETH_ALEN; + memcpy(pos, &orig_dsn, 4); + pos += 4; + memcpy(pos, &lifetime, 4); + pos += 4; + memcpy(pos, &metric, 4); + pos += 4; + if (action == MPATH_PREQ) { + /* destination count */ + *pos++ = 1; + *pos++ = dst_flags; + } + memcpy(pos, dst, ETH_ALEN); + pos += ETH_ALEN; + memcpy(pos, &dst_dsn, 4); + + ieee80211_sta_tx(dev, skb, 0); + return 0; +} + +/** + * mesh_send_path error - Sends a PERR mesh management frame + * + * @dst: broken destination + * @dst_dsn: dsn of the broken destination + * @ra: node this frame is addressed to + */ +int mesh_path_error_tx(u8 *dst, __le32 dst_dsn, u8 *ra, + struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); + struct ieee80211_mgmt *mgmt; + u8 *pos; + int ie_len; + + if (!skb) + return -1; + skb_reserve(skb, local->hw.extra_tx_headroom); + /* 25 is the size of the common mgmt part (24) plus the size of the + * common action part (1) + */ + mgmt = (struct ieee80211_mgmt *) + skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action)); + memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action)); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_ACTION); + + memcpy(mgmt->da, ra, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + /* BSSID is left zeroed, wildcard value */ + mgmt->u.action.category = MESH_PATH_SEL_CATEGORY; + mgmt->u.action.u.mesh_action.action_code = MPATH_PERR; + ie_len = 12; + pos = skb_put(skb, 2 + ie_len); + *pos++ = WLAN_EID_PERR; + *pos++ = ie_len; + /* mode flags, reserved */ + *pos++ = 0; + /* number of destinations */ + *pos++ = 1; + memcpy(pos, dst, ETH_ALEN); + pos += ETH_ALEN; + memcpy(pos, &dst_dsn, 4); + + ieee80211_sta_tx(dev, skb, 0); + return 0; +} + +static u32 airtime_link_metric_get(struct ieee80211_local *local, + struct sta_info *sta) +{ + struct ieee80211_supported_band *sband; + /* This should be adjusted for each device */ + int device_constant = 1 << ARITH_SHIFT; + int test_frame_len = TEST_FRAME_LEN << ARITH_SHIFT; + int s_unit = 1 << ARITH_SHIFT; + int rate, err; + u32 tx_time, estimated_retx; + u64 result; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + if (sta->fail_avg >= 100) + return MAX_METRIC; + err = (sta->fail_avg << ARITH_SHIFT) / 100; + + /* bitrate is in units of 100 Kbps, while we need rate in units of + * 1Mbps. This will be corrected on tx_time computation. + */ + rate = sband->bitrates[sta->txrate_idx].bitrate; + tx_time = (device_constant + 10 * test_frame_len / rate); + estimated_retx = ((1 << (2 * ARITH_SHIFT)) / (s_unit - err)); + result = (tx_time * estimated_retx) >> (2 * ARITH_SHIFT) ; + return (u32)result; +} + +/** + * hwmp_route_info_get - Update routing info to originator and transmitter + * + * @dev: local mesh interface + * @mgmt: mesh management frame + * @hwmp_ie: hwmp information element (PREP or PREQ) + * + * This function updates the path routing information to the originator and the + * transmitter of a HWMP PREQ or PREP fram. + * + * Returns: metric to frame originator or 0 if the frame should not be further + * processed + * + * Notes: this function is the only place (besides user-provided info) where + * path routing information is updated. + */ +static u32 hwmp_route_info_get(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + u8 *hwmp_ie) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct mesh_path *mpath; + struct sta_info *sta; + bool fresh_info; + u8 *orig_addr, *ta; + u32 orig_dsn, orig_metric; + unsigned long orig_lifetime, exp_time; + u32 last_hop_metric, new_metric; + bool process = true; + u8 action = mgmt->u.action.u.mesh_action.action_code; + + rcu_read_lock(); + sta = sta_info_get(local, mgmt->sa); + if (!sta) + return 0; + + last_hop_metric = airtime_link_metric_get(local, sta); + /* Update and check originator routing info */ + fresh_info = true; + + switch (action) { + case MPATH_PREQ: + orig_addr = PREQ_IE_ORIG_ADDR(hwmp_ie); + orig_dsn = PREQ_IE_ORIG_DSN(hwmp_ie); + orig_lifetime = PREQ_IE_LIFETIME(hwmp_ie); + orig_metric = PREQ_IE_METRIC(hwmp_ie); + break; + case MPATH_PREP: + /* Originator here refers to the MP that was the destination in + * the Path Request. The draft refers to that MP as the + * destination address, even though usually it is the origin of + * the PREP frame. We divert from the nomenclature in the draft + * so that we can easily use a single function to gather path + * information from both PREQ and PREP frames. + */ + orig_addr = PREP_IE_ORIG_ADDR(hwmp_ie); + orig_dsn = PREP_IE_ORIG_DSN(hwmp_ie); + orig_lifetime = PREP_IE_LIFETIME(hwmp_ie); + orig_metric = PREP_IE_METRIC(hwmp_ie); + break; + default: + sta_info_put(sta); + return 0; + } + new_metric = orig_metric + last_hop_metric; + if (new_metric < orig_metric) + new_metric = MAX_METRIC; + exp_time = TU_TO_EXP_TIME(orig_lifetime); + + if (memcmp(orig_addr, dev->dev_addr, ETH_ALEN) == 0) { + /* This MP is the originator, we are not interested in this + * frame, except for updating transmitter's path info. + */ + process = false; + fresh_info = false; + } else { + mpath = mesh_path_lookup(orig_addr, dev); + if (mpath) { + spin_lock_bh(&mpath->state_lock); + if (mpath->flags & MESH_PATH_FIXED) + fresh_info = false; + else if ((mpath->flags & MESH_PATH_ACTIVE) && + (mpath->flags & MESH_PATH_DSN_VALID)) { + if (DSN_GT(mpath->dsn, orig_dsn) || + (mpath->dsn == orig_dsn && + action == MPATH_PREQ && + new_metric > mpath->metric)) { + process = false; + fresh_info = false; + } + } + } else { + mesh_path_add(orig_addr, dev); + mpath = mesh_path_lookup(orig_addr, dev); + if (!mpath) { + rcu_read_unlock(); + sta_info_put(sta); + return 0; + } + spin_lock_bh(&mpath->state_lock); + } + + if (fresh_info) { + mesh_path_assign_nexthop(mpath, sta); + mpath->flags |= MESH_PATH_DSN_VALID; + mpath->metric = new_metric; + mpath->dsn = orig_dsn; + mpath->exp_time = time_after(mpath->exp_time, exp_time) + ? mpath->exp_time : exp_time; + mesh_path_activate(mpath); + spin_unlock_bh(&mpath->state_lock); + mesh_path_tx_pending(mpath); + /* draft says preq_id should be saved to, but there does + * not seem to be any use for it, skipping by now + */ + } else + spin_unlock_bh(&mpath->state_lock); + } + + /* Update and check transmitter routing info */ + ta = mgmt->sa; + if (memcmp(orig_addr, ta, ETH_ALEN) == 0) + fresh_info = false; + else { + fresh_info = true; + + mpath = mesh_path_lookup(ta, dev); + if (mpath) { + spin_lock_bh(&mpath->state_lock); + if ((mpath->flags & MESH_PATH_FIXED) || + ((mpath->flags & MESH_PATH_ACTIVE) && + (last_hop_metric > mpath->metric))) + fresh_info = false; + } else { + mesh_path_add(ta, dev); + mpath = mesh_path_lookup(ta, dev); + if (!mpath) { + rcu_read_unlock(); + sta_info_put(sta); + return 0; + } + spin_lock_bh(&mpath->state_lock); + } + + if (fresh_info) { + mesh_path_assign_nexthop(mpath, sta); + mpath->flags &= ~MESH_PATH_DSN_VALID; + mpath->metric = last_hop_metric; + mpath->exp_time = time_after(mpath->exp_time, exp_time) + ? mpath->exp_time : exp_time; + mesh_path_activate(mpath); + spin_unlock_bh(&mpath->state_lock); + mesh_path_tx_pending(mpath); + } else + spin_unlock_bh(&mpath->state_lock); + } + + sta_info_put(sta); + rcu_read_unlock(); + + return process ? new_metric : 0; +} + +static void hwmp_preq_frame_process(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + u8 *preq_elem, u32 metric) { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct mesh_path *mpath; + u8 *dst_addr, *orig_addr; + u8 dst_flags, ttl; + u32 orig_dsn, dst_dsn, lifetime; + bool reply = false; + bool forward = true; + + /* Update destination DSN, if present */ + dst_addr = PREQ_IE_DST_ADDR(preq_elem); + orig_addr = PREQ_IE_ORIG_ADDR(preq_elem); + dst_dsn = PREQ_IE_DST_DSN(preq_elem); + orig_dsn = PREQ_IE_ORIG_DSN(preq_elem); + dst_flags = PREQ_IE_DST_F(preq_elem); + + if (memcmp(dst_addr, dev->dev_addr, ETH_ALEN) == 0) { + forward = false; + reply = true; + metric = 0; + if (time_after(jiffies, ifsta->last_dsn_update + + net_traversal_jiffies(sdata)) || + time_before(jiffies, ifsta->last_dsn_update)) { + dst_dsn = ++ifsta->dsn; + ifsta->last_dsn_update = jiffies; + } + } else { + rcu_read_lock(); + mpath = mesh_path_lookup(dst_addr, dev); + if (mpath) { + if ((!(mpath->flags & MESH_PATH_DSN_VALID)) || + DSN_LT(mpath->dsn, dst_dsn)) { + mpath->dsn = dst_dsn; + mpath->flags &= MESH_PATH_DSN_VALID; + } else if ((!(dst_flags & MP_F_DO)) && + (mpath->flags & MESH_PATH_ACTIVE)) { + reply = true; + metric = mpath->metric; + dst_dsn = mpath->dsn; + if (dst_flags & MP_F_RF) + dst_flags |= MP_F_DO; + else + forward = false; + } + } + rcu_read_unlock(); + } + + if (reply) { + lifetime = PREQ_IE_LIFETIME(preq_elem); + ttl = ifsta->mshcfg.dot11MeshTTL; + if (ttl != 0) + mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr, + __cpu_to_le32(dst_dsn), 0, orig_addr, + __cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl, + __cpu_to_le32(lifetime), __cpu_to_le32(metric), + 0, dev); + else + ifsta->mshstats.dropped_frames_ttl++; + } + + if (forward) { + u32 preq_id; + u8 hopcount, flags; + + ttl = PREQ_IE_TTL(preq_elem); + lifetime = PREQ_IE_LIFETIME(preq_elem); + if (ttl <= 1) { + ifsta->mshstats.dropped_frames_ttl++; + return; + } + --ttl; + flags = PREQ_IE_FLAGS(preq_elem); + preq_id = PREQ_IE_PREQ_ID(preq_elem); + hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; + mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, + __cpu_to_le32(orig_dsn), dst_flags, dst_addr, + __cpu_to_le32(dst_dsn), dev->broadcast, + hopcount, ttl, __cpu_to_le32(lifetime), + __cpu_to_le32(metric), __cpu_to_le32(preq_id), + dev); + ifsta->mshstats.fwded_frames++; + } +} + + +static void hwmp_prep_frame_process(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + u8 *prep_elem, u32 metric) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct mesh_path *mpath; + u8 *dst_addr, *orig_addr; + u8 ttl, hopcount, flags; + u8 next_hop[ETH_ALEN]; + u32 dst_dsn, orig_dsn, lifetime; + + /* Note that we divert from the draft nomenclature and denominate + * destination to what the draft refers to as origininator. So in this + * function destnation refers to the final destination of the PREP, + * which corresponds with the originator of the PREQ which this PREP + * replies + */ + dst_addr = PREP_IE_DST_ADDR(prep_elem); + if (memcmp(dst_addr, dev->dev_addr, ETH_ALEN) == 0) + /* destination, no forwarding required */ + return; + + ttl = PREP_IE_TTL(prep_elem); + if (ttl <= 1) { + sdata->u.sta.mshstats.dropped_frames_ttl++; + return; + } + + rcu_read_lock(); + mpath = mesh_path_lookup(dst_addr, dev); + if (mpath) + spin_lock_bh(&mpath->state_lock); + else + goto fail; + if (!(mpath->flags & MESH_PATH_ACTIVE)) { + spin_unlock_bh(&mpath->state_lock); + goto fail; + } + memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN); + spin_unlock_bh(&mpath->state_lock); + --ttl; + flags = PREP_IE_FLAGS(prep_elem); + lifetime = PREP_IE_LIFETIME(prep_elem); + hopcount = PREP_IE_HOPCOUNT(prep_elem) + 1; + orig_addr = PREP_IE_ORIG_ADDR(prep_elem); + dst_dsn = PREP_IE_DST_DSN(prep_elem); + orig_dsn = PREP_IE_ORIG_DSN(prep_elem); + + mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, + __cpu_to_le32(orig_dsn), 0, dst_addr, + __cpu_to_le32(dst_dsn), mpath->next_hop->addr, hopcount, ttl, + __cpu_to_le32(lifetime), __cpu_to_le32(metric), + 0, dev); + rcu_read_unlock(); + sdata->u.sta.mshstats.fwded_frames++; + return; + +fail: + rcu_read_unlock(); + sdata->u.sta.mshstats.dropped_frames_no_route++; + return; +} + +static void hwmp_perr_frame_process(struct net_device *dev, + struct ieee80211_mgmt *mgmt, u8 *perr_elem) +{ + struct mesh_path *mpath; + u8 *ta, *dst_addr; + u32 dst_dsn; + + ta = mgmt->sa; + dst_addr = PERR_IE_DST_ADDR(perr_elem); + dst_dsn = PERR_IE_DST_DSN(perr_elem); + rcu_read_lock(); + mpath = mesh_path_lookup(dst_addr, dev); + if (mpath) { + spin_lock_bh(&mpath->state_lock); + if (mpath->flags & MESH_PATH_ACTIVE && + memcmp(ta, mpath->next_hop->addr, ETH_ALEN) == 0 && + (!(mpath->flags & MESH_PATH_DSN_VALID) || + DSN_GT(dst_dsn, mpath->dsn))) { + mpath->flags &= ~MESH_PATH_ACTIVE; + mpath->dsn = dst_dsn; + spin_unlock_bh(&mpath->state_lock); + mesh_path_error_tx(dst_addr, dst_dsn, dev->broadcast, + dev); + } else + spin_unlock_bh(&mpath->state_lock); + } + rcu_read_unlock(); +} + + + +void mesh_rx_path_sel_frame(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + struct ieee802_11_elems elems; + size_t baselen; + u32 last_hop_metric; + + baselen = (u8 *) mgmt->u.action.u.mesh_action.variable - (u8 *) mgmt; + ieee802_11_parse_elems(mgmt->u.action.u.mesh_action.variable, + len - baselen, &elems); + + switch (mgmt->u.action.u.mesh_action.action_code) { + case MPATH_PREQ: + if (!elems.preq || elems.preq_len != 37) + /* Right now we support just 1 destination and no AE */ + return; + last_hop_metric = hwmp_route_info_get(dev, mgmt, elems.preq); + if (!last_hop_metric) + return; + hwmp_preq_frame_process(dev, mgmt, elems.preq, last_hop_metric); + break; + case MPATH_PREP: + if (!elems.prep || elems.prep_len != 31) + /* Right now we support no AE */ + return; + last_hop_metric = hwmp_route_info_get(dev, mgmt, elems.prep); + if (!last_hop_metric) + return; + hwmp_prep_frame_process(dev, mgmt, elems.prep, last_hop_metric); + break; + case MPATH_PERR: + if (!elems.perr || elems.perr_len != 12) + /* Right now we support only one destination per PERR */ + return; + hwmp_perr_frame_process(dev, mgmt, elems.perr); + default: + return; + } + +} + +/** + * mesh_queue_preq - queue a PREQ to a given destination + * + * @mpath: mesh path to discover + * @flags: special attributes of the PREQ to be sent + * + * Locking: the function must be called from within a rcu read lock block. + * + */ +static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) +{ + struct ieee80211_sub_if_data *sdata = + IEEE80211_DEV_TO_SUB_IF(mpath->dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct mesh_preq_queue *preq_node; + + preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_KERNEL); + if (!preq_node) { + printk(KERN_DEBUG "Mesh HWMP: could not allocate PREQ node\n"); + return; + } + + spin_lock(&ifsta->mesh_preq_queue_lock); + if (ifsta->preq_queue_len == MAX_PREQ_QUEUE_LEN) { + spin_unlock(&ifsta->mesh_preq_queue_lock); + kfree(preq_node); + if (printk_ratelimit()) + printk(KERN_DEBUG "Mesh HWMP: PREQ node queue full\n"); + return; + } + + memcpy(preq_node->dst, mpath->dst, ETH_ALEN); + preq_node->flags = flags; + + list_add_tail(&preq_node->list, &ifsta->preq_queue.list); + ++ifsta->preq_queue_len; + spin_unlock(&ifsta->mesh_preq_queue_lock); + + if (time_after(jiffies, ifsta->last_preq + min_preq_int_jiff(sdata))) + queue_work(sdata->local->hw.workqueue, &ifsta->work); + + else if (time_before(jiffies, ifsta->last_preq)) { + /* avoid long wait if did not send preqs for a long time + * and jiffies wrapped around + */ + ifsta->last_preq = jiffies - min_preq_int_jiff(sdata) - 1; + queue_work(sdata->local->hw.workqueue, &ifsta->work); + } else + mod_timer(&ifsta->mesh_path_timer, ifsta->last_preq + + min_preq_int_jiff(sdata)); +} + +/** + * mesh_path_start_discovery - launch a path discovery from the PREQ queue + * + * @dev: local mesh interface + */ +void mesh_path_start_discovery(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = + IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct mesh_preq_queue *preq_node; + struct mesh_path *mpath; + u8 ttl, dst_flags; + u32 lifetime; + + spin_lock(&ifsta->mesh_preq_queue_lock); + if (!ifsta->preq_queue_len || + time_before(jiffies, ifsta->last_preq + + min_preq_int_jiff(sdata))) { + spin_unlock(&ifsta->mesh_preq_queue_lock); + return; + } + + preq_node = list_first_entry(&ifsta->preq_queue.list, + struct mesh_preq_queue, list); + list_del(&preq_node->list); + --ifsta->preq_queue_len; + spin_unlock(&ifsta->mesh_preq_queue_lock); + + rcu_read_lock(); + mpath = mesh_path_lookup(preq_node->dst, dev); + if (!mpath) + goto enddiscovery; + + spin_lock_bh(&mpath->state_lock); + if (preq_node->flags & PREQ_Q_F_START) { + if (mpath->flags & MESH_PATH_RESOLVING) { + spin_unlock_bh(&mpath->state_lock); + goto enddiscovery; + } else { + mpath->flags &= ~MESH_PATH_RESOLVED; + mpath->flags |= MESH_PATH_RESOLVING; + mpath->discovery_retries = 0; + mpath->discovery_timeout = disc_timeout_jiff(sdata); + } + } else if (!(mpath->flags & MESH_PATH_RESOLVING) || + mpath->flags & MESH_PATH_RESOLVED) { + mpath->flags &= ~MESH_PATH_RESOLVING; + spin_unlock_bh(&mpath->state_lock); + goto enddiscovery; + } + + ifsta->last_preq = jiffies; + + if (time_after(jiffies, ifsta->last_dsn_update + + net_traversal_jiffies(sdata)) || + time_before(jiffies, ifsta->last_dsn_update)) { + ++ifsta->dsn; + sdata->u.sta.last_dsn_update = jiffies; + } + lifetime = default_lifetime(sdata); + ttl = sdata->u.sta.mshcfg.dot11MeshTTL; + if (ttl == 0) { + sdata->u.sta.mshstats.dropped_frames_ttl++; + spin_unlock_bh(&mpath->state_lock); + goto enddiscovery; + } + + if (preq_node->flags & PREQ_Q_F_REFRESH) + dst_flags = MP_F_DO; + else + dst_flags = MP_F_RF; + + spin_unlock_bh(&mpath->state_lock); + mesh_path_sel_frame_tx(MPATH_PREQ, 0, dev->dev_addr, + __cpu_to_le32(ifsta->dsn), dst_flags, mpath->dst, + __cpu_to_le32(mpath->dsn), dev->broadcast, 0, + ttl, __cpu_to_le32(lifetime), 0, + __cpu_to_le32(ifsta->preq_id++), dev); + mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); + +enddiscovery: + rcu_read_unlock(); + kfree(preq_node); +} + +/** + * ieee80211s_lookup_nexthop - put the appropriate next hop on a mesh frame + * + * @next_hop: output argument for next hop address + * @skb: frame to be sent + * @dev: network device the frame will be sent through + * + * Returns: 0 if the next hop was found. Nonzero otherwise. If no next hop is + * found, the function will start a path discovery and queue the frame so it is + * sent when the path is resolved. This means the caller must not free the skb + * in this case. + */ +int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb, + struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct sk_buff *skb_to_free = NULL; + struct mesh_path *mpath; + int err = 0; + + rcu_read_lock(); + mpath = mesh_path_lookup(skb->data, dev); + + if (!mpath) { + mesh_path_add(skb->data, dev); + mpath = mesh_path_lookup(skb->data, dev); + if (!mpath) { + dev_kfree_skb(skb); + sdata->u.sta.mshstats.dropped_frames_no_route++; + err = -ENOSPC; + goto endlookup; + } + } + + if (mpath->flags & MESH_PATH_ACTIVE) { + if (time_after(jiffies, mpath->exp_time - + msecs_to_jiffies(sdata->u.sta.mshcfg.path_refresh_time)) + && skb->pkt_type != PACKET_OTHERHOST + && !(mpath->flags & MESH_PATH_RESOLVING) + && !(mpath->flags & MESH_PATH_FIXED)) { + mesh_queue_preq(mpath, + PREQ_Q_F_START | PREQ_Q_F_REFRESH); + } + memcpy(next_hop, mpath->next_hop->addr, + ETH_ALEN); + } else { + if (!(mpath->flags & MESH_PATH_RESOLVING)) { + /* Start discovery only if it is not running yet */ + mesh_queue_preq(mpath, PREQ_Q_F_START); + } + + if (skb_queue_len(&mpath->frame_queue) >= + MESH_FRAME_QUEUE_LEN) { + skb_to_free = mpath->frame_queue.next; + skb_unlink(skb_to_free, &mpath->frame_queue); + } + + skb_queue_tail(&mpath->frame_queue, skb); + if (skb_to_free) + mesh_path_discard_frame(skb_to_free, dev); + err = -ENOENT; + } + +endlookup: + rcu_read_unlock(); + return err; +} + +void mesh_path_timer(unsigned long data) +{ + struct ieee80211_sub_if_data *sdata; + struct mesh_path *mpath; + bool delete = false; + + rcu_read_lock(); + mpath = (struct mesh_path *) data; + mpath = rcu_dereference(mpath); + if (!mpath) + goto endmpathtimer; + spin_lock_bh(&mpath->state_lock); + sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev); + if (mpath->flags & MESH_PATH_DELETE) { + mpath->flags = 0; + delete = true; + } else if (mpath->flags & MESH_PATH_RESOLVED || + (!(mpath->flags & MESH_PATH_RESOLVING))) + mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED); + else if (mpath->discovery_retries < max_preq_retries(sdata)) { + ++mpath->discovery_retries; + mpath->discovery_timeout *= 2; + mesh_queue_preq(mpath, 0); + } else { + mpath->flags = 0; + mpath->exp_time = jiffies; + mesh_path_flush_pending(mpath); + } + + spin_unlock_bh(&mpath->state_lock); +endmpathtimer: + rcu_read_unlock(); + if (delete) + mesh_path_del(mpath->dst, mpath->dev); +} -- cgit v1.2.3-59-g8ed1b From 9f42f607058a80bfb7b4f687bb84016ae129cfd1 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:16 +0100 Subject: mac80211: mesh statistics and config through debugfs This patch contains the debugfs code for mesh statistics and configuration parameters. Please note that generic support for r/w debugfs attributes has been added. Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_netdev.c | 197 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) (limited to 'net') diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 29f7b98ba1fb..107b0fe778d6 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -39,6 +39,29 @@ static ssize_t ieee80211_if_read( return ret; } +#ifdef CONFIG_MAC80211_MESH +static ssize_t ieee80211_if_write( + struct ieee80211_sub_if_data *sdata, + char const __user *userbuf, + size_t count, loff_t *ppos, + int (*format)(struct ieee80211_sub_if_data *, char *)) +{ + char buf[10]; + int buf_size; + + memset(buf, 0x00, sizeof(buf)); + buf_size = min(count, (sizeof(buf)-1)); + read_lock(&dev_base_lock); + if (copy_from_user(buf, userbuf, buf_size)) + goto endwrite; + if (sdata->dev->reg_state == NETREG_REGISTERED) + (*format)(sdata, buf); +endwrite: + read_unlock(&dev_base_lock); + return count; +} +#endif + #define IEEE80211_IF_FMT(name, field, format_string) \ static ssize_t ieee80211_if_fmt_##name( \ const struct ieee80211_sub_if_data *sdata, char *buf, \ @@ -46,6 +69,19 @@ static ssize_t ieee80211_if_fmt_##name( \ { \ return scnprintf(buf, buflen, format_string, sdata->field); \ } +#define IEEE80211_IF_WFMT(name, field, type) \ +static int ieee80211_if_wfmt_##name( \ + struct ieee80211_sub_if_data *sdata, char *buf) \ +{ \ + unsigned long tmp; \ + char *endp; \ + \ + tmp = simple_strtoul(buf, &endp, 0); \ + if ((endp == buf) || ((type)tmp != tmp)) \ + return -EINVAL; \ + sdata->field = tmp; \ + return 0; \ +} #define IEEE80211_IF_FMT_DEC(name, field) \ IEEE80211_IF_FMT(name, field, "%d\n") #define IEEE80211_IF_FMT_HEX(name, field) \ @@ -88,6 +124,34 @@ static const struct file_operations name##_ops = { \ IEEE80211_IF_FMT_##format(name, field) \ __IEEE80211_IF_FILE(name) +#define __IEEE80211_IF_WFILE(name) \ +static ssize_t ieee80211_if_read_##name(struct file *file, \ + char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + return ieee80211_if_read(file->private_data, \ + userbuf, count, ppos, \ + ieee80211_if_fmt_##name); \ +} \ +static ssize_t ieee80211_if_write_##name(struct file *file, \ + const char __user *userbuf, \ + size_t count, loff_t *ppos) \ +{ \ + return ieee80211_if_write(file->private_data, \ + userbuf, count, ppos, \ + ieee80211_if_wfmt_##name); \ +} \ +static const struct file_operations name##_ops = { \ + .read = ieee80211_if_read_##name, \ + .write = ieee80211_if_write_##name, \ + .open = mac80211_open_file_generic, \ +} + +#define IEEE80211_IF_WFILE(name, field, format, type) \ + IEEE80211_IF_FMT_##format(name, field) \ + IEEE80211_IF_WFMT(name, field, type) \ + __IEEE80211_IF_WFILE(name) + /* common attributes */ IEEE80211_IF_FILE(channel_use, channel_use, DEC); IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC); @@ -106,6 +170,7 @@ IEEE80211_IF_FILE(assoc_tries, u.sta.assoc_tries, DEC); IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX); IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC); IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC); +IEEE80211_IF_FILE(num_beacons_sta, u.sta.num_beacons, DEC); static ssize_t ieee80211_if_fmt_flags( const struct ieee80211_sub_if_data *sdata, char *buf, int buflen) @@ -139,6 +204,42 @@ __IEEE80211_IF_FILE(num_buffered_multicast); /* WDS attributes */ IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC); +#ifdef CONFIG_MAC80211_MESH +/* Mesh stats attributes */ +IEEE80211_IF_FILE(fwded_frames, u.sta.mshstats.fwded_frames, DEC); +IEEE80211_IF_FILE(dropped_frames_ttl, u.sta.mshstats.dropped_frames_ttl, DEC); +IEEE80211_IF_FILE(dropped_frames_no_route, + u.sta.mshstats.dropped_frames_no_route, DEC); +IEEE80211_IF_FILE(estab_plinks, u.sta.mshstats.estab_plinks, ATOMIC); + +/* Mesh parameters */ +IEEE80211_IF_WFILE(dot11MeshMaxRetries, + u.sta.mshcfg.dot11MeshMaxRetries, DEC, u8); +IEEE80211_IF_WFILE(dot11MeshRetryTimeout, + u.sta.mshcfg.dot11MeshRetryTimeout, DEC, u16); +IEEE80211_IF_WFILE(dot11MeshConfirmTimeout, + u.sta.mshcfg.dot11MeshConfirmTimeout, DEC, u16); +IEEE80211_IF_WFILE(dot11MeshHoldingTimeout, + u.sta.mshcfg.dot11MeshHoldingTimeout, DEC, u16); +IEEE80211_IF_WFILE(dot11MeshTTL, u.sta.mshcfg.dot11MeshTTL, DEC, u8); +IEEE80211_IF_WFILE(auto_open_plinks, u.sta.mshcfg.auto_open_plinks, DEC, bool); +IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks, + u.sta.mshcfg.dot11MeshMaxPeerLinks, DEC, u16); +IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout, + u.sta.mshcfg.dot11MeshHWMPactivePathTimeout, DEC, u32); +IEEE80211_IF_WFILE(dot11MeshHWMPpreqMinInterval, + u.sta.mshcfg.dot11MeshHWMPpreqMinInterval, DEC, u16); +IEEE80211_IF_WFILE(dot11MeshHWMPnetDiameterTraversalTime, + u.sta.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC, u16); +IEEE80211_IF_WFILE(dot11MeshHWMPmaxPREQretries, + u.sta.mshcfg.dot11MeshHWMPmaxPREQretries, DEC, u8); +IEEE80211_IF_WFILE(path_refresh_time, + u.sta.mshcfg.path_refresh_time, DEC, u32); +IEEE80211_IF_WFILE(min_discovery_timeout, + u.sta.mshcfg.min_discovery_timeout, DEC, u16); +#endif + + #define DEBUGFS_ADD(name, type)\ sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ sdata->debugfsdir, sdata, &name##_ops); @@ -161,6 +262,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_ADD(auth_alg, sta); DEBUGFS_ADD(auth_transaction, sta); DEBUGFS_ADD(flags, sta); + DEBUGFS_ADD(num_beacons_sta, sta); } static void add_ap_files(struct ieee80211_sub_if_data *sdata) @@ -192,12 +294,57 @@ static void add_monitor_files(struct ieee80211_sub_if_data *sdata) { } +#ifdef CONFIG_MAC80211_MESH +#define MESHSTATS_ADD(name)\ + sdata->mesh_stats.name = debugfs_create_file(#name, 0444,\ + sdata->mesh_stats_dir, sdata, &name##_ops); + +static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) +{ + sdata->mesh_stats_dir = debugfs_create_dir("mesh_stats", + sdata->debugfsdir); + MESHSTATS_ADD(fwded_frames); + MESHSTATS_ADD(dropped_frames_ttl); + MESHSTATS_ADD(dropped_frames_no_route); + MESHSTATS_ADD(estab_plinks); +} + +#define MESHPARAMS_ADD(name)\ + sdata->mesh_config.name = debugfs_create_file(#name, 0644,\ + sdata->mesh_config_dir, sdata, &name##_ops); + +static void add_mesh_config(struct ieee80211_sub_if_data *sdata) +{ + sdata->mesh_config_dir = debugfs_create_dir("mesh_config", + sdata->debugfsdir); + MESHPARAMS_ADD(dot11MeshMaxRetries); + MESHPARAMS_ADD(dot11MeshRetryTimeout); + MESHPARAMS_ADD(dot11MeshConfirmTimeout); + MESHPARAMS_ADD(dot11MeshHoldingTimeout); + MESHPARAMS_ADD(dot11MeshTTL); + MESHPARAMS_ADD(auto_open_plinks); + MESHPARAMS_ADD(dot11MeshMaxPeerLinks); + MESHPARAMS_ADD(dot11MeshHWMPactivePathTimeout); + MESHPARAMS_ADD(dot11MeshHWMPpreqMinInterval); + MESHPARAMS_ADD(dot11MeshHWMPnetDiameterTraversalTime); + MESHPARAMS_ADD(dot11MeshHWMPmaxPREQretries); + MESHPARAMS_ADD(path_refresh_time); + MESHPARAMS_ADD(min_discovery_timeout); +} +#endif + static void add_files(struct ieee80211_sub_if_data *sdata) { if (!sdata->debugfsdir) return; switch (sdata->vif.type) { + case IEEE80211_IF_TYPE_MESH_POINT: +#ifdef CONFIG_MAC80211_MESH + add_mesh_stats(sdata); + add_mesh_config(sdata); +#endif + /* fall through */ case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: add_sta_files(sdata); @@ -243,6 +390,7 @@ static void del_sta_files(struct ieee80211_sub_if_data *sdata) DEBUGFS_DEL(auth_alg, sta); DEBUGFS_DEL(auth_transaction, sta); DEBUGFS_DEL(flags, sta); + DEBUGFS_DEL(num_beacons_sta, sta); } static void del_ap_files(struct ieee80211_sub_if_data *sdata) @@ -274,12 +422,61 @@ static void del_monitor_files(struct ieee80211_sub_if_data *sdata) { } +#ifdef CONFIG_MAC80211_MESH +#define MESHSTATS_DEL(name) \ + do { \ + debugfs_remove(sdata->mesh_stats.name); \ + sdata->mesh_stats.name = NULL; \ + } while (0) + +static void del_mesh_stats(struct ieee80211_sub_if_data *sdata) +{ + MESHSTATS_DEL(fwded_frames); + MESHSTATS_DEL(dropped_frames_ttl); + MESHSTATS_DEL(dropped_frames_no_route); + MESHSTATS_DEL(estab_plinks); + debugfs_remove(sdata->mesh_stats_dir); + sdata->mesh_stats_dir = NULL; +} + +#define MESHPARAMS_DEL(name) \ + do { \ + debugfs_remove(sdata->mesh_config.name); \ + sdata->mesh_config.name = NULL; \ + } while (0) + +static void del_mesh_config(struct ieee80211_sub_if_data *sdata) +{ + MESHPARAMS_DEL(dot11MeshMaxRetries); + MESHPARAMS_DEL(dot11MeshRetryTimeout); + MESHPARAMS_DEL(dot11MeshConfirmTimeout); + MESHPARAMS_DEL(dot11MeshHoldingTimeout); + MESHPARAMS_DEL(dot11MeshTTL); + MESHPARAMS_DEL(auto_open_plinks); + MESHPARAMS_DEL(dot11MeshMaxPeerLinks); + MESHPARAMS_DEL(dot11MeshHWMPactivePathTimeout); + MESHPARAMS_DEL(dot11MeshHWMPpreqMinInterval); + MESHPARAMS_DEL(dot11MeshHWMPnetDiameterTraversalTime); + MESHPARAMS_DEL(dot11MeshHWMPmaxPREQretries); + MESHPARAMS_DEL(path_refresh_time); + MESHPARAMS_DEL(min_discovery_timeout); + debugfs_remove(sdata->mesh_config_dir); + sdata->mesh_config_dir = NULL; +} +#endif + static void del_files(struct ieee80211_sub_if_data *sdata, int type) { if (!sdata->debugfsdir) return; switch (type) { + case IEEE80211_IF_TYPE_MESH_POINT: +#ifdef CONFIG_MAC80211_MESH + del_mesh_stats(sdata); + del_mesh_config(sdata); +#endif + /* fall through */ case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: del_sta_files(sdata); -- cgit v1.2.3-59-g8ed1b From c5dd9c2bd0b2422dbcd57fe8158d1d7d36c07dd9 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:17 +0100 Subject: mac80211: mesh path and mesh peer configuration This adds code to allow adding mesh interfaces and configuring mesh peers etc. Also, it adds code for station dumping. Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 269 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 259 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 0e97ceee640c..b1befac1736a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -15,6 +15,11 @@ #include "ieee80211_i.h" #include "cfg.h" #include "ieee80211_rate.h" +#ifdef CONFIG_MAC80211_MESH +#include "mesh.h" +#endif + +#define DEFAULT_RATES 0 static enum ieee80211_if_types nl80211_type_to_mac80211_type(enum nl80211_iftype type) @@ -28,6 +33,10 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type) return IEEE80211_IF_TYPE_STA; case NL80211_IFTYPE_MONITOR: return IEEE80211_IF_TYPE_MNTR; +#ifdef CONFIG_MAC80211_MESH + case NL80211_IFTYPE_MESH_POINT: + return IEEE80211_IF_TYPE_MESH_POINT; +#endif default: return IEEE80211_IF_TYPE_INVALID; } @@ -110,6 +119,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, ieee80211_if_reinit(dev); ieee80211_if_set_type(dev, itype); +#ifdef CONFIG_MAC80211_MESH + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && + params->mesh_id_len) { + sdata->u.sta.mesh_id_len = params->mesh_id_len; + memcpy(sdata->u.sta.mesh_id, params->mesh_id, + params->mesh_id_len); + } +#endif + if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags) return 0; @@ -297,6 +315,51 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, return 0; } +static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) +{ +#ifdef CONFIG_MAC80211_MESH + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); +#endif + + sinfo->filled = STATION_INFO_INACTIVE_TIME | + STATION_INFO_RX_BYTES | + STATION_INFO_TX_BYTES; + + sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); + sinfo->rx_bytes = sta->rx_bytes; + sinfo->tx_bytes = sta->tx_bytes; + +#ifdef CONFIG_MAC80211_MESH + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { + sinfo->filled |= STATION_INFO_LLID | + STATION_INFO_PLID | + STATION_INFO_PLINK_STATE; + + sinfo->llid = le16_to_cpu(sta->llid); + sinfo->plid = le16_to_cpu(sta->plid); + sinfo->plink_state = sta->plink_state; + } +#endif +} + + +static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *mac, struct station_info *sinfo) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta; + + sta = sta_info_get_by_idx(local, idx, dev); + if (!sta) + return -ENOENT; + + memcpy(mac, sta->addr, ETH_ALEN); + sta_set_sinfo(sta, sinfo); + sta_info_put(sta); + + return 0; +} + static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_info *sinfo) { @@ -308,15 +371,7 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, return -ENOENT; /* XXX: verify sta->dev == dev */ - - sinfo->filled = STATION_INFO_INACTIVE_TIME | - STATION_INFO_RX_BYTES | - STATION_INFO_TX_BYTES; - - sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); - sinfo->rx_bytes = sta->rx_bytes; - sinfo->tx_bytes = sta->tx_bytes; - + sta_set_sinfo(sta, sinfo); sta_info_put(sta); return 0; @@ -525,6 +580,9 @@ static void sta_apply_parameters(struct ieee80211_local *local, u32 rates; int i, j; struct ieee80211_supported_band *sband; +#ifdef CONFIG_MAC80211_MESH + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); +#endif if (params->station_flags & STATION_FLAG_CHANGED) { sta->flags &= ~WLAN_STA_AUTHORIZED; @@ -562,6 +620,19 @@ static void sta_apply_parameters(struct ieee80211_local *local, } sta->supp_rates[local->oper_channel->band] = rates; } + +#ifdef CONFIG_MAC80211_MESH + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && + params->plink_action) + switch (params->plink_action) { + case PLINK_ACTION_OPEN: + mesh_plink_open(sta); + break; + case PLINK_ACTION_BLOCK: + mesh_plink_block(sta); + break; + } +#endif } static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, @@ -584,7 +655,13 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, } else sdata = IEEE80211_DEV_TO_SUB_IF(dev); - sta = sta_info_add(local, dev, mac, GFP_KERNEL); +#ifdef CONFIG_MAC80211_MESH + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + sta = mesh_plink_add(mac, DEFAULT_RATES, dev); + else +#endif + sta = sta_info_add(local, dev, mac, GFP_KERNEL); + if (IS_ERR(sta)) return PTR_ERR(sta); @@ -656,6 +733,170 @@ static int ieee80211_change_station(struct wiphy *wiphy, return 0; } +#ifdef CONFIG_MAC80211_MESH +static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, + u8 *dst, u8 *next_hop) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct mesh_path *mpath; + struct sta_info *sta; + int err; + + if (!netif_running(dev)) + return -ENETDOWN; + + if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) + return -ENOTSUPP; + + sta = sta_info_get(local, next_hop); + if (!sta) + return -ENOENT; + + err = mesh_path_add(dst, dev); + if (err) + return err; + + rcu_read_lock(); + mpath = mesh_path_lookup(dst, dev); + if (!mpath) { + rcu_read_unlock(); + sta_info_put(sta); + return -ENXIO; + } + mesh_path_fix_nexthop(mpath, sta); + sta_info_put(sta); + rcu_read_unlock(); + return 0; +} + +static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev, + u8 *dst) +{ + if (dst) + return mesh_path_del(dst, dev); + + mesh_path_flush(dev); + return 0; +} + +static int ieee80211_change_mpath(struct wiphy *wiphy, + struct net_device *dev, + u8 *dst, u8 *next_hop) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct mesh_path *mpath; + struct sta_info *sta; + + if (!netif_running(dev)) + return -ENETDOWN; + + if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) + return -ENOTSUPP; + + sta = sta_info_get(local, next_hop); + if (!sta) + return -ENOENT; + + rcu_read_lock(); + mpath = mesh_path_lookup(dst, dev); + if (!mpath) { + rcu_read_unlock(); + sta_info_put(sta); + return -ENOENT; + } + + mesh_path_fix_nexthop(mpath, sta); + sta_info_put(sta); + rcu_read_unlock(); + return 0; +} + +static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop, + struct mpath_info *pinfo) +{ + if (mpath->next_hop) + memcpy(next_hop, mpath->next_hop->addr, ETH_ALEN); + else + memset(next_hop, 0, ETH_ALEN); + + pinfo->filled = MPATH_INFO_FRAME_QLEN | + MPATH_INFO_DSN | + MPATH_INFO_METRIC | + MPATH_INFO_EXPTIME | + MPATH_INFO_DISCOVERY_TIMEOUT | + MPATH_INFO_DISCOVERY_RETRIES | + MPATH_INFO_FLAGS; + + pinfo->frame_qlen = mpath->frame_queue.qlen; + pinfo->dsn = mpath->dsn; + pinfo->metric = mpath->metric; + if (time_before(jiffies, mpath->exp_time)) + pinfo->exptime = jiffies_to_msecs(mpath->exp_time - jiffies); + pinfo->discovery_timeout = + jiffies_to_msecs(mpath->discovery_timeout); + pinfo->discovery_retries = mpath->discovery_retries; + pinfo->flags = 0; + if (mpath->flags & MESH_PATH_ACTIVE) + pinfo->flags |= NL80211_MPATH_FLAG_ACTIVE; + if (mpath->flags & MESH_PATH_RESOLVING) + pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; + if (mpath->flags & MESH_PATH_DSN_VALID) + pinfo->flags |= NL80211_MPATH_FLAG_DSN_VALID; + if (mpath->flags & MESH_PATH_FIXED) + pinfo->flags |= NL80211_MPATH_FLAG_FIXED; + if (mpath->flags & MESH_PATH_RESOLVING) + pinfo->flags |= NL80211_MPATH_FLAG_RESOLVING; + + pinfo->flags = mpath->flags; +} + +static int ieee80211_get_mpath(struct wiphy *wiphy, struct net_device *dev, + u8 *dst, u8 *next_hop, struct mpath_info *pinfo) + +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct mesh_path *mpath; + + if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) + return -ENOTSUPP; + + rcu_read_lock(); + mpath = mesh_path_lookup(dst, dev); + if (!mpath) { + rcu_read_unlock(); + return -ENOENT; + } + memcpy(dst, mpath->dst, ETH_ALEN); + mpath_set_pinfo(mpath, next_hop, pinfo); + rcu_read_unlock(); + return 0; +} + +static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, + int idx, u8 *dst, u8 *next_hop, + struct mpath_info *pinfo) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct mesh_path *mpath; + + if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) + return -ENOTSUPP; + + rcu_read_lock(); + mpath = mesh_path_lookup_by_idx(idx, dev); + if (!mpath) { + rcu_read_unlock(); + return -ENOENT; + } + memcpy(dst, mpath->dst, ETH_ALEN); + mpath_set_pinfo(mpath, next_hop, pinfo); + rcu_read_unlock(); + return 0; +} +#endif + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -671,4 +912,12 @@ struct cfg80211_ops mac80211_config_ops = { .del_station = ieee80211_del_station, .change_station = ieee80211_change_station, .get_station = ieee80211_get_station, + .dump_station = ieee80211_dump_station, +#ifdef CONFIG_MAC80211_MESH + .add_mpath = ieee80211_add_mpath, + .del_mpath = ieee80211_del_mpath, + .change_mpath = ieee80211_change_mpath, + .get_mpath = ieee80211_get_mpath, + .dump_mpath = ieee80211_dump_mpath, +#endif }; -- cgit v1.2.3-59-g8ed1b From f7a921443740d7dafc65b17aa32531730d358f50 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Sat, 23 Feb 2008 15:17:18 +0100 Subject: mac80211: complete the mesh (interface handling) code This completes the mesh interface handling code and a few other bits about the mac80211 module. Signed-off-by: Luis Carlos Cobo Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 190917a74c3e..7106d651f4f9 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -26,6 +26,9 @@ #include "ieee80211_i.h" #include "ieee80211_rate.h" +#ifdef CONFIG_MAC80211_MESH +#include "mesh.h" +#endif #include "wep.h" #include "wme.h" #include "aes_ccm.h" @@ -138,9 +141,15 @@ static void ieee80211_master_set_multicast_list(struct net_device *dev) static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) { + int meshhdrlen; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + meshhdrlen = (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) ? 5 : 0; + /* FIX: what would be proper limits for MTU? * This interface uses 802.3 frames. */ - if (new_mtu < 256 || new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6) { + if (new_mtu < 256 || + new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) { printk(KERN_WARNING "%s: invalid MTU %d\n", dev->name, new_mtu); return -EINVAL; @@ -441,6 +450,9 @@ static int ieee80211_stop(struct net_device *dev) ieee80211_configure_filter(local); netif_tx_unlock_bh(local->mdev); break; + case IEEE80211_IF_TYPE_MESH_POINT: + sta_info_flush(local, dev); + /* fall through */ case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: sdata->u.sta.state = IEEE80211_DISABLED; @@ -926,6 +938,11 @@ static int __ieee80211_if_config(struct net_device *dev, conf.bssid = sdata->u.sta.bssid; conf.ssid = sdata->u.sta.ssid; conf.ssid_len = sdata->u.sta.ssid_len; +#ifdef CONFIG_MAC80211_MESH + } else if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { + conf.beacon = beacon; + ieee80211_start_mesh(dev); +#endif } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { conf.ssid = sdata->u.ap.ssid; conf.ssid_len = sdata->u.ap.ssid_len; @@ -938,6 +955,11 @@ static int __ieee80211_if_config(struct net_device *dev, int ieee80211_if_config(struct net_device *dev) { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && + (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) + return ieee80211_if_config_beacon(dev); return __ieee80211_if_config(dev, NULL, NULL); } @@ -1802,6 +1824,10 @@ static void __exit ieee80211_exit(void) rc80211_simple_exit(); rc80211_pid_exit(); +#ifdef CONFIG_MAC80211_MESH + if (mesh_allocated) + ieee80211s_stop(); +#endif ieee80211_wme_unregister(); ieee80211_debugfs_netdev_exit(); } -- cgit v1.2.3-59-g8ed1b From 902acc7896d7649fb30e4b22bd4e643c7f34b02c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 23 Feb 2008 15:17:19 +0100 Subject: mac80211: clean up mesh code Various cleanups, reducing the #ifdef mess and other things. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 8 +++ net/mac80211/cfg.c | 32 +++-------- net/mac80211/ieee80211.c | 9 +-- net/mac80211/ieee80211_i.h | 56 ++++++++++++++++--- net/mac80211/ieee80211_iface.c | 66 ++++------------------ net/mac80211/ieee80211_sta.c | 72 +++++++++++------------- net/mac80211/mesh.c | 67 ++++++++++++++++++++++ net/mac80211/mesh.h | 13 ++++- net/mac80211/mesh_plink.c | 28 +++++++--- net/mac80211/rc80211_pid_algo.c | 3 - net/mac80211/rx.c | 28 +++++----- net/mac80211/sta_info.c | 13 +---- net/mac80211/sta_info.h | 2 - net/mac80211/tx.c | 120 +++++++++++++++++----------------------- net/mac80211/util.c | 32 ----------- 15 files changed, 277 insertions(+), 272 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 934cc25f757a..6aca472d7a02 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -465,6 +465,14 @@ struct ieee80211_vif { u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); }; +static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) +{ +#ifdef CONFIG_MAC80211_MESH + return vif->type == IEEE80211_IF_TYPE_MESH_POINT; +#endif + return false; +} + /** * struct ieee80211_if_init_conf - initial configuration of an interface * diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b1befac1736a..6ac49231efa9 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -15,9 +15,7 @@ #include "ieee80211_i.h" #include "cfg.h" #include "ieee80211_rate.h" -#ifdef CONFIG_MAC80211_MESH #include "mesh.h" -#endif #define DEFAULT_RATES 0 @@ -119,14 +117,10 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, ieee80211_if_reinit(dev); ieee80211_if_set_type(dev, itype); -#ifdef CONFIG_MAC80211_MESH - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && - params->mesh_id_len) { - sdata->u.sta.mesh_id_len = params->mesh_id_len; - memcpy(sdata->u.sta.mesh_id, params->mesh_id, - params->mesh_id_len); - } -#endif + if (ieee80211_vif_is_mesh(&sdata->vif) && params->mesh_id_len) + ieee80211_if_sta_set_mesh_id(&sdata->u.sta, + params->mesh_id_len, + params->mesh_id); if (sdata->vif.type != IEEE80211_IF_TYPE_MNTR || !flags) return 0; @@ -317,9 +311,7 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) { -#ifdef CONFIG_MAC80211_MESH struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); -#endif sinfo->filled = STATION_INFO_INACTIVE_TIME | STATION_INFO_RX_BYTES | @@ -329,8 +321,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->rx_bytes = sta->rx_bytes; sinfo->tx_bytes = sta->tx_bytes; + if (ieee80211_vif_is_mesh(&sdata->vif)) { #ifdef CONFIG_MAC80211_MESH - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { sinfo->filled |= STATION_INFO_LLID | STATION_INFO_PLID | STATION_INFO_PLINK_STATE; @@ -338,8 +330,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->llid = le16_to_cpu(sta->llid); sinfo->plid = le16_to_cpu(sta->plid); sinfo->plink_state = sta->plink_state; - } #endif + } } @@ -580,9 +572,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, u32 rates; int i, j; struct ieee80211_supported_band *sband; -#ifdef CONFIG_MAC80211_MESH struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); -#endif if (params->station_flags & STATION_FLAG_CHANGED) { sta->flags &= ~WLAN_STA_AUTHORIZED; @@ -621,9 +611,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, sta->supp_rates[local->oper_channel->band] = rates; } -#ifdef CONFIG_MAC80211_MESH - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && - params->plink_action) + if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { switch (params->plink_action) { case PLINK_ACTION_OPEN: mesh_plink_open(sta); @@ -632,7 +620,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, mesh_plink_block(sta); break; } -#endif + } } static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, @@ -655,11 +643,9 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, } else sdata = IEEE80211_DEV_TO_SUB_IF(dev); -#ifdef CONFIG_MAC80211_MESH - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + if (ieee80211_vif_is_mesh(&sdata->vif)) sta = mesh_plink_add(mac, DEFAULT_RATES, dev); else -#endif sta = sta_info_add(local, dev, mac, GFP_KERNEL); if (IS_ERR(sta)) diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 7106d651f4f9..727af295c969 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -26,9 +26,7 @@ #include "ieee80211_i.h" #include "ieee80211_rate.h" -#ifdef CONFIG_MAC80211_MESH #include "mesh.h" -#endif #include "wep.h" #include "wme.h" #include "aes_ccm.h" @@ -938,11 +936,9 @@ static int __ieee80211_if_config(struct net_device *dev, conf.bssid = sdata->u.sta.bssid; conf.ssid = sdata->u.sta.ssid; conf.ssid_len = sdata->u.sta.ssid_len; -#ifdef CONFIG_MAC80211_MESH - } else if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { + } else if (ieee80211_vif_is_mesh(&sdata->vif)) { conf.beacon = beacon; ieee80211_start_mesh(dev); -#endif } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { conf.ssid = sdata->u.ap.ssid; conf.ssid_len = sdata->u.ap.ssid_len; @@ -1824,10 +1820,9 @@ static void __exit ieee80211_exit(void) rc80211_simple_exit(); rc80211_pid_exit(); -#ifdef CONFIG_MAC80211_MESH if (mesh_allocated) ieee80211s_stop(); -#endif + ieee80211_wme_unregister(); ieee80211_debugfs_netdev_exit(); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 49466b6996d1..7394c9b783b8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -93,9 +93,8 @@ struct ieee80211_sta_bss { #ifdef CONFIG_MAC80211_MESH u8 *mesh_id; size_t mesh_id_len; -#endif - /* mesh_cfg left out the ifdef to reduce clutter on bss handling */ u8 *mesh_cfg; +#endif #define IEEE80211_MAX_SUPP_RATES 32 u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; size_t supp_rates_len; @@ -113,6 +112,30 @@ struct ieee80211_sta_bss { u8 erp_value; }; +static inline u8 *bss_mesh_cfg(struct ieee80211_sta_bss *bss) +{ +#ifdef CONFIG_MAC80211_MESH + return bss->mesh_cfg; +#endif + return NULL; +} + +static inline u8 *bss_mesh_id(struct ieee80211_sta_bss *bss) +{ +#ifdef CONFIG_MAC80211_MESH + return bss->mesh_id; +#endif + return NULL; +} + +static inline u8 bss_mesh_id_len(struct ieee80211_sta_bss *bss) +{ +#ifdef CONFIG_MAC80211_MESH + return bss->mesh_id_len; +#endif + return 0; +} + typedef unsigned __bitwise__ ieee80211_tx_result; #define TX_CONTINUE ((__force ieee80211_tx_result) 0u) @@ -233,7 +256,6 @@ struct ieee80211_if_vlan { struct list_head list; }; -#ifdef CONFIG_MAC80211_MESH struct mesh_stats { __u32 fwded_frames; /* Mesh forwarded frames */ __u32 dropped_frames_ttl; /* Not transmitted since mesh_ttl == 0*/ @@ -249,7 +271,6 @@ struct mesh_preq_queue { u8 flags; }; - struct mesh_config { /* Timeouts in ms */ /* Mesh plink management parameters */ @@ -268,7 +289,7 @@ struct mesh_config { u32 path_refresh_time; u16 min_discovery_timeout; }; -#endif + /* flags used in struct ieee80211_if_sta.flags */ #define IEEE80211_STA_SSID_SET BIT(0) @@ -361,6 +382,22 @@ struct ieee80211_if_sta { int num_beacons; /* number of TXed beacon frames by this STA */ }; +static inline void ieee80211_if_sta_set_mesh_id(struct ieee80211_if_sta *ifsta, + u8 mesh_id_len, u8 *mesh_id) +{ +#ifdef CONFIG_MAC80211_MESH + ifsta->mesh_id_len = mesh_id_len; + memcpy(ifsta->mesh_id, mesh_id, mesh_id_len); +#endif +} + +#ifdef CONFIG_MAC80211_MESH +#define IEEE80211_IFSTA_MESH_CTR_INC(sta, name) \ + do { (sta)->mshstats.name++; } while (0) +#else +#define IEEE80211_IFSTA_MESH_CTR_INC(sta, name) \ + do { } while (0) +#endif /* flags used in struct ieee80211_sub_if_data.flags */ #define IEEE80211_SDATA_ALLMULTI BIT(0) @@ -472,7 +509,7 @@ struct ieee80211_sub_if_data { struct dentry *dropped_frames_ttl; struct dentry *dropped_frames_no_route; struct dentry *estab_plinks; - struct timer_list mesh_path_timer; + struct timer_list mesh_path_timer; } mesh_stats; struct dentry *mesh_config_dir; @@ -884,12 +921,17 @@ void sta_addba_resp_timer_expired(unsigned long data); u64 ieee80211_sta_get_rates(struct ieee80211_local *local, struct ieee802_11_elems *elems, enum ieee80211_band band); -void ieee80211_start_mesh(struct net_device *dev); void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, int encrypt); void ieee802_11_parse_elems(u8 *start, size_t len, struct ieee802_11_elems *elems); +#ifdef CONFIG_MAC80211_MESH +void ieee80211_start_mesh(struct net_device *dev); +#else +static inline void ieee80211_start_mesh(struct net_device *dev) +{} +#endif /* ieee80211_iface.c */ int ieee80211_if_add(struct net_device *dev, const char *name, diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index c2f92b78bfc9..b0f17a2b1a42 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -15,9 +15,7 @@ #include "ieee80211_i.h" #include "sta_info.h" #include "debugfs_netdev.h" -#ifdef CONFIG_MAC80211_MESH #include "mesh.h" -#endif void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) { @@ -82,14 +80,11 @@ int ieee80211_if_add(struct net_device *dev, const char *name, ieee80211_debugfs_add_netdev(sdata); ieee80211_if_set_type(ndev, type); -#ifdef CONFIG_MAC80211_MESH - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && - params && params->mesh_id_len) { - sdata->u.sta.mesh_id_len = params->mesh_id_len; - memcpy(sdata->u.sta.mesh_id, params->mesh_id, - params->mesh_id_len); - } -#endif + if (ieee80211_vif_is_mesh(&sdata->vif) && + params && params->mesh_id_len) + ieee80211_if_sta_set_mesh_id(&sdata->u.sta, + params->mesh_id_len, + params->mesh_id); /* we're under RTNL so all this is fine */ if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) { @@ -170,47 +165,8 @@ void ieee80211_if_set_type(struct net_device *dev, int type) msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); sdata->bss = &msdata->u.ap; -#ifdef CONFIG_MAC80211_MESH - if (type == IEEE80211_IF_TYPE_MESH_POINT) { - ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T; - ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T; - ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T; - ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR; - ifsta->mshcfg.dot11MeshTTL = MESH_TTL; - ifsta->mshcfg.auto_open_plinks = true; - ifsta->mshcfg.dot11MeshMaxPeerLinks = - MESH_MAX_ESTAB_PLINKS; - ifsta->mshcfg.dot11MeshHWMPactivePathTimeout = - MESH_PATH_TIMEOUT; - ifsta->mshcfg.dot11MeshHWMPpreqMinInterval = - MESH_PREQ_MIN_INT; - ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime = - MESH_DIAM_TRAVERSAL_TIME; - ifsta->mshcfg.dot11MeshHWMPmaxPREQretries = - MESH_MAX_PREQ_RETRIES; - ifsta->mshcfg.path_refresh_time = - MESH_PATH_REFRESH_TIME; - ifsta->mshcfg.min_discovery_timeout = - MESH_MIN_DISCOVERY_TIMEOUT; - ifsta->accepting_plinks = true; - ifsta->preq_id = 0; - ifsta->dsn = 0; - atomic_set(&ifsta->mpaths, 0); - mesh_rmc_init(dev); - ifsta->last_preq = jiffies; - /* Allocate all mesh structures when creating the first - * mesh interface. - */ - if (!mesh_allocated) - ieee80211s_init(); - mesh_ids_set_default(ifsta); - setup_timer(&ifsta->mesh_path_timer, - ieee80211_mesh_path_timer, - (unsigned long) sdata); - INIT_LIST_HEAD(&ifsta->preq_queue.list); - spin_lock_init(&ifsta->mesh_preq_queue_lock); - } -#endif + if (ieee80211_vif_is_mesh(&sdata->vif)) + ieee80211_mesh_init_sdata(sdata); break; } case IEEE80211_IF_TYPE_MNTR: @@ -240,6 +196,10 @@ void ieee80211_if_reinit(struct net_device *dev) ieee80211_if_sdata_deinit(sdata); + /* Need to handle mesh specially to allow eliding the function call */ + if (ieee80211_vif_is_mesh(&sdata->vif)) + mesh_rmc_free(dev); + switch (sdata->vif.type) { case IEEE80211_IF_TYPE_INVALID: /* cannot happen */ @@ -292,10 +252,6 @@ void ieee80211_if_reinit(struct net_device *dev) } break; case IEEE80211_IF_TYPE_MESH_POINT: -#ifdef CONFIG_MAC80211_MESH - mesh_rmc_free(dev); -#endif - /* fall through */ case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: kfree(sdata->u.sta.extra_ie); diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index d2dedcb5a954..9f933aeca719 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -31,9 +31,7 @@ #include "ieee80211_i.h" #include "ieee80211_rate.h" #include "ieee80211_led.h" -#ifdef CONFIG_MAC80211_MESH #include "mesh.h" -#endif #define IEEE80211_AUTH_TIMEOUT (HZ / 5) #define IEEE80211_AUTH_MAX_TRIES 3 @@ -1897,12 +1895,13 @@ static void __ieee80211_rx_bss_hash_add(struct net_device *dev, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); u8 hash_idx; -#ifdef CONFIG_MAC80211_MESH - if (bss->mesh_cfg) - hash_idx = mesh_id_hash(bss->mesh_id, bss->mesh_id_len); + + if (bss_mesh_cfg(bss)) + hash_idx = mesh_id_hash(bss_mesh_id(bss), + bss_mesh_id_len(bss)); else -#endif hash_idx = STA_HASH(bss->bssid); + bss->hnext = local->sta_bss_hash[hash_idx]; local->sta_bss_hash[hash_idx] = bss; } @@ -1967,7 +1966,8 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, spin_lock_bh(&local->sta_bss_lock); bss = local->sta_bss_hash[STA_HASH(bssid)]; while (bss) { - if (!bss->mesh_cfg && !memcmp(bss->bssid, bssid, ETH_ALEN) && + if (!bss_mesh_cfg(bss) && + !memcmp(bss->bssid, bssid, ETH_ALEN) && bss->freq == freq && bss->ssid_len == ssid_len && (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { @@ -1991,8 +1991,8 @@ ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len, spin_lock_bh(&local->sta_bss_lock); bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)]; while (bss) { - if (bss->mesh_cfg && - !memcmp(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN) && + if (bss_mesh_cfg(bss) && + !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) && bss->freq == freq && mesh_id_len == bss->mesh_id_len && (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id, @@ -2053,10 +2053,8 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) kfree(bss->rsn_ie); kfree(bss->wmm_ie); kfree(bss->ht_ie); -#ifdef CONFIG_MAC80211_MESH - kfree(bss->mesh_id); - kfree(bss->mesh_cfg); -#endif + kfree(bss_mesh_id(bss)); + kfree(bss_mesh_cfg(bss)); kfree(bss); } @@ -2322,16 +2320,14 @@ static void ieee80211_rx_bss_info(struct net_device *dev, beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); -#ifdef CONFIG_MAC80211_MESH - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && elems.mesh_id - && elems.mesh_config) - if (mesh_matches_local(&elems, dev)) { - u64 rates = ieee80211_sta_get_rates(local, &elems, - rx_status->band); - mesh_neighbour_update(mgmt->sa, rates, dev, - mesh_peer_accepts_plinks(&elems, dev)); - } -#endif + if (ieee80211_vif_is_mesh(&sdata->vif) && elems.mesh_id && + elems.mesh_config && mesh_matches_local(&elems, dev)) { + u64 rates = ieee80211_sta_get_rates(local, &elems, + rx_status->band); + + mesh_neighbour_update(mgmt->sa, rates, dev, + mesh_peer_accepts_plinks(&elems, dev)); + } if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && @@ -2712,9 +2708,7 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev, size_t len, struct ieee80211_rx_status *rx_status) { -#ifdef CONFIG_MAC80211_MESH struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); -#endif if (len < IEEE80211_MIN_ACTION_SIZE) return; @@ -2747,17 +2741,14 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev, break; } break; -#ifdef CONFIG_MAC80211_MESH case PLINK_CATEGORY: - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + if (ieee80211_vif_is_mesh(&sdata->vif)) mesh_rx_plink_frame(dev, mgmt, len, rx_status); break; - case MESH_PATH_SEL_CATEGORY: - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + if (ieee80211_vif_is_mesh(&sdata->vif)) mesh_rx_path_sel_frame(dev, mgmt, len); break; -#endif default: if (net_ratelimit()) printk(KERN_DEBUG "%s: Rx unknown action frame - " @@ -3027,8 +3018,9 @@ void ieee80211_sta_work(struct work_struct *work) ieee80211_sta_rx_queued_mgmt(dev, skb); #ifdef CONFIG_MAC80211_MESH - if (ifsta->preq_queue_len && time_after(jiffies, ifsta->last_preq + - msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval))) + if (ifsta->preq_queue_len && + time_after(jiffies, + ifsta->last_preq + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval))) mesh_path_start_discovery(dev); #endif @@ -3810,13 +3802,11 @@ ieee80211_sta_scan_result(struct net_device *dev, memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWESSID; - if (bss->mesh_cfg) { -#ifdef CONFIG_MAC80211_MESH - iwe.u.data.length = bss->mesh_id_len; + if (bss_mesh_cfg(bss)) { + iwe.u.data.length = bss_mesh_id_len(bss); iwe.u.data.flags = 1; current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - bss->mesh_id); -#endif + bss_mesh_id(bss)); } else { iwe.u.data.length = bss->ssid_len; iwe.u.data.flags = 1; @@ -3825,10 +3815,10 @@ ieee80211_sta_scan_result(struct net_device *dev, } if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS - || bss->mesh_cfg)) { + || bss_mesh_cfg(bss))) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWMODE; - if (bss->mesh_cfg) + if (bss_mesh_cfg(bss)) iwe.u.mode = IW_MODE_MESH; else if (bss->capability & WLAN_CAPABILITY_ESS) iwe.u.mode = IW_MODE_MASTER; @@ -3919,9 +3909,9 @@ ieee80211_sta_scan_result(struct net_device *dev, } } - if (bss->mesh_cfg) { + if (bss_mesh_cfg(bss)) { char *buf; - u8 *cfg = bss->mesh_cfg; + u8 *cfg = bss_mesh_cfg(bss); buf = kmalloc(200, GFP_ATOMIC); if (buf) { memset(&iwe, 0, sizeof(iwe)); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 8ff533005d92..ebe1a7a80bad 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -381,3 +381,70 @@ endgrow: else return newtbl; } + +/** + * ieee80211_new_mesh_header - create a new mesh header + * @meshhdr: uninitialized mesh header + * @sdata: mesh interface to be used + * + * Return the header length. + */ +int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, + struct ieee80211_sub_if_data *sdata) +{ + meshhdr->flags = 0; + meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL; + + meshhdr->seqnum[0] = sdata->u.sta.mesh_seqnum[0]++; + meshhdr->seqnum[1] = sdata->u.sta.mesh_seqnum[1]; + meshhdr->seqnum[2] = sdata->u.sta.mesh_seqnum[2]; + + if (sdata->u.sta.mesh_seqnum[0] == 0) { + sdata->u.sta.mesh_seqnum[1]++; + if (sdata->u.sta.mesh_seqnum[1] == 0) + sdata->u.sta.mesh_seqnum[2]++; + } + + return 5; +} + +void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + + ifsta->mshcfg.dot11MeshRetryTimeout = MESH_RET_T; + ifsta->mshcfg.dot11MeshConfirmTimeout = MESH_CONF_T; + ifsta->mshcfg.dot11MeshHoldingTimeout = MESH_HOLD_T; + ifsta->mshcfg.dot11MeshMaxRetries = MESH_MAX_RETR; + ifsta->mshcfg.dot11MeshTTL = MESH_TTL; + ifsta->mshcfg.auto_open_plinks = true; + ifsta->mshcfg.dot11MeshMaxPeerLinks = + MESH_MAX_ESTAB_PLINKS; + ifsta->mshcfg.dot11MeshHWMPactivePathTimeout = + MESH_PATH_TIMEOUT; + ifsta->mshcfg.dot11MeshHWMPpreqMinInterval = + MESH_PREQ_MIN_INT; + ifsta->mshcfg.dot11MeshHWMPnetDiameterTraversalTime = + MESH_DIAM_TRAVERSAL_TIME; + ifsta->mshcfg.dot11MeshHWMPmaxPREQretries = + MESH_MAX_PREQ_RETRIES; + ifsta->mshcfg.path_refresh_time = + MESH_PATH_REFRESH_TIME; + ifsta->mshcfg.min_discovery_timeout = + MESH_MIN_DISCOVERY_TIMEOUT; + ifsta->accepting_plinks = true; + ifsta->preq_id = 0; + ifsta->dsn = 0; + atomic_set(&ifsta->mpaths, 0); + mesh_rmc_init(sdata->dev); + ifsta->last_preq = jiffies; + /* Allocate all mesh structures when creating the first mesh interface. */ + if (!mesh_allocated) + ieee80211s_init(); + mesh_ids_set_default(ifsta); + setup_timer(&ifsta->mesh_path_timer, + ieee80211_mesh_path_timer, + (unsigned long) sdata); + INIT_LIST_HEAD(&ifsta->preq_queue.list); + spin_lock_init(&ifsta->mesh_preq_queue_lock); +} diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index ac8923793908..d565b3fb9e6a 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -11,10 +11,10 @@ #ifndef IEEE80211S_H #define IEEE80211S_H -#include "ieee80211_i.h" +#include #include +#include "ieee80211_i.h" -extern int mesh_allocated; /* Data structures */ @@ -211,6 +211,8 @@ void mesh_rmc_free(struct net_device *dev); int mesh_rmc_init(struct net_device *dev); void ieee80211s_init(void); void ieee80211s_stop(void); +void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); + /* Mesh paths */ int mesh_nexthop_lookup(u8 *next_hop, struct sk_buff *skb, struct net_device *dev); @@ -257,6 +259,9 @@ void mesh_path_timer(unsigned long data); void mesh_path_flush_by_nexthop(struct sta_info *sta); void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev); +#ifdef CONFIG_MAC80211_MESH +extern int mesh_allocated; + static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata) { return sdata->u.sta.mshcfg.dot11MeshMaxPeerLinks - @@ -278,6 +283,10 @@ static inline void mesh_path_activate(struct mesh_path *mpath) for (i = 0; i <= x->hash_mask; i++) \ hlist_for_each_entry_rcu(node, p, &x->hash_buckets[i], list) +#else +#define mesh_allocated 0 +#endif + #define MESH_PREQ(skb) (skb->cb + 30) #endif /* IEEE80211S_H */ diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 5cd97e99be62..0b0e8d7eb9c7 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -6,11 +6,11 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#include +#include #include "ieee80211_i.h" #include "ieee80211_rate.h" #include "mesh.h" -#include #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG #define mpl_dbg(fmt, args...) printk(KERN_DEBUG fmt, ##args) @@ -131,7 +131,7 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) } /** - * mesh_plink_deactivate - deactivate mesh peer link + * __mesh_plink_deactivate - deactivate mesh peer link * * @sta: mesh peer link to deactivate * @@ -139,7 +139,7 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) * * Locking: the caller must hold sta->plink_lock */ -void mesh_plink_deactivate(struct sta_info *sta) +static void __mesh_plink_deactivate(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); if (sta->plink_state == ESTAB) @@ -148,6 +148,20 @@ void mesh_plink_deactivate(struct sta_info *sta) mesh_path_flush_by_nexthop(sta); } +/** + * __mesh_plink_deactivate - deactivate mesh peer link + * + * @sta: mesh peer link to deactivate + * + * All mesh paths with this peer as next hop will be flushed + */ +void mesh_plink_deactivate(struct sta_info *sta) +{ + spin_lock_bh(&sta->plink_lock); + __mesh_plink_deactivate(sta); + spin_unlock_bh(&sta->plink_lock); +} + static int mesh_plink_frame_tx(struct net_device *dev, enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid, __le16 reason) { @@ -365,7 +379,7 @@ void mesh_plink_block(struct sta_info *sta) #endif spin_lock_bh(&sta->plink_lock); - mesh_plink_deactivate(sta); + __mesh_plink_deactivate(sta); sta->plink_state = BLOCKED; spin_unlock_bh(&sta->plink_lock); } @@ -390,7 +404,7 @@ int mesh_plink_close(struct sta_info *sta) sta_info_put(sta); return 0; } else if (sta->plink_state == ESTAB) { - mesh_plink_deactivate(sta); + __mesh_plink_deactivate(sta); /* The timer should not be running */ if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) __sta_info_get(sta); @@ -699,7 +713,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, case CLS_ACPT: reason = cpu_to_le16(MESH_CLOSE_RCVD); sta->reason = reason; - mesh_plink_deactivate(sta); + __mesh_plink_deactivate(sta); sta->plink_state = HOLDING; llid = sta->llid; if (!mod_plink_timer(sta, diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 4a51647a41af..217c0f487bba 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -15,10 +15,7 @@ #include #include #include "ieee80211_rate.h" -#ifdef CONFIG_MAC80211_MESH #include "mesh.h" -#endif - #include "rc80211_pid.h" diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index cc4a896c617f..d0018fc40b09 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -20,9 +20,7 @@ #include "ieee80211_i.h" #include "ieee80211_led.h" -#ifdef CONFIG_MAC80211_MESH #include "mesh.h" -#endif #include "wep.h" #include "wpa.h" #include "tkip.h" @@ -439,6 +437,13 @@ ieee80211_rx_mesh_check(struct ieee80211_txrx_data *rx) else return RX_CONTINUE; } +#undef msh_h_get +#else +static inline ieee80211_rx_result +ieee80211_rx_mesh_check(struct ieee80211_txrx_data *rx) +{ + return RX_CONTINUE; +} #endif @@ -477,10 +482,8 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) * responsible for filtering on both auth and assoc states. */ -#ifdef CONFIG_MAC80211_MESH - if (rx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + if (ieee80211_vif_is_mesh(&rx->sdata->vif)) return ieee80211_rx_mesh_check(rx); -#endif if (unlikely(((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA || ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL && @@ -1111,8 +1114,7 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) hdrlen = ieee80211_get_hdrlen(fc); -#ifdef CONFIG_MAC80211_MESH - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { + if (ieee80211_vif_is_mesh(&sdata->vif)) { int meshhdrlen = ieee80211_get_mesh_hdrlen( (struct ieee80211s_hdr *) (skb->data + hdrlen)); /* Copy on cb: @@ -1126,7 +1128,6 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) memcpy(MESH_PREQ(skb), hdr->addr2, ETH_ALEN); hdrlen += meshhdrlen; } -#endif /* convert IEEE 802.11 header + possible LLC headers into Ethernet * header @@ -1306,9 +1307,8 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) } } -#ifdef CONFIG_MAC80211_MESH /* Mesh forwarding */ - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { + if (ieee80211_vif_is_mesh(&sdata->vif)) { u8 *mesh_ttl = &((struct ieee80211s_hdr *)skb->cb)->ttl; (*mesh_ttl)--; @@ -1321,12 +1321,13 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) else xmit_skb->pkt_type = PACKET_OTHERHOST; } else - sdata->u.sta.mshstats.dropped_frames_ttl++; - + IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta, + dropped_frames_ttl); } else if (skb->pkt_type != PACKET_OTHERHOST && compare_ether_addr(dev->dev_addr, skb->data) != 0) { if (*mesh_ttl == 0) { - sdata->u.sta.mshstats.dropped_frames_ttl++; + IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta, + dropped_frames_ttl); dev_kfree_skb(skb); skb = NULL; } else { @@ -1337,7 +1338,6 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) } } } -#endif if (skb) { /* deliver to local stack */ diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 1f3c9eb98500..81c4e3392f40 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -21,9 +21,7 @@ #include "ieee80211_rate.h" #include "sta_info.h" #include "debugfs_sta.h" -#ifdef CONFIG_MAC80211_MESH #include "mesh.h" -#endif /* Caller must hold local->sta_lock */ static void sta_info_hash_add(struct ieee80211_local *local, @@ -309,10 +307,8 @@ void sta_info_remove(struct sta_info *sta) } local->num_sta--; -#ifdef CONFIG_MAC80211_MESH - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + if (ieee80211_vif_is_mesh(&sdata->vif)) mesh_accept_plinks_update(sdata->dev); -#endif } void sta_info_free(struct sta_info *sta) @@ -329,13 +325,8 @@ void sta_info_free(struct sta_info *sta) sta_info_remove(sta); write_unlock_bh(&local->sta_lock); -#ifdef CONFIG_MAC80211_MESH - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) { - spin_lock_bh(&sta->plink_lock); + if (ieee80211_vif_is_mesh(&sdata->vif)) mesh_plink_deactivate(sta); - spin_unlock_bh(&sta->plink_lock); - } -#endif while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { local->total_ps_buffered--; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 9d1d7a0e3114..4ad500373d5a 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -107,7 +107,6 @@ struct tid_ampdu_rx { struct timer_list session_timer; }; -#ifdef CONFIG_MAC80211_MESH enum plink_state { LISTEN, OPN_SNT, @@ -117,7 +116,6 @@ enum plink_state { HOLDING, BLOCKED }; -#endif /** * struct sta_ampdu_mlme - STA aggregation information. diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index fc1ffb55ed5c..3b06e0d8f35c 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -26,9 +26,7 @@ #include "ieee80211_i.h" #include "ieee80211_led.h" -#ifdef CONFIG_MAC80211_MESH #include "mesh.h" -#endif #include "wep.h" #include "wpa.h" #include "wme.h" @@ -1460,7 +1458,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, goto fail; } meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr, - sdata); + sdata); } hdrlen = 30; break; @@ -1778,40 +1776,6 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, read_unlock_bh(&local->sta_lock); } -#ifdef CONFIG_MAC80211_MESH -static struct sk_buff *ieee80211_mesh_beacon_get(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); - struct ieee80211_mgmt *mgmt; - u8 *pos; - - if (!skb) - return NULL; - skb_reserve(skb, local->hw.extra_tx_headroom); - mgmt = (struct ieee80211_mgmt *) - skb_put(skb, 24 + sizeof(mgmt->u.beacon)); - memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_BEACON); - memset(mgmt->da, 0xff, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - /* BSSID is left zeroed, wildcard value */ - mgmt->u.beacon.beacon_int = - cpu_to_le16(local->hw.conf.beacon_int); - mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ - - pos = skb_put(skb, 2); - *pos++ = WLAN_EID_SSID; - *pos++ = 0x0; - - mesh_mgmt_ies_add(skb, dev); - - return skb; -} -#endif - - struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_tx_control *control) @@ -1824,8 +1788,10 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct rate_selection rsel; struct beacon_data *beacon; struct ieee80211_supported_band *sband; + struct ieee80211_mgmt *mgmt; int *num_beacons; - int err = 0; + bool err = true; + u8 *pos; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; @@ -1834,47 +1800,65 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, sdata = vif_to_sdata(vif); bdev = sdata->dev; - switch (sdata->vif.type) { - case IEEE80211_IF_TYPE_AP: + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { ap = &sdata->u.ap; beacon = rcu_dereference(ap->beacon); - if (!ap || !beacon) { - err = -1; - break; - } + if (ap && beacon) { + /* + * headroom, head length, + * tail length and maximum TIM length + */ + skb = dev_alloc_skb(local->tx_headroom + + beacon->head_len + + beacon->tail_len + 256); + if (!skb) + goto out; - /* headroom, head length, tail length and maximum TIM length */ - skb = dev_alloc_skb(local->tx_headroom + beacon->head_len + - beacon->tail_len + 256); - if (!skb) - goto out; + skb_reserve(skb, local->tx_headroom); + memcpy(skb_put(skb, beacon->head_len), beacon->head, + beacon->head_len); - skb_reserve(skb, local->tx_headroom); - memcpy(skb_put(skb, beacon->head_len), beacon->head, - beacon->head_len); + ieee80211_include_sequence(sdata, + (struct ieee80211_hdr *)skb->data); - ieee80211_include_sequence(sdata, - (struct ieee80211_hdr *)skb->data); + ieee80211_beacon_add_tim(local, ap, skb, beacon); - ieee80211_beacon_add_tim(local, ap, skb, beacon); + if (beacon->tail) + memcpy(skb_put(skb, beacon->tail_len), + beacon->tail, beacon->tail_len); - if (beacon->tail) - memcpy(skb_put(skb, beacon->tail_len), beacon->tail, - beacon->tail_len); + num_beacons = &ap->num_beacons; - num_beacons = &ap->num_beacons; - break; + err = false; + } + } else if (ieee80211_vif_is_mesh(&sdata->vif)) { + /* headroom, head length, tail length and maximum TIM length */ + skb = dev_alloc_skb(local->tx_headroom + 400); + if (!skb) + goto out; + + skb_reserve(skb, local->hw.extra_tx_headroom); + mgmt = (struct ieee80211_mgmt *) + skb_put(skb, 24 + sizeof(mgmt->u.beacon)); + memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_BEACON); + memset(mgmt->da, 0xff, ETH_ALEN); + memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); + /* BSSID is left zeroed, wildcard value */ + mgmt->u.beacon.beacon_int = + cpu_to_le16(local->hw.conf.beacon_int); + mgmt->u.beacon.capab_info = 0x0; /* 0x0 for MPs */ + + pos = skb_put(skb, 2); + *pos++ = WLAN_EID_SSID; + *pos++ = 0x0; + + mesh_mgmt_ies_add(skb, sdata->dev); -#ifdef CONFIG_MAC80211_MESH - case IEEE80211_IF_TYPE_MESH_POINT: - skb = ieee80211_mesh_beacon_get(bdev); num_beacons = &sdata->u.sta.num_beacons; - break; -#endif - default: - err = -1; - break; + err = false; } if (err) { diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 6b50b6c12da3..b46496fa2e10 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -26,9 +26,7 @@ #include "ieee80211_i.h" #include "ieee80211_rate.h" -#ifdef CONFIG_MAC80211_MESH #include "mesh.h" -#endif #include "wme.h" /* privid for wiphys to determine whether they belong to us or not */ @@ -149,7 +147,6 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) } EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); -#ifdef CONFIG_MAC80211_MESH int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) { int ae = meshhdr->flags & IEEE80211S_FLAGS_AE; @@ -167,7 +164,6 @@ int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) return 5; } } -#endif void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) { @@ -418,31 +414,3 @@ void ieee80211_iterate_active_interfaces( rcu_read_unlock(); } EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); - -#ifdef CONFIG_MAC80211_MESH -/** - * ieee80211_new_mesh_header - create a new mesh header - * @meshhdr: uninitialized mesh header - * @sdata: mesh interface to be used - * - * Return the header length. - */ -int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr, - struct ieee80211_sub_if_data *sdata) -{ - meshhdr->flags = 0; - meshhdr->ttl = sdata->u.sta.mshcfg.dot11MeshTTL; - - meshhdr->seqnum[0] = sdata->u.sta.mesh_seqnum[0]++; - meshhdr->seqnum[1] = sdata->u.sta.mesh_seqnum[1]; - meshhdr->seqnum[2] = sdata->u.sta.mesh_seqnum[2]; - - if (sdata->u.sta.mesh_seqnum[0] == 0) { - sdata->u.sta.mesh_seqnum[1]++; - if (sdata->u.sta.mesh_seqnum[1] == 0) - sdata->u.sta.mesh_seqnum[2]++; - } - - return 5; -} -#endif -- cgit v1.2.3-59-g8ed1b From dc0b0f7d1e34b797b98e4d16122b3ea6f775154c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 23 Feb 2008 15:17:20 +0100 Subject: mac80211: mesh hwmp locking fixes This fixes missing unlocks noticed by sparse. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 9a501aae48eb..c2f40ef418cf 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -264,8 +264,10 @@ static u32 hwmp_route_info_get(struct net_device *dev, rcu_read_lock(); sta = sta_info_get(local, mgmt->sa); - if (!sta) + if (!sta) { + rcu_read_unlock(); return 0; + } last_hop_metric = airtime_link_metric_get(local, sta); /* Update and check originator routing info */ @@ -293,6 +295,7 @@ static u32 hwmp_route_info_get(struct net_device *dev, break; default: sta_info_put(sta); + rcu_read_unlock(); return 0; } new_metric = orig_metric + last_hop_metric; -- cgit v1.2.3-59-g8ed1b From 2f5ce793c0817d8d38f1c7ad23945607d57e47d6 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 23 Feb 2008 15:17:21 +0100 Subject: mac80211: enable mesh in Kconfig Currently marked BROKEN because of endianness problems. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Kconfig | 15 +++++++++++++++ net/mac80211/Makefile | 6 ++++++ 2 files changed, 21 insertions(+) (limited to 'net') diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 45c7c0c3875e..57bf358b2e7c 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -81,6 +81,14 @@ config MAC80211_RC_SIMPLE Say N unless you know what you are doing. endmenu +config MAC80211_MESH + bool "Enable mac80211 mesh networking (pre-802.11s) support" + depends on MAC80211 && EXPERIMENTAL && BROKEN + ---help--- + This options enables support of pre-802.11s mesh interfaces. + For more information visit http://o11s.org + + config MAC80211_LEDS bool "Enable LED triggers" depends on MAC80211 && LEDS_TRIGGERS @@ -166,3 +174,10 @@ config MAC80211_VERBOSE_PS_DEBUG ---help--- Say Y here to print out verbose powersave mode debug messages. + +config MAC80211_VERBOSE_MPL_DEBUG + bool "Verbose mesh peer link debugging" + depends on MAC80211_DEBUG && MAC80211_MESH + ---help--- + Say Y here to print out verbose mesh peer link + debug messages. diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 9d7a19581a29..829ce4256b76 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -36,6 +36,12 @@ mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ debugfs_netdev.o \ debugfs_key.o +mac80211-$(CONFIG_MAC80211_MESH) += \ + mesh.o \ + mesh_pathtbl.o \ + mesh_plink.o \ + mesh_hwmp.o + # Build rate control algorithm(s) CFLAGS_rc80211_simple.o += -DRC80211_SIMPLE_COMPILE -- cgit v1.2.3-59-g8ed1b From ff59dc76e6e996092e4e11f4a6a370702428ead5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 10:11:50 +0100 Subject: mac80211: add missing "break" statement in mesh code This inserts a missing break statement which, if hit, would cause the code to fall-through and unlock a spinlock twice. Noticed via sparse's "lock count wrong in basic block" warning and careful code inspection. Signed-off-by: Johannes Berg Cc: Luis Carlos Cobo Signed-off-by: John W. Linville --- net/mac80211/mesh_plink.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 0b0e8d7eb9c7..c2f4fe7a30b6 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -691,6 +691,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, spin_unlock_bh(&sta->plink_lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); + break; case OPN_ACPT: if (del_timer(&sta->plink_timer)) sta_info_put(sta); -- cgit v1.2.3-59-g8ed1b From 5c142e8db4b2a10dad103d49f309381cb9fc6a87 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 10:13:31 +0100 Subject: mac80211: clarify mesh Kconfig This clarifies that the mesh networking code is currently based on Draft 1.08 of the 802.11 Mesh Networking amendment. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 57bf358b2e7c..5ca576e77615 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -85,8 +85,9 @@ config MAC80211_MESH bool "Enable mac80211 mesh networking (pre-802.11s) support" depends on MAC80211 && EXPERIMENTAL && BROKEN ---help--- - This options enables support of pre-802.11s mesh interfaces. - For more information visit http://o11s.org + This options enables support of Draft 802.11s mesh networking. + The implementation is based on Draft 1.08 of the Mesh Networking + amendment. For more information visit http://o11s.org/. config MAC80211_LEDS -- cgit v1.2.3-59-g8ed1b From c1edd987a4ae08908d8ec08c550240ea065e0649 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 16:15:06 +0100 Subject: mac80211: export mesh_plink_broken This needs to be exported because rate control algorithms can be modular. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh_pathtbl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 37094942e728..3cbdbb23d75a 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -257,6 +257,7 @@ void mesh_plink_broken(struct sta_info *sta) } rcu_read_unlock(); } +EXPORT_SYMBOL(mesh_plink_broken); /** * mesh_path_flush_by_nexthop - Deletes mesh paths if their next hop matches -- cgit v1.2.3-59-g8ed1b From d6d1a5a7096172a1592115331a420630adf47f8c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 16:24:38 +0100 Subject: mac80211: clean up mesh RX path a bit more Moves another ifdef into the sta_info header file in favour of compiling more code even w/o CONFIG_MAC80211_MESH. Signed-off-by: Johannes Berg Cc: Luis Carlos Cobo Signed-off-by: John W. Linville --- net/mac80211/rx.c | 17 ++++++----------- net/mac80211/sta_info.h | 8 ++++++++ 2 files changed, 14 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d0018fc40b09..1ff1301ca3df 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -391,13 +391,14 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) return RX_CONTINUE; } -#ifdef CONFIG_MAC80211_MESH -#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l)) static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_txrx_data *rx) { int hdrlen = ieee80211_get_hdrlen(rx->fc); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; + +#define msh_h_get(h, l) ((struct ieee80211s_hdr *) ((u8 *)h + l)) + if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) { if (!((rx->fc & IEEE80211_FCTL_FROMDS) && (rx->fc & IEEE80211_FCTL_TODS))) @@ -410,8 +411,9 @@ ieee80211_rx_mesh_check(struct ieee80211_txrx_data *rx) * establisment frame, beacon or probe, drop the frame. */ - if (!rx->sta || rx->sta->plink_state != ESTAB) { + if (!rx->sta || sta_plink_state(rx->sta) != ESTAB) { struct ieee80211_mgmt *mgmt; + if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) return RX_DROP_MONITOR; @@ -434,17 +436,10 @@ ieee80211_rx_mesh_check(struct ieee80211_txrx_data *rx) is_broadcast_ether_addr(hdr->addr1) && mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev)) return RX_DROP_MONITOR; - else - return RX_CONTINUE; -} #undef msh_h_get -#else -static inline ieee80211_rx_result -ieee80211_rx_mesh_check(struct ieee80211_txrx_data *rx) -{ + return RX_CONTINUE; } -#endif static ieee80211_rx_result diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4ad500373d5a..4d0840b8c58e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -235,6 +235,14 @@ struct sta_info { #endif }; +static inline enum plink_state sta_plink_state(struct sta_info *sta) +{ +#ifdef CONFIG_MAC80211_MESH + return sta->plink_state; +#endif + return LISTEN; +} + /* Maximum number of concurrently registered stations */ #define MAX_STA_COUNT 2007 -- cgit v1.2.3-59-g8ed1b From 42096b634f87bb65e08d1fa61462d5b30d9779ca Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 21:36:27 +0100 Subject: mac80211: fix kernel-doc comment for mesh_plink_deactivate Accidentally copied in a __mesh_plink_deactivate, noticed by Luis Carlos Cobo. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh_plink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index c2f4fe7a30b6..b5fbe970e48f 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -131,7 +131,7 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) } /** - * __mesh_plink_deactivate - deactivate mesh peer link + * mesh_plink_deactivate - deactivate mesh peer link * * @sta: mesh peer link to deactivate * -- cgit v1.2.3-59-g8ed1b From 7495883bdd07e6a233f8a7f3d85c085c1618a203 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 22:17:30 +0100 Subject: mac80211: reorder a few fields in sta_info Three __le16s followed by an enum (int) leave a two-byte hole of padding which we can use for two of the other fields. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/sta_info.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4d0840b8c58e..b9dfb6fa893a 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -209,11 +209,11 @@ struct sta_info { __le16 llid; /* Local link ID */ __le16 plid; /* Peer link ID */ __le16 reason; /* Buffer for cancel reason on HOLDING state */ + u8 plink_retries; /* Retries in establishment */ + bool ignore_plink_timer; enum plink_state plink_state; u32 plink_timeout; struct timer_list plink_timer; - u8 plink_retries; /* Retries in establishment */ - bool ignore_plink_timer; spinlock_t plink_lock; /* For peer_state reads / updates and other updates in the structure. Ensures robust transitions for the peerlink FSM */ -- cgit v1.2.3-59-g8ed1b From 5cf121c3cdb955583bf0c5d28c992b7968a4aa1a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 16:27:43 +0100 Subject: mac80211: split ieee80211_txrx_data Split it into ieee80211_tx_data and ieee80211_rx_data to clarify usage/flag usage and remove the stupid union thing. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 86 ++++++++-------- net/mac80211/rx.c | 163 +++++++++++++++--------------- net/mac80211/tx.c | 244 ++++++++++++++++++++++----------------------- net/mac80211/util.c | 8 +- net/mac80211/wep.c | 24 ++--- net/mac80211/wep.h | 4 +- net/mac80211/wpa.c | 80 +++++++-------- net/mac80211/wpa.h | 12 +-- 8 files changed, 315 insertions(+), 306 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7394c9b783b8..d3b5cc57af40 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -142,26 +142,51 @@ typedef unsigned __bitwise__ ieee80211_tx_result; #define TX_DROP ((__force ieee80211_tx_result) 1u) #define TX_QUEUED ((__force ieee80211_tx_result) 2u) +#define IEEE80211_TX_FRAGMENTED BIT(0) +#define IEEE80211_TX_UNICAST BIT(1) +#define IEEE80211_TX_PS_BUFFERED BIT(2) +#define IEEE80211_TX_PROBE_LAST_FRAG BIT(3) +#define IEEE80211_TX_INJECTED BIT(4) + +struct ieee80211_tx_data { + struct sk_buff *skb; + struct net_device *dev; + struct ieee80211_local *local; + struct ieee80211_sub_if_data *sdata; + struct sta_info *sta; + u16 fc, ethertype; + struct ieee80211_key *key; + unsigned int flags; + + struct ieee80211_tx_control *control; + struct ieee80211_channel *channel; + struct ieee80211_rate *rate; + /* use this rate (if set) for last fragment; rate can + * be set to lower rate for the first fragments, e.g., + * when using CTS protection with IEEE 802.11g. */ + struct ieee80211_rate *last_frag_rate; + + /* Extra fragments (in addition to the first fragment + * in skb) */ + int num_extra_frag; + struct sk_buff **extra_frag; +}; + + typedef unsigned __bitwise__ ieee80211_rx_result; #define RX_CONTINUE ((__force ieee80211_rx_result) 0u) #define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u) #define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u) #define RX_QUEUED ((__force ieee80211_rx_result) 3u) - -/* flags used in struct ieee80211_txrx_data.flags */ -/* whether the MSDU was fragmented */ -#define IEEE80211_TXRXD_FRAGMENTED BIT(0) -#define IEEE80211_TXRXD_TXUNICAST BIT(1) -#define IEEE80211_TXRXD_TXPS_BUFFERED BIT(2) -#define IEEE80211_TXRXD_TXPROBE_LAST_FRAG BIT(3) -#define IEEE80211_TXRXD_RXIN_SCAN BIT(4) +#define IEEE80211_RX_IN_SCAN BIT(0) /* frame is destined to interface currently processed (incl. multicast frames) */ -#define IEEE80211_TXRXD_RXRA_MATCH BIT(5) -#define IEEE80211_TXRXD_TX_INJECTED BIT(6) -#define IEEE80211_TXRXD_RX_AMSDU BIT(7) -#define IEEE80211_TXRXD_RX_CMNTR_REPORTED BIT(8) -struct ieee80211_txrx_data { +#define IEEE80211_RX_RA_MATCH BIT(1) +#define IEEE80211_RX_AMSDU BIT(2) +#define IEEE80211_RX_CMNTR_REPORTED BIT(3) +#define IEEE80211_RX_FRAGMENTED BIT(4) + +struct ieee80211_rx_data { struct sk_buff *skb; struct net_device *dev; struct ieee80211_local *local; @@ -170,31 +195,14 @@ struct ieee80211_txrx_data { u16 fc, ethertype; struct ieee80211_key *key; unsigned int flags; - union { - struct { - struct ieee80211_tx_control *control; - struct ieee80211_channel *channel; - struct ieee80211_rate *rate; - /* use this rate (if set) for last fragment; rate can - * be set to lower rate for the first fragments, e.g., - * when using CTS protection with IEEE 802.11g. */ - struct ieee80211_rate *last_frag_rate; - - /* Extra fragments (in addition to the first fragment - * in skb) */ - int num_extra_frag; - struct sk_buff **extra_frag; - } tx; - struct { - struct ieee80211_rx_status *status; - struct ieee80211_rate *rate; - int sent_ps_buffered; - int queue; - int load; - u32 tkip_iv32; - u16 tkip_iv16; - } rx; - } u; + + struct ieee80211_rx_status *status; + struct ieee80211_rate *rate; + int sent_ps_buffered; + int queue; + int load; + u32 tkip_iv32; + u16 tkip_iv16; }; /* flags used in struct ieee80211_tx_packet_data.flags */ @@ -842,7 +850,7 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) int ieee80211_hw_config(struct ieee80211_local *local); int ieee80211_if_config(struct net_device *dev); int ieee80211_if_config_beacon(struct net_device *dev); -void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx); +void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); void ieee80211_if_setup(struct net_device *dev); int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 1ff1301ca3df..2e65ca1cd1aa 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -251,7 +251,7 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb, } -static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx) +static void ieee80211_parse_qos(struct ieee80211_rx_data *rx) { u8 *data = rx->skb->data; int tid; @@ -262,9 +262,9 @@ static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx) /* frame has qos control */ tid = qc[0] & QOS_CONTROL_TID_MASK; if (qc[0] & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT) - rx->flags |= IEEE80211_TXRXD_RX_AMSDU; + rx->flags |= IEEE80211_RX_AMSDU; else - rx->flags &= ~IEEE80211_TXRXD_RX_AMSDU; + rx->flags &= ~IEEE80211_RX_AMSDU; } else { if (unlikely((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT)) { /* Separate TID for management frames */ @@ -280,13 +280,13 @@ static void ieee80211_parse_qos(struct ieee80211_txrx_data *rx) if (rx->sta) I802_DEBUG_INC(rx->sta->wme_rx_queue[tid]); - rx->u.rx.queue = tid; + rx->queue = tid; /* Set skb->priority to 1d tag if highest order bit of TID is not set. * For now, set skb->priority to 0 for other cases. */ rx->skb->priority = (tid > 7) ? 0 : tid; } -static void ieee80211_verify_ip_alignment(struct ieee80211_txrx_data *rx) +static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx) { #ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT int hdrlen; @@ -314,7 +314,7 @@ static void ieee80211_verify_ip_alignment(struct ieee80211_txrx_data *rx) * to move the 802.11 header further back in that case. */ hdrlen = ieee80211_get_hdrlen(rx->fc); - if (rx->flags & IEEE80211_TXRXD_RX_AMSDU) + if (rx->flags & IEEE80211_RX_AMSDU) hdrlen += ETH_HLEN; WARN_ON_ONCE(((unsigned long)(rx->skb->data + hdrlen)) & 3); #endif @@ -357,32 +357,32 @@ static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, /* rx handlers */ static ieee80211_rx_result -ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_if_stats(struct ieee80211_rx_data *rx) { if (rx->sta) - rx->sta->channel_use_raw += rx->u.rx.load; - rx->sdata->channel_use_raw += rx->u.rx.load; + rx->sta->channel_use_raw += rx->load; + rx->sdata->channel_use_raw += rx->load; return RX_CONTINUE; } static ieee80211_rx_result -ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) { struct ieee80211_local *local = rx->local; struct sk_buff *skb = rx->skb; if (unlikely(local->sta_hw_scanning)) - return ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status); + return ieee80211_sta_rx_scan(rx->dev, skb, rx->status); if (unlikely(local->sta_sw_scanning)) { /* drop all the other packets during a software scan anyway */ - if (ieee80211_sta_rx_scan(rx->dev, skb, rx->u.rx.status) + if (ieee80211_sta_rx_scan(rx->dev, skb, rx->status) != RX_QUEUED) dev_kfree_skb(skb); return RX_QUEUED; } - if (unlikely(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) { + if (unlikely(rx->flags & IEEE80211_RX_IN_SCAN)) { /* scanning finished during invoking of handlers */ I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); return RX_DROP_UNUSABLE; @@ -392,7 +392,7 @@ ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) } static ieee80211_rx_result -ieee80211_rx_mesh_check(struct ieee80211_txrx_data *rx) +ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) { int hdrlen = ieee80211_get_hdrlen(rx->fc); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; @@ -443,7 +443,7 @@ ieee80211_rx_mesh_check(struct ieee80211_txrx_data *rx) static ieee80211_rx_result -ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_check(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr; @@ -452,15 +452,15 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) /* Drop duplicate 802.11 retransmissions (IEEE 802.11 Chap. 9.2.9) */ if (rx->sta && !is_multicast_ether_addr(hdr->addr1)) { if (unlikely(rx->fc & IEEE80211_FCTL_RETRY && - rx->sta->last_seq_ctrl[rx->u.rx.queue] == + rx->sta->last_seq_ctrl[rx->queue] == hdr->seq_ctrl)) { - if (rx->flags & IEEE80211_TXRXD_RXRA_MATCH) { + if (rx->flags & IEEE80211_RX_RA_MATCH) { rx->local->dot11FrameDuplicateCount++; rx->sta->num_duplicates++; } return RX_DROP_MONITOR; } else - rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl; + rx->sta->last_seq_ctrl[rx->queue] = hdr->seq_ctrl; } if (unlikely(rx->skb->len < 16)) { @@ -488,7 +488,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) if ((!(rx->fc & IEEE80211_FCTL_FROMDS) && !(rx->fc & IEEE80211_FCTL_TODS) && (rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) - || !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { + || !(rx->flags & IEEE80211_RX_RA_MATCH)) { /* Drop IBSS frames and frames for other hosts * silently. */ return RX_DROP_MONITOR; @@ -502,7 +502,7 @@ ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) static ieee80211_rx_result -ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; int keyidx; @@ -543,7 +543,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) * No point in finding a key and decrypting if the frame is neither * addressed to us nor a multicast frame. */ - if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) + if (!(rx->flags & IEEE80211_RX_RA_MATCH)) return RX_CONTINUE; if (rx->sta) @@ -561,8 +561,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) * we somehow allow the driver to tell us which key * the hardware used if this flag is set? */ - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) + if ((rx->status->flag & RX_FLAG_DECRYPTED) && + (rx->status->flag & RX_FLAG_IV_STRIPPED)) return RX_CONTINUE; hdrlen = ieee80211_get_hdrlen(rx->fc); @@ -603,8 +603,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) /* Check for weak IVs if possible */ if (rx->sta && rx->key->conf.alg == ALG_WEP && ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) || - !(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) && + (!(rx->status->flag & RX_FLAG_IV_STRIPPED) || + !(rx->status->flag & RX_FLAG_DECRYPTED)) && ieee80211_wep_is_weak_iv(rx->skb, rx->key)) rx->sta->wep_weak_iv_count++; @@ -621,7 +621,7 @@ ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) } /* either the frame has been decrypted or will be dropped */ - rx->u.rx.status->flag |= RX_FLAG_DECRYPTED; + rx->status->flag |= RX_FLAG_DECRYPTED; return result; } @@ -691,7 +691,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) } static ieee80211_rx_result -ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) { struct sta_info *sta = rx->sta; struct net_device *dev = rx->dev; @@ -720,20 +720,20 @@ ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) sta->last_rx = jiffies; } - if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) + if (!(rx->flags & IEEE80211_RX_RA_MATCH)) return RX_CONTINUE; sta->rx_fragments++; sta->rx_bytes += rx->skb->len; - sta->last_rssi = rx->u.rx.status->ssi; - sta->last_signal = rx->u.rx.status->signal; - sta->last_noise = rx->u.rx.status->noise; + sta->last_rssi = rx->status->ssi; + sta->last_signal = rx->status->signal; + sta->last_noise = rx->status->noise; if (!(rx->fc & IEEE80211_FCTL_MOREFRAGS)) { /* Change STA power saving mode only in the end of a frame * exchange sequence */ if ((sta->flags & WLAN_STA_PS) && !(rx->fc & IEEE80211_FCTL_PM)) - rx->u.rx.sent_ps_buffered += ap_sta_ps_end(dev, sta); + rx->sent_ps_buffered += ap_sta_ps_end(dev, sta); else if (!(sta->flags & WLAN_STA_PS) && (rx->fc & IEEE80211_FCTL_PM)) ap_sta_ps_start(dev, sta); @@ -838,7 +838,7 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, } static ieee80211_rx_result -ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr; u16 sc; @@ -864,14 +864,14 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) if (frag == 0) { /* This is the first fragment of a new frame. */ entry = ieee80211_reassemble_add(rx->sdata, frag, seq, - rx->u.rx.queue, &(rx->skb)); + rx->queue, &(rx->skb)); if (rx->key && rx->key->conf.alg == ALG_CCMP && (rx->fc & IEEE80211_FCTL_PROTECTED)) { /* Store CCMP PN so that we can verify that the next * fragment has a sequential PN value. */ entry->ccmp = 1; memcpy(entry->last_pn, - rx->key->u.ccmp.rx_pn[rx->u.rx.queue], + rx->key->u.ccmp.rx_pn[rx->queue], CCMP_PN_LEN); } return RX_QUEUED; @@ -881,7 +881,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) * fragment cache. Add this fragment to the end of the pending entry. */ entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq, - rx->u.rx.queue, hdr); + rx->queue, hdr); if (!entry) { I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag); return RX_DROP_MONITOR; @@ -900,7 +900,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) if (pn[i]) break; } - rpn = rx->key->u.ccmp.rx_pn[rx->u.rx.queue]; + rpn = rx->key->u.ccmp.rx_pn[rx->queue]; if (memcmp(pn, rpn, CCMP_PN_LEN) != 0) { if (net_ratelimit()) printk(KERN_DEBUG "%s: defrag: CCMP PN not " @@ -941,7 +941,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) } /* Complete frame has been reassembled - process it now */ - rx->flags |= IEEE80211_TXRXD_FRAGMENTED; + rx->flags |= IEEE80211_RX_FRAGMENTED; out: if (rx->sta) @@ -954,7 +954,7 @@ ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) } static ieee80211_rx_result -ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); struct sk_buff *skb; @@ -964,7 +964,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) if (likely(!rx->sta || (rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_CTL || (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_PSPOLL || - !(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))) + !(rx->flags & IEEE80211_RX_RA_MATCH))) return RX_CONTINUE; if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) && @@ -1008,7 +1008,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) if (no_pending_pkts) sta_info_clear_tim_bit(rx->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - } else if (!rx->u.rx.sent_ps_buffered) { + } else if (!rx->sent_ps_buffered) { /* * FIXME: This can be the result of a race condition between * us expiring a frame and the station polling for it. @@ -1029,7 +1029,7 @@ ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) } static ieee80211_rx_result -ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx) { u16 fc = rx->fc; u8 *data = rx->skb->data; @@ -1049,7 +1049,7 @@ ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) } static int -ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx) +ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx) { if (unlikely(!rx->sta || !(rx->sta->flags & WLAN_STA_AUTHORIZED))) { #ifdef CONFIG_MAC80211_DEBUG @@ -1064,13 +1064,13 @@ ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx) } static int -ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx) +ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx) { /* * Pass through unencrypted frames if the hardware has * decrypted them already. */ - if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) + if (rx->status->flag & RX_FLAG_DECRYPTED) return 0; /* Drop unencrypted frames if key is set. */ @@ -1087,7 +1087,7 @@ ieee80211_drop_unencrypted(struct ieee80211_txrx_data *rx) } static int -ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) +ieee80211_data_to_8023(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->dev; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; @@ -1235,7 +1235,7 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) /* * requires that rx->skb is a frame with ethernet header */ -static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx) +static bool ieee80211_frame_allowed(struct ieee80211_rx_data *rx) { static const u8 pae_group_addr[ETH_ALEN] = { 0x01, 0x80, 0xC2, 0x00, 0x00, 0x03 }; @@ -1261,7 +1261,7 @@ static bool ieee80211_frame_allowed(struct ieee80211_txrx_data *rx) * requires that rx->skb is a frame with ethernet header */ static void -ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) +ieee80211_deliver_skb(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->dev; struct ieee80211_local *local = rx->local; @@ -1275,7 +1275,7 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) if (local->bridge_packets && (sdata->vif.type == IEEE80211_IF_TYPE_AP || sdata->vif.type == IEEE80211_IF_TYPE_VLAN) && - (rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) { + (rx->flags & IEEE80211_RX_RA_MATCH)) { if (is_multicast_ether_addr(ehdr->h_dest)) { /* * send multicast frames both to higher layers in @@ -1351,7 +1351,7 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) } static ieee80211_rx_result -ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->dev; struct ieee80211_local *local = rx->local; @@ -1371,7 +1371,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) if (unlikely(!WLAN_FC_DATA_PRESENT(fc))) return RX_DROP_MONITOR; - if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU)) + if (!(rx->flags & IEEE80211_RX_AMSDU)) return RX_CONTINUE; err = ieee80211_data_to_8023(rx); @@ -1468,7 +1468,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) } static ieee80211_rx_result -ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_data(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->dev; u16 fc; @@ -1499,7 +1499,7 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) } static ieee80211_rx_result -ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) { struct ieee80211_local *local = rx->local; struct ieee80211_hw *hw = &local->hw; @@ -1542,11 +1542,11 @@ ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx) } static ieee80211_rx_result -ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata; - if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) + if (!(rx->flags & IEEE80211_RX_RA_MATCH)) return RX_DROP_MONITOR; sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev); @@ -1554,7 +1554,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) sdata->vif.type == IEEE80211_IF_TYPE_IBSS || sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) && !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) - ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status); + ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->status); else return RX_DROP_MONITOR; @@ -1563,7 +1563,7 @@ ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) static void ieee80211_rx_michael_mic_report(struct net_device *dev, struct ieee80211_hdr *hdr, - struct ieee80211_txrx_data *rx) + struct ieee80211_rx_data *rx) { int keyidx, hdrlen; DECLARE_MAC_BUF(mac); @@ -1633,7 +1633,8 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, rx->skb = NULL; } -static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx) +/* TODO: use IEEE80211_RX_FRAGMENTED */ +static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata; struct ieee80211_local *local = rx->local; @@ -1646,9 +1647,9 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx) } __attribute__ ((packed)) *rthdr; struct sk_buff *skb = rx->skb, *skb2; struct net_device *prev_dev = NULL; - struct ieee80211_rx_status *status = rx->u.rx.status; + struct ieee80211_rx_status *status = rx->status; - if (rx->flags & IEEE80211_TXRXD_RX_CMNTR_REPORTED) + if (rx->flags & IEEE80211_RX_CMNTR_REPORTED) goto out_free_skb; if (skb_headroom(skb) < sizeof(*rthdr) && @@ -1663,7 +1664,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx) (1 << IEEE80211_RADIOTAP_RATE) | (1 << IEEE80211_RADIOTAP_CHANNEL)); - rthdr->rate = rx->u.rx.rate->bitrate / 5; + rthdr->rate = rx->rate->bitrate / 5; rthdr->chan_freq = cpu_to_le16(status->freq); if (status->band == IEEE80211_BAND_5GHZ) @@ -1706,14 +1707,14 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_txrx_data *rx) } else goto out_free_skb; - rx->flags |= IEEE80211_TXRXD_RX_CMNTR_REPORTED; + rx->flags |= IEEE80211_RX_CMNTR_REPORTED; return; out_free_skb: dev_kfree_skb(skb); } -typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_txrx_data *); +typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_rx_data *); static ieee80211_rx_handler ieee80211_rx_handlers[] = { ieee80211_rx_h_if_stats, @@ -1737,7 +1738,7 @@ static ieee80211_rx_handler ieee80211_rx_handlers[] = }; static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, - struct ieee80211_txrx_data *rx, + struct ieee80211_rx_data *rx, struct sk_buff *skb) { ieee80211_rx_handler *handler; @@ -1780,7 +1781,7 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, /* main receive path */ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, - u8 *bssid, struct ieee80211_txrx_data *rx, + u8 *bssid, struct ieee80211_rx_data *rx, struct ieee80211_hdr *hdr) { int multicast = is_multicast_ether_addr(hdr->addr1); @@ -1790,15 +1791,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, if (!bssid) return 0; if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { - if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) + if (!(rx->flags & IEEE80211_RX_IN_SCAN)) return 0; - rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; + rx->flags &= ~IEEE80211_RX_RA_MATCH; } else if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { if (!(sdata->dev->flags & IFF_PROMISC)) return 0; - rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; + rx->flags &= ~IEEE80211_RX_RA_MATCH; } break; case IEEE80211_IF_TYPE_IBSS: @@ -1808,15 +1809,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, (rx->fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) return 1; else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { - if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) + if (!(rx->flags & IEEE80211_RX_IN_SCAN)) return 0; - rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; + rx->flags &= ~IEEE80211_RX_RA_MATCH; } else if (!multicast && compare_ether_addr(sdata->dev->dev_addr, hdr->addr1) != 0) { if (!(sdata->dev->flags & IFF_PROMISC)) return 0; - rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; + rx->flags &= ~IEEE80211_RX_RA_MATCH; } else if (!rx->sta) rx->sta = ieee80211_ibss_add_sta(sdata->dev, rx->skb, bssid, hdr->addr2); @@ -1828,7 +1829,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, if (!(sdata->dev->flags & IFF_PROMISC)) return 0; - rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; + rx->flags &= ~IEEE80211_RX_RA_MATCH; } break; case IEEE80211_IF_TYPE_VLAN: @@ -1839,12 +1840,12 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, return 0; } else if (!ieee80211_bssid_match(bssid, sdata->dev->dev_addr)) { - if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) + if (!(rx->flags & IEEE80211_RX_IN_SCAN)) return 0; - rx->flags &= ~IEEE80211_TXRXD_RXRA_MATCH; + rx->flags &= ~IEEE80211_RX_RA_MATCH; } if (sdata->dev == sdata->local->mdev && - !(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) + !(rx->flags & IEEE80211_RX_IN_SCAN)) /* do not receive anything via * master device when not scanning */ return 0; @@ -1881,7 +1882,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; struct ieee80211_hdr *hdr; - struct ieee80211_txrx_data rx; + struct ieee80211_rx_data rx; u16 type; int prepares; struct ieee80211_sub_if_data *prev = NULL; @@ -1893,9 +1894,9 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, rx.skb = skb; rx.local = local; - rx.u.rx.status = status; - rx.u.rx.load = load; - rx.u.rx.rate = rate; + rx.status = status; + rx.load = load; + rx.rate = rate; rx.fc = le16_to_cpu(hdr->frame_control); type = rx.fc & IEEE80211_FCTL_FTYPE; @@ -1914,7 +1915,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, } if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning)) - rx.flags |= IEEE80211_TXRXD_RXIN_SCAN; + rx.flags |= IEEE80211_RX_IN_SCAN; ieee80211_parse_qos(&rx); ieee80211_verify_ip_alignment(&rx); @@ -1929,7 +1930,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, continue; bssid = ieee80211_get_bssid(hdr, skb->len, sdata->vif.type); - rx.flags |= IEEE80211_TXRXD_RXRA_MATCH; + rx.flags |= IEEE80211_RX_RA_MATCH; prepares = prepare_for_handlers(sdata, bssid, &rx, hdr); if (!prepares) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 3b06e0d8f35c..33e314f3aab7 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -87,11 +87,11 @@ static inline void ieee80211_dump_frame(const char *ifname, const char *title, } #endif /* CONFIG_MAC80211_LOWTX_FRAME_DUMP */ -static u16 ieee80211_duration(struct ieee80211_txrx_data *tx, int group_addr, +static u16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, int next_frag_len) { int rate, mrate, erp, dur, i; - struct ieee80211_rate *txrate = tx->u.tx.rate; + struct ieee80211_rate *txrate = tx->rate; struct ieee80211_local *local = tx->local; struct ieee80211_supported_band *sband; @@ -234,7 +234,7 @@ static int inline is_ieee80211_device(struct net_device *dev, /* tx handlers */ static ieee80211_tx_result -ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) +ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG struct sk_buff *skb = tx->skb; @@ -242,7 +242,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ u32 sta_flags; - if (unlikely(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) + if (unlikely(tx->flags & IEEE80211_TX_INJECTED)) return TX_CONTINUE; if (unlikely(tx->local->sta_sw_scanning) && @@ -253,12 +253,12 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) if (tx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) return TX_CONTINUE; - if (tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED) + if (tx->flags & IEEE80211_TX_PS_BUFFERED) return TX_CONTINUE; sta_flags = tx->sta ? tx->sta->flags : 0; - if (likely(tx->flags & IEEE80211_TXRXD_TXUNICAST)) { + if (likely(tx->flags & IEEE80211_TX_UNICAST)) { if (unlikely(!(sta_flags & WLAN_STA_ASSOC) && tx->sdata->vif.type != IEEE80211_IF_TYPE_IBSS && (tx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { @@ -288,7 +288,7 @@ ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) } static ieee80211_tx_result -ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx) +ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; @@ -346,7 +346,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) } static ieee80211_tx_result -ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) +ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) { /* * broadcast/multicast frame @@ -383,13 +383,13 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) } /* buffered in hardware */ - tx->u.tx.control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM; + tx->control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM; return TX_CONTINUE; } static ieee80211_tx_result -ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) +ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) { struct sta_info *sta = tx->sta; DECLARE_MAC_BUF(mac); @@ -443,32 +443,32 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) } static ieee80211_tx_result -ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) +ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx) { - if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)) + if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED)) return TX_CONTINUE; - if (tx->flags & IEEE80211_TXRXD_TXUNICAST) + if (tx->flags & IEEE80211_TX_UNICAST) return ieee80211_tx_h_unicast_ps_buf(tx); else return ieee80211_tx_h_multicast_ps_buf(tx); } static ieee80211_tx_result -ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) +ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) { struct ieee80211_key *key; u16 fc = tx->fc; - if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) + if (unlikely(tx->control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) tx->key = NULL; else if (tx->sta && (key = rcu_dereference(tx->sta->key))) tx->key = key; else if ((key = rcu_dereference(tx->sdata->default_key))) tx->key = key; else if (tx->sdata->drop_unencrypted && - !(tx->u.tx.control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && - !(tx->flags & IEEE80211_TXRXD_TX_INJECTED)) { + !(tx->control->flags & IEEE80211_TXCTL_EAPOL_FRAME) && + !(tx->flags & IEEE80211_TX_INJECTED)) { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); return TX_DROP; } else @@ -497,13 +497,13 @@ ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) } if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) - tx->u.tx.control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; + tx->control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; return TX_CONTINUE; } static ieee80211_tx_result -ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) +ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; size_t hdrlen, per_fragm, num_fragm, payload_len, left; @@ -513,7 +513,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) u8 *pos; int frag_threshold = tx->local->fragmentation_threshold; - if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED)) + if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) return TX_CONTINUE; first = tx->skb; @@ -565,8 +565,8 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) } skb_trim(first, hdrlen + per_fragm); - tx->u.tx.num_extra_frag = num_fragm - 1; - tx->u.tx.extra_frag = frags; + tx->num_extra_frag = num_fragm - 1; + tx->extra_frag = frags; return TX_CONTINUE; @@ -583,7 +583,7 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) } static ieee80211_tx_result -ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) +ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) { if (!tx->key) return TX_CONTINUE; @@ -603,56 +603,56 @@ ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) } static ieee80211_tx_result -ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) +ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) { struct rate_selection rsel; struct ieee80211_supported_band *sband; sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; - if (likely(!tx->u.tx.rate)) { + if (likely(!tx->rate)) { rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); - tx->u.tx.rate = rsel.rate; + tx->rate = rsel.rate; if (unlikely(rsel.probe)) { - tx->u.tx.control->flags |= + tx->control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; - tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; - tx->u.tx.control->alt_retry_rate = tx->u.tx.rate; - tx->u.tx.rate = rsel.probe; + tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; + tx->control->alt_retry_rate = tx->rate; + tx->rate = rsel.probe; } else - tx->u.tx.control->alt_retry_rate = NULL; + tx->control->alt_retry_rate = NULL; - if (!tx->u.tx.rate) + if (!tx->rate) return TX_DROP; } else - tx->u.tx.control->alt_retry_rate = NULL; + tx->control->alt_retry_rate = NULL; if (tx->sdata->bss_conf.use_cts_prot && - (tx->flags & IEEE80211_TXRXD_FRAGMENTED) && rsel.nonerp) { - tx->u.tx.last_frag_rate = tx->u.tx.rate; + (tx->flags & IEEE80211_TX_FRAGMENTED) && rsel.nonerp) { + tx->last_frag_rate = tx->rate; if (rsel.probe) - tx->flags &= ~IEEE80211_TXRXD_TXPROBE_LAST_FRAG; + tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG; else - tx->flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; - tx->u.tx.rate = rsel.nonerp; - tx->u.tx.control->tx_rate = rsel.nonerp; - tx->u.tx.control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; + tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; + tx->rate = rsel.nonerp; + tx->control->tx_rate = rsel.nonerp; + tx->control->flags &= ~IEEE80211_TXCTL_RATE_CTRL_PROBE; } else { - tx->u.tx.last_frag_rate = tx->u.tx.rate; - tx->u.tx.control->tx_rate = tx->u.tx.rate; + tx->last_frag_rate = tx->rate; + tx->control->tx_rate = tx->rate; } - tx->u.tx.control->tx_rate = tx->u.tx.rate; + tx->control->tx_rate = tx->rate; return TX_CONTINUE; } static ieee80211_tx_result -ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) +ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; u16 fc = le16_to_cpu(hdr->frame_control); u16 dur; - struct ieee80211_tx_control *control = tx->u.tx.control; + struct ieee80211_tx_control *control = tx->control; if (!control->retry_limit) { if (!is_multicast_ether_addr(hdr->addr1)) { @@ -674,7 +674,7 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) } } - if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { + if (tx->flags & IEEE80211_TX_FRAGMENTED) { /* Do not use multiple retry rates when sending fragmented * frames. * TODO: The last fragment could still use multiple retry @@ -686,8 +686,8 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) * there are associated non-ERP stations and RTS/CTS is not configured * for the frame. */ if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && - (tx->u.tx.rate->flags & IEEE80211_RATE_ERP_G) && - (tx->flags & IEEE80211_TXRXD_TXUNICAST) && + (tx->rate->flags & IEEE80211_RATE_ERP_G) && + (tx->flags & IEEE80211_TX_UNICAST) && tx->sdata->bss_conf.use_cts_prot && !(control->flags & IEEE80211_TXCTL_USE_RTS_CTS)) control->flags |= IEEE80211_TXCTL_USE_CTS_PROTECT; @@ -696,18 +696,18 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) * short preambles at the selected rate and short preambles are * available on the network at the current point in time. */ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && - (tx->u.tx.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && + (tx->rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) && tx->sdata->bss_conf.use_short_preamble && (!tx->sta || (tx->sta->flags & WLAN_STA_SHORT_PREAMBLE))) { - tx->u.tx.control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; + tx->control->flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; } /* Setup duration field for the first fragment of the frame. Duration * for remaining fragments will be updated when they are being sent * to low-level driver in ieee80211_tx(). */ dur = ieee80211_duration(tx, is_multicast_ether_addr(hdr->addr1), - (tx->flags & IEEE80211_TXRXD_FRAGMENTED) ? - tx->u.tx.extra_frag[0]->len : 0); + (tx->flags & IEEE80211_TX_FRAGMENTED) ? + tx->extra_frag[0]->len : 0); hdr->duration_id = cpu_to_le16(dur); if ((control->flags & IEEE80211_TXCTL_USE_RTS_CTS) || @@ -723,7 +723,7 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) control->alt_retry_rate = NULL; /* Use min(data rate, max base rate) as CTS/RTS rate */ - rate = tx->u.tx.rate; + rate = tx->rate; baserate = NULL; for (idx = 0; idx < sband->n_bitrates; idx++) { @@ -745,12 +745,12 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) tx->sta->tx_packets++; tx->sta->tx_fragments++; tx->sta->tx_bytes += tx->skb->len; - if (tx->u.tx.extra_frag) { + if (tx->extra_frag) { int i; - tx->sta->tx_fragments += tx->u.tx.num_extra_frag; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + tx->sta->tx_fragments += tx->num_extra_frag; + for (i = 0; i < tx->num_extra_frag; i++) { tx->sta->tx_bytes += - tx->u.tx.extra_frag[i]->len; + tx->extra_frag[i]->len; } } } @@ -759,13 +759,13 @@ ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) } static ieee80211_tx_result -ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) +ieee80211_tx_h_load_stats(struct ieee80211_tx_data *tx) { struct ieee80211_local *local = tx->local; struct sk_buff *skb = tx->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; u32 load = 0, hdrtime; - struct ieee80211_rate *rate = tx->u.tx.rate; + struct ieee80211_rate *rate = tx->rate; /* TODO: this could be part of tx_status handling, so that the number * of retries would be known; TX rate should in that case be stored @@ -776,8 +776,8 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, * 1 usec = 1/8 * (1080 / 10) = 13.5 */ - if (tx->u.tx.channel->band == IEEE80211_BAND_5GHZ || - (tx->u.tx.channel->band == IEEE80211_BAND_2GHZ && + if (tx->channel->band == IEEE80211_BAND_5GHZ || + (tx->channel->band == IEEE80211_BAND_2GHZ && rate->flags & IEEE80211_RATE_ERP_G)) hdrtime = CHAN_UTIL_HDR_SHORT; else @@ -787,20 +787,20 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) if (!is_multicast_ether_addr(hdr->addr1)) load += hdrtime; - if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_RTS_CTS) + if (tx->control->flags & IEEE80211_TXCTL_USE_RTS_CTS) load += 2 * hdrtime; - else if (tx->u.tx.control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) + else if (tx->control->flags & IEEE80211_TXCTL_USE_CTS_PROTECT) load += hdrtime; /* TODO: optimise again */ load += skb->len * CHAN_UTIL_RATE_LCM / rate->bitrate; - if (tx->u.tx.extra_frag) { + if (tx->extra_frag) { int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + for (i = 0; i < tx->num_extra_frag; i++) { load += 2 * hdrtime; - load += tx->u.tx.extra_frag[i]->len * - tx->u.tx.rate->bitrate; + load += tx->extra_frag[i]->len * + tx->rate->bitrate; } } @@ -815,7 +815,7 @@ ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) } -typedef ieee80211_tx_result (*ieee80211_tx_handler)(struct ieee80211_txrx_data *); +typedef ieee80211_tx_result (*ieee80211_tx_handler)(struct ieee80211_tx_data *); static ieee80211_tx_handler ieee80211_tx_handlers[] = { ieee80211_tx_h_check_assoc, @@ -838,7 +838,7 @@ static ieee80211_tx_handler ieee80211_tx_handlers[] = * with Radiotap Header -- only called for monitor mode interface */ static ieee80211_tx_result -__ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, +__ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, struct sk_buff *skb) { /* @@ -854,13 +854,13 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, (struct ieee80211_radiotap_header *) skb->data; struct ieee80211_supported_band *sband; int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); - struct ieee80211_tx_control *control = tx->u.tx.control; + struct ieee80211_tx_control *control = tx->control; sband = tx->local->hw.wiphy->bands[tx->local->hw.conf.channel->band]; control->flags |= IEEE80211_TXCTL_DO_NOT_ENCRYPT; - tx->flags |= IEEE80211_TXRXD_TX_INJECTED; - tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; + tx->flags |= IEEE80211_TX_INJECTED; + tx->flags &= ~IEEE80211_TX_FRAGMENTED; /* * for every radiotap entry that is present @@ -896,7 +896,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, r = &sband->bitrates[i]; if (r->bitrate == target_rate) { - tx->u.tx.rate = r; + tx->rate = r; break; } } @@ -934,7 +934,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, control->flags &= ~IEEE80211_TXCTL_DO_NOT_ENCRYPT; if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) - tx->flags |= IEEE80211_TXRXD_FRAGMENTED; + tx->flags |= IEEE80211_TX_FRAGMENTED; break; /* @@ -965,7 +965,7 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, * initialises @tx */ static ieee80211_tx_result -__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, +__ieee80211_tx_prepare(struct ieee80211_tx_data *tx, struct sk_buff *skb, struct net_device *dev, struct ieee80211_tx_control *control) @@ -981,12 +981,12 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, tx->dev = dev; /* use original interface */ tx->local = local; tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); - tx->u.tx.control = control; + tx->control = control; /* * Set this flag (used below to indicate "automatic fragmentation"), * it will be cleared/left by radiotap as desired. */ - tx->flags |= IEEE80211_TXRXD_FRAGMENTED; + tx->flags |= IEEE80211_TX_FRAGMENTED; /* process and remove the injection radiotap header */ sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -1007,20 +1007,20 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, tx->fc = le16_to_cpu(hdr->frame_control); if (is_multicast_ether_addr(hdr->addr1)) { - tx->flags &= ~IEEE80211_TXRXD_TXUNICAST; + tx->flags &= ~IEEE80211_TX_UNICAST; control->flags |= IEEE80211_TXCTL_NO_ACK; } else { - tx->flags |= IEEE80211_TXRXD_TXUNICAST; + tx->flags |= IEEE80211_TX_UNICAST; control->flags &= ~IEEE80211_TXCTL_NO_ACK; } - if (tx->flags & IEEE80211_TXRXD_FRAGMENTED) { - if ((tx->flags & IEEE80211_TXRXD_TXUNICAST) && + if (tx->flags & IEEE80211_TX_FRAGMENTED) { + if ((tx->flags & IEEE80211_TX_UNICAST) && skb->len + FCS_LEN > local->fragmentation_threshold && !local->ops->set_frag_threshold) - tx->flags |= IEEE80211_TXRXD_FRAGMENTED; + tx->flags |= IEEE80211_TX_FRAGMENTED; else - tx->flags &= ~IEEE80211_TXRXD_FRAGMENTED; + tx->flags &= ~IEEE80211_TX_FRAGMENTED; } if (!tx->sta) @@ -1043,7 +1043,7 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, /* * NB: @tx is uninitialised when passed in here */ -static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, +static int ieee80211_tx_prepare(struct ieee80211_tx_data *tx, struct sk_buff *skb, struct net_device *mdev, struct ieee80211_tx_control *control) @@ -1066,9 +1066,9 @@ static int ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, } static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, - struct ieee80211_txrx_data *tx) + struct ieee80211_tx_data *tx) { - struct ieee80211_tx_control *control = tx->u.tx.control; + struct ieee80211_tx_control *control = tx->control; int ret, i; if (!ieee80211_qdisc_installed(local->mdev) && @@ -1085,20 +1085,20 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, local->mdev->trans_start = jiffies; ieee80211_led_tx(local, 1); } - if (tx->u.tx.extra_frag) { + if (tx->extra_frag) { control->flags &= ~(IEEE80211_TXCTL_USE_RTS_CTS | IEEE80211_TXCTL_USE_CTS_PROTECT | IEEE80211_TXCTL_CLEAR_PS_FILT | IEEE80211_TXCTL_FIRST_FRAGMENT); - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - if (!tx->u.tx.extra_frag[i]) + for (i = 0; i < tx->num_extra_frag; i++) { + if (!tx->extra_frag[i]) continue; if (__ieee80211_queue_stopped(local, control->queue)) return IEEE80211_TX_FRAG_AGAIN; - if (i == tx->u.tx.num_extra_frag) { - control->tx_rate = tx->u.tx.last_frag_rate; + if (i == tx->num_extra_frag) { + control->tx_rate = tx->last_frag_rate; - if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG) + if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG) control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; else @@ -1108,18 +1108,18 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, ieee80211_dump_frame(wiphy_name(local->hw.wiphy), "TX to low-level driver", - tx->u.tx.extra_frag[i]); + tx->extra_frag[i]); ret = local->ops->tx(local_to_hw(local), - tx->u.tx.extra_frag[i], + tx->extra_frag[i], control); if (ret) return IEEE80211_TX_FRAG_AGAIN; local->mdev->trans_start = jiffies; ieee80211_led_tx(local, 1); - tx->u.tx.extra_frag[i] = NULL; + tx->extra_frag[i] = NULL; } - kfree(tx->u.tx.extra_frag); - tx->u.tx.extra_frag = NULL; + kfree(tx->extra_frag); + tx->extra_frag = NULL; } return IEEE80211_TX_OK; } @@ -1130,7 +1130,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; ieee80211_tx_handler *handler; - struct ieee80211_txrx_data tx; + struct ieee80211_tx_data tx; ieee80211_tx_result res = TX_DROP, res_prepare; int ret, i; @@ -1156,7 +1156,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, rcu_read_lock(); sta = tx.sta; - tx.u.tx.channel = local->hw.conf.channel; + tx.channel = local->hw.conf.channel; for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { @@ -1181,18 +1181,18 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, return 0; } - if (tx.u.tx.extra_frag) { - for (i = 0; i < tx.u.tx.num_extra_frag; i++) { + if (tx.extra_frag) { + for (i = 0; i < tx.num_extra_frag; i++) { int next_len, dur; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) - tx.u.tx.extra_frag[i]->data; + tx.extra_frag[i]->data; - if (i + 1 < tx.u.tx.num_extra_frag) { - next_len = tx.u.tx.extra_frag[i + 1]->len; + if (i + 1 < tx.num_extra_frag) { + next_len = tx.extra_frag[i + 1]->len; } else { next_len = 0; - tx.u.tx.rate = tx.u.tx.last_frag_rate; + tx.rate = tx.last_frag_rate; } dur = ieee80211_duration(&tx, 0, next_len); hdr->duration_id = cpu_to_le16(dur); @@ -1227,11 +1227,11 @@ retry: memcpy(&store->control, control, sizeof(struct ieee80211_tx_control)); store->skb = skb; - store->extra_frag = tx.u.tx.extra_frag; - store->num_extra_frag = tx.u.tx.num_extra_frag; - store->last_frag_rate = tx.u.tx.last_frag_rate; + store->extra_frag = tx.extra_frag; + store->num_extra_frag = tx.num_extra_frag; + store->last_frag_rate = tx.last_frag_rate; store->last_frag_rate_ctrl_probe = - !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG); + !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG); } rcu_read_unlock(); return 0; @@ -1239,10 +1239,10 @@ retry: drop: if (skb) dev_kfree_skb(skb); - for (i = 0; i < tx.u.tx.num_extra_frag; i++) - if (tx.u.tx.extra_frag[i]) - dev_kfree_skb(tx.u.tx.extra_frag[i]); - kfree(tx.u.tx.extra_frag); + for (i = 0; i < tx.num_extra_frag; i++) + if (tx.extra_frag[i]) + dev_kfree_skb(tx.extra_frag[i]); + kfree(tx.extra_frag); rcu_read_unlock(); return 0; } @@ -1670,7 +1670,7 @@ void ieee80211_tx_pending(unsigned long data) struct ieee80211_local *local = (struct ieee80211_local *)data; struct net_device *dev = local->mdev; struct ieee80211_tx_stored_packet *store; - struct ieee80211_txrx_data tx; + struct ieee80211_tx_data tx; int i, ret, reschedule = 0; netif_tx_lock_bh(dev); @@ -1682,13 +1682,13 @@ void ieee80211_tx_pending(unsigned long data) continue; } store = &local->pending_packet[i]; - tx.u.tx.control = &store->control; - tx.u.tx.extra_frag = store->extra_frag; - tx.u.tx.num_extra_frag = store->num_extra_frag; - tx.u.tx.last_frag_rate = store->last_frag_rate; + tx.control = &store->control; + tx.extra_frag = store->extra_frag; + tx.num_extra_frag = store->num_extra_frag; + tx.last_frag_rate = store->last_frag_rate; tx.flags = 0; if (store->last_frag_rate_ctrl_probe) - tx.flags |= IEEE80211_TXRXD_TXPROBE_LAST_FRAG; + tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG; ret = __ieee80211_tx(local, store->skb, &tx); if (ret) { if (ret == IEEE80211_TX_FRAG_AGAIN) @@ -1943,7 +1943,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct sk_buff *skb; struct sta_info *sta; ieee80211_tx_handler *handler; - struct ieee80211_txrx_data tx; + struct ieee80211_tx_data tx; ieee80211_tx_result res = TX_DROP; struct net_device *bdev; struct ieee80211_sub_if_data *sdata; @@ -1991,8 +1991,8 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, dev_kfree_skb_any(skb); } sta = tx.sta; - tx.flags |= IEEE80211_TXRXD_TXPS_BUFFERED; - tx.u.tx.channel = local->hw.conf.channel; + tx.flags |= IEEE80211_TX_PS_BUFFERED; + tx.channel = local->hw.conf.channel; for (handler = ieee80211_tx_handlers; *handler != NULL; handler++) { res = (*handler)(&tx); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index b46496fa2e10..57c404f3f6d0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -165,17 +165,17 @@ int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr) } } -void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) +void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx->skb->data; hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - if (tx->u.tx.extra_frag) { + if (tx->extra_frag) { struct ieee80211_hdr *fhdr; int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { + for (i = 0; i < tx->num_extra_frag; i++) { fhdr = (struct ieee80211_hdr *) - tx->u.tx.extra_frag[i]->data; + tx->extra_frag[i]->data; fhdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); } } diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index a33ef5cfa9ad..affcecd78c10 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -306,14 +306,14 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) } ieee80211_rx_result -ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) +ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) { if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA && ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT || (rx->fc & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_AUTH)) return RX_CONTINUE; - if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { + if (!(rx->status->flag & RX_FLAG_DECRYPTED)) { if (ieee80211_wep_decrypt(rx->local, rx->skb, rx->key)) { #ifdef CONFIG_MAC80211_DEBUG if (net_ratelimit()) @@ -322,7 +322,7 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) #endif /* CONFIG_MAC80211_DEBUG */ return RX_DROP_UNUSABLE; } - } else if (!(rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) { + } else if (!(rx->status->flag & RX_FLAG_IV_STRIPPED)) { ieee80211_wep_remove_iv(rx->local, rx->skb, rx->key); /* remove ICV */ skb_trim(rx->skb, rx->skb->len - 4); @@ -331,13 +331,13 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) return RX_CONTINUE; } -static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) +static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { if (ieee80211_wep_encrypt(tx->local, skb, tx->key)) return -1; } else { - tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; + tx->control->key_idx = tx->key->conf.hw_key_idx; if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { if (!ieee80211_wep_add_iv(tx->local, skb, tx->key)) return -1; @@ -347,21 +347,21 @@ static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) } ieee80211_tx_result -ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx) +ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx) { - tx->u.tx.control->iv_len = WEP_IV_LEN; - tx->u.tx.control->icv_len = WEP_ICV_LEN; - ieee80211_tx_set_iswep(tx); + tx->control->iv_len = WEP_IV_LEN; + tx->control->icv_len = WEP_ICV_LEN; + ieee80211_tx_set_protected(tx); if (wep_encrypt_skb(tx, tx->skb) < 0) { I802_DEBUG_INC(tx->local->tx_handlers_drop_wep); return TX_DROP; } - if (tx->u.tx.extra_frag) { + if (tx->extra_frag) { int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - if (wep_encrypt_skb(tx, tx->u.tx.extra_frag[i]) < 0) { + for (i = 0; i < tx->num_extra_frag; i++) { + if (wep_encrypt_skb(tx, tx->extra_frag[i]) < 0) { I802_DEBUG_INC(tx->local-> tx_handlers_drop_wep); return TX_DROP; diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index 43aef50cd0d6..9f723938b63f 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -29,8 +29,8 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); ieee80211_rx_result -ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx); +ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx); ieee80211_tx_result -ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx); +ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx); #endif /* WEP_H */ diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index b35e51c6ce0c..df0b7341efc8 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -71,7 +71,7 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da, ieee80211_tx_result -ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) +ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) { u8 *data, *sa, *da, *key, *mic, qos_tid; size_t data_len; @@ -90,7 +90,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) return TX_DROP; if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(tx->flags & IEEE80211_TXRXD_FRAGMENTED) && + !(tx->flags & IEEE80211_TX_FRAGMENTED) && !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) && !wpa_test) { /* hwaccel - with no need for preallocated room for Michael MIC @@ -124,7 +124,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) ieee80211_rx_result -ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) +ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) { u8 *data, *sa, *da, *key = NULL, qos_tid; size_t data_len; @@ -139,7 +139,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) /* * No way to verify the MIC if the hardware stripped it */ - if (rx->u.rx.status->flag & RX_FLAG_MMIC_STRIPPED) + if (rx->status->flag & RX_FLAG_MMIC_STRIPPED) return RX_CONTINUE; if (!rx->key || rx->key->conf.alg != ALG_TKIP || @@ -161,7 +161,7 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) ALG_TKIP_TEMP_AUTH_TX_MIC_KEY]; michael_mic(key, da, sa, qos_tid & 0x0f, data, data_len, mic); if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0 || wpa_test) { - if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) + if (!(rx->flags & IEEE80211_RX_RA_MATCH)) return RX_DROP_UNUSABLE; printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from " @@ -176,14 +176,14 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx) skb_trim(skb, skb->len - MICHAEL_MIC_LEN); /* update IV in key information to be able to detect replays */ - rx->key->u.tkip.iv32_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv32; - rx->key->u.tkip.iv16_rx[rx->u.rx.queue] = rx->u.rx.tkip_iv16; + rx->key->u.tkip.iv32_rx[rx->queue] = rx->tkip_iv32; + rx->key->u.tkip.iv16_rx[rx->queue] = rx->tkip_iv16; return RX_CONTINUE; } -static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, +static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb, int test) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -228,7 +228,7 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, 0x7f), (u8) key->u.tkip.iv16); - tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; + tx->control->key_idx = tx->key->conf.hw_key_idx; return 0; } @@ -243,30 +243,30 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, ieee80211_tx_result -ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx) +ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; int wpa_test = 0, test = 0; - tx->u.tx.control->icv_len = TKIP_ICV_LEN; - tx->u.tx.control->iv_len = TKIP_IV_LEN; - ieee80211_tx_set_iswep(tx); + tx->control->icv_len = TKIP_ICV_LEN; + tx->control->iv_len = TKIP_IV_LEN; + ieee80211_tx_set_protected(tx); if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && !wpa_test) { /* hwaccel - with no need for preallocated room for IV/ICV */ - tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; + tx->control->key_idx = tx->key->conf.hw_key_idx; return TX_CONTINUE; } if (tkip_encrypt_skb(tx, skb, test) < 0) return TX_DROP; - if (tx->u.tx.extra_frag) { + if (tx->extra_frag) { int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - if (tkip_encrypt_skb(tx, tx->u.tx.extra_frag[i], test) + for (i = 0; i < tx->num_extra_frag; i++) { + if (tkip_encrypt_skb(tx, tx->extra_frag[i], test) < 0) return TX_DROP; } @@ -277,7 +277,7 @@ ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx) ieee80211_rx_result -ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) +ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; u16 fc; @@ -295,8 +295,8 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) if (!rx->sta || skb->len - hdrlen < 12) return RX_DROP_UNUSABLE; - if (rx->u.rx.status->flag & RX_FLAG_DECRYPTED) { - if (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED) { + if (rx->status->flag & RX_FLAG_DECRYPTED) { + if (rx->status->flag & RX_FLAG_IV_STRIPPED) { /* * Hardware took care of all processing, including * replay protection, and stripped the ICV/IV so @@ -312,9 +312,9 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, key, skb->data + hdrlen, skb->len - hdrlen, rx->sta->addr, - hwaccel, rx->u.rx.queue, - &rx->u.rx.tkip_iv32, - &rx->u.rx.tkip_iv16); + hwaccel, rx->queue, + &rx->tkip_iv32, + &rx->tkip_iv16); if (res != TKIP_DECRYPT_OK || wpa_test) { #ifdef CONFIG_MAC80211_DEBUG if (net_ratelimit()) @@ -429,7 +429,7 @@ static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr) } -static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, +static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb, int test) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -478,7 +478,7 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { /* hwaccel - with preallocated room for CCMP header */ - tx->u.tx.control->key_idx = key->conf.hw_key_idx; + tx->control->key_idx = key->conf.hw_key_idx; return 0; } @@ -492,30 +492,30 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, ieee80211_tx_result -ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx) +ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; int test = 0; - tx->u.tx.control->icv_len = CCMP_MIC_LEN; - tx->u.tx.control->iv_len = CCMP_HDR_LEN; - ieee80211_tx_set_iswep(tx); + tx->control->icv_len = CCMP_MIC_LEN; + tx->control->iv_len = CCMP_HDR_LEN; + ieee80211_tx_set_protected(tx); if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { /* hwaccel - with no need for preallocated room for CCMP " * header or MIC fields */ - tx->u.tx.control->key_idx = tx->key->conf.hw_key_idx; + tx->control->key_idx = tx->key->conf.hw_key_idx; return TX_CONTINUE; } if (ccmp_encrypt_skb(tx, skb, test) < 0) return TX_DROP; - if (tx->u.tx.extra_frag) { + if (tx->extra_frag) { int i; - for (i = 0; i < tx->u.tx.num_extra_frag; i++) { - if (ccmp_encrypt_skb(tx, tx->u.tx.extra_frag[i], test) + for (i = 0; i < tx->num_extra_frag; i++) { + if (ccmp_encrypt_skb(tx, tx->extra_frag[i], test) < 0) return TX_DROP; } @@ -526,7 +526,7 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx) ieee80211_rx_result -ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) +ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; u16 fc; @@ -547,15 +547,15 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) if (!rx->sta || data_len < 0) return RX_DROP_UNUSABLE; - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) + if ((rx->status->flag & RX_FLAG_DECRYPTED) && + (rx->status->flag & RX_FLAG_IV_STRIPPED)) return RX_CONTINUE; (void) ccmp_hdr2pn(pn, skb->data + hdrlen); - if (memcmp(pn, key->u.ccmp.rx_pn[rx->u.rx.queue], CCMP_PN_LEN) <= 0) { + if (memcmp(pn, key->u.ccmp.rx_pn[rx->queue], CCMP_PN_LEN) <= 0) { #ifdef CONFIG_MAC80211_DEBUG - u8 *ppn = key->u.ccmp.rx_pn[rx->u.rx.queue]; + u8 *ppn = key->u.ccmp.rx_pn[rx->queue]; printk(KERN_DEBUG "%s: CCMP replay detected for RX frame from " "%s (RX PN %02x%02x%02x%02x%02x%02x <= prev. PN " @@ -568,7 +568,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) return RX_DROP_UNUSABLE; } - if (!(rx->u.rx.status->flag & RX_FLAG_DECRYPTED)) { + if (!(rx->status->flag & RX_FLAG_DECRYPTED)) { /* hardware didn't decrypt/verify MIC */ u8 *scratch, *b_0, *aad; @@ -593,7 +593,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) } } - memcpy(key->u.ccmp.rx_pn[rx->u.rx.queue], pn, CCMP_PN_LEN); + memcpy(key->u.ccmp.rx_pn[rx->queue], pn, CCMP_PN_LEN); /* Remove CCMP header and MIC */ skb_trim(skb, skb->len - CCMP_MIC_LEN); diff --git a/net/mac80211/wpa.h b/net/mac80211/wpa.h index 16e4dba4aa70..d42d221d8a1d 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h @@ -14,18 +14,18 @@ #include "ieee80211_i.h" ieee80211_tx_result -ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx); +ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx); ieee80211_rx_result -ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx); +ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx); ieee80211_tx_result -ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx); +ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx); ieee80211_rx_result -ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx); +ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx); ieee80211_tx_result -ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx); +ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx); ieee80211_rx_result -ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx); +ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx); #endif /* WPA_H */ -- cgit v1.2.3-59-g8ed1b From d0709a65181beb787ef3f58cfe45536a2bb254c8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 16:27:46 +0100 Subject: mac80211: RCU-ify STA info structure access This makes access to the STA hash table/list use RCU to protect against freeing of items. However, it's not a true RCU, the copy step is missing: whenever somebody changes a STA item it is simply updated. This is an existing race condition that is now somewhat understandable. This patch also fixes the race key freeing vs. STA destruction by making sure that sta_info_destroy() is always called under RTNL and frees the key. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 31 ++- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 27 +- net/mac80211/cfg.c | 110 ++++---- net/mac80211/debugfs_sta.c | 4 +- net/mac80211/debugfs_sta.h | 2 + net/mac80211/ieee80211.c | 78 ++++-- net/mac80211/ieee80211_i.h | 13 +- net/mac80211/ieee80211_iface.c | 11 +- net/mac80211/ieee80211_ioctl.c | 42 ++-- net/mac80211/ieee80211_rate.c | 8 +- net/mac80211/ieee80211_rate.h | 1 + net/mac80211/ieee80211_sta.c | 123 ++++++--- net/mac80211/key.c | 8 +- net/mac80211/mesh.c | 5 +- net/mac80211/mesh.h | 16 +- net/mac80211/mesh_hwmp.c | 6 +- net/mac80211/mesh_pathtbl.c | 30 ++- net/mac80211/mesh_plink.c | 101 ++++---- net/mac80211/rc80211_pid_algo.c | 25 +- net/mac80211/rc80211_simple.c | 18 +- net/mac80211/rx.c | 24 +- net/mac80211/sta_info.c | 387 ++++++++++++++++++----------- net/mac80211/sta_info.h | 61 +++-- net/mac80211/tx.c | 48 ++-- net/mac80211/wme.c | 8 +- 25 files changed, 701 insertions(+), 486 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index a8223c4cc97c..c4bfba6f3c2b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -471,10 +471,11 @@ static void rs_tx_status(void *priv_rate, return; } + rcu_read_lock(); + sta = sta_info_get(local, hdr->addr1); if (!sta || !sta->rate_ctrl_priv) { - if (sta) - sta_info_put(sta); + rcu_read_unlock(); IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); return; } @@ -547,7 +548,7 @@ static void rs_tx_status(void *priv_rate, spin_unlock_irqrestore(&rs_sta->lock, flags); - sta_info_put(sta); + rcu_read_unlock(); IWL_DEBUG_RATE("leave\n"); @@ -658,6 +659,8 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, IWL_DEBUG_RATE("enter\n"); + rcu_read_lock(); + sta = sta_info_get(local, hdr->addr1); /* Send management frames and broadcast/multicast data using lowest @@ -668,8 +671,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, !sta || !sta->rate_ctrl_priv) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); sel->rate = rate_lowest(local, band, sta); - if (sta) - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -811,7 +813,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, else sta->txrate_idx = sta->last_txrate_idx; - sta_info_put(sta); + rcu_read_unlock(); IWL_DEBUG_RATE("leave: %d\n", index); @@ -843,13 +845,15 @@ int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) unsigned long now = jiffies; u32 max_time = 0; + rcu_read_lock(); + sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); if (!sta || !sta->rate_ctrl_priv) { - if (sta) { - sta_info_put(sta); + if (sta) IWL_DEBUG_RATE("leave - no private rate data!\n"); - } else + else IWL_DEBUG_RATE("leave - no station!\n"); + rcu_read_unlock(); return sprintf(buf, "station %d not found\n", sta_id); } @@ -890,7 +894,7 @@ int iwl3945_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) i = j; } spin_unlock_irqrestore(&rs_sta->lock, flags); - sta_info_put(sta); + rcu_read_unlock(); /* Display the average rate of all samples taken. * @@ -927,11 +931,12 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) return; } + rcu_read_lock(); + sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); if (!sta || !sta->rate_ctrl_priv) { - if (sta) - sta_info_put(sta); IWL_DEBUG_RATE("leave - no private rate data!\n"); + rcu_read_unlock(); return; } @@ -958,7 +963,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) break; } - sta_info_put(sta); + rcu_read_unlock(); spin_unlock_irqrestore(&rs_sta->lock, flags); rssi = priv->last_rx_rssi; diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 48a6a85355ec..46d85fd07faa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -847,12 +847,12 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, if (retries > 15) retries = 15; + rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); if (!sta || !sta->rate_ctrl_priv) { - if (sta) - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -891,7 +891,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, if ((rs_index < 0) || (rs_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("bad rate index at: %d rate 0x%X\n", rs_index, tx_mcs.rate_n_flags); - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -909,7 +909,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, IWL_DEBUG_RATE("initial rate does not match 0x%x 0x%x\n", tx_mcs.rate_n_flags, le32_to_cpu(table->rs_table[0].rate_n_flags)); - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -1025,7 +1025,7 @@ static void rs_tx_status(void *priv_rate, struct net_device *dev, /* See if there's a better rate or modulation mode to try. */ rs_rate_scale_perform(priv, dev, hdr, sta); - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -2219,6 +2219,8 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); + rcu_read_lock(); + sta = sta_info_get(local, hdr->addr1); /* Send management frames and broadcast/multicast data using lowest @@ -2227,8 +2229,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || !sta || !sta->rate_ctrl_priv) { sel->rate = rate_lowest(local, sband, sta); - if (sta) - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -2261,7 +2262,7 @@ static void rs_get_rate(void *priv_rate, struct net_device *dev, sel->rate = rate_lowest(local, sband, sta); return; } - sta_info_put(sta); + rcu_read_unlock(); sel->rate = &priv->ieee_rates[i]; } @@ -2735,13 +2736,15 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) u32 max_time = 0; u8 lq_type, antenna; + rcu_read_lock(); + sta = sta_info_get(local, priv->stations[sta_id].sta.sta.addr); if (!sta || !sta->rate_ctrl_priv) { - if (sta) { - sta_info_put(sta); + if (sta) IWL_DEBUG_RATE("leave - no private rate data!\n"); - } else + else IWL_DEBUG_RATE("leave - no station!\n"); + rcu_read_unlock(); return sprintf(buf, "station %d not found\n", sta_id); } @@ -2808,7 +2811,7 @@ int iwl4965_fill_rs_info(struct ieee80211_hw *hw, char *buf, u8 sta_id) "active_search %d rate index %d\n", lq_type, antenna, lq_sta->search_better_tbl, sta->last_txrate_idx); - sta_info_put(sta); + rcu_read_unlock(); return cnt; } diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6ac49231efa9..e9ba6fcc0e45 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -136,7 +136,6 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_sub_if_data *sdata; struct sta_info *sta = NULL; enum ieee80211_key_alg alg; - int ret; struct ieee80211_key *key; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -170,12 +169,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, ieee80211_key_link(key, sdata, sta); - ret = 0; - - if (sta) - sta_info_put(sta); - - return ret; + return 0; } static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, @@ -184,7 +178,6 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_sub_if_data *sdata; struct sta_info *sta; int ret; - struct ieee80211_key *key; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -195,21 +188,18 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, ret = 0; if (sta->key) { - key = sta->key; - ieee80211_key_free(key); + ieee80211_key_free(sta->key); WARN_ON(sta->key); } else ret = -ENOENT; - sta_info_put(sta); return ret; } if (!sdata->keys[key_idx]) return -ENOENT; - key = sdata->keys[key_idx]; - ieee80211_key_free(key); + ieee80211_key_free(sdata->keys[key_idx]); WARN_ON(sdata->keys[key_idx]); return 0; @@ -292,8 +282,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, err = 0; out: - if (sta) - sta_info_put(sta); return err; } @@ -311,7 +299,7 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + struct ieee80211_sub_if_data *sdata = sta->sdata; sinfo->filled = STATION_INFO_INACTIVE_TIME | STATION_INFO_RX_BYTES | @@ -340,16 +328,20 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; + int ret = -ENOENT; + + rcu_read_lock(); sta = sta_info_get_by_idx(local, idx, dev); - if (!sta) - return -ENOENT; + if (sta) { + ret = 0; + memcpy(mac, sta->addr, ETH_ALEN); + sta_set_sinfo(sta, sinfo); + } - memcpy(mac, sta->addr, ETH_ALEN); - sta_set_sinfo(sta, sinfo); - sta_info_put(sta); + rcu_read_unlock(); - return 0; + return ret; } static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, @@ -357,16 +349,21 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; + int ret = -ENOENT; - sta = sta_info_get(local, mac); - if (!sta) - return -ENOENT; + rcu_read_lock(); /* XXX: verify sta->dev == dev */ - sta_set_sinfo(sta, sinfo); - sta_info_put(sta); - return 0; + sta = sta_info_get(local, mac); + if (sta) { + ret = 0; + sta_set_sinfo(sta, sinfo); + } + + rcu_read_unlock(); + + return ret; } /* @@ -559,8 +556,8 @@ static void ieee80211_send_layer2_update(struct sta_info *sta) msg->xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */ msg->xid_info[2] = 0; /* XID sender's receive window size (RW) */ - skb->dev = sta->dev; - skb->protocol = eth_type_trans(skb, sta->dev); + skb->dev = sta->sdata->dev; + skb->protocol = eth_type_trans(skb, sta->sdata->dev); memset(skb->cb, 0, sizeof(skb->cb)); netif_rx(skb); } @@ -572,7 +569,7 @@ static void sta_apply_parameters(struct ieee80211_local *local, u32 rates; int i, j; struct ieee80211_supported_band *sband; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + struct ieee80211_sub_if_data *sdata = sta->sdata; if (params->station_flags & STATION_FLAG_CHANGED) { sta->flags &= ~WLAN_STA_AUTHORIZED; @@ -644,14 +641,13 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (ieee80211_vif_is_mesh(&sdata->vif)) - sta = mesh_plink_add(mac, DEFAULT_RATES, dev); + sta = mesh_plink_add(mac, DEFAULT_RATES, sdata); else - sta = sta_info_add(local, dev, mac, GFP_KERNEL); + sta = sta_info_add(sdata, mac); if (IS_ERR(sta)) return PTR_ERR(sta); - sta->dev = sdata->dev; if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || sdata->vif.type == IEEE80211_IF_TYPE_AP) ieee80211_send_layer2_update(sta); @@ -662,15 +658,14 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, rate_control_rate_init(sta, local); - sta_info_put(sta); - return 0; } static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; if (mac) { @@ -679,10 +674,14 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, if (!sta) return -ENOENT; - sta_info_free(sta); - sta_info_put(sta); + sta_info_unlink(&sta); + + if (sta) { + synchronize_rcu(); + sta_info_destroy(sta); + } } else - sta_info_flush(local, dev); + sta_info_flush(local, sdata); return 0; } @@ -701,21 +700,19 @@ static int ieee80211_change_station(struct wiphy *wiphy, if (!sta) return -ENOENT; - if (params->vlan && params->vlan != sta->dev) { + if (params->vlan && params->vlan != sta->sdata->dev) { vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN || vlansdata->vif.type != IEEE80211_IF_TYPE_AP) return -EINVAL; - sta->dev = params->vlan; + sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); ieee80211_send_layer2_update(sta); } sta_apply_parameters(local, sta, params); - sta_info_put(sta); - return 0; } @@ -735,23 +732,26 @@ static int ieee80211_add_mpath(struct wiphy *wiphy, struct net_device *dev, if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) return -ENOTSUPP; + rcu_read_lock(); sta = sta_info_get(local, next_hop); - if (!sta) + if (!sta) { + rcu_read_unlock(); return -ENOENT; + } err = mesh_path_add(dst, dev); - if (err) + if (err) { + rcu_read_unlock(); return err; + } - rcu_read_lock(); mpath = mesh_path_lookup(dst, dev); if (!mpath) { rcu_read_unlock(); - sta_info_put(sta); return -ENXIO; } mesh_path_fix_nexthop(mpath, sta); - sta_info_put(sta); + rcu_read_unlock(); return 0; } @@ -760,7 +760,7 @@ static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev, u8 *dst) { if (dst) - return mesh_path_del(dst, dev); + return mesh_path_del(dst, dev, false); mesh_path_flush(dev); return 0; @@ -781,20 +781,22 @@ static int ieee80211_change_mpath(struct wiphy *wiphy, if (sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) return -ENOTSUPP; + rcu_read_lock(); + sta = sta_info_get(local, next_hop); - if (!sta) + if (!sta) { + rcu_read_unlock(); return -ENOENT; + } - rcu_read_lock(); mpath = mesh_path_lookup(dst, dev); if (!mpath) { rcu_read_unlock(); - sta_info_put(sta); return -ENOENT; } mesh_path_fix_nexthop(mpath, sta); - sta_info_put(sta); + rcu_read_unlock(); return 0; } diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index ed7c9f3b4602..73cfb4da464d 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -51,7 +51,7 @@ static const struct file_operations sta_ ##name## _ops = { \ STA_OPS(name) STA_FILE(aid, aid, D); -STA_FILE(dev, dev->name, S); +STA_FILE(dev, sdata->dev->name, S); STA_FILE(rx_packets, rx_packets, LU); STA_FILE(tx_packets, tx_packets, LU); STA_FILE(rx_bytes, rx_bytes, LU); @@ -200,7 +200,7 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct sta_info *sta = file->private_data; - struct net_device *dev = sta->dev; + struct net_device *dev = sta->sdata->dev; struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_hw *hw = &local->hw; u8 *da = sta->addr; diff --git a/net/mac80211/debugfs_sta.h b/net/mac80211/debugfs_sta.h index 574a1cd54b96..8b608903259f 100644 --- a/net/mac80211/debugfs_sta.h +++ b/net/mac80211/debugfs_sta.h @@ -1,6 +1,8 @@ #ifndef __MAC80211_DEBUGFS_STA_H #define __MAC80211_DEBUGFS_STA_H +#include "sta_info.h" + #ifdef CONFIG_MAC80211_DEBUGFS void ieee80211_sta_debugfs_add(struct sta_info *sta); void ieee80211_sta_debugfs_remove(struct sta_info *sta); diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 727af295c969..85b1391375c0 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -375,15 +375,19 @@ static int ieee80211_stop(struct net_device *dev) sdata = IEEE80211_DEV_TO_SUB_IF(dev); - list_for_each_entry(sta, &local->sta_list, list) { - if (sta->dev == dev) + rcu_read_lock(); + + list_for_each_entry_rcu(sta, &local->sta_list, list) { + if (sta->sdata == sdata) for (i = 0; i < STA_TID_NUM; i++) - ieee80211_sta_stop_rx_ba_session(sta->dev, + ieee80211_sta_stop_rx_ba_session(sdata->dev, sta->addr, i, WLAN_BACK_RECIPIENT, WLAN_REASON_QSTA_LEAVE_QBSS); } + rcu_read_unlock(); + netif_stop_queue(dev); /* @@ -449,7 +453,7 @@ static int ieee80211_stop(struct net_device *dev) netif_tx_unlock_bh(local->mdev); break; case IEEE80211_IF_TYPE_MESH_POINT: - sta_info_flush(local, dev); + sta_info_flush(local, sdata); /* fall through */ case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: @@ -522,9 +526,12 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) print_mac(mac, ra), tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ + rcu_read_lock(); + sta = sta_info_get(local, ra); if (!sta) { printk(KERN_DEBUG "Could not find the station\n"); + rcu_read_unlock(); return -ENOENT; } @@ -564,7 +571,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) spin_unlock_bh(&local->mdev->queue_lock); goto start_ba_exit; } - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + sdata = sta->sdata; /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the * call back right away, it must see that the flow has begun */ @@ -601,7 +608,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) sta->ampdu_mlme.dialog_token_allocator; sta->ampdu_mlme.tid_tx[tid].ssn = start_seq_num; - ieee80211_send_addba_request(sta->dev, ra, tid, + ieee80211_send_addba_request(sta->sdata->dev, ra, tid, sta->ampdu_mlme.tid_tx[tid].dialog_token, sta->ampdu_mlme.tid_tx[tid].ssn, 0x40, 5000); @@ -614,7 +621,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) start_ba_exit: spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - sta_info_put(sta); + rcu_read_unlock(); return ret; } EXPORT_SYMBOL(ieee80211_start_tx_ba_session); @@ -637,9 +644,12 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, print_mac(mac, ra), tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ + rcu_read_lock(); sta = sta_info_get(local, ra); - if (!sta) + if (!sta) { + rcu_read_unlock(); return -ENOENT; + } /* check if the TID is in aggregation */ state = &sta->ampdu_mlme.tid_tx[tid].state; @@ -673,7 +683,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, stop_BA_exit: spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - sta_info_put(sta); + rcu_read_unlock(); return ret; } EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); @@ -691,8 +701,10 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) return; } + rcu_read_lock(); sta = sta_info_get(local, ra); if (!sta) { + rcu_read_unlock(); printk(KERN_DEBUG "Could not find station: %s\n", print_mac(mac, ra)); return; @@ -705,7 +717,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", *state); spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -718,7 +730,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); } spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - sta_info_put(sta); + rcu_read_unlock(); } EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); @@ -739,10 +751,12 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n", print_mac(mac, ra), tid); + rcu_read_lock(); sta = sta_info_get(local, ra); if (!sta) { printk(KERN_DEBUG "Could not find station: %s\n", print_mac(mac, ra)); + rcu_read_unlock(); return; } state = &sta->ampdu_mlme.tid_tx[tid].state; @@ -750,13 +764,13 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); - sta_info_put(sta); spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + rcu_read_unlock(); return; } if (*state & HT_AGG_STATE_INITIATOR_MSK) - ieee80211_send_delba(sta->dev, ra, tid, + ieee80211_send_delba(sta->sdata->dev, ra, tid, WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); agg_queue = sta->tid_to_tx_q[tid]; @@ -777,7 +791,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0; spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - sta_info_put(sta); + rcu_read_unlock(); } EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); @@ -887,32 +901,41 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) struct sta_info *sta; DECLARE_MAC_BUF(mac); + might_sleep(); + if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) return 0; + rcu_read_lock(); + /* Create STA entry for the new peer */ - sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); - if (IS_ERR(sta)) + sta = sta_info_add(sdata, remote_addr); + if (IS_ERR(sta)) { + rcu_read_unlock(); return PTR_ERR(sta); + } sta->flags |= WLAN_STA_AUTHORIZED; - sta_info_put(sta); - /* Remove STA entry for the old peer */ sta = sta_info_get(local, sdata->u.wds.remote_addr); - if (sta) { - sta_info_free(sta); - sta_info_put(sta); - } else { + if (sta) + sta_info_unlink(&sta); + else printk(KERN_DEBUG "%s: could not find STA entry for WDS link " "peer %s\n", dev->name, print_mac(mac, sdata->u.wds.remote_addr)); - } /* Update WDS link data */ memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN); + rcu_read_unlock(); + + if (sta) { + synchronize_rcu(); + sta_info_destroy(sta); + } + return 0; } @@ -1330,6 +1353,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, return; } + rcu_read_lock(); + if (status->excessive_retries) { struct sta_info *sta; sta = sta_info_get(local, hdr->addr1); @@ -1343,10 +1368,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, status->flags |= IEEE80211_TX_STATUS_TX_FILTERED; ieee80211_handle_filtered_frame(local, sta, skb, status); - sta_info_put(sta); + rcu_read_unlock(); return; } - sta_info_put(sta); } } @@ -1356,12 +1380,14 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, if (sta) { ieee80211_handle_filtered_frame(local, sta, skb, status); - sta_info_put(sta); + rcu_read_unlock(); return; } } else rate_control_tx_status(local->mdev, skb, status); + rcu_read_unlock(); + ieee80211_led_tx(local, 0); /* SNMP counters diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d3b5cc57af40..8e440c5706dd 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -574,6 +574,7 @@ struct ieee80211_local { unsigned int filter_flags; /* FIF_* */ struct iw_statistics wstats; u8 wstats_flags; + bool tim_in_locked_section; /* see ieee80211_beacon_get() */ int tx_headroom; /* required headroom for hardware/radiotap */ enum { @@ -591,9 +592,15 @@ struct ieee80211_local { struct sk_buff_head skb_queue; struct sk_buff_head skb_queue_unreliable; - /* Station data structures */ - rwlock_t sta_lock; /* protects STA data structures */ - int num_sta; /* number of stations in sta_list */ + /* Station data */ + /* + * The lock only protects the list, hash, timer and counter + * against manipulation, reads are done in RCU. Additionally, + * the lock protects each BSS's TIM bitmap and a few items + * in a STA info structure. + */ + spinlock_t sta_lock; + unsigned long num_sta; struct list_head sta_list; struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index b0f17a2b1a42..98b22736e883 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -240,16 +240,21 @@ void ieee80211_if_reinit(struct net_device *dev) break; } case IEEE80211_IF_TYPE_WDS: + rcu_read_lock(); sta = sta_info_get(local, sdata->u.wds.remote_addr); if (sta) { - sta_info_free(sta); - sta_info_put(sta); + sta_info_unlink(&sta); } else { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Someone had deleted my STA " "entry for the WDS link\n", dev->name); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ } + rcu_read_unlock(); + if (sta) { + synchronize_rcu(); + sta_info_destroy(sta); + } break; case IEEE80211_IF_TYPE_MESH_POINT: case IEEE80211_IF_TYPE_STA: @@ -275,7 +280,7 @@ void ieee80211_if_reinit(struct net_device *dev) } /* remove all STAs that are bound to this virtual interface */ - sta_info_flush(local, dev); + sta_info_flush(local, sdata); memset(&sdata->u, 0, sizeof(sdata->u)); ieee80211_if_sdata_init(sdata); diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 38e2d83e15f4..5147152b9268 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -33,8 +33,7 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, size_t key_len) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int ret; - struct sta_info *sta = NULL; + struct sta_info *sta; struct ieee80211_key *key; struct ieee80211_sub_if_data *sdata; @@ -51,24 +50,23 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, key = sdata->keys[idx]; } else { sta = sta_info_get(local, sta_addr); - if (!sta) { - ret = -ENOENT; - key = NULL; - goto err_out; - } - + if (!sta) + return -ENOENT; key = sta->key; } if (!key) - ret = -ENOENT; - else - ret = 0; + return -ENOENT; + + ieee80211_key_free(key); + return 0; } else { key = ieee80211_key_alloc(alg, idx, key_len, _key); if (!key) return -ENOMEM; + sta = NULL; + if (!is_broadcast_ether_addr(sta_addr)) { set_tx_key = 0; /* @@ -78,14 +76,14 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, * work around this. */ if (idx != 0 && alg != ALG_WEP) { - ret = -EINVAL; - goto err_out; + ieee80211_key_free(key); + return -EINVAL; } sta = sta_info_get(local, sta_addr); if (!sta) { - ret = -ENOENT; - goto err_out; + ieee80211_key_free(key); + return -ENOENT; } } @@ -93,18 +91,9 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, if (set_tx_key || (!sta && !sdata->default_key && key)) ieee80211_set_default_key(sdata, idx); - - /* don't free key later */ - key = NULL; - - ret = 0; } - err_out: - if (sta) - sta_info_put(sta); - ieee80211_key_free(key); - return ret; + return 0; } static int ieee80211_ioctl_siwgenie(struct net_device *dev, @@ -625,7 +614,7 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, else rate->value = 0; rate->value *= 100000; - sta_info_put(sta); + return 0; } @@ -1000,7 +989,6 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev wstats->qual.qual = sta->last_signal; wstats->qual.noise = sta->last_noise; wstats->qual.updated = local->wstats_flags; - sta_info_put(sta); } return wstats; } diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c index ebe29b716b27..4de06f128d90 100644 --- a/net/mac80211/ieee80211_rate.c +++ b/net/mac80211/ieee80211_rate.c @@ -170,9 +170,12 @@ void rate_control_get_rate(struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct rate_control_ref *ref = local->rate_ctrl; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct sta_info *sta = sta_info_get(local, hdr->addr1); + struct sta_info *sta; int i; + rcu_read_lock(); + sta = sta_info_get(local, hdr->addr1); + memset(sel, 0, sizeof(struct rate_selection)); ref->ops->get_rate(ref->priv, dev, sband, skb, sel); @@ -190,8 +193,7 @@ void rate_control_get_rate(struct net_device *dev, } } - if (sta) - sta_info_put(sta); + rcu_read_unlock(); } struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h index 5f9a2ca49a57..bfd0a1982e4a 100644 --- a/net/mac80211/ieee80211_rate.h +++ b/net/mac80211/ieee80211_rate.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "ieee80211_i.h" #include "sta_info.h" diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 9f933aeca719..a3e96eb59eb0 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -845,6 +846,8 @@ static void ieee80211_associated(struct net_device *dev, ifsta->state = IEEE80211_ASSOCIATED; + rcu_read_lock(); + sta = sta_info_get(local, ifsta->bssid); if (!sta) { printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", @@ -860,7 +863,7 @@ static void ieee80211_associated(struct net_device *dev, "range\n", dev->name, print_mac(mac, ifsta->bssid)); disassoc = 1; - sta_info_free(sta); + sta_info_unlink(&sta); } else ieee80211_send_probe_req(dev, ifsta->bssid, local->scan_ssid, @@ -876,8 +879,17 @@ static void ieee80211_associated(struct net_device *dev, ifsta->ssid_len); } } - sta_info_put(sta); } + + rcu_read_unlock(); + + if (disassoc && sta) { + synchronize_rcu(); + rtnl_lock(); + sta_info_destroy(sta); + rtnl_unlock(); + } + if (disassoc) { ifsta->state = IEEE80211_DISABLED; ieee80211_set_associated(dev, ifsta, 0); @@ -1103,9 +1115,13 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, int ret = -EOPNOTSUPP; DECLARE_MAC_BUF(mac); + rcu_read_lock(); + sta = sta_info_get(local, mgmt->sa); - if (!sta) + if (!sta) { + rcu_read_unlock(); return; + } /* extract session parameters from addba request frame */ dialog_token = mgmt->u.action.u.addba_req.dialog_token; @@ -1197,9 +1213,9 @@ end: spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); end_no_lock: - ieee80211_send_addba_resp(sta->dev, sta->addr, tid, dialog_token, - status, 1, buf_size, timeout); - sta_info_put(sta); + ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid, + dialog_token, status, 1, buf_size, timeout); + rcu_read_unlock(); } static void ieee80211_sta_process_addba_resp(struct net_device *dev, @@ -1213,9 +1229,13 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, u16 tid; u8 *state; + rcu_read_lock(); + sta = sta_info_get(local, mgmt->sa); - if (!sta) + if (!sta) { + rcu_read_unlock(); return; + } capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; @@ -1230,7 +1250,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -1244,7 +1264,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" "%d\n", *state); - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -1271,7 +1291,7 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, ieee80211_stop_tx_ba_session(hw, sta->addr, tid, WLAN_BACK_INITIATOR); } - sta_info_put(sta); + rcu_read_unlock(); } void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, @@ -1326,16 +1346,20 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, struct sta_info *sta; int ret, i; + rcu_read_lock(); + sta = sta_info_get(local, ra); - if (!sta) + if (!sta) { + rcu_read_unlock(); return; + } /* check if TID is in operational state */ spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); if (sta->ampdu_mlme.tid_rx[tid].state != HT_AGG_STATE_OPERATIONAL) { spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); - sta_info_put(sta); + rcu_read_unlock(); return; } sta->ampdu_mlme.tid_rx[tid].state = @@ -1374,7 +1398,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf); sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE; - sta_info_put(sta); + rcu_read_unlock(); } @@ -1387,9 +1411,13 @@ static void ieee80211_sta_process_delba(struct net_device *dev, u16 initiator; DECLARE_MAC_BUF(mac); + rcu_read_lock(); + sta = sta_info_get(local, mgmt->sa); - if (!sta) + if (!sta) { + rcu_read_unlock(); return; + } params = le16_to_cpu(mgmt->u.action.u.delba.params); tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; @@ -1414,7 +1442,7 @@ static void ieee80211_sta_process_delba(struct net_device *dev, ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, WLAN_BACK_RECIPIENT); } - sta_info_put(sta); + rcu_read_unlock(); } /* @@ -1437,9 +1465,13 @@ void sta_addba_resp_timer_expired(unsigned long data) struct sta_info *sta; u8 *state; + rcu_read_lock(); + sta = sta_info_get(local, temp_sta->addr); - if (!sta) + if (!sta) { + rcu_read_unlock(); return; + } state = &sta->ampdu_mlme.tid_tx[tid].state; /* check if the TID waits for addBA response */ @@ -1461,7 +1493,7 @@ void sta_addba_resp_timer_expired(unsigned long data) WLAN_BACK_INITIATOR); timer_expired_exit: - sta_info_put(sta); + rcu_read_unlock(); } /* @@ -1481,8 +1513,8 @@ void sta_rx_agg_session_timer_expired(unsigned long data) timer_to_tid[0]); printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); - ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, (u16)*ptid, - WLAN_BACK_TIMER, + ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr, + (u16)*ptid, WLAN_BACK_TIMER, WLAN_REASON_QSTA_TIMEOUT); } @@ -1791,14 +1823,18 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (ifsta->assocresp_ies) memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); + rcu_read_lock(); + /* Add STA entry for the AP */ sta = sta_info_get(local, ifsta->bssid); if (!sta) { struct ieee80211_sta_bss *bss; - sta = sta_info_add(local, dev, ifsta->bssid, GFP_KERNEL); + + sta = sta_info_add(sdata, ifsta->bssid); if (IS_ERR(sta)) { printk(KERN_DEBUG "%s: failed to add STA entry for the" " AP (error %ld)\n", dev->name, PTR_ERR(sta)); + rcu_read_unlock(); return; } bss = ieee80211_rx_bss_get(dev, ifsta->bssid, @@ -1812,7 +1848,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, } } - sta->dev = dev; sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | WLAN_STA_AUTHORIZED; @@ -1883,7 +1918,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, bss_conf->aid = aid; ieee80211_set_associated(dev, ifsta, 1); - sta_info_put(sta); + rcu_read_unlock(); ieee80211_associated(dev, ifsta); } @@ -2329,6 +2364,8 @@ static void ieee80211_rx_bss_info(struct net_device *dev, mesh_peer_accepts_plinks(&elems, dev)); } + rcu_read_lock(); + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && (sta = sta_info_get(local, mgmt->sa))) { @@ -2354,9 +2391,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, (unsigned long long) supp_rates, (unsigned long long) sta->supp_rates[rx_status->band]); } - sta_info_put(sta); } + rcu_read_unlock(); + if (elems.ds_params && elems.ds_params_len == 1) freq = ieee80211_channel_to_frequency(elems.ds_params[0]); else @@ -2550,8 +2588,10 @@ static void ieee80211_rx_bss_info(struct net_device *dev, "local TSF - IBSS merge with BSSID %s\n", dev->name, print_mac(mac, mgmt->bssid)); ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); + rcu_read_lock(); ieee80211_ibss_add_sta(dev, NULL, mgmt->bssid, mgmt->sa); + rcu_read_unlock(); } } @@ -2893,17 +2933,20 @@ static int ieee80211_sta_active_ibss(struct net_device *dev) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int active = 0; struct sta_info *sta; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - read_lock_bh(&local->sta_lock); - list_for_each_entry(sta, &local->sta_list, list) { - if (sta->dev == dev && + rcu_read_lock(); + + list_for_each_entry_rcu(sta, &local->sta_list, list) { + if (sta->sdata == sdata && time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, jiffies)) { active++; break; } } - read_unlock_bh(&local->sta_lock); + + rcu_read_unlock(); return active; } @@ -2915,22 +2958,25 @@ static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time) struct sta_info *sta, *tmp; LIST_HEAD(tmp_list); DECLARE_MAC_BUF(mac); + unsigned long flags; - write_lock_bh(&local->sta_lock); + spin_lock_irqsave(&local->sta_lock, flags); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) if (time_after(jiffies, sta->last_rx + exp_time)) { printk(KERN_DEBUG "%s: expiring inactive STA %s\n", dev->name, print_mac(mac, sta->addr)); - __sta_info_get(sta); - sta_info_remove(sta); - list_add(&sta->list, &tmp_list); + sta_info_unlink(&sta); + if (sta) + list_add(&sta->list, &tmp_list); } - write_unlock_bh(&local->sta_lock); + spin_unlock_irqrestore(&local->sta_lock, flags); - list_for_each_entry_safe(sta, tmp, &tmp_list, list) { - sta_info_free(sta); - sta_info_put(sta); - } + synchronize_rcu(); + + rtnl_lock(); + list_for_each_entry_safe(sta, tmp, &tmp_list, list) + sta_info_destroy(sta); + rtnl_unlock(); } @@ -3977,6 +4023,7 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len) } +/* must be called under RCU read lock */ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, struct sk_buff *skb, u8 *bssid, u8 *addr) @@ -3999,7 +4046,7 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); - sta = sta_info_add(local, dev, addr, GFP_ATOMIC); + sta = sta_info_add(sdata, addr); if (IS_ERR(sta)) return NULL; @@ -4010,7 +4057,7 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, rate_control_rate_init(sta, local); - return sta; /* caller will call sta_info_put() */ + return sta; } diff --git a/net/mac80211/key.c b/net/mac80211/key.c index eac9c59dbc4d..df0c04cedbe4 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -240,14 +240,17 @@ void ieee80211_key_link(struct ieee80211_key *key, if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { struct sta_info *ap; + rcu_read_lock(); + /* same here, the AP could be using QoS */ ap = sta_info_get(key->local, key->sdata->u.sta.bssid); if (ap) { if (ap->flags & WLAN_STA_WME) key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; - sta_info_put(ap); } + + rcu_read_unlock(); } } @@ -290,6 +293,9 @@ void ieee80211_key_free(struct ieee80211_key *key) __ieee80211_key_replace(key->sdata, key->sta, key, NULL); + /* + * Do NOT remove this without looking at sta_info_destroy() + */ synchronize_rcu(); /* diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index ebe1a7a80bad..9de1ccc11cf9 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -83,11 +83,10 @@ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie, /** * mesh_accept_plinks_update: update accepting_plink in local mesh beacons * - * @dev: mesh interface in which mesh beacons are going to be updated + * @sdata: mesh interface in which mesh beacons are going to be updated */ -void mesh_accept_plinks_update(struct net_device *dev) +void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); bool free_plinks; /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0, diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index d565b3fb9e6a..576eee83d859 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -65,9 +65,10 @@ enum mesh_path_flags { * @state_lock: mesh pat state lock * * - * The combination of dst and dev is unique in the mesh path table. A reference - * to the next_hop sta will be kept and in case this sta is removed, the - * mesh_path structure must be also removed or substitued in a rcu safe way + * The combination of dst and dev is unique in the mesh path table. Since the + * next_hop STA is only protected by RCU as well, deleting the STA must also + * remove/substitute the mesh_path structure and wait until that is no longer + * reachable before destroying the STA completely. */ struct mesh_path { u8 dst[ETH_ALEN]; @@ -230,8 +231,9 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, bool add); bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie, struct net_device *dev); -void mesh_accept_plinks_update(struct net_device *dev); -struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev); +void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); +struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, + struct ieee80211_sub_if_data *sdata); void mesh_plink_broken(struct sta_info *sta); void mesh_plink_deactivate(struct sta_info *sta); int mesh_plink_open(struct sta_info *sta); @@ -254,7 +256,7 @@ void mesh_path_flush_pending(struct mesh_path *mpath); void mesh_path_tx_pending(struct mesh_path *mpath); int mesh_pathtbl_init(void); void mesh_pathtbl_unregister(void); -int mesh_path_del(u8 *addr, struct net_device *dev); +int mesh_path_del(u8 *addr, struct net_device *dev, bool force); void mesh_path_timer(unsigned long data); void mesh_path_flush_by_nexthop(struct sta_info *sta); void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev); @@ -270,7 +272,7 @@ static inline int mesh_plink_free_count(struct ieee80211_sub_if_data *sdata) static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata) { - return (min(mesh_plink_free_count(sdata), + return (min_t(long, mesh_plink_free_count(sdata), MESH_MAX_PLINKS - sdata->local->num_sta)) > 0; } diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index c2f40ef418cf..d8530fe7a0b3 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -294,7 +294,6 @@ static u32 hwmp_route_info_get(struct net_device *dev, orig_metric = PREP_IE_METRIC(hwmp_ie); break; default: - sta_info_put(sta); rcu_read_unlock(); return 0; } @@ -330,7 +329,6 @@ static u32 hwmp_route_info_get(struct net_device *dev, mpath = mesh_path_lookup(orig_addr, dev); if (!mpath) { rcu_read_unlock(); - sta_info_put(sta); return 0; } spin_lock_bh(&mpath->state_lock); @@ -372,7 +370,6 @@ static u32 hwmp_route_info_get(struct net_device *dev, mpath = mesh_path_lookup(ta, dev); if (!mpath) { rcu_read_unlock(); - sta_info_put(sta); return 0; } spin_lock_bh(&mpath->state_lock); @@ -391,7 +388,6 @@ static u32 hwmp_route_info_get(struct net_device *dev, spin_unlock_bh(&mpath->state_lock); } - sta_info_put(sta); rcu_read_unlock(); return process ? new_metric : 0; @@ -861,5 +857,5 @@ void mesh_path_timer(unsigned long data) endmpathtimer: rcu_read_unlock(); if (delete) - mesh_path_del(mpath->dst, mpath->dev); + mesh_path_del(mpath->dst, mpath->dev, false); } diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 3cbdbb23d75a..a17f2b299045 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -55,10 +55,7 @@ static DEFINE_RWLOCK(pathtbl_resize_lock); */ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta) { - __sta_info_get(sta); - if (mpath->next_hop) - sta_info_put(mpath->next_hop); - mpath->next_hop = sta; + rcu_assign_pointer(mpath->next_hop, sta); } @@ -236,7 +233,7 @@ void mesh_plink_broken(struct sta_info *sta) struct mesh_path *mpath; struct mpath_node *node; struct hlist_node *p; - struct net_device *dev = sta->dev; + struct net_device *dev = sta->sdata->dev; int i; rcu_read_lock(); @@ -266,9 +263,9 @@ EXPORT_SYMBOL(mesh_plink_broken); * * RCU notes: this function is called when a mesh plink transitions from ESTAB * to any other state, since ESTAB state is the only one that allows path - * creation. This will happen before the sta can be freed (since we hold - * a reference to it) so any reader in a rcu read block will be protected - * against the plink dissapearing. + * creation. This will happen before the sta can be freed (because + * sta_info_destroy() calls this) so any reader in a rcu read block will be + * protected against the plink disappearing. */ void mesh_path_flush_by_nexthop(struct sta_info *sta) { @@ -280,7 +277,7 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta) for_each_mesh_entry(mesh_paths, p, node, i) { mpath = node->mpath; if (mpath->next_hop == sta) - mesh_path_del(mpath->dst, mpath->dev); + mesh_path_del(mpath->dst, mpath->dev, true); } } @@ -294,7 +291,7 @@ void mesh_path_flush(struct net_device *dev) for_each_mesh_entry(mesh_paths, p, node, i) { mpath = node->mpath; if (mpath->dev == dev) - mesh_path_del(mpath->dst, mpath->dev); + mesh_path_del(mpath->dst, mpath->dev, false); } } @@ -303,8 +300,8 @@ static void mesh_path_node_reclaim(struct rcu_head *rp) struct mpath_node *node = container_of(rp, struct mpath_node, rcu); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(node->mpath->dev); - if (node->mpath->next_hop) - sta_info_put(node->mpath->next_hop); + + rcu_assign_pointer(node->mpath->next_hop, NULL); atomic_dec(&sdata->u.sta.mpaths); kfree(node->mpath); kfree(node); @@ -319,9 +316,10 @@ static void mesh_path_node_reclaim(struct rcu_head *rp) * Returns: 0 if succesful * * State: if the path is being resolved, the deletion will be postponed until - * the path resolution completes or times out. + * the path resolution completes or times out, unless the force parameter + * is given. */ -int mesh_path_del(u8 *addr, struct net_device *dev) +int mesh_path_del(u8 *addr, struct net_device *dev, bool force) { struct mesh_path *mpath; struct mpath_node *node; @@ -340,7 +338,7 @@ int mesh_path_del(u8 *addr, struct net_device *dev) if (mpath->dev == dev && memcmp(addr, mpath->dst, ETH_ALEN) == 0) { spin_lock_bh(&mpath->state_lock); - if (mpath->flags & MESH_PATH_RESOLVING) { + if (!force && mpath->flags & MESH_PATH_RESOLVING) { mpath->flags |= MESH_PATH_DELETE; } else { mpath->flags |= MESH_PATH_RESOLVING; @@ -510,7 +508,7 @@ void mesh_path_expire(struct net_device *dev) time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) { spin_unlock_bh(&mpath->state_lock); - mesh_path_del(mpath->dst, mpath->dev); + mesh_path_del(mpath->dst, mpath->dev, false); } else spin_unlock_bh(&mpath->state_lock); } diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index b5fbe970e48f..c2b80500ae72 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -65,14 +65,14 @@ static inline void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) { atomic_inc(&sdata->u.sta.mshstats.estab_plinks); - mesh_accept_plinks_update(sdata->dev); + mesh_accept_plinks_update(sdata); } static inline void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) { atomic_dec(&sdata->u.sta.mshstats.estab_plinks); - mesh_accept_plinks_update(sdata->dev); + mesh_accept_plinks_update(sdata); } /** @@ -99,12 +99,13 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) * * Returns: non-NULL on success, ERR_PTR() on error. */ -struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) +struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, + struct ieee80211_sub_if_data *sdata) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; - if (memcmp(hw_addr, dev->dev_addr, ETH_ALEN) == 0) + if (compare_ether_addr(hw_addr, sdata->dev->dev_addr) == 0) /* never add ourselves as neighbours */ return ERR_PTR(-EINVAL); @@ -114,7 +115,7 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) if (local->num_sta >= MESH_MAX_PLINKS) return ERR_PTR(-ENOSPC); - sta = sta_info_add(local, dev, hw_addr, GFP_KERNEL); + sta = sta_info_add(sdata, hw_addr); if (IS_ERR(sta)) return sta; @@ -125,7 +126,7 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) sta->supp_rates[local->hw.conf.channel->band] = rates; rate_control_rate_init(sta, local); - mesh_accept_plinks_update(dev); + mesh_accept_plinks_update(sdata); return sta; } @@ -141,7 +142,8 @@ struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, struct net_device *dev) */ static void __mesh_plink_deactivate(struct sta_info *sta) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + struct ieee80211_sub_if_data *sdata = sta->sdata; + if (sta->plink_state == ESTAB) mesh_plink_dec_estab_count(sdata); sta->plink_state = BLOCKED; @@ -246,11 +248,15 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; + rcu_read_lock(); + sta = sta_info_get(local, hw_addr); if (!sta) { - sta = mesh_plink_add(hw_addr, rates, dev); - if (IS_ERR(sta)) + sta = mesh_plink_add(hw_addr, rates, sdata); + if (IS_ERR(sta)) { + rcu_read_unlock(); return; + } } sta->last_rx = jiffies; @@ -260,7 +266,7 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, sdata->u.sta.mshcfg.auto_open_plinks) mesh_plink_open(sta); - sta_info_put(sta); + rcu_read_unlock(); } static void mesh_plink_timer(unsigned long data) @@ -273,6 +279,11 @@ static void mesh_plink_timer(unsigned long data) DECLARE_MAC_BUF(mac); #endif + /* + * This STA is valid because sta_info_destroy() will + * del_timer_sync() this timer after having made sure + * it cannot be readded (by deleting the plink.) + */ sta = (struct sta_info *) data; spin_lock_bh(&sta->plink_lock); @@ -286,8 +297,8 @@ static void mesh_plink_timer(unsigned long data) reason = 0; llid = sta->llid; plid = sta->plid; - dev = sta->dev; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sdata = sta->sdata; + dev = sdata->dev; switch (sta->plink_state) { case OPN_RCVD: @@ -302,8 +313,7 @@ static void mesh_plink_timer(unsigned long data) sta->plink_timeout = sta->plink_timeout + rand % sta->plink_timeout; ++sta->plink_retries; - if (!mod_plink_timer(sta, sta->plink_timeout)) - __sta_info_get(sta); + mod_plink_timer(sta, sta->plink_timeout); spin_unlock_bh(&sta->plink_lock); mesh_plink_frame_tx(dev, PLINK_OPEN, sta->addr, llid, 0, 0); @@ -316,16 +326,14 @@ static void mesh_plink_timer(unsigned long data) if (!reason) reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); sta->plink_state = HOLDING; - if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) - __sta_info_get(sta); + mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); spin_unlock_bh(&sta->plink_lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; case HOLDING: /* holding timer */ - if (del_timer(&sta->plink_timer)) - sta_info_put(sta); + del_timer(&sta->plink_timer); mesh_plink_fsm_restart(sta); spin_unlock_bh(&sta->plink_lock); break; @@ -333,8 +341,6 @@ static void mesh_plink_timer(unsigned long data) spin_unlock_bh(&sta->plink_lock); break; } - - sta_info_put(sta); } static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) @@ -343,14 +349,13 @@ static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout) sta->plink_timer.data = (unsigned long) sta; sta->plink_timer.function = mesh_plink_timer; sta->plink_timeout = timeout; - __sta_info_get(sta); add_timer(&sta->plink_timer); } int mesh_plink_open(struct sta_info *sta) { __le16 llid; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + struct ieee80211_sub_if_data *sdata = sta->sdata; #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG DECLARE_MAC_BUF(mac); #endif @@ -360,7 +365,6 @@ int mesh_plink_open(struct sta_info *sta) sta->llid = llid; if (sta->plink_state != LISTEN) { spin_unlock_bh(&sta->plink_lock); - sta_info_put(sta); return -EBUSY; } sta->plink_state = OPN_SNT; @@ -369,7 +373,8 @@ int mesh_plink_open(struct sta_info *sta) mpl_dbg("Mesh plink: starting establishment with %s\n", print_mac(mac, sta->addr)); - return mesh_plink_frame_tx(sta->dev, PLINK_OPEN, sta->addr, llid, 0, 0); + return mesh_plink_frame_tx(sdata->dev, PLINK_OPEN, + sta->addr, llid, 0, 0); } void mesh_plink_block(struct sta_info *sta) @@ -386,7 +391,7 @@ void mesh_plink_block(struct sta_info *sta) int mesh_plink_close(struct sta_info *sta) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + struct ieee80211_sub_if_data *sdata = sta->sdata; int llid, plid, reason; #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG DECLARE_MAC_BUF(mac); @@ -401,13 +406,11 @@ int mesh_plink_close(struct sta_info *sta) if (sta->plink_state == LISTEN || sta->plink_state == BLOCKED) { mesh_plink_fsm_restart(sta); spin_unlock_bh(&sta->plink_lock); - sta_info_put(sta); return 0; } else if (sta->plink_state == ESTAB) { __mesh_plink_deactivate(sta); /* The timer should not be running */ - if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) - __sta_info_get(sta); + mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); } else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) sta->ignore_plink_timer = true; @@ -415,15 +418,16 @@ int mesh_plink_close(struct sta_info *sta) llid = sta->llid; plid = sta->plid; spin_unlock_bh(&sta->plink_lock); - mesh_plink_frame_tx(sta->dev, PLINK_CLOSE, sta->addr, llid, plid, - reason); + mesh_plink_frame_tx(sta->sdata->dev, PLINK_CLOSE, sta->addr, llid, + plid, reason); return 0; } void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, size_t len, struct ieee80211_rx_status *rx_status) { - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; struct ieee802_11_elems elems; struct sta_info *sta; enum plink_event event; @@ -435,7 +439,6 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG DECLARE_MAC_BUF(mac); #endif - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (is_multicast_ether_addr(mgmt->da)) { mpl_dbg("Mesh plink: ignore frame from multicast address"); @@ -474,14 +477,17 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7)) memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2); + rcu_read_lock(); + sta = sta_info_get(local, mgmt->sa); if (!sta && ftype != PLINK_OPEN) { mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); + rcu_read_unlock(); return; } if (sta && sta->plink_state == BLOCKED) { - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -505,13 +511,15 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, u64 rates; if (!mesh_plink_free_count(sdata)) { mpl_dbg("Mesh plink error: no more free plinks\n"); + rcu_read_unlock(); return; } rates = ieee80211_sta_get_rates(local, &elems, rx_status->band); - sta = mesh_plink_add(mgmt->sa, rates, dev); + sta = mesh_plink_add(mgmt->sa, rates, sdata); if (IS_ERR(sta)) { mpl_dbg("Mesh plink error: plink table full\n"); + rcu_read_unlock(); return; } event = OPN_ACPT; @@ -521,14 +529,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, switch (ftype) { case PLINK_OPEN: if (!mesh_plink_free_count(sdata) || - (sta->plid && sta->plid != plid)) + (sta->plid && sta->plid != plid)) event = OPN_IGNR; else event = OPN_ACPT; break; case PLINK_CONFIRM: if (!mesh_plink_free_count(sdata) || - (sta->llid != llid || sta->plid != plid)) + (sta->llid != llid || sta->plid != plid)) event = CNF_IGNR; else event = CNF_ACPT; @@ -555,7 +563,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, default: mpl_dbg("Mesh plink: unknown frame subtype\n"); spin_unlock_bh(&sta->plink_lock); - sta_info_put(sta); + rcu_read_unlock(); return; } } @@ -659,8 +667,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, plid, 0); break; case CNF_ACPT: - if (del_timer(&sta->plink_timer)) - sta_info_put(sta); + del_timer(&sta->plink_timer); sta->plink_state = ESTAB; mesh_plink_inc_estab_count(sdata); spin_unlock_bh(&sta->plink_lock); @@ -693,8 +700,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, plid, reason); break; case OPN_ACPT: - if (del_timer(&sta->plink_timer)) - sta_info_put(sta); + del_timer(&sta->plink_timer); sta->plink_state = ESTAB; mesh_plink_inc_estab_count(sdata); spin_unlock_bh(&sta->plink_lock); @@ -717,9 +723,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, __mesh_plink_deactivate(sta); sta->plink_state = HOLDING; llid = sta->llid; - if (!mod_plink_timer(sta, - dot11MeshHoldingTimeout(sdata))) - __sta_info_get(sta); + mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); spin_unlock_bh(&sta->plink_lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); @@ -738,10 +742,8 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, case HOLDING: switch (event) { case CLS_ACPT: - if (del_timer(&sta->plink_timer)) { + if (del_timer(&sta->plink_timer)) sta->ignore_plink_timer = 1; - sta_info_put(sta); - } mesh_plink_fsm_restart(sta); spin_unlock_bh(&sta->plink_lock); break; @@ -766,5 +768,6 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, spin_unlock_bh(&sta->plink_lock); break; } - sta_info_put(sta); + + rcu_read_unlock(); } diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 217c0f487bba..a1993161de99 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -77,7 +77,7 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local, int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; int cur = sta->txrate_idx; - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + sdata = sta->sdata; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; band = sband->band; n_bitrates = sband->n_bitrates; @@ -149,7 +149,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, struct sta_info *sta) { #ifdef CONFIG_MAC80211_MESH - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + struct ieee80211_sub_if_data *sdata = sta->sdata; #endif struct rc_pid_sta_info *spinfo = sta->rate_ctrl_priv; struct rc_pid_rateinfo *rinfo = pinfo->rinfo; @@ -249,23 +249,25 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, unsigned long period; struct ieee80211_supported_band *sband; + rcu_read_lock(); + sta = sta_info_get(local, hdr->addr1); sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; if (!sta) - return; + goto unlock; /* Don't update the state if we're not controlling the rate. */ - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + sdata = sta->sdata; if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { sta->txrate_idx = sdata->bss->max_ratectrl_rateidx; - return; + goto unlock; } /* Ignore all frames that were sent with a different rate than the rate * we currently advise mac80211 to use. */ if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) - goto ignore; + goto unlock; spinfo = sta->rate_ctrl_priv; spinfo->tx_num_xmit++; @@ -303,8 +305,8 @@ static void rate_control_pid_tx_status(void *priv, struct net_device *dev, if (time_after(jiffies, spinfo->last_sample + period)) rate_control_pid_sample(pinfo, local, sta); -ignore: - sta_info_put(sta); + unlock: + rcu_read_unlock(); } static void rate_control_pid_get_rate(void *priv, struct net_device *dev, @@ -319,6 +321,8 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, int rateidx; u16 fc; + rcu_read_lock(); + sta = sta_info_get(local, hdr->addr1); /* Send management frames and broadcast/multicast data using lowest @@ -327,8 +331,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1) || !sta) { sel->rate = rate_lowest(local, sband, sta); - if (sta) - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -344,7 +347,7 @@ static void rate_control_pid_get_rate(void *priv, struct net_device *dev, sta->last_txrate_idx = rateidx; - sta_info_put(sta); + rcu_read_unlock(); sel->rate = &sband->bitrates[rateidx]; diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c index bcc541d4b95c..4f72fdca7f12 100644 --- a/net/mac80211/rc80211_simple.c +++ b/net/mac80211/rc80211_simple.c @@ -40,7 +40,7 @@ static void rate_control_rate_inc(struct ieee80211_local *local, int i = sta->txrate_idx; int maxrate; - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + sdata = sta->sdata; if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { /* forced unicast rate - do not change STA rate */ return; @@ -70,7 +70,7 @@ static void rate_control_rate_dec(struct ieee80211_local *local, struct ieee80211_supported_band *sband; int i = sta->txrate_idx; - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + sdata = sta->sdata; if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { /* forced unicast rate - do not change STA rate */ return; @@ -118,10 +118,12 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, struct sta_info *sta; struct sta_rate_control *srctrl; + rcu_read_lock(); + sta = sta_info_get(local, hdr->addr1); if (!sta) - return; + goto unlock; srctrl = sta->rate_ctrl_priv; srctrl->tx_num_xmit++; @@ -191,7 +193,8 @@ static void rate_control_simple_tx_status(void *priv, struct net_device *dev, } } - sta_info_put(sta); + unlock: + rcu_read_unlock(); } @@ -208,6 +211,8 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev, int rateidx; u16 fc; + rcu_read_lock(); + sta = sta_info_get(local, hdr->addr1); /* Send management frames and broadcast/multicast data using lowest @@ -216,8 +221,7 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev, if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1) || !sta) { sel->rate = rate_lowest(local, sband, sta); - if (sta) - sta_info_put(sta); + rcu_read_unlock(); return; } @@ -233,7 +237,7 @@ rate_control_simple_get_rate(void *priv, struct net_device *dev, sta->last_txrate_idx = rateidx; - sta_info_put(sta); + rcu_read_unlock(); sel->rate = &sband->bitrates[rateidx]; } diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 2e65ca1cd1aa..8e1e2859bfd5 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -631,7 +631,7 @@ static void ap_sta_ps_start(struct net_device *dev, struct sta_info *sta) struct ieee80211_sub_if_data *sdata; DECLARE_MAC_BUF(mac); - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + sdata = sta->sdata; if (sdata->bss) atomic_inc(&sdata->bss->num_sta_ps); @@ -652,7 +652,7 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) struct ieee80211_tx_packet_data *pkt_data; DECLARE_MAC_BUF(mac); - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + sdata = sta->sdata; if (sdata->bss) atomic_dec(&sdata->bss->num_sta_ps); @@ -1287,7 +1287,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) "multicast frame\n", dev->name); } else { dsta = sta_info_get(local, skb->data); - if (dsta && dsta->dev == dev) { + if (dsta && dsta->sdata->dev == dev) { /* * The destination station is associated to * this AP (in this VLAN), so send the frame @@ -1297,8 +1297,6 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) xmit_skb = skb; skb = NULL; } - if (dsta) - sta_info_put(dsta); } } @@ -1905,13 +1903,13 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, rx.sta = sta_info_get(local, hdr->addr2); if (rx.sta) { - rx.dev = rx.sta->dev; - rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); + rx.sdata = rx.sta->sdata; + rx.dev = rx.sta->sdata->dev; } if ((status->flag & RX_FLAG_MMIC_ERROR)) { ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx); - goto end; + return; } if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning)) @@ -1970,10 +1968,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, ieee80211_invoke_rx_handlers(prev, &rx, skb); } else dev_kfree_skb(skb); - - end: - if (rx.sta) - sta_info_put(rx.sta); } #define SEQ_MODULO 0x1000 @@ -2150,7 +2144,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, /* if this mpdu is fragmented - terminate rx aggregation session */ sc = le16_to_cpu(hdr->seq_ctrl); if (sc & IEEE80211_SCTL_FRAG) { - ieee80211_sta_stop_rx_ba_session(sta->dev, sta->addr, + ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr, tid, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); ret = 1; goto end_reorder; @@ -2160,9 +2154,7 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, mpdu_seq_num = (sc & IEEE80211_SCTL_SEQ) >> 4; ret = ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb, mpdu_seq_num, 0); -end_reorder: - if (sta) - sta_info_put(sta); + end_reorder: return ret; } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 81c4e3392f40..ee5b66abc0f1 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "ieee80211_i.h" @@ -23,14 +24,43 @@ #include "debugfs_sta.h" #include "mesh.h" -/* Caller must hold local->sta_lock */ -static void sta_info_hash_add(struct ieee80211_local *local, - struct sta_info *sta) -{ - sta->hnext = local->sta_hash[STA_HASH(sta->addr)]; - local->sta_hash[STA_HASH(sta->addr)] = sta; -} - +/** + * DOC: STA information lifetime rules + * + * STA info structures (&struct sta_info) are managed in a hash table + * for faster lookup and a list for iteration. They are managed using + * RCU, i.e. access to the list and hash table is protected by RCU. + * + * STA info structures are always "alive" when they are added with + * @sta_info_add() [this may be changed in the future to allow allocating + * outside of a critical section!], they are then added to the hash + * table and list. Therefore, @sta_info_add() must also be RCU protected, + * also, the caller of @sta_info_add() cannot assume that it owns the + * structure. + * + * Because there are debugfs entries for each station, and adding those + * must be able to sleep, it is also possible to "pin" a station entry, + * that means it can be removed from the hash table but not be freed. + * See the comment in @__sta_info_unlink() for more information. + * + * In order to remove a STA info structure, the caller needs to first + * unlink it (@sta_info_unlink()) from the list and hash tables and + * then wait for an RCU synchronisation before it can be freed. Due to + * the pinning and the possibility of multiple callers trying to remove + * the same STA info at the same time, @sta_info_unlink() can clear the + * STA info pointer it is passed to indicate that the STA info is owned + * by somebody else now. + * + * If @sta_info_unlink() did not clear the pointer then the caller owns + * the STA info structure now and is responsible of destroying it with + * a call to @sta_info_destroy(), not before RCU synchronisation, of + * course. Note that sta_info_destroy() must be protected by the RTNL. + * + * In all other cases, there is no concept of ownership on a STA entry, + * each structure is owned by the global hash table/list until it is + * removed. All users of the structure need to be RCU protected so that + * the structure won't be freed before they are done using it. + */ /* Caller must hold local->sta_lock */ static int sta_info_hash_del(struct ieee80211_local *local, @@ -42,46 +72,39 @@ static int sta_info_hash_del(struct ieee80211_local *local, if (!s) return -ENOENT; if (s == sta) { - local->sta_hash[STA_HASH(sta->addr)] = s->hnext; + rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)], + s->hnext); return 0; } while (s->hnext && s->hnext != sta) s = s->hnext; if (s->hnext) { - s->hnext = sta->hnext; + rcu_assign_pointer(s->hnext, sta->hnext); return 0; } return -ENOENT; } -/* must hold local->sta_lock */ +/* protected by RCU */ static struct sta_info *__sta_info_find(struct ieee80211_local *local, u8 *addr) { struct sta_info *sta; - sta = local->sta_hash[STA_HASH(addr)]; + sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]); while (sta) { if (compare_ether_addr(sta->addr, addr) == 0) break; - sta = sta->hnext; + sta = rcu_dereference(sta->hnext); } return sta; } struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) { - struct sta_info *sta; - - read_lock_bh(&local->sta_lock); - sta = __sta_info_find(local, addr); - if (sta) - __sta_info_get(sta); - read_unlock_bh(&local->sta_lock); - - return sta; + return __sta_info_find(local, addr); } EXPORT_SYMBOL(sta_info_get); @@ -91,81 +114,101 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, struct sta_info *sta; int i = 0; - read_lock_bh(&local->sta_lock); - list_for_each_entry(sta, &local->sta_list, list) { + list_for_each_entry_rcu(sta, &local->sta_list, list) { if (i < idx) { ++i; continue; - } else if (!dev || dev == sta->dev) { - __sta_info_get(sta); - read_unlock_bh(&local->sta_lock); + } else if (!dev || dev == sta->sdata->dev) { return sta; } } - read_unlock_bh(&local->sta_lock); return NULL; } -static void sta_info_release(struct kref *kref) +void sta_info_destroy(struct sta_info *sta) { - struct sta_info *sta = container_of(kref, struct sta_info, kref); struct ieee80211_local *local = sta->local; struct sk_buff *skb; int i; - /* free sta structure; it has already been removed from - * hash table etc. external structures. Make sure that all - * buffered frames are release (one might have been added - * after sta_info_free() was called). */ + ASSERT_RTNL(); + might_sleep(); + + rate_control_remove_sta_debugfs(sta); + ieee80211_sta_debugfs_remove(sta); + +#ifdef CONFIG_MAC80211_MESH + if (ieee80211_vif_is_mesh(&sta->sdata->vif)) + mesh_plink_deactivate(sta); +#endif + + /* + * NOTE: This will call synchronize_rcu() internally to + * make sure no key references can be in use. We rely on + * that here for the mesh code! + */ + ieee80211_key_free(sta->key); + WARN_ON(sta->key); + +#ifdef CONFIG_MAC80211_MESH + if (ieee80211_vif_is_mesh(&sta->sdata->vif)) + del_timer_sync(&sta->plink_timer); +#endif + while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { local->total_ps_buffered--; dev_kfree_skb_any(skb); } - while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { + + while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) dev_kfree_skb_any(skb); - } + for (i = 0; i < STA_TID_NUM; i++) { del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); } rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); rate_control_put(sta->rate_ctrl); + kfree(sta); } -void sta_info_put(struct sta_info *sta) +/* Caller must hold local->sta_lock */ +static void sta_info_hash_add(struct ieee80211_local *local, + struct sta_info *sta) { - kref_put(&sta->kref, sta_info_release); + sta->hnext = local->sta_hash[STA_HASH(sta->addr)]; + rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)], sta); } -EXPORT_SYMBOL(sta_info_put); - -struct sta_info *sta_info_add(struct ieee80211_local *local, - struct net_device *dev, u8 *addr, gfp_t gfp) +struct sta_info *sta_info_add(struct ieee80211_sub_if_data *sdata, + u8 *addr) { + struct ieee80211_local *local = sdata->local; struct sta_info *sta; int i; DECLARE_MAC_BUF(mac); + unsigned long flags; - sta = kzalloc(sizeof(*sta), gfp); + sta = kzalloc(sizeof(*sta), GFP_ATOMIC); if (!sta) return ERR_PTR(-ENOMEM); - kref_init(&sta->kref); + memcpy(sta->addr, addr, ETH_ALEN); + sta->local = local; + sta->sdata = sdata; sta->rate_ctrl = rate_control_get(local->rate_ctrl); - sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, gfp); + sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, + GFP_ATOMIC); if (!sta->rate_ctrl_priv) { rate_control_put(sta->rate_ctrl); kfree(sta); return ERR_PTR(-ENOMEM); } - memcpy(sta->addr, addr, ETH_ALEN); - sta->local = local; - sta->dev = dev; spin_lock_init(&sta->ampdu_mlme.ampdu_rx); spin_lock_init(&sta->ampdu_mlme.ampdu_tx); for (i = 0; i < STA_TID_NUM; i++) { @@ -190,29 +233,26 @@ struct sta_info *sta_info_add(struct ieee80211_local *local, } skb_queue_head_init(&sta->ps_tx_buf); skb_queue_head_init(&sta->tx_filtered); - write_lock_bh(&local->sta_lock); - /* mark sta as used (by caller) */ - __sta_info_get(sta); + spin_lock_irqsave(&local->sta_lock, flags); /* check if STA exists already */ if (__sta_info_find(local, addr)) { - write_unlock_bh(&local->sta_lock); - sta_info_put(sta); + spin_unlock_irqrestore(&local->sta_lock, flags); return ERR_PTR(-EEXIST); } list_add(&sta->list, &local->sta_list); local->num_sta++; sta_info_hash_add(local, sta); - if (local->ops->sta_notify) { - struct ieee80211_sub_if_data *sdata; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + /* notify driver */ + if (local->ops->sta_notify) { if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) sdata = sdata->u.vlan.ap; local->ops->sta_notify(local_to_hw(local), &sdata->vif, STA_NOTIFY_ADD, addr); } - write_unlock_bh(&local->sta_lock); + + spin_unlock_irqrestore(&local->sta_lock, flags); #ifdef CONFIG_MAC80211_VERBOSE_DEBUG printk(KERN_DEBUG "%s: Added STA %s\n", @@ -252,19 +292,20 @@ static void __sta_info_set_tim_bit(struct ieee80211_if_ap *bss, { if (bss) __bss_tim_set(bss, sta->aid); - if (sta->local->ops->set_tim) + if (sta->local->ops->set_tim) { + sta->local->tim_in_locked_section = true; sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 1); + sta->local->tim_in_locked_section = false; + } } void sta_info_set_tim_bit(struct sta_info *sta) { - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + unsigned long flags; - read_lock_bh(&sta->local->sta_lock); - __sta_info_set_tim_bit(sdata->bss, sta); - read_unlock_bh(&sta->local->sta_lock); + spin_lock_irqsave(&sta->local->sta_lock, flags); + __sta_info_set_tim_bit(sta->sdata->bss, sta); + spin_unlock_irqrestore(&sta->local->sta_lock, flags); } static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, @@ -272,93 +313,135 @@ static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, { if (bss) __bss_tim_clear(bss, sta->aid); - if (sta->local->ops->set_tim) + if (sta->local->ops->set_tim) { + sta->local->tim_in_locked_section = true; sta->local->ops->set_tim(local_to_hw(sta->local), sta->aid, 0); + sta->local->tim_in_locked_section = false; + } } void sta_info_clear_tim_bit(struct sta_info *sta) { - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + unsigned long flags; - read_lock_bh(&sta->local->sta_lock); - __sta_info_clear_tim_bit(sdata->bss, sta); - read_unlock_bh(&sta->local->sta_lock); + spin_lock_irqsave(&sta->local->sta_lock, flags); + __sta_info_clear_tim_bit(sta->sdata->bss, sta); + spin_unlock_irqrestore(&sta->local->sta_lock, flags); } -/* Caller must hold local->sta_lock */ -void sta_info_remove(struct sta_info *sta) +/* + * See comment in __sta_info_unlink, + * caller must hold local->sta_lock. + */ +static void __sta_info_pin(struct sta_info *sta) { - struct ieee80211_local *local = sta->local; - struct ieee80211_sub_if_data *sdata; + WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_NORMAL); + sta->pin_status = STA_INFO_PIN_STAT_PINNED; +} - /* don't do anything if we've been removed already */ - if (sta_info_hash_del(local, sta)) - return; +/* + * See comment in __sta_info_unlink, returns sta if it + * needs to be destroyed. + */ +static struct sta_info *__sta_info_unpin(struct sta_info *sta) +{ + struct sta_info *ret = NULL; + unsigned long flags; - list_del(&sta->list); - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); - if (sta->flags & WLAN_STA_PS) { - sta->flags &= ~WLAN_STA_PS; - if (sdata->bss) - atomic_dec(&sdata->bss->num_sta_ps); - __sta_info_clear_tim_bit(sdata->bss, sta); - } - local->num_sta--; + spin_lock_irqsave(&sta->local->sta_lock, flags); + WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_DESTROY && + sta->pin_status != STA_INFO_PIN_STAT_PINNED); + if (sta->pin_status == STA_INFO_PIN_STAT_DESTROY) + ret = sta; + sta->pin_status = STA_INFO_PIN_STAT_NORMAL; + spin_unlock_irqrestore(&sta->local->sta_lock, flags); - if (ieee80211_vif_is_mesh(&sdata->vif)) - mesh_accept_plinks_update(sdata->dev); + return ret; } -void sta_info_free(struct sta_info *sta) +static void __sta_info_unlink(struct sta_info **sta) { - struct sk_buff *skb; - struct ieee80211_local *local = sta->local; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); - - DECLARE_MAC_BUF(mac); - - might_sleep(); + struct ieee80211_local *local = (*sta)->local; + struct ieee80211_sub_if_data *sdata = (*sta)->sdata; +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + DECLARE_MAC_BUF(mbuf); +#endif + /* + * pull caller's reference if we're already gone. + */ + if (sta_info_hash_del(local, *sta)) { + *sta = NULL; + return; + } - write_lock_bh(&local->sta_lock); - sta_info_remove(sta); - write_unlock_bh(&local->sta_lock); + /* + * Also pull caller's reference if the STA is pinned by the + * task that is adding the debugfs entries. In that case, we + * leave the STA "to be freed". + * + * The rules are not trivial, but not too complex either: + * (1) pin_status is only modified under the sta_lock + * (2) sta_info_debugfs_add_work() will set the status + * to PINNED when it found an item that needs a new + * debugfs directory created. In that case, that item + * must not be freed although all *RCU* users are done + * with it. Hence, we tell the caller of _unlink() + * that the item is already gone (as can happen when + * two tasks try to unlink/destroy at the same time) + * (3) We set the pin_status to DESTROY here when we + * find such an item. + * (4) sta_info_debugfs_add_work() will reset the pin_status + * from PINNED to NORMAL when it is done with the item, + * but will check for DESTROY before resetting it in + * which case it will free the item. + */ + if ((*sta)->pin_status == STA_INFO_PIN_STAT_PINNED) { + (*sta)->pin_status = STA_INFO_PIN_STAT_DESTROY; + *sta = NULL; + return; + } - if (ieee80211_vif_is_mesh(&sdata->vif)) - mesh_plink_deactivate(sta); + list_del(&(*sta)->list); - while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { - local->total_ps_buffered--; - dev_kfree_skb(skb); - } - while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { - dev_kfree_skb(skb); + if ((*sta)->flags & WLAN_STA_PS) { + (*sta)->flags &= ~WLAN_STA_PS; + if (sdata->bss) + atomic_dec(&sdata->bss->num_sta_ps); + __sta_info_clear_tim_bit(sdata->bss, *sta); } -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Removed STA %s\n", - wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr)); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - - ieee80211_key_free(sta->key); - WARN_ON(sta->key); + local->num_sta--; if (local->ops->sta_notify) { - if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) sdata = sdata->u.vlan.ap; local->ops->sta_notify(local_to_hw(local), &sdata->vif, - STA_NOTIFY_REMOVE, sta->addr); + STA_NOTIFY_REMOVE, (*sta)->addr); } - rate_control_remove_sta_debugfs(sta); - ieee80211_sta_debugfs_remove(sta); + if (ieee80211_vif_is_mesh(&sdata->vif)) { + mesh_accept_plinks_update(sdata); +#ifdef CONFIG_MAC80211_MESH + del_timer(&(*sta)->plink_timer); +#endif + } - sta_info_put(sta); +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: Removed STA %s\n", + wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->addr)); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ } +void sta_info_unlink(struct sta_info **sta) +{ + struct ieee80211_local *local = (*sta)->local; + unsigned long flags; + + spin_lock_irqsave(&local->sta_lock, flags); + __sta_info_unlink(sta); + spin_unlock_irqrestore(&local->sta_lock, flags); +} static inline int sta_info_buffer_expired(struct ieee80211_local *local, struct sta_info *sta, @@ -404,7 +487,7 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, if (!skb) break; - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + sdata = sta->sdata; local->total_ps_buffered--; printk(KERN_DEBUG "Buffered frame expired (STA " "%s)\n", print_mac(mac, sta->addr)); @@ -421,13 +504,10 @@ static void sta_info_cleanup(unsigned long data) struct ieee80211_local *local = (struct ieee80211_local *) data; struct sta_info *sta; - read_lock_bh(&local->sta_lock); - list_for_each_entry(sta, &local->sta_list, list) { - __sta_info_get(sta); + rcu_read_lock(); + list_for_each_entry_rcu(sta, &local->sta_list, list) sta_info_cleanup_expire_buffered(local, sta); - sta_info_put(sta); - } - read_unlock_bh(&local->sta_lock); + rcu_read_unlock(); local->sta_cleanup.expires = round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); @@ -435,37 +515,45 @@ static void sta_info_cleanup(unsigned long data) } #ifdef CONFIG_MAC80211_DEBUGFS -static void sta_info_debugfs_add_task(struct work_struct *work) +static void sta_info_debugfs_add_work(struct work_struct *work) { struct ieee80211_local *local = container_of(work, struct ieee80211_local, sta_debugfs_add); struct sta_info *sta, *tmp; + unsigned long flags; while (1) { sta = NULL; - read_lock_bh(&local->sta_lock); + + spin_lock_irqsave(&local->sta_lock, flags); list_for_each_entry(tmp, &local->sta_list, list) { if (!tmp->debugfs.dir) { sta = tmp; - __sta_info_get(sta); + __sta_info_pin(sta); break; } } - read_unlock_bh(&local->sta_lock); + spin_unlock_irqrestore(&local->sta_lock, flags); if (!sta) break; ieee80211_sta_debugfs_add(sta); rate_control_add_sta_debugfs(sta); - sta_info_put(sta); + + sta = __sta_info_unpin(sta); + + if (sta) { + synchronize_rcu(); + sta_info_destroy(sta); + } } } #endif void sta_info_init(struct ieee80211_local *local) { - rwlock_init(&local->sta_lock); + spin_lock_init(&local->sta_lock); INIT_LIST_HEAD(&local->sta_list); setup_timer(&local->sta_cleanup, sta_info_cleanup, @@ -474,7 +562,7 @@ void sta_info_init(struct ieee80211_local *local) round_jiffies(jiffies + STA_INFO_CLEANUP_INTERVAL); #ifdef CONFIG_MAC80211_DEBUGFS - INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_task); + INIT_WORK(&local->sta_debugfs_add, sta_info_debugfs_add_work); #endif } @@ -493,24 +581,29 @@ void sta_info_stop(struct ieee80211_local *local) /** * sta_info_flush - flush matching STA entries from the STA table * @local: local interface data - * @dev: matching rule for the net device (sta->dev) or %NULL to match all STAs + * @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs */ -void sta_info_flush(struct ieee80211_local *local, struct net_device *dev) +void sta_info_flush(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) { struct sta_info *sta, *tmp; LIST_HEAD(tmp_list); + unsigned long flags; - write_lock_bh(&local->sta_lock); - list_for_each_entry_safe(sta, tmp, &local->sta_list, list) - if (!dev || dev == sta->dev) { - __sta_info_get(sta); - sta_info_remove(sta); - list_add_tail(&sta->list, &tmp_list); - } - write_unlock_bh(&local->sta_lock); + might_sleep(); - list_for_each_entry_safe(sta, tmp, &tmp_list, list) { - sta_info_free(sta); - sta_info_put(sta); + spin_lock_irqsave(&local->sta_lock, flags); + list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { + if (!sdata || sdata == sta->sdata) { + __sta_info_unlink(&sta); + if (sta) + list_add_tail(&sta->list, &tmp_list); + } } + spin_unlock_irqrestore(&local->sta_lock, flags); + + synchronize_rcu(); + + list_for_each_entry_safe(sta, tmp, &tmp_list, list) + sta_info_destroy(sta); } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b9dfb6fa893a..787124c253af 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -12,7 +12,6 @@ #include #include #include -#include #include "ieee80211_key.h" /** @@ -134,8 +133,14 @@ struct sta_ampdu_mlme { u8 dialog_token_allocator; }; + +/* see __sta_info_unlink */ +#define STA_INFO_PIN_STAT_NORMAL 0 +#define STA_INFO_PIN_STAT_PINNED 1 +#define STA_INFO_PIN_STAT_DESTROY 2 + + struct sta_info { - struct kref kref; struct list_head list; struct sta_info *hnext; /* next entry in hash table list */ @@ -166,8 +171,8 @@ struct sta_info { /* last rates used to send a frame to this STA */ int last_txrate_idx, last_nonerp_txrate_idx; - struct net_device *dev; /* which net device is this station associated - * to */ + /* sub_if_data this sta belongs to */ + struct ieee80211_sub_if_data *sdata; struct ieee80211_key *key; @@ -199,6 +204,12 @@ struct sta_info { u16 listen_interval; + /* + * for use by the internal lifetime management, + * see __sta_info_unlink + */ + u8 pin_status; + struct ieee80211_ht_info ht_info; /* 802.11n HT capabilities of this STA */ struct sta_ampdu_mlme ampdu_mlme; @@ -262,25 +273,37 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta) */ #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) -static inline void __sta_info_get(struct sta_info *sta) -{ - kref_get(&sta->kref); -} - -struct sta_info * sta_info_get(struct ieee80211_local *local, u8 *addr); +/* + * Get a STA info, must have be under RCU read lock. + */ +struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr); +/* + * Get STA info by index, BROKEN! + */ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, struct net_device *dev); -void sta_info_put(struct sta_info *sta); -struct sta_info *sta_info_add(struct ieee80211_local *local, - struct net_device *dev, u8 *addr, gfp_t gfp); -void sta_info_remove(struct sta_info *sta); -void sta_info_free(struct sta_info *sta); -void sta_info_init(struct ieee80211_local *local); -int sta_info_start(struct ieee80211_local *local); -void sta_info_stop(struct ieee80211_local *local); -void sta_info_flush(struct ieee80211_local *local, struct net_device *dev); +/* + * Add a new STA info, must be under RCU read lock + * because otherwise the returned reference isn't + * necessarily valid long enough. + */ +struct sta_info *sta_info_add(struct ieee80211_sub_if_data *sdata, + u8 *addr); +/* + * Unlink a STA info from the hash table/list. + * This can NULL the STA pointer if somebody else + * has already unlinked it. + */ +void sta_info_unlink(struct sta_info **sta); +void sta_info_destroy(struct sta_info *sta); void sta_info_set_tim_bit(struct sta_info *sta); void sta_info_clear_tim_bit(struct sta_info *sta); +void sta_info_init(struct ieee80211_local *local); +int sta_info_start(struct ieee80211_local *local); +void sta_info_stop(struct ieee80211_local *local); +void sta_info_flush(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata); + #endif /* STA_INFO_H */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 33e314f3aab7..80f4343a3007 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -327,10 +327,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) } total += skb_queue_len(&ap->ps_bc_buf); } - rcu_read_unlock(); - read_lock_bh(&local->sta_lock); - list_for_each_entry(sta, &local->sta_list, list) { + list_for_each_entry_rcu(sta, &local->sta_list, list) { skb = skb_dequeue(&sta->ps_tx_buf); if (skb) { purged++; @@ -338,7 +336,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) } total += skb_queue_len(&sta->ps_tx_buf); } - read_unlock_bh(&local->sta_lock); + + rcu_read_unlock(); local->total_ps_buffered = total; printk(KERN_DEBUG "%s: PS buffers full - purged %d frames\n", @@ -1141,20 +1140,17 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, return 0; } + rcu_read_lock(); + /* initialises tx */ res_prepare = __ieee80211_tx_prepare(&tx, skb, dev, control); if (res_prepare == TX_DROP) { dev_kfree_skb(skb); + rcu_read_unlock(); return 0; } - /* - * key references are protected using RCU and this requires that - * we are in a read-site RCU section during receive processing - */ - rcu_read_lock(); - sta = tx.sta; tx.channel = local->hw.conf.channel; @@ -1167,9 +1163,6 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb, skb = tx.skb; /* handlers are allowed to change skb */ - if (sta) - sta_info_put(sta); - if (unlikely(res == TX_DROP)) { I802_DEBUG_INC(local->tx_handlers_drop); goto drop; @@ -1489,11 +1482,11 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, * in AP mode) */ if (!is_multicast_ether_addr(hdr.addr1)) { + rcu_read_lock(); sta = sta_info_get(local, hdr.addr1); - if (sta) { + if (sta) sta_flags = sta->flags; - sta_info_put(sta); - } + rcu_read_unlock(); } /* receiver is QoS enabled, use a QoS type frame */ @@ -1722,7 +1715,6 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, /* Generate bitmap for TIM only if there are any STAs in power save * mode. */ - read_lock_bh(&local->sta_lock); if (atomic_read(&bss->num_sta_ps) > 0) /* in the hope that this is faster than * checking byte-for-byte */ @@ -1773,7 +1765,6 @@ static void ieee80211_beacon_add_tim(struct ieee80211_local *local, *pos++ = aid0; /* Bitmap control */ *pos++ = 0; /* Part Virt Bitmap */ } - read_unlock_bh(&local->sta_lock); } struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, @@ -1821,7 +1812,22 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, ieee80211_include_sequence(sdata, (struct ieee80211_hdr *)skb->data); - ieee80211_beacon_add_tim(local, ap, skb, beacon); + /* + * Not very nice, but we want to allow the driver to call + * ieee80211_beacon_get() as a response to the set_tim() + * callback. That, however, is already invoked under the + * sta_lock to guarantee consistent and race-free update + * of the tim bitmap in mac80211 and the driver. + */ + if (local->tim_in_locked_section) { + ieee80211_beacon_add_tim(local, ap, skb, beacon); + } else { + unsigned long flags; + + spin_lock_irqsave(&local->sta_lock, flags); + ieee80211_beacon_add_tim(local, ap, skb, beacon); + spin_unlock_irqrestore(&local->sta_lock, flags); + } if (beacon->tail) memcpy(skb_put(skb, beacon->tail_len), @@ -1965,7 +1971,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, rcu_read_unlock(); return NULL; } - rcu_read_unlock(); if (bss->dtim_count != 0) return NULL; /* send buffered bc/mc only after DTIM beacon */ @@ -2010,8 +2015,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, skb = NULL; } - if (sta) - sta_info_put(sta); + rcu_read_unlock(); return skb; } diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 8cc036decc82..4e94e4026e78 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -153,6 +153,7 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) if (pkt_data->flags & IEEE80211_TXPD_REQUEUE) { queue = pkt_data->queue; + rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); tid = skb->priority & QOS_CONTROL_TAG1D_MASK; if (sta) { @@ -164,8 +165,8 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) } else { pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; } - sta_info_put(sta); } + rcu_read_unlock(); skb_queue_tail(&q->requeued[queue], skb); qd->q.qlen++; return 0; @@ -187,6 +188,8 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) p++; *p = 0; + rcu_read_lock(); + sta = sta_info_get(local, hdr->addr1); if (sta) { int ampdu_queue = sta->tid_to_tx_q[tid]; @@ -197,8 +200,9 @@ static int wme_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) } else { pkt_data->flags &= ~IEEE80211_TXPD_AMPDU; } - sta_info_put(sta); } + + rcu_read_unlock(); } if (unlikely(queue >= local->hw.queues)) { -- cgit v1.2.3-59-g8ed1b From 73651ee6396c499ccb59ebc84c9274db01ed026d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 16:27:47 +0100 Subject: mac80211: split sta_info_add sta_info_add() has two functions: allocating a station info structure and inserting it into the hash table/list. Splitting these two functions allows allocating with GFP_KERNEL in many places instead of GFP_ATOMIC which is now required by the RCU protection. Additionally, in many places RCU protection is now no longer needed at all because between sta_info_alloc() and sta_info_insert() the caller owns the structure. This fixes a few race conditions with setting initial flags and similar, but not all (see comments in ieee80211_sta.c and cfg.c). More documentation on the existing races will be in a follow-up patch. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 42 ++++++++++++++++++++------ net/mac80211/ieee80211.c | 18 ++++++----- net/mac80211/ieee80211_sta.c | 44 ++++++++++++++++++++------- net/mac80211/mesh.h | 4 +-- net/mac80211/mesh_plink.c | 43 +++++++++++++++----------- net/mac80211/sta_info.c | 72 ++++++++++++++++++++++++++++++-------------- net/mac80211/sta_info.h | 17 ++++++++--- 7 files changed, 166 insertions(+), 74 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index e9ba6fcc0e45..6263cfc148c0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -571,6 +571,12 @@ static void sta_apply_parameters(struct ieee80211_local *local, struct ieee80211_supported_band *sband; struct ieee80211_sub_if_data *sdata = sta->sdata; + /* + * FIXME: updating the flags is racy when this function is + * called from ieee80211_change_station(), this will + * be resolved in a future patch. + */ + if (params->station_flags & STATION_FLAG_CHANGED) { sta->flags &= ~WLAN_STA_AUTHORIZED; if (params->station_flags & STATION_FLAG_AUTHORIZED) @@ -585,6 +591,13 @@ static void sta_apply_parameters(struct ieee80211_local *local, sta->flags |= WLAN_STA_WME; } + /* + * FIXME: updating the following information is racy when this + * function is called from ieee80211_change_station(). + * However, all this information should be static so + * maybe we should just reject attemps to change it. + */ + if (params->aid) { sta->aid = params->aid; if (sta->aid > IEEE80211_MAX_AID) @@ -626,6 +639,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct sta_info *sta; struct ieee80211_sub_if_data *sdata; + int err; /* Prevent a race with changing the rate control algorithm */ if (!netif_running(dev)) @@ -641,16 +655,11 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); if (ieee80211_vif_is_mesh(&sdata->vif)) - sta = mesh_plink_add(mac, DEFAULT_RATES, sdata); + sta = mesh_plink_alloc(sdata, mac, DEFAULT_RATES, GFP_KERNEL); else - sta = sta_info_add(sdata, mac); - - if (IS_ERR(sta)) - return PTR_ERR(sta); - - if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || - sdata->vif.type == IEEE80211_IF_TYPE_AP) - ieee80211_send_layer2_update(sta); + sta = sta_info_alloc(sdata, mac, GFP_KERNEL); + if (!sta) + return -ENOMEM; sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; @@ -658,6 +667,21 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, rate_control_rate_init(sta, local); + rcu_read_lock(); + + err = sta_info_insert(sta); + if (err) { + sta_info_destroy(sta); + rcu_read_unlock(); + return err; + } + + if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || + sdata->vif.type == IEEE80211_IF_TYPE_AP) + ieee80211_send_layer2_update(sta); + + rcu_read_unlock(); + return 0; } diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 85b1391375c0..22cba82a0c6f 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -899,6 +899,7 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta; + int err; DECLARE_MAC_BUF(mac); might_sleep(); @@ -906,16 +907,19 @@ int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) return 0; - rcu_read_lock(); - /* Create STA entry for the new peer */ - sta = sta_info_add(sdata, remote_addr); - if (IS_ERR(sta)) { - rcu_read_unlock(); - return PTR_ERR(sta); - } + sta = sta_info_alloc(sdata, remote_addr, GFP_KERNEL); + if (!sta) + return -ENOMEM; sta->flags |= WLAN_STA_AUTHORIZED; + err = sta_info_insert(sta); + if (err) { + sta_info_destroy(sta); + return err; + } + + rcu_read_lock(); /* Remove STA entry for the old peer */ sta = sta_info_get(local, sdata->u.wds.remote_addr); diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index a3e96eb59eb0..892b5f96a427 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1454,7 +1454,7 @@ void sta_addba_resp_timer_expired(unsigned long data) { /* not an elegant detour, but there is no choice as the timer passes * only one argument, and both sta_info and TID are needed, so init - * flow in sta_info_add gives the TID as data, while the timer_to_id + * flow in sta_info_create gives the TID as data, while the timer_to_id * array gives the sta through container_of */ u16 tid = *(int *)data; struct sta_info *temp_sta = container_of((void *)data, @@ -1505,7 +1505,7 @@ void sta_rx_agg_session_timer_expired(unsigned long data) { /* not an elegant detour, but there is no choice as the timer passes * only one argument, and verious sta_info are needed here, so init - * flow in sta_info_add gives the TID as data, while the timer_to_id + * flow in sta_info_create gives the TID as data, while the timer_to_id * array gives the sta through container_of */ u8 *ptid = (u8 *)data; u8 *timer_to_id = ptid - *ptid; @@ -1829,11 +1829,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, sta = sta_info_get(local, ifsta->bssid); if (!sta) { struct ieee80211_sta_bss *bss; + int err; - sta = sta_info_add(sdata, ifsta->bssid); - if (IS_ERR(sta)) { - printk(KERN_DEBUG "%s: failed to add STA entry for the" - " AP (error %ld)\n", dev->name, PTR_ERR(sta)); + sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC); + if (!sta) { + printk(KERN_DEBUG "%s: failed to alloc STA entry for" + " the AP\n", dev->name); rcu_read_unlock(); return; } @@ -1846,8 +1847,27 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, sta->last_noise = bss->noise; ieee80211_rx_bss_put(dev, bss); } + + err = sta_info_insert(sta); + if (err) { + printk(KERN_DEBUG "%s: failed to insert STA entry for" + " the AP (error %d)\n", dev->name, err); + sta_info_destroy(sta); + rcu_read_unlock(); + return; + } } + /* + * FIXME: Do we really need to update the sta_info's information here? + * We already know about the AP (we found it in our list) so it + * should already be filled with the right info, no? + * As is stands, all this is racy because typically we assume + * the information that is filled in here (except flags) doesn't + * change while a STA structure is alive. As such, it should move + * to between the sta_info_alloc() and sta_info_insert() above. + */ + sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | WLAN_STA_AUTHORIZED; @@ -2588,10 +2608,8 @@ static void ieee80211_rx_bss_info(struct net_device *dev, "local TSF - IBSS merge with BSSID %s\n", dev->name, print_mac(mac, mgmt->bssid)); ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); - rcu_read_lock(); ieee80211_ibss_add_sta(dev, NULL, mgmt->bssid, mgmt->sa); - rcu_read_unlock(); } } @@ -4023,7 +4041,6 @@ int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len) } -/* must be called under RCU read lock */ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, struct sk_buff *skb, u8 *bssid, u8 *addr) @@ -4046,8 +4063,8 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); - sta = sta_info_add(sdata, addr); - if (IS_ERR(sta)) + sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); + if (!sta) return NULL; sta->flags |= WLAN_STA_AUTHORIZED; @@ -4057,6 +4074,11 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, rate_control_rate_init(sta, local); + if (sta_info_insert(sta)) { + sta_info_destroy(sta); + return NULL; + } + return sta; } diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 576eee83d859..aee0b9eb36e3 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -232,8 +232,8 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie, struct net_device *dev); void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); -struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, - struct ieee80211_sub_if_data *sdata); +struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, + u8 *hw_addr, u64 rates, gfp_t gfp); void mesh_plink_broken(struct sta_info *sta); void mesh_plink_deactivate(struct sta_info *sta); int mesh_plink_open(struct sta_info *sta); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index c2b80500ae72..85cb75d53c43 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -89,44 +89,41 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) } /** - * mesh_plink_add - allocate and add a new mesh peer link + * mesh_plink_alloc - allocate a new mesh peer link * + * @sdata: local mesh interface * @hw_addr: hardware address (ETH_ALEN length) * @rates: rates the mesh peer supports - * @dev: local mesh interface * * The initial state of the new plink is set to LISTEN * - * Returns: non-NULL on success, ERR_PTR() on error. + * Returns: NULL on error. */ -struct sta_info *mesh_plink_add(u8 *hw_addr, u64 rates, - struct ieee80211_sub_if_data *sdata) +struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, + u8 *hw_addr, u64 rates, gfp_t gfp) { struct ieee80211_local *local = sdata->local; struct sta_info *sta; if (compare_ether_addr(hw_addr, sdata->dev->dev_addr) == 0) /* never add ourselves as neighbours */ - return ERR_PTR(-EINVAL); + return NULL; if (is_multicast_ether_addr(hw_addr)) - return ERR_PTR(-EINVAL); + return NULL; if (local->num_sta >= MESH_MAX_PLINKS) - return ERR_PTR(-ENOSPC); + return NULL; - sta = sta_info_add(sdata, hw_addr); - if (IS_ERR(sta)) - return sta; + sta = sta_info_alloc(sdata, hw_addr, gfp); + if (!sta) + return NULL; sta->plink_state = LISTEN; spin_lock_init(&sta->plink_lock); init_timer(&sta->plink_timer); sta->flags |= WLAN_STA_AUTHORIZED; sta->supp_rates[local->hw.conf.channel->band] = rates; - rate_control_rate_init(sta, local); - - mesh_accept_plinks_update(sdata); return sta; } @@ -252,8 +249,13 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, sta = sta_info_get(local, hw_addr); if (!sta) { - sta = mesh_plink_add(hw_addr, rates, sdata); - if (IS_ERR(sta)) { + sta = mesh_plink_alloc(sdata, hw_addr, rates, GFP_ATOMIC); + if (!sta) { + rcu_read_unlock(); + return; + } + if (sta_info_insert(sta)) { + sta_info_destroy(sta); rcu_read_unlock(); return; } @@ -516,12 +518,17 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, } rates = ieee80211_sta_get_rates(local, &elems, rx_status->band); - sta = mesh_plink_add(mgmt->sa, rates, sdata); - if (IS_ERR(sta)) { + sta = mesh_plink_alloc(sdata, mgmt->sa, rates, GFP_ATOMIC); + if (!sta) { mpl_dbg("Mesh plink error: plink table full\n"); rcu_read_unlock(); return; } + if (sta_info_insert(sta)) { + sta_info_destroy(sta); + rcu_read_unlock(); + return; + } event = OPN_ACPT; spin_lock_bh(&sta->plink_lock); } else { diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index ee5b66abc0f1..a230a9597398 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -31,12 +31,13 @@ * for faster lookup and a list for iteration. They are managed using * RCU, i.e. access to the list and hash table is protected by RCU. * - * STA info structures are always "alive" when they are added with - * @sta_info_add() [this may be changed in the future to allow allocating - * outside of a critical section!], they are then added to the hash - * table and list. Therefore, @sta_info_add() must also be RCU protected, - * also, the caller of @sta_info_add() cannot assume that it owns the - * structure. + * Upon allocating a STA info structure with @sta_info_alloc() or + * mesh_plink_alloc(), the caller owns that structure. It must then either + * destroy it using @sta_info_destroy() (which is pretty useless) or insert + * it into the hash table using @sta_info_insert() which demotes the reference + * from ownership to a regular RCU-protected reference; if the function + * is called without protection by an RCU critical section the reference + * is instantly invalidated. * * Because there are debugfs entries for each station, and adding those * must be able to sleep, it is also possible to "pin" a station entry, @@ -131,6 +132,10 @@ void sta_info_destroy(struct sta_info *sta) struct ieee80211_local *local = sta->local; struct sk_buff *skb; int i; + DECLARE_MAC_BUF(mbuf); + + if (!sta) + return; ASSERT_RTNL(); might_sleep(); @@ -171,6 +176,11 @@ void sta_info_destroy(struct sta_info *sta) rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); rate_control_put(sta->rate_ctrl); +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: Destroyed STA %s\n", + wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr)); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + kfree(sta); } @@ -183,18 +193,17 @@ static void sta_info_hash_add(struct ieee80211_local *local, rcu_assign_pointer(local->sta_hash[STA_HASH(sta->addr)], sta); } -struct sta_info *sta_info_add(struct ieee80211_sub_if_data *sdata, - u8 *addr) +struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, + u8 *addr, gfp_t gfp) { struct ieee80211_local *local = sdata->local; struct sta_info *sta; int i; - DECLARE_MAC_BUF(mac); - unsigned long flags; + DECLARE_MAC_BUF(mbuf); - sta = kzalloc(sizeof(*sta), GFP_ATOMIC); + sta = kzalloc(sizeof(*sta), gfp); if (!sta) - return ERR_PTR(-ENOMEM); + return NULL; memcpy(sta->addr, addr, ETH_ALEN); sta->local = local; @@ -202,11 +211,11 @@ struct sta_info *sta_info_add(struct ieee80211_sub_if_data *sdata, sta->rate_ctrl = rate_control_get(local->rate_ctrl); sta->rate_ctrl_priv = rate_control_alloc_sta(sta->rate_ctrl, - GFP_ATOMIC); + gfp); if (!sta->rate_ctrl_priv) { rate_control_put(sta->rate_ctrl); kfree(sta); - return ERR_PTR(-ENOMEM); + return NULL; } spin_lock_init(&sta->ampdu_mlme.ampdu_rx); @@ -233,11 +242,27 @@ struct sta_info *sta_info_add(struct ieee80211_sub_if_data *sdata, } skb_queue_head_init(&sta->ps_tx_buf); skb_queue_head_init(&sta->tx_filtered); + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: Allocated STA %s\n", + wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr)); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + + return sta; +} + +int sta_info_insert(struct sta_info *sta) +{ + struct ieee80211_local *local = sta->local; + struct ieee80211_sub_if_data *sdata = sta->sdata; + unsigned long flags; + DECLARE_MAC_BUF(mac); + spin_lock_irqsave(&local->sta_lock, flags); /* check if STA exists already */ - if (__sta_info_find(local, addr)) { + if (__sta_info_find(local, sta->addr)) { spin_unlock_irqrestore(&local->sta_lock, flags); - return ERR_PTR(-EEXIST); + return -EEXIST; } list_add(&sta->list, &local->sta_list); local->num_sta++; @@ -249,16 +274,16 @@ struct sta_info *sta_info_add(struct ieee80211_sub_if_data *sdata, sdata = sdata->u.vlan.ap; local->ops->sta_notify(local_to_hw(local), &sdata->vif, - STA_NOTIFY_ADD, addr); + STA_NOTIFY_ADD, sta->addr); } - spin_unlock_irqrestore(&local->sta_lock, flags); - #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Added STA %s\n", - wiphy_name(local->hw.wiphy), print_mac(mac, addr)); + printk(KERN_DEBUG "%s: Inserted STA %s\n", + wiphy_name(local->hw.wiphy), print_mac(mac, sta->addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + spin_unlock_irqrestore(&local->sta_lock, flags); + #ifdef CONFIG_MAC80211_DEBUGFS /* debugfs entry adding might sleep, so schedule process * context task for adding entry for STAs that do not yet @@ -266,7 +291,10 @@ struct sta_info *sta_info_add(struct ieee80211_sub_if_data *sdata, queue_work(local->hw.workqueue, &local->sta_debugfs_add); #endif - return sta; + if (ieee80211_vif_is_mesh(&sdata->vif)) + mesh_accept_plinks_update(sdata); + + return 0; } static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 787124c253af..3f788228eeff 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -283,12 +283,19 @@ struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr); struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, struct net_device *dev); /* - * Add a new STA info, must be under RCU read lock - * because otherwise the returned reference isn't - * necessarily valid long enough. + * Create a new STA info, caller owns returned structure + * until sta_info_insert(). */ -struct sta_info *sta_info_add(struct ieee80211_sub_if_data *sdata, - u8 *addr); +struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, + u8 *addr, gfp_t gfp); +/* + * Insert STA info into hash table/list, returns zero or a + * -EEXIST if (if the same MAC address is already present). + * + * Calling this without RCU protection makes the caller + * relinquish its reference to @sta. + */ +int sta_info_insert(struct sta_info *sta); /* * Unlink a STA info from the hash table/list. * This can NULL the STA pointer if somebody else -- cgit v1.2.3-59-g8ed1b From 693b1bbcc47b3fd436068f294147357f90cd1296 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 16:27:48 +0100 Subject: mac80211: clean up sta_info and document locking This patch cleans up the sta_info struct and documents how each set of variables is locked. Notably, flags locking is completely missing. It also adds kernel-doc for some (but not all yet) members of the struct. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_sta.c | 2 +- net/mac80211/sta_info.h | 135 +++++++++++++++++++++++++++------------------ 2 files changed, 83 insertions(+), 54 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 73cfb4da464d..fc2c1a192ed2 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -67,7 +67,7 @@ STA_FILE(last_rssi, last_rssi, D); STA_FILE(last_signal, last_signal, D); STA_FILE(last_noise, last_noise, D); STA_FILE(channel_use, channel_use, D); -STA_FILE(wep_weak_iv_count, wep_weak_iv_count, D); +STA_FILE(wep_weak_iv_count, wep_weak_iv_count, LU); static ssize_t sta_flags_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 3f788228eeff..fb5411d01f82 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -139,84 +139,113 @@ struct sta_ampdu_mlme { #define STA_INFO_PIN_STAT_PINNED 1 #define STA_INFO_PIN_STAT_DESTROY 2 - +/** + * struct sta_info - STA information + * + * This structure collects information about a station that + * mac80211 is communicating with. + * + * @list: global linked list entry + * @hnext: hash table linked list pointer + * @local: pointer to the global information + * @addr: MAC address of this STA + * @aid: STA's unique AID (1..2007, 0 = not assigned yet), + * only used in AP (and IBSS?) mode + * @flags: STA flags, see &enum ieee80211_sta_info_flags + * @ps_tx_buf: buffer of frames to transmit to this station + * when it leaves power saving state + * @tx_filtered: buffer of frames we already tried to transmit + * but were filtered by hardware due to STA having entered + * power saving state + * @rx_packets: Number of MSDUs received from this STA + * @rx_bytes: Number of bytes received from this STA + * @supp_rates: Bitmap of supported rates (per band) + * @ht_info: HT capabilities of this STA + */ struct sta_info { + /* General information, mostly static */ struct list_head list; - struct sta_info *hnext; /* next entry in hash table list */ - + struct sta_info *hnext; struct ieee80211_local *local; - - u8 addr[ETH_ALEN]; - u16 aid; /* STA's unique AID (1..2007), 0 = not yet assigned */ - u32 flags; /* WLAN_STA_ */ - - struct sk_buff_head ps_tx_buf; /* buffer of TX frames for station in - * power saving state */ - struct sk_buff_head tx_filtered; /* buffer of TX frames that were - * already given to low-level driver, - * but were filtered */ - unsigned long rx_packets, tx_packets; /* number of RX/TX MSDUs */ - unsigned long rx_bytes, tx_bytes; - unsigned long tx_retry_failed, tx_retry_count; - unsigned long tx_filtered_count; - /* moving percentage of failed MSDUs */ - unsigned int fail_avg; - - unsigned int wep_weak_iv_count; /* number of RX frames with weak IV */ - - unsigned long last_rx; - /* bitmap of supported rates per band */ - u64 supp_rates[IEEE80211_NUM_BANDS]; - int txrate_idx; - /* last rates used to send a frame to this STA */ - int last_txrate_idx, last_nonerp_txrate_idx; - - /* sub_if_data this sta belongs to */ struct ieee80211_sub_if_data *sdata; - struct ieee80211_key *key; - - u32 tx_num_consecutive_failures; - u32 tx_num_mpdu_ok; - u32 tx_num_mpdu_fail; - struct rate_control_ref *rate_ctrl; void *rate_ctrl_priv; + struct ieee80211_ht_info ht_info; + u64 supp_rates[IEEE80211_NUM_BANDS]; + u8 addr[ETH_ALEN]; + u16 aid; + u16 listen_interval; - /* last received seq/frag number from this STA (per RX queue) */ - __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; + /* + * for use by the internal lifetime management, + * see __sta_info_unlink + */ + u8 pin_status; + + /* frequently updated information, needs locking? */ + u32 flags; + + /* + * STA powersave frame queues, no more than the internal + * locking required. + */ + struct sk_buff_head ps_tx_buf; + struct sk_buff_head tx_filtered; + + /* Updated from RX path only, no locking requirements */ + unsigned long rx_packets, rx_bytes; + unsigned long wep_weak_iv_count; + unsigned long last_rx; unsigned long num_duplicates; /* number of duplicate frames received * from this STA */ - unsigned long tx_fragments; /* number of transmitted MPDUs */ unsigned long rx_fragments; /* number of received MPDUs */ unsigned long rx_dropped; /* number of dropped MPDUs from this STA */ - int last_rssi; /* RSSI of last received frame from this STA */ int last_signal; /* signal of last received frame from this STA */ int last_noise; /* noise of last received frame from this STA */ - int channel_use; - int channel_use_raw; - + /* last received seq/frag number from this STA (per RX queue) */ + __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES]; #ifdef CONFIG_MAC80211_DEBUG_COUNTERS unsigned int wme_rx_queue[NUM_RX_DATA_QUEUES]; +#endif + + /* Updated from TX status path only, no locking requirements */ + unsigned long tx_filtered_count; + unsigned long tx_retry_failed, tx_retry_count; + /* TODO: update in generic code not rate control? */ + u32 tx_num_consecutive_failures; + u32 tx_num_mpdu_ok; + u32 tx_num_mpdu_fail; + /* moving percentage of failed MSDUs */ + unsigned int fail_avg; + + /* Updated from TX path only, no locking requirements */ + unsigned long tx_packets; /* number of RX/TX MSDUs */ + unsigned long tx_bytes; + unsigned long tx_fragments; /* number of transmitted MPDUs */ + int txrate_idx; + int last_txrate_idx; +#ifdef CONFIG_MAC80211_DEBUG_COUNTERS unsigned int wme_tx_queue[NUM_RX_DATA_QUEUES]; -#endif /* CONFIG_MAC80211_DEBUG_COUNTERS */ +#endif - u16 listen_interval; + /* Debug counters, no locking doesn't matter */ + int channel_use; + int channel_use_raw; /* - * for use by the internal lifetime management, - * see __sta_info_unlink + * Aggregation information, comes with own locking. */ - u8 pin_status; - - struct ieee80211_ht_info ht_info; /* 802.11n HT capabilities - of this STA */ struct sta_ampdu_mlme ampdu_mlme; - u8 timer_to_tid[STA_TID_NUM]; /* convert timer id to tid */ + u8 timer_to_tid[STA_TID_NUM]; /* identity mapping to ID timers */ u8 tid_to_tx_q[STA_TID_NUM]; /* map tid to tx queue */ + #ifdef CONFIG_MAC80211_MESH - /* mesh peer link attributes */ + /* + * Mesh peer link attributes + * TODO: move to a sub-structure that is referenced with pointer? + */ __le16 llid; /* Local link ID */ __le16 plid; /* Peer link ID */ __le16 reason; /* Buffer for cancel reason on HOLDING state */ -- cgit v1.2.3-59-g8ed1b From 44213b5e13c907bf4aa2e73941944f90184c8772 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 25 Feb 2008 16:27:49 +0100 Subject: mac80211: remove STA entries when taking down interface When we take down an interface, we need to remove the STA info items that belong to it because otherwise we might invoke a sta_notify() callback in the driver when we later delete the STA entries, but in that case the driver will already have removed its knowledge of the interface they belonged to leading to confusion. Also, we could invoke the set_tim() callback after the driver removed its knowledge of the interface, which can lead to a crash if it requests a beacon with a then-invalid vif pointer! A side effect of this patch is that, because it was easier, it disallows changing the WDS peer while an interface is up. Should that actually be necessary, it can be added back, but the WDS peer STA entry may not be added while the interface is UP so for now I've simplified the WDS peer's STA entry lifetime management. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 99 ++++++++++++++++++------------------------ net/mac80211/ieee80211_i.h | 1 - net/mac80211/ieee80211_iface.c | 22 ++-------- net/mac80211/ieee80211_ioctl.c | 18 ++++++-- net/mac80211/sta_info.c | 14 +++++- net/mac80211/sta_info.h | 2 +- 6 files changed, 73 insertions(+), 83 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 22cba82a0c6f..484b063a3538 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -183,6 +183,7 @@ static int ieee80211_open(struct net_device *dev) struct ieee80211_if_init_conf conf; int res; bool need_hw_reconfig = 0; + struct sta_info *sta; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -256,6 +257,20 @@ static int ieee80211_open(struct net_device *dev) case IEEE80211_IF_TYPE_WDS: if (is_zero_ether_addr(sdata->u.wds.remote_addr)) return -ENOLINK; + + /* Create STA entry for the WDS peer */ + sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, + GFP_KERNEL); + if (!sta) + return -ENOMEM; + + sta->flags |= WLAN_STA_AUTHORIZED; + + res = sta_info_insert(sta); + if (res) { + sta_info_destroy(sta); + return res; + } break; case IEEE80211_IF_TYPE_VLAN: if (!sdata->u.vlan.ap) @@ -367,14 +382,20 @@ static int ieee80211_open(struct net_device *dev) static int ieee80211_stop(struct net_device *dev) { - struct ieee80211_sub_if_data *sdata; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; struct ieee80211_if_init_conf conf; struct sta_info *sta; int i; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + /* + * Stop TX on this interface first. + */ + netif_stop_queue(dev); + /* + * Now delete all active aggregation sessions. + */ rcu_read_lock(); list_for_each_entry_rcu(sta, &local->sta_list, list) { @@ -388,7 +409,24 @@ static int ieee80211_stop(struct net_device *dev) rcu_read_unlock(); - netif_stop_queue(dev); + /* + * Remove all stations associated with this interface. + * + * This must be done before calling ops->remove_interface() + * because otherwise we can later invoke ops->sta_notify() + * whenever the STAs are removed, and that invalidates driver + * assumptions about always getting a vif pointer that is valid + * (because if we remove a STA after ops->remove_interface() + * the driver will have removed the vif info already!) + * + * We could relax this and only unlink the stations from the + * hash table and list but keep them on a per-sdata list that + * will be inserted back again when the interface is brought + * up again, but I don't currently see a use case for that, + * except with WDS which gets a STA entry created when it is + * brought up. + */ + sta_info_flush(local, sdata); /* * Don't count this interface for promisc/allmulti while it @@ -453,8 +491,6 @@ static int ieee80211_stop(struct net_device *dev) netif_tx_unlock_bh(local->mdev); break; case IEEE80211_IF_TYPE_MESH_POINT: - sta_info_flush(local, sdata); - /* fall through */ case IEEE80211_IF_TYPE_STA: case IEEE80211_IF_TYPE_IBSS: sdata->u.sta.state = IEEE80211_DISABLED; @@ -892,57 +928,6 @@ void ieee80211_if_setup(struct net_device *dev) dev->destructor = ieee80211_if_free; } -/* WDS specialties */ - -int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct sta_info *sta; - int err; - DECLARE_MAC_BUF(mac); - - might_sleep(); - - if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) - return 0; - - /* Create STA entry for the new peer */ - sta = sta_info_alloc(sdata, remote_addr, GFP_KERNEL); - if (!sta) - return -ENOMEM; - - sta->flags |= WLAN_STA_AUTHORIZED; - err = sta_info_insert(sta); - if (err) { - sta_info_destroy(sta); - return err; - } - - rcu_read_lock(); - - /* Remove STA entry for the old peer */ - sta = sta_info_get(local, sdata->u.wds.remote_addr); - if (sta) - sta_info_unlink(&sta); - else - printk(KERN_DEBUG "%s: could not find STA entry for WDS link " - "peer %s\n", - dev->name, print_mac(mac, sdata->u.wds.remote_addr)); - - /* Update WDS link data */ - memcpy(&sdata->u.wds.remote_addr, remote_addr, ETH_ALEN); - - rcu_read_unlock(); - - if (sta) { - synchronize_rcu(); - sta_info_destroy(sta); - } - - return 0; -} - /* everything else */ static int __ieee80211_if_config(struct net_device *dev, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8e440c5706dd..7f10ff5d4a0b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -858,7 +858,6 @@ int ieee80211_hw_config(struct ieee80211_local *local); int ieee80211_if_config(struct net_device *dev); int ieee80211_if_config_beacon(struct net_device *dev); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); -int ieee80211_if_update_wds(struct net_device *dev, u8 *remote_addr); void ieee80211_if_setup(struct net_device *dev); int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, struct ieee80211_ht_info *req_ht_cap, diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 98b22736e883..80954a512185 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -187,8 +187,8 @@ void ieee80211_if_reinit(struct net_device *dev) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct sta_info *sta; struct sk_buff *skb; + int flushed; ASSERT_RTNL(); @@ -240,21 +240,7 @@ void ieee80211_if_reinit(struct net_device *dev) break; } case IEEE80211_IF_TYPE_WDS: - rcu_read_lock(); - sta = sta_info_get(local, sdata->u.wds.remote_addr); - if (sta) { - sta_info_unlink(&sta); - } else { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Someone had deleted my STA " - "entry for the WDS link\n", dev->name); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - } - rcu_read_unlock(); - if (sta) { - synchronize_rcu(); - sta_info_destroy(sta); - } + /* nothing to do */ break; case IEEE80211_IF_TYPE_MESH_POINT: case IEEE80211_IF_TYPE_STA: @@ -279,8 +265,8 @@ void ieee80211_if_reinit(struct net_device *dev) break; } - /* remove all STAs that are bound to this virtual interface */ - sta_info_flush(local, sdata); + flushed = sta_info_flush(local, sdata); + WARN_ON(flushed); memset(&sdata->u, 0, sizeof(sdata->u)); ieee80211_if_sdata_init(sdata); diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 5147152b9268..1d91575a0fe9 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -468,10 +468,20 @@ static int ieee80211_ioctl_siwap(struct net_device *dev, ieee80211_sta_req_auth(dev, &sdata->u.sta); return 0; } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) { - if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, - ETH_ALEN) == 0) - return 0; - return ieee80211_if_update_wds(dev, (u8 *) &ap_addr->sa_data); + /* + * If it is necessary to update the WDS peer address + * while the interface is running, then we need to do + * more work here, namely if it is running we need to + * add a new and remove the old STA entry, this is + * normally handled by _open() and _stop(). + */ + if (netif_running(dev)) + return -EBUSY; + + memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, + ETH_ALEN); + + return 0; } return -EOPNOTSUPP; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a230a9597398..a767042ec4fd 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -258,6 +258,8 @@ int sta_info_insert(struct sta_info *sta) unsigned long flags; DECLARE_MAC_BUF(mac); + WARN_ON(!netif_running(sdata->dev)); + spin_lock_irqsave(&local->sta_lock, flags); /* check if STA exists already */ if (__sta_info_find(local, sta->addr)) { @@ -608,14 +610,18 @@ void sta_info_stop(struct ieee80211_local *local) /** * sta_info_flush - flush matching STA entries from the STA table + * + * Returns the number of removed STA entries. + * * @local: local interface data * @sdata: matching rule for the net device (sta->dev) or %NULL to match all STAs */ -void sta_info_flush(struct ieee80211_local *local, +int sta_info_flush(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata) { struct sta_info *sta, *tmp; LIST_HEAD(tmp_list); + int ret = 0; unsigned long flags; might_sleep(); @@ -624,8 +630,10 @@ void sta_info_flush(struct ieee80211_local *local, list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { if (!sdata || sdata == sta->sdata) { __sta_info_unlink(&sta); - if (sta) + if (sta) { list_add_tail(&sta->list, &tmp_list); + ret++; + } } } spin_unlock_irqrestore(&local->sta_lock, flags); @@ -634,4 +642,6 @@ void sta_info_flush(struct ieee80211_local *local, list_for_each_entry_safe(sta, tmp, &tmp_list, list) sta_info_destroy(sta); + + return ret; } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index fb5411d01f82..547bfc3b2431 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -339,7 +339,7 @@ void sta_info_clear_tim_bit(struct sta_info *sta); void sta_info_init(struct ieee80211_local *local); int sta_info_start(struct ieee80211_local *local); void sta_info_stop(struct ieee80211_local *local); -void sta_info_flush(struct ieee80211_local *local, +int sta_info_flush(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); #endif /* STA_INFO_H */ -- cgit v1.2.3-59-g8ed1b From 7c8076bd8be3fd2a9a94f9687cf39e3505f0e4ec Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 26 Feb 2008 10:53:57 +0100 Subject: mac80211: don't clear next_hop in path reclaim Luis pointed out that this path is going to be freed right away anyway so there's no point in assigning next_hop. Signed-off-by: Johannes Berg Cc: Luis Carlos Cobo Signed-off-by: John W. Linville --- net/mac80211/mesh_pathtbl.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index a17f2b299045..ab4d757c453b 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -301,7 +301,6 @@ static void mesh_path_node_reclaim(struct rcu_head *rp) struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(node->mpath->dev); - rcu_assign_pointer(node->mpath->next_hop, NULL); atomic_dec(&sdata->u.sta.mpaths); kfree(node->mpath); kfree(node); -- cgit v1.2.3-59-g8ed1b From dbbea6713d6096cd1c411cb453a6b71292c78b33 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 26 Feb 2008 14:34:06 +0100 Subject: mac80211: add documentation book Quite a while ago I started this book. The required kernel-doc patches have since gone into the tree so it is now possible to build the book in mainline. The actual documentation is still rather incomplete and not all things are linked into the book, but this enables us to edit the documentation collaboratively, hopefully driver authors can add documentation based on their experience with mac80211. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- Documentation/DocBook/Makefile | 3 +- Documentation/DocBook/mac80211.tmpl | 335 ++++++++++++++++++++++++++++++++++++ include/net/mac80211.h | 7 +- net/mac80211/key.c | 4 +- net/mac80211/sta_info.c | 16 +- 5 files changed, 351 insertions(+), 14 deletions(-) create mode 100644 Documentation/DocBook/mac80211.tmpl (limited to 'net') diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 300e1707893f..9ebd1f00c6e7 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -11,7 +11,8 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \ procfs-guide.xml writing_usb_driver.xml networking.xml \ kernel-api.xml filesystems.xml lsm.xml usb.xml \ gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ - genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml + genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \ + mac80211.xml ### # The build process is as follows (targets): diff --git a/Documentation/DocBook/mac80211.tmpl b/Documentation/DocBook/mac80211.tmpl new file mode 100644 index 000000000000..b651e0a4b1c0 --- /dev/null +++ b/Documentation/DocBook/mac80211.tmpl @@ -0,0 +1,335 @@ + + + + + + The mac80211 subsystem for kernel developers + + + + Johannes + Berg + +
johannes@sipsolutions.net
+
+
+
+ + + 2007 + 2008 + Johannes Berg + + + + + This documentation is free software; you can redistribute + it and/or modify it under the terms of the GNU General Public + License version 2 as published by the Free Software Foundation. + + + + This documentation is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details. + + + + You should have received a copy of the GNU General Public + License along with this documentation; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, + MA 02111-1307 USA + + + + For more details see the file COPYING in the source + distribution of Linux. + + + + +!Pinclude/net/mac80211.h Introduction +!Pinclude/net/mac80211.h Warning + +
+ + + + + + + The basic mac80211 driver interface + + + You should read and understand the information contained + within this part of the book while implementing a driver. + In some chapters, advanced usage is noted, that may be + skipped at first. + + + This part of the book only covers station and monitor mode + functionality, additional information required to implement + the other modes is covered in the second part of the book. + + + + + Basic hardware handling + TBD + + This chapter shall contain information on getting a hw + struct allocated and registered with mac80211. + + + Since it is required to allocate rates/modes before registering + a hw struct, this chapter shall also contain information on setting + up the rate/mode structs. + + + Additionally, some discussion about the callbacks and + the general programming model should be in here, including + the definition of ieee80211_ops which will be referred to + a lot. + + + Finally, a discussion of hardware capabilities should be done + with references to other parts of the book. + + +!Finclude/net/mac80211.h ieee80211_hw +!Finclude/net/mac80211.h ieee80211_hw_flags +!Finclude/net/mac80211.h SET_IEEE80211_DEV +!Finclude/net/mac80211.h SET_IEEE80211_PERM_ADDR +!Finclude/net/mac80211.h ieee80211_ops +!Finclude/net/mac80211.h ieee80211_alloc_hw +!Finclude/net/mac80211.h ieee80211_register_hw +!Finclude/net/mac80211.h ieee80211_get_tx_led_name +!Finclude/net/mac80211.h ieee80211_get_rx_led_name +!Finclude/net/mac80211.h ieee80211_get_assoc_led_name +!Finclude/net/mac80211.h ieee80211_get_radio_led_name +!Finclude/net/mac80211.h ieee80211_unregister_hw +!Finclude/net/mac80211.h ieee80211_free_hw + + + + PHY configuration + TBD + + This chapter should describe PHY handling including + start/stop callbacks and the various structures used. + +!Finclude/net/mac80211.h ieee80211_conf +!Finclude/net/mac80211.h ieee80211_conf_flags + + + + Virtual interfaces + TBD + + This chapter should describe virtual interface basics + that are relevant to the driver (VLANs, MGMT etc are not.) + It should explain the use of the add_iface/remove_iface + callbacks as well as the interface configuration callbacks. + + Things related to AP mode should be discussed there. + + Things related to supporting multiple interfaces should be + in the appropriate chapter, a BIG FAT note should be here about + this though and the recommendation to allow only a single + interface in STA mode at first! + +!Finclude/net/mac80211.h ieee80211_if_types +!Finclude/net/mac80211.h ieee80211_if_init_conf +!Finclude/net/mac80211.h ieee80211_if_conf + + + + Receive and transmit processing + + what should be here + TBD + + This should describe the receive and transmit + paths in mac80211/the drivers as well as + transmit status handling. + + + + Frame format +!Pinclude/net/mac80211.h Frame format + + + Alignment issues + TBD + + + Calling into mac80211 from interrupts +!Pinclude/net/mac80211.h Calling mac80211 from interrupts + + + functions/definitions +!Finclude/net/mac80211.h ieee80211_rx_status +!Finclude/net/mac80211.h mac80211_rx_flags +!Finclude/net/mac80211.h ieee80211_tx_control +!Finclude/net/mac80211.h ieee80211_tx_status_flags +!Finclude/net/mac80211.h ieee80211_rx +!Finclude/net/mac80211.h ieee80211_rx_irqsafe +!Finclude/net/mac80211.h ieee80211_tx_status +!Finclude/net/mac80211.h ieee80211_tx_status_irqsafe +!Finclude/net/mac80211.h ieee80211_rts_get +!Finclude/net/mac80211.h ieee80211_rts_duration +!Finclude/net/mac80211.h ieee80211_ctstoself_get +!Finclude/net/mac80211.h ieee80211_ctstoself_duration +!Finclude/net/mac80211.h ieee80211_generic_frame_duration +!Finclude/net/mac80211.h ieee80211_get_hdrlen_from_skb +!Finclude/net/mac80211.h ieee80211_get_hdrlen +!Finclude/net/mac80211.h ieee80211_wake_queue +!Finclude/net/mac80211.h ieee80211_stop_queue +!Finclude/net/mac80211.h ieee80211_start_queues +!Finclude/net/mac80211.h ieee80211_stop_queues +!Finclude/net/mac80211.h ieee80211_wake_queues + + + + + Frame filtering +!Pinclude/net/mac80211.h Frame filtering +!Finclude/net/mac80211.h ieee80211_filter_flags + + + + + Advanced driver interface + + + Information contained within this part of the book is + of interest only for advanced interaction of mac80211 + with drivers to exploit more hardware capabilities and + improve performance. + + + + + Hardware crypto acceleration +!Pinclude/net/mac80211.h Hardware crypto acceleration + +!Finclude/net/mac80211.h set_key_cmd +!Finclude/net/mac80211.h ieee80211_key_conf +!Finclude/net/mac80211.h ieee80211_key_alg +!Finclude/net/mac80211.h ieee80211_key_flags + + + + Multiple queues and QoS support + TBD +!Finclude/net/mac80211.h ieee80211_tx_queue_params +!Finclude/net/mac80211.h ieee80211_tx_queue_stats_data +!Finclude/net/mac80211.h ieee80211_tx_queue + + + + Access point mode support + TBD + Some parts of the if_conf should be discussed here instead + + Insert notes about VLAN interfaces with hw crypto here or + in the hw crypto chapter. + +!Finclude/net/mac80211.h ieee80211_get_buffered_bc +!Finclude/net/mac80211.h ieee80211_beacon_get + + + + Supporting multiple virtual interfaces + TBD + + Note: WDS with identical MAC address should almost always be OK + + + Insert notes about having multiple virtual interfaces with + different MAC addresses here, note which configurations are + supported by mac80211, add notes about supporting hw crypto + with it. + + + + + Hardware scan offload + TBD +!Finclude/net/mac80211.h ieee80211_scan_completed + + + + + Rate control interface + + TBD + + This part of the book describes the rate control algorithm + interface and how it relates to mac80211 and drivers. + + + + dummy chapter + TBD + + + + + Internals + + TBD + + This part of the book describes mac80211 internals. + + + + + Key handling + + Key handling basics +!Pnet/mac80211/key.c Key handling basics + + + MORE TBD + TBD + + + + + Receive processing + TBD + + + + Transmit processing + TBD + + + + Station info handling + + Programming information +!Fnet/mac80211/sta_info.h sta_info +!Fnet/mac80211/sta_info.h ieee80211_sta_info_flags + + + STA information lifetime rules +!Pnet/mac80211/sta_info.c STA information lifetime rules + + + + + Synchronisation + TBD + Locking, lots of RCU + + +
diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 6aca472d7a02..d002b1c6e78e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -407,7 +407,6 @@ enum ieee80211_conf_flags { * @channel: the channel to tune to */ struct ieee80211_conf { - unsigned int regulatory_domain; int radio_enabled; int beacon_int; @@ -437,6 +436,7 @@ struct ieee80211_conf { * @IEEE80211_IF_TYPE_WDS: interface in WDS mode. * @IEEE80211_IF_TYPE_VLAN: VLAN interface bound to an AP, drivers * will never see this type. + * @IEEE80211_IF_TYPE_MESH_POINT: 802.11s mesh point */ enum ieee80211_if_types { IEEE80211_IF_TYPE_INVALID, @@ -1096,8 +1096,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, /** * ieee80211_register_hw - Register hardware device * - * You must call this function before any other functions - * except ieee80211_register_hwmode. + * You must call this function before any other functions in + * mac80211. Note that before a hardware can be registered, you + * need to fill the contained wiphy's information. * * @hw: the device to register as returned by ieee80211_alloc_hw() */ diff --git a/net/mac80211/key.c b/net/mac80211/key.c index df0c04cedbe4..166d0f00d135 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -20,8 +20,8 @@ #include "aes_ccm.h" -/* - * Key handling basics +/** + * DOC: Key handling basics * * Key handling in mac80211 is done based on per-interface (sub_if_data) * keys and per-station keys. Since each station belongs to an interface, diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a767042ec4fd..42414b441592 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -31,10 +31,10 @@ * for faster lookup and a list for iteration. They are managed using * RCU, i.e. access to the list and hash table is protected by RCU. * - * Upon allocating a STA info structure with @sta_info_alloc() or + * Upon allocating a STA info structure with sta_info_alloc() or * mesh_plink_alloc(), the caller owns that structure. It must then either - * destroy it using @sta_info_destroy() (which is pretty useless) or insert - * it into the hash table using @sta_info_insert() which demotes the reference + * destroy it using sta_info_destroy() (which is pretty useless) or insert + * it into the hash table using sta_info_insert() which demotes the reference * from ownership to a regular RCU-protected reference; if the function * is called without protection by an RCU critical section the reference * is instantly invalidated. @@ -42,19 +42,19 @@ * Because there are debugfs entries for each station, and adding those * must be able to sleep, it is also possible to "pin" a station entry, * that means it can be removed from the hash table but not be freed. - * See the comment in @__sta_info_unlink() for more information. + * See the comment in __sta_info_unlink() for more information. * * In order to remove a STA info structure, the caller needs to first - * unlink it (@sta_info_unlink()) from the list and hash tables and + * unlink it (sta_info_unlink()) from the list and hash tables and * then wait for an RCU synchronisation before it can be freed. Due to * the pinning and the possibility of multiple callers trying to remove - * the same STA info at the same time, @sta_info_unlink() can clear the + * the same STA info at the same time, sta_info_unlink() can clear the * STA info pointer it is passed to indicate that the STA info is owned * by somebody else now. * - * If @sta_info_unlink() did not clear the pointer then the caller owns + * If sta_info_unlink() did not clear the pointer then the caller owns * the STA info structure now and is responsible of destroying it with - * a call to @sta_info_destroy(), not before RCU synchronisation, of + * a call to sta_info_destroy(), not before RCU synchronisation, of * course. Note that sta_info_destroy() must be protected by the RTNL. * * In all other cases, there is no concept of ownership on a STA entry, -- cgit v1.2.3-59-g8ed1b From 03e4497ebeaa8011eb0ab0a54496ed6413b9d1a4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 27 Feb 2008 09:56:40 +0100 Subject: mac80211: fix sta_info mesh timer bug I noticed a bug I introduced when mesh is enabled: sta_info_destroy() will end up calling cancel_timer() on a timer that has never been initialized because the timer is only initialized in mesh_plink_alloc(), not in sta_info_alloc(). This patch moves the initialization of all mesh related fields into sta_info_alloc(), adds a bit of sanity checking to the cfg80211 handlers and sta_info_insert() and makes mesh_plink_alloc() a static helper function that is only used from the mesh plink code. Signed-off-by: Johannes Berg Cc: Luis Carlos Cobo Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 13 +++++++------ net/mac80211/mesh.h | 2 -- net/mac80211/mesh_plink.c | 31 +++++-------------------------- net/mac80211/sta_info.c | 33 +++++++++++++++++++++++++-------- 4 files changed, 37 insertions(+), 42 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6263cfc148c0..69238fa67bf2 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -17,8 +17,6 @@ #include "ieee80211_rate.h" #include "mesh.h" -#define DEFAULT_RATES 0 - static enum ieee80211_if_types nl80211_type_to_mac80211_type(enum nl80211_iftype type) { @@ -654,10 +652,13 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, } else sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (ieee80211_vif_is_mesh(&sdata->vif)) - sta = mesh_plink_alloc(sdata, mac, DEFAULT_RATES, GFP_KERNEL); - else - sta = sta_info_alloc(sdata, mac, GFP_KERNEL); + if (compare_ether_addr(mac, dev->dev_addr) == 0) + return -EINVAL; + + if (is_multicast_ether_addr(mac)) + return -EINVAL; + + sta = sta_info_alloc(sdata, mac, GFP_KERNEL); if (!sta) return -ENOMEM; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index aee0b9eb36e3..add9b0ddda81 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -232,8 +232,6 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie, struct net_device *dev); void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata); -struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, - u8 *hw_addr, u64 rates, gfp_t gfp); void mesh_plink_broken(struct sta_info *sta); void mesh_plink_deactivate(struct sta_info *sta); int mesh_plink_open(struct sta_info *sta); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 85cb75d53c43..7f02ae8abe90 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -88,40 +88,19 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) sta->llid = sta->plid = sta->reason = sta->plink_retries = 0; } -/** - * mesh_plink_alloc - allocate a new mesh peer link - * - * @sdata: local mesh interface - * @hw_addr: hardware address (ETH_ALEN length) - * @rates: rates the mesh peer supports - * - * The initial state of the new plink is set to LISTEN - * - * Returns: NULL on error. - */ -struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, - u8 *hw_addr, u64 rates, gfp_t gfp) +static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, + u8 *hw_addr, u64 rates) { struct ieee80211_local *local = sdata->local; struct sta_info *sta; - if (compare_ether_addr(hw_addr, sdata->dev->dev_addr) == 0) - /* never add ourselves as neighbours */ - return NULL; - - if (is_multicast_ether_addr(hw_addr)) - return NULL; - if (local->num_sta >= MESH_MAX_PLINKS) return NULL; - sta = sta_info_alloc(sdata, hw_addr, gfp); + sta = sta_info_alloc(sdata, hw_addr, GFP_ATOMIC); if (!sta) return NULL; - sta->plink_state = LISTEN; - spin_lock_init(&sta->plink_lock); - init_timer(&sta->plink_timer); sta->flags |= WLAN_STA_AUTHORIZED; sta->supp_rates[local->hw.conf.channel->band] = rates; @@ -249,7 +228,7 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, sta = sta_info_get(local, hw_addr); if (!sta) { - sta = mesh_plink_alloc(sdata, hw_addr, rates, GFP_ATOMIC); + sta = mesh_plink_alloc(sdata, hw_addr, rates); if (!sta) { rcu_read_unlock(); return; @@ -518,7 +497,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, } rates = ieee80211_sta_get_rates(local, &elems, rx_status->band); - sta = mesh_plink_alloc(sdata, mgmt->sa, rates, GFP_ATOMIC); + sta = mesh_plink_alloc(sdata, mgmt->sa, rates); if (!sta) { mpl_dbg("Mesh plink error: plink table full\n"); rcu_read_unlock(); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 42414b441592..909fa38edb6c 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -31,13 +31,12 @@ * for faster lookup and a list for iteration. They are managed using * RCU, i.e. access to the list and hash table is protected by RCU. * - * Upon allocating a STA info structure with sta_info_alloc() or - * mesh_plink_alloc(), the caller owns that structure. It must then either - * destroy it using sta_info_destroy() (which is pretty useless) or insert - * it into the hash table using sta_info_insert() which demotes the reference - * from ownership to a regular RCU-protected reference; if the function - * is called without protection by an RCU critical section the reference - * is instantly invalidated. + * Upon allocating a STA info structure with sta_info_alloc(), the caller owns + * that structure. It must then either destroy it using sta_info_destroy() + * (which is pretty useless) or insert it into the hash table using + * sta_info_insert() which demotes the reference from ownership to a regular + * RCU-protected reference; if the function is called without protection by an + * RCU critical section the reference is instantly invalidated. * * Because there are debugfs entries for each station, and adding those * must be able to sleep, it is also possible to "pin" a station entry, @@ -248,6 +247,12 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr)); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ +#ifdef CONFIG_MAC80211_MESH + sta->plink_state = LISTEN; + spin_lock_init(&sta->plink_lock); + init_timer(&sta->plink_timer); +#endif + return sta; } @@ -258,7 +263,19 @@ int sta_info_insert(struct sta_info *sta) unsigned long flags; DECLARE_MAC_BUF(mac); - WARN_ON(!netif_running(sdata->dev)); + /* + * Can't be a WARN_ON because it can be triggered through a race: + * something inserts a STA (on one CPU) without holding the RTNL + * and another CPU turns off the net device. + */ + if (unlikely(!netif_running(sdata->dev))) + return -ENETDOWN; + + if (WARN_ON(compare_ether_addr(sta->addr, sdata->dev->dev_addr) == 0)) + return -EINVAL; + + if (WARN_ON(is_multicast_ether_addr(sta->addr))) + return -EINVAL; spin_lock_irqsave(&local->sta_lock, flags); /* check if STA exists already */ -- cgit v1.2.3-59-g8ed1b From 96c46546e28282a743b97f26e94c7565350898b7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sat, 1 Mar 2008 19:32:18 +0100 Subject: mac80211: always insert key into list Today I hit one of my new WARN_ONs in the mac80211 code because a key wasn't being freed correctly. After wondering for a while I finally tracked it to the fact that STA keys aren't added to the per-sdata key list correctly, they are supposed to always be on that list, not just for default keys. This patch fixes that. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/key.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 166d0f00d135..f91fb4092652 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -174,6 +174,9 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, { int idx, defkey; + if (new) + list_add(&new->list, &sdata->key_list); + if (sta) { rcu_assign_pointer(sta->key, new); } else { @@ -190,9 +193,6 @@ static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, ieee80211_set_default_key(sdata, -1); rcu_assign_pointer(sdata->keys[idx], new); - if (new) - list_add(&new->list, &sdata->key_list); - if (defkey && new) ieee80211_set_default_key(sdata, new->conf.keyidx); } -- cgit v1.2.3-59-g8ed1b From 37659ff8e1d8d1f9c86bdb974d41479ccd001213 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Fri, 29 Feb 2008 12:13:38 -0800 Subject: mac80211: fix mesh endianness sparse warnings and unmark it as broken This patch fixes all the mesh related endianness warnings reported by sparse. As they were the reason why Johannes marked mesh as BROKEN, that flag has been removed. Signed-off-by: Luis Carlos Cobo Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/Kconfig | 2 +- net/mac80211/mesh_hwmp.c | 24 ++++++++++++------------ net/mac80211/mesh_plink.c | 5 +++-- 3 files changed, 16 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 5ca576e77615..3c3f62faae1e 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -83,7 +83,7 @@ endmenu config MAC80211_MESH bool "Enable mac80211 mesh networking (pre-802.11s) support" - depends on MAC80211 && EXPERIMENTAL && BROKEN + depends on MAC80211 && EXPERIMENTAL ---help--- This options enables support of Draft 802.11s mesh networking. The implementation is based on Draft 1.08 of the Mesh Networking diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index d8530fe7a0b3..3ee46e43ead9 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -30,16 +30,16 @@ #define PREQ_IE_FLAGS(x) (*(x)) #define PREQ_IE_HOPCOUNT(x) (*(x + 1)) #define PREQ_IE_TTL(x) (*(x + 2)) -#define PREQ_IE_PREQ_ID(x) le32_to_cpu(*((u32 *) (x + 3))) +#define PREQ_IE_PREQ_ID(x) le32_to_cpu(*((__le32 *) (x + 3))) #define PREQ_IE_ORIG_ADDR(x) (x + 7) -#define PREQ_IE_ORIG_DSN(x) le32_to_cpu(*((u32 *) (x + 13))) -#define PREQ_IE_LIFETIME(x) le32_to_cpu(*((u32 *) \ +#define PREQ_IE_ORIG_DSN(x) le32_to_cpu(*((__le32 *) (x + 13))) +#define PREQ_IE_LIFETIME(x) le32_to_cpu(*((__le32 *) \ (AE_F_SET(x) ? x + 23 : x + 17))) -#define PREQ_IE_METRIC(x) le32_to_cpu(*((u32 *) \ +#define PREQ_IE_METRIC(x) le32_to_cpu(*((__le32 *) \ (AE_F_SET(x) ? x + 27 : x + 21))) #define PREQ_IE_DST_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) #define PREQ_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) -#define PREQ_IE_DST_DSN(x) le32_to_cpu(*((u32 *) \ +#define PREQ_IE_DST_DSN(x) le32_to_cpu(*((__le32 *) \ (AE_F_SET(x) ? x + 39 : x + 33))) @@ -47,17 +47,17 @@ #define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) #define PREP_IE_TTL(x) PREQ_IE_TTL(x) #define PREP_IE_ORIG_ADDR(x) (x + 3) -#define PREP_IE_ORIG_DSN(x) le32_to_cpu(*((u32 *) (x + 9))) -#define PREP_IE_LIFETIME(x) le32_to_cpu(*((u32 *) \ +#define PREP_IE_ORIG_DSN(x) le32_to_cpu(*((__le32 *) (x + 9))) +#define PREP_IE_LIFETIME(x) le32_to_cpu(*((__le32 *) \ (AE_F_SET(x) ? x + 19 : x + 13))) -#define PREP_IE_METRIC(x) le32_to_cpu(*((u32 *) \ +#define PREP_IE_METRIC(x) le32_to_cpu(*((__le32 *) \ (AE_F_SET(x) ? x + 23 : x + 17))) #define PREP_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) -#define PREP_IE_DST_DSN(x) le32_to_cpu(*((u32 *) \ +#define PREP_IE_DST_DSN(x) le32_to_cpu(*((__le32 *) \ (AE_F_SET(x) ? x + 33 : x + 27))) #define PERR_IE_DST_ADDR(x) (x + 2) -#define PERR_IE_DST_DSN(x) le32_to_cpu(*((u32 *) (x + 8))) +#define PERR_IE_DST_DSN(x) le32_to_cpu(*((__le32 *) (x + 8))) #define TU_TO_EXP_TIME(x) (jiffies + msecs_to_jiffies(x * 1024 / 1000)) #define MSEC_TO_TU(x) (x*1000/1024) @@ -566,8 +566,8 @@ static void hwmp_perr_frame_process(struct net_device *dev, mpath->flags &= ~MESH_PATH_ACTIVE; mpath->dsn = dst_dsn; spin_unlock_bh(&mpath->state_lock); - mesh_path_error_tx(dst_addr, dst_dsn, dev->broadcast, - dev); + mesh_path_error_tx(dst_addr, __cpu_to_le32(dst_dsn), + dev->broadcast, dev); } else spin_unlock_bh(&mpath->state_lock); } diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 7f02ae8abe90..307c90e61df6 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -85,7 +85,8 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) static inline void mesh_plink_fsm_restart(struct sta_info *sta) { sta->plink_state = LISTEN; - sta->llid = sta->plid = sta->reason = sta->plink_retries = 0; + sta->llid = sta->plid = sta->reason = 0; + sta->plink_retries = 0; } static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, @@ -373,7 +374,7 @@ void mesh_plink_block(struct sta_info *sta) int mesh_plink_close(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; - int llid, plid, reason; + __le16 llid, plid, reason; #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG DECLARE_MAC_BUF(mac); #endif -- cgit v1.2.3-59-g8ed1b From 1d1b535969ca5572d87a6fcac49e1e1a31241b99 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Fri, 29 Feb 2008 12:15:28 -0800 Subject: mac80211: fix incorrect parenthesis Pointed out by Johannes Berg. Signed-off-by: Luis Carlos Cobo Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 892b5f96a427..c9d00187e790 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -3878,8 +3878,8 @@ ieee80211_sta_scan_result(struct net_device *dev, bss->ssid); } - if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS - || bss_mesh_cfg(bss))) { + if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) + || bss_mesh_cfg(bss)) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWMODE; if (bss_mesh_cfg(bss)) -- cgit v1.2.3-59-g8ed1b From 3b091cd4941912081730ffa17948da6d148c822d Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Fri, 29 Feb 2008 12:20:39 -0800 Subject: mac80211: move comment to better location Signed-off-by: Luis Carlos Cobo Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 9de1ccc11cf9..54d5ced566ef 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -48,11 +48,6 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev) struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *sta = &sdata->u.sta; - if (sta->mesh_id_len == ie->mesh_id_len && - memcmp(sta->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && - memcmp(sta->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 && - memcmp(sta->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 && - memcmp(sta->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0) /* * As support for each feature is added, check for matching * - On mesh config capabilities @@ -63,6 +58,11 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct net_device *dev) * - MDA enabled * - Power management control on fc */ + if (sta->mesh_id_len == ie->mesh_id_len && + memcmp(sta->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 && + memcmp(sta->mesh_pp_id, ie->mesh_config + PP_OFFSET, 4) == 0 && + memcmp(sta->mesh_pm_id, ie->mesh_config + PM_OFFSET, 4) == 0 && + memcmp(sta->mesh_cc_id, ie->mesh_config + CC_OFFSET, 4) == 0) return true; return false; -- cgit v1.2.3-59-g8ed1b From 4f5d4c4da89c7aa0fa194a7fd3e52233067932ea Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Fri, 29 Feb 2008 12:32:46 -0800 Subject: mac80211: breakdown mesh network attributes in different extra fields for wext Signed-off-by: Luis Carlos Cobo Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index c9d00187e790..75ced9a5476c 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -3976,18 +3976,35 @@ ieee80211_sta_scan_result(struct net_device *dev, if (bss_mesh_cfg(bss)) { char *buf; u8 *cfg = bss_mesh_cfg(bss); - buf = kmalloc(200, GFP_ATOMIC); + buf = kmalloc(50, GFP_ATOMIC); if (buf) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; - sprintf(buf, "Mesh network (version %d)\n" - "\t\t\tPath Selection Protocol ID: 0x%02X%02X%02X%02X\n" - "\t\t\tPath Selection Metric ID: 0x%02X%02X%02X%02X\n" - "\t\t\tCongestion Control Mode ID: 0x%02X%02X%02X%02X\n" - "\t\t\tChannel Precedence: 0x%02X%02X%02X%02X", - cfg[0], cfg[1], cfg[2], cfg[3], cfg[4], cfg[5], cfg[6], - cfg[7], cfg[8], cfg[9], cfg[10], cfg[11], cfg[12], - cfg[13], cfg[14], cfg[15], cfg[16]); + sprintf(buf, "Mesh network (version %d)", cfg[0]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + sprintf(buf, "Path Selection Protocol ID: " + "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], + cfg[4]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + sprintf(buf, "Path Selection Metric ID: " + "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], + cfg[8]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + sprintf(buf, "Congestion Control Mode ID: " + "0x%02X%02X%02X%02X", cfg[9], cfg[10], + cfg[11], cfg[12]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + sprintf(buf, "Channel Precedence: " + "0x%02X%02X%02X%02X", cfg[13], cfg[14], + cfg[15], cfg[16]); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); -- cgit v1.2.3-59-g8ed1b From aa2b5928433ce6ba98cf31ab048c7882aeae56a3 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Fri, 29 Feb 2008 14:30:32 -0800 Subject: mac80211: clean up use of endianness conversion functions Signed-off-by: Luis Carlos Cobo Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 30 +++++++++++++++--------------- net/mac80211/mesh_plink.c | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 3ee46e43ead9..c8c7d9aa4b94 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -449,9 +449,9 @@ static void hwmp_preq_frame_process(struct net_device *dev, ttl = ifsta->mshcfg.dot11MeshTTL; if (ttl != 0) mesh_path_sel_frame_tx(MPATH_PREP, 0, dst_addr, - __cpu_to_le32(dst_dsn), 0, orig_addr, - __cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl, - __cpu_to_le32(lifetime), __cpu_to_le32(metric), + cpu_to_le32(dst_dsn), 0, orig_addr, + cpu_to_le32(orig_dsn), mgmt->sa, 0, ttl, + cpu_to_le32(lifetime), cpu_to_le32(metric), 0, dev); else ifsta->mshstats.dropped_frames_ttl++; @@ -472,10 +472,10 @@ static void hwmp_preq_frame_process(struct net_device *dev, preq_id = PREQ_IE_PREQ_ID(preq_elem); hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, - __cpu_to_le32(orig_dsn), dst_flags, dst_addr, - __cpu_to_le32(dst_dsn), dev->broadcast, - hopcount, ttl, __cpu_to_le32(lifetime), - __cpu_to_le32(metric), __cpu_to_le32(preq_id), + cpu_to_le32(orig_dsn), dst_flags, dst_addr, + cpu_to_le32(dst_dsn), dev->broadcast, + hopcount, ttl, cpu_to_le32(lifetime), + cpu_to_le32(metric), cpu_to_le32(preq_id), dev); ifsta->mshstats.fwded_frames++; } @@ -531,9 +531,9 @@ static void hwmp_prep_frame_process(struct net_device *dev, orig_dsn = PREP_IE_ORIG_DSN(prep_elem); mesh_path_sel_frame_tx(MPATH_PREP, flags, orig_addr, - __cpu_to_le32(orig_dsn), 0, dst_addr, - __cpu_to_le32(dst_dsn), mpath->next_hop->addr, hopcount, ttl, - __cpu_to_le32(lifetime), __cpu_to_le32(metric), + cpu_to_le32(orig_dsn), 0, dst_addr, + cpu_to_le32(dst_dsn), mpath->next_hop->addr, hopcount, ttl, + cpu_to_le32(lifetime), cpu_to_le32(metric), 0, dev); rcu_read_unlock(); sdata->u.sta.mshstats.fwded_frames++; @@ -566,7 +566,7 @@ static void hwmp_perr_frame_process(struct net_device *dev, mpath->flags &= ~MESH_PATH_ACTIVE; mpath->dsn = dst_dsn; spin_unlock_bh(&mpath->state_lock); - mesh_path_error_tx(dst_addr, __cpu_to_le32(dst_dsn), + mesh_path_error_tx(dst_addr, cpu_to_le32(dst_dsn), dev->broadcast, dev); } else spin_unlock_bh(&mpath->state_lock); @@ -745,10 +745,10 @@ void mesh_path_start_discovery(struct net_device *dev) spin_unlock_bh(&mpath->state_lock); mesh_path_sel_frame_tx(MPATH_PREQ, 0, dev->dev_addr, - __cpu_to_le32(ifsta->dsn), dst_flags, mpath->dst, - __cpu_to_le32(mpath->dsn), dev->broadcast, 0, - ttl, __cpu_to_le32(lifetime), 0, - __cpu_to_le32(ifsta->preq_id++), dev); + cpu_to_le32(ifsta->dsn), dst_flags, mpath->dst, + cpu_to_le32(mpath->dsn), dev->broadcast, 0, + ttl, cpu_to_le32(lifetime), 0, + cpu_to_le32(ifsta->preq_id++), dev); mod_timer(&mpath->timer, jiffies + mpath->discovery_timeout); enddiscovery: diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 307c90e61df6..23d951a83668 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -557,7 +557,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, mpl_dbg("Mesh plink (peer, state, llid, plid, event): %s %d %d %d %d\n", print_mac(mac, mgmt->sa), sta->plink_state, - __le16_to_cpu(sta->llid), __le16_to_cpu(sta->plid), + le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), event); reason = 0; switch (sta->plink_state) { -- cgit v1.2.3-59-g8ed1b From 89a1ad6990d884796c5280d13aa58d216dffa08d Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Fri, 29 Feb 2008 14:49:37 -0800 Subject: mac80211: delete mesh_path timer on mesh_path removal This avoids dereferencing a no longer existing struct mesh_path. Signed-off-by: Luis Carlos Cobo Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh_pathtbl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index ab4d757c453b..bd58849f9dfb 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -301,6 +301,7 @@ static void mesh_path_node_reclaim(struct rcu_head *rp) struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(node->mpath->dev); + del_timer_sync(&node->mpath->timer); atomic_dec(&sdata->u.sta.mpaths); kfree(node->mpath); kfree(node); -- cgit v1.2.3-59-g8ed1b From cfa22c716f65b4d286a68aeacee4a7361a4035e6 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Fri, 29 Feb 2008 15:04:13 -0800 Subject: mac80211: always force mesh_path deletions Postponing the deletion is not really useful anymore. Signed-off-by: Luis Carlos Cobo Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 2 +- net/mac80211/mesh.h | 4 +--- net/mac80211/mesh_hwmp.c | 8 +------- net/mac80211/mesh_pathtbl.c | 24 ++++++++---------------- 4 files changed, 11 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 69238fa67bf2..6b183a3526b0 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -785,7 +785,7 @@ static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev, u8 *dst) { if (dst) - return mesh_path_del(dst, dev, false); + return mesh_path_del(dst, dev); mesh_path_flush(dev); return 0; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index add9b0ddda81..742003d3a841 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -30,7 +30,6 @@ * @MESH_PATH_FIXED: the mesh path has been manually set and should not be * modified * @MESH_PATH_RESOLVED: the mesh path can has been resolved - * @MESH_PATH_DELETE: the mesh path is scheduled to be deleted * * MESH_PATH_RESOLVED and MESH_PATH_DELETE are used by the mesh path timer to * decide when to stop or cancel the mesh path discovery. @@ -41,7 +40,6 @@ enum mesh_path_flags { MESH_PATH_DSN_VALID = BIT(2), MESH_PATH_FIXED = BIT(3), MESH_PATH_RESOLVED = BIT(4), - MESH_PATH_DELETE = BIT(5), }; /** @@ -254,7 +252,7 @@ void mesh_path_flush_pending(struct mesh_path *mpath); void mesh_path_tx_pending(struct mesh_path *mpath); int mesh_pathtbl_init(void); void mesh_pathtbl_unregister(void); -int mesh_path_del(u8 *addr, struct net_device *dev, bool force); +int mesh_path_del(u8 *addr, struct net_device *dev); void mesh_path_timer(unsigned long data); void mesh_path_flush_by_nexthop(struct sta_info *sta); void mesh_path_discard_frame(struct sk_buff *skb, struct net_device *dev); diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index c8c7d9aa4b94..324ebea10c4c 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -828,7 +828,6 @@ void mesh_path_timer(unsigned long data) { struct ieee80211_sub_if_data *sdata; struct mesh_path *mpath; - bool delete = false; rcu_read_lock(); mpath = (struct mesh_path *) data; @@ -837,10 +836,7 @@ void mesh_path_timer(unsigned long data) goto endmpathtimer; spin_lock_bh(&mpath->state_lock); sdata = IEEE80211_DEV_TO_SUB_IF(mpath->dev); - if (mpath->flags & MESH_PATH_DELETE) { - mpath->flags = 0; - delete = true; - } else if (mpath->flags & MESH_PATH_RESOLVED || + if (mpath->flags & MESH_PATH_RESOLVED || (!(mpath->flags & MESH_PATH_RESOLVING))) mpath->flags &= ~(MESH_PATH_RESOLVING | MESH_PATH_RESOLVED); else if (mpath->discovery_retries < max_preq_retries(sdata)) { @@ -856,6 +852,4 @@ void mesh_path_timer(unsigned long data) spin_unlock_bh(&mpath->state_lock); endmpathtimer: rcu_read_unlock(); - if (delete) - mesh_path_del(mpath->dst, mpath->dev, false); } diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index bd58849f9dfb..f74e4ce40ec7 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -277,7 +277,7 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta) for_each_mesh_entry(mesh_paths, p, node, i) { mpath = node->mpath; if (mpath->next_hop == sta) - mesh_path_del(mpath->dst, mpath->dev, true); + mesh_path_del(mpath->dst, mpath->dev); } } @@ -291,7 +291,7 @@ void mesh_path_flush(struct net_device *dev) for_each_mesh_entry(mesh_paths, p, node, i) { mpath = node->mpath; if (mpath->dev == dev) - mesh_path_del(mpath->dst, mpath->dev, false); + mesh_path_del(mpath->dst, mpath->dev); } } @@ -314,12 +314,8 @@ static void mesh_path_node_reclaim(struct rcu_head *rp) * @dev: local interface * * Returns: 0 if succesful - * - * State: if the path is being resolved, the deletion will be postponed until - * the path resolution completes or times out, unless the force parameter - * is given. */ -int mesh_path_del(u8 *addr, struct net_device *dev, bool force) +int mesh_path_del(u8 *addr, struct net_device *dev) { struct mesh_path *mpath; struct mpath_node *node; @@ -338,14 +334,10 @@ int mesh_path_del(u8 *addr, struct net_device *dev, bool force) if (mpath->dev == dev && memcmp(addr, mpath->dst, ETH_ALEN) == 0) { spin_lock_bh(&mpath->state_lock); - if (!force && mpath->flags & MESH_PATH_RESOLVING) { - mpath->flags |= MESH_PATH_DELETE; - } else { - mpath->flags |= MESH_PATH_RESOLVING; - hlist_del_rcu(&node->list); - call_rcu(&node->rcu, mesh_path_node_reclaim); - atomic_dec(&mesh_paths->entries); - } + mpath->flags |= MESH_PATH_RESOLVING; + hlist_del_rcu(&node->list); + call_rcu(&node->rcu, mesh_path_node_reclaim); + atomic_dec(&mesh_paths->entries); spin_unlock_bh(&mpath->state_lock); goto enddel; } @@ -508,7 +500,7 @@ void mesh_path_expire(struct net_device *dev) time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) { spin_unlock_bh(&mpath->state_lock); - mesh_path_del(mpath->dst, mpath->dev, false); + mesh_path_del(mpath->dst, mpath->dev); } else spin_unlock_bh(&mpath->state_lock); } -- cgit v1.2.3-59-g8ed1b From b4e08ea141e6d663dec31b31d6289baeaaa2a3a2 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Fri, 29 Feb 2008 15:46:08 -0800 Subject: mac80211: add PLINK_ prefix and kernel doc to enum plink_state Signed-off-by: Luis Carlos Cobo Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh.c | 6 ++-- net/mac80211/mesh_pathtbl.c | 6 ++-- net/mac80211/mesh_plink.c | 69 +++++++++++++++++++++++---------------------- net/mac80211/rx.c | 2 +- net/mac80211/sta_info.c | 2 +- net/mac80211/sta_info.h | 31 ++++++++++++++------ 6 files changed, 65 insertions(+), 51 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 54d5ced566ef..594a3356a508 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -91,9 +91,9 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0, * the mesh interface might be able to establish plinks with peers that - * are already on the table but are not on ESTAB state. However, in - * general the mesh interface is not accepting peer link requests from - * new peers, and that must be reflected in the beacon + * are already on the table but are not on PLINK_ESTAB state. However, + * in general the mesh interface is not accepting peer link requests + * from new peers, and that must be reflected in the beacon */ free_plinks = mesh_plink_availables(sdata); diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index f74e4ce40ec7..135022d7ee57 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -261,9 +261,9 @@ EXPORT_SYMBOL(mesh_plink_broken); * * @sta - mesh peer to match * - * RCU notes: this function is called when a mesh plink transitions from ESTAB - * to any other state, since ESTAB state is the only one that allows path - * creation. This will happen before the sta can be freed (because + * RCU notes: this function is called when a mesh plink transitions from + * PLINK_ESTAB to any other state, since PLINK_ESTAB state is the only one that + * allows path creation. This will happen before the sta can be freed (because * sta_info_destroy() calls this) so any reader in a rcu read block will be * protected against the plink disappearing. */ diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 23d951a83668..18fe52436c47 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -84,7 +84,7 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) */ static inline void mesh_plink_fsm_restart(struct sta_info *sta) { - sta->plink_state = LISTEN; + sta->plink_state = PLINK_LISTEN; sta->llid = sta->plid = sta->reason = 0; sta->plink_retries = 0; } @@ -121,9 +121,9 @@ static void __mesh_plink_deactivate(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; - if (sta->plink_state == ESTAB) + if (sta->plink_state == PLINK_ESTAB) mesh_plink_dec_estab_count(sdata); - sta->plink_state = BLOCKED; + sta->plink_state = PLINK_BLOCKED; mesh_path_flush_by_nexthop(sta); } @@ -243,7 +243,7 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, sta->last_rx = jiffies; sta->supp_rates[local->hw.conf.channel->band] = rates; - if (peer_accepting_plinks && sta->plink_state == LISTEN && + if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN && sdata->u.sta.accepting_plinks && sdata->u.sta.mshcfg.auto_open_plinks) mesh_plink_open(sta); @@ -283,8 +283,8 @@ static void mesh_plink_timer(unsigned long data) dev = sdata->dev; switch (sta->plink_state) { - case OPN_RCVD: - case OPN_SNT: + case PLINK_OPN_RCVD: + case PLINK_OPN_SNT: /* retry timer */ if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { u32 rand; @@ -303,17 +303,17 @@ static void mesh_plink_timer(unsigned long data) } reason = cpu_to_le16(MESH_MAX_RETRIES); /* fall through on else */ - case CNF_RCVD: + case PLINK_CNF_RCVD: /* confirm timer */ if (!reason) reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); - sta->plink_state = HOLDING; + sta->plink_state = PLINK_HOLDING; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); spin_unlock_bh(&sta->plink_lock); mesh_plink_frame_tx(dev, PLINK_CLOSE, sta->addr, llid, plid, reason); break; - case HOLDING: + case PLINK_HOLDING: /* holding timer */ del_timer(&sta->plink_timer); mesh_plink_fsm_restart(sta); @@ -345,11 +345,11 @@ int mesh_plink_open(struct sta_info *sta) spin_lock_bh(&sta->plink_lock); get_random_bytes(&llid, 2); sta->llid = llid; - if (sta->plink_state != LISTEN) { + if (sta->plink_state != PLINK_LISTEN) { spin_unlock_bh(&sta->plink_lock); return -EBUSY; } - sta->plink_state = OPN_SNT; + sta->plink_state = PLINK_OPN_SNT; mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); spin_unlock_bh(&sta->plink_lock); mpl_dbg("Mesh plink: starting establishment with %s\n", @@ -367,7 +367,7 @@ void mesh_plink_block(struct sta_info *sta) spin_lock_bh(&sta->plink_lock); __mesh_plink_deactivate(sta); - sta->plink_state = BLOCKED; + sta->plink_state = PLINK_BLOCKED; spin_unlock_bh(&sta->plink_lock); } @@ -385,18 +385,19 @@ int mesh_plink_close(struct sta_info *sta) sta->reason = cpu_to_le16(MESH_LINK_CANCELLED); reason = sta->reason; - if (sta->plink_state == LISTEN || sta->plink_state == BLOCKED) { + if (sta->plink_state == PLINK_LISTEN || + sta->plink_state == PLINK_BLOCKED) { mesh_plink_fsm_restart(sta); spin_unlock_bh(&sta->plink_lock); return 0; - } else if (sta->plink_state == ESTAB) { + } else if (sta->plink_state == PLINK_ESTAB) { __mesh_plink_deactivate(sta); /* The timer should not be running */ mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); } else if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) sta->ignore_plink_timer = true; - sta->plink_state = HOLDING; + sta->plink_state = PLINK_HOLDING; llid = sta->llid; plid = sta->plid; spin_unlock_bh(&sta->plink_lock); @@ -468,7 +469,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, return; } - if (sta && sta->plink_state == BLOCKED) { + if (sta && sta->plink_state == PLINK_BLOCKED) { rcu_read_unlock(); return; } @@ -529,7 +530,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, event = CNF_ACPT; break; case PLINK_CLOSE: - if (sta->plink_state == ESTAB) + if (sta->plink_state == PLINK_ESTAB) /* Do not check for llid or plid. This does not * follow the standard but since multiple plinks * per sta are not supported, it is necessary in @@ -562,14 +563,14 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, reason = 0; switch (sta->plink_state) { /* spin_unlock as soon as state is updated at each case */ - case LISTEN: + case PLINK_LISTEN: switch (event) { case CLS_ACPT: mesh_plink_fsm_restart(sta); spin_unlock_bh(&sta->plink_lock); break; case OPN_ACPT: - sta->plink_state = OPN_RCVD; + sta->plink_state = PLINK_OPN_RCVD; sta->plid = plid; get_random_bytes(&llid, 2); sta->llid = llid; @@ -586,7 +587,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, } break; - case OPN_SNT: + case PLINK_OPN_SNT: switch (event) { case OPN_RJCT: case CNF_RJCT: @@ -595,7 +596,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, if (!reason) reason = cpu_to_le16(MESH_CLOSE_RCVD); sta->reason = reason; - sta->plink_state = HOLDING; + sta->plink_state = PLINK_HOLDING; if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) sta->ignore_plink_timer = true; @@ -607,7 +608,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, break; case OPN_ACPT: /* retry timer is left untouched */ - sta->plink_state = OPN_RCVD; + sta->plink_state = PLINK_OPN_RCVD; sta->plid = plid; llid = sta->llid; spin_unlock_bh(&sta->plink_lock); @@ -615,7 +616,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, plid, 0); break; case CNF_ACPT: - sta->plink_state = CNF_RCVD; + sta->plink_state = PLINK_CNF_RCVD; if (!mod_plink_timer(sta, dot11MeshConfirmTimeout(sdata))) sta->ignore_plink_timer = true; @@ -628,7 +629,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, } break; - case OPN_RCVD: + case PLINK_OPN_RCVD: switch (event) { case OPN_RJCT: case CNF_RJCT: @@ -637,7 +638,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, if (!reason) reason = cpu_to_le16(MESH_CLOSE_RCVD); sta->reason = reason; - sta->plink_state = HOLDING; + sta->plink_state = PLINK_HOLDING; if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) sta->ignore_plink_timer = true; @@ -655,7 +656,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, break; case CNF_ACPT: del_timer(&sta->plink_timer); - sta->plink_state = ESTAB; + sta->plink_state = PLINK_ESTAB; mesh_plink_inc_estab_count(sdata); spin_unlock_bh(&sta->plink_lock); mpl_dbg("Mesh plink with %s ESTABLISHED\n", @@ -667,7 +668,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, } break; - case CNF_RCVD: + case PLINK_CNF_RCVD: switch (event) { case OPN_RJCT: case CNF_RJCT: @@ -676,7 +677,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, if (!reason) reason = cpu_to_le16(MESH_CLOSE_RCVD); sta->reason = reason; - sta->plink_state = HOLDING; + sta->plink_state = PLINK_HOLDING; if (!mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata))) sta->ignore_plink_timer = true; @@ -688,7 +689,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, break; case OPN_ACPT: del_timer(&sta->plink_timer); - sta->plink_state = ESTAB; + sta->plink_state = PLINK_ESTAB; mesh_plink_inc_estab_count(sdata); spin_unlock_bh(&sta->plink_lock); mpl_dbg("Mesh plink with %s ESTABLISHED\n", @@ -702,13 +703,13 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, } break; - case ESTAB: + case PLINK_ESTAB: switch (event) { case CLS_ACPT: reason = cpu_to_le16(MESH_CLOSE_RCVD); sta->reason = reason; __mesh_plink_deactivate(sta); - sta->plink_state = HOLDING; + sta->plink_state = PLINK_HOLDING; llid = sta->llid; mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); spin_unlock_bh(&sta->plink_lock); @@ -726,7 +727,7 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, break; } break; - case HOLDING: + case PLINK_HOLDING: switch (event) { case CLS_ACPT: if (del_timer(&sta->plink_timer)) @@ -749,8 +750,8 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, } break; default: - /* should not get here, BLOCKED is dealt with at the beggining - * of the function + /* should not get here, PLINK_BLOCKED is dealt with at the + * beggining of the function */ spin_unlock_bh(&sta->plink_lock); break; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8e1e2859bfd5..644d2774469d 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -411,7 +411,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) * establisment frame, beacon or probe, drop the frame. */ - if (!rx->sta || sta_plink_state(rx->sta) != ESTAB) { + if (!rx->sta || sta_plink_state(rx->sta) != PLINK_ESTAB) { struct ieee80211_mgmt *mgmt; if ((rx->fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_MGMT) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 909fa38edb6c..e27f896dae53 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -248,7 +248,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ #ifdef CONFIG_MAC80211_MESH - sta->plink_state = LISTEN; + sta->plink_state = PLINK_LISTEN; spin_lock_init(&sta->plink_lock); init_timer(&sta->plink_timer); #endif diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 547bfc3b2431..f166c8039f2b 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -106,14 +106,27 @@ struct tid_ampdu_rx { struct timer_list session_timer; }; +/** + * enum plink_state - state of a mesh peer link finite state machine + * + * @PLINK_LISTEN: initial state, considered the implicit state of non existant + * mesh peer links + * @PLINK_OPN_SNT: mesh plink open frame has been sent to this mesh peer + * @PLINK_OPN_RCVD: mesh plink open frame has been received from this mesh peer + * @PLINK_CNF_RCVD: mesh plink confirm frame has been received from this mesh + * peer + * @PLINK_ESTAB: mesh peer link is established + * @PLINK_HOLDING: mesh peer link is being closed or cancelled + * @PLINK_BLOCKED: all frames transmitted from this mesh plink are discarded + */ enum plink_state { - LISTEN, - OPN_SNT, - OPN_RCVD, - CNF_RCVD, - ESTAB, - HOLDING, - BLOCKED + PLINK_LISTEN, + PLINK_OPN_SNT, + PLINK_OPN_RCVD, + PLINK_CNF_RCVD, + PLINK_ESTAB, + PLINK_HOLDING, + PLINK_BLOCKED }; /** @@ -248,7 +261,7 @@ struct sta_info { */ __le16 llid; /* Local link ID */ __le16 plid; /* Peer link ID */ - __le16 reason; /* Buffer for cancel reason on HOLDING state */ + __le16 reason; /* Cancel reason on PLINK_HOLDING state */ u8 plink_retries; /* Retries in establishment */ bool ignore_plink_timer; enum plink_state plink_state; @@ -280,7 +293,7 @@ static inline enum plink_state sta_plink_state(struct sta_info *sta) #ifdef CONFIG_MAC80211_MESH return sta->plink_state; #endif - return LISTEN; + return PLINK_LISTEN; } -- cgit v1.2.3-59-g8ed1b From a00de5d08b4bcd1e95d02667029406224bd0619b Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Fri, 29 Feb 2008 17:07:54 -0800 Subject: mac80211: path IE fields macros, fix alignment problems and clean up Signed-off-by: Luis Carlos Cobo Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh_hwmp.c | 68 +++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 33 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 324ebea10c4c..576a6e55323e 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -7,6 +7,7 @@ * published by the Free Software Foundation. */ +#include #include "mesh.h" #define IEEE80211_FC(type, stype) cpu_to_le16(type | stype) @@ -24,40 +25,41 @@ /* Reply and forward */ #define MP_F_RF 0x2 +static inline u32 u32_field_get(u8 *preq_elem, int offset, bool ae) +{ + if (ae) + offset += 6; + return le32_to_cpu(get_unaligned((__le32 *) (preq_elem + offset))); +} + /* HWMP IE processing macros */ -#define AE_F (1<<6) -#define AE_F_SET(x) (*x & AE_F) -#define PREQ_IE_FLAGS(x) (*(x)) -#define PREQ_IE_HOPCOUNT(x) (*(x + 1)) -#define PREQ_IE_TTL(x) (*(x + 2)) -#define PREQ_IE_PREQ_ID(x) le32_to_cpu(*((__le32 *) (x + 3))) -#define PREQ_IE_ORIG_ADDR(x) (x + 7) -#define PREQ_IE_ORIG_DSN(x) le32_to_cpu(*((__le32 *) (x + 13))) -#define PREQ_IE_LIFETIME(x) le32_to_cpu(*((__le32 *) \ - (AE_F_SET(x) ? x + 23 : x + 17))) -#define PREQ_IE_METRIC(x) le32_to_cpu(*((__le32 *) \ - (AE_F_SET(x) ? x + 27 : x + 21))) -#define PREQ_IE_DST_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) -#define PREQ_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) -#define PREQ_IE_DST_DSN(x) le32_to_cpu(*((__le32 *) \ - (AE_F_SET(x) ? x + 39 : x + 33))) - - -#define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x) -#define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) -#define PREP_IE_TTL(x) PREQ_IE_TTL(x) -#define PREP_IE_ORIG_ADDR(x) (x + 3) -#define PREP_IE_ORIG_DSN(x) le32_to_cpu(*((__le32 *) (x + 9))) -#define PREP_IE_LIFETIME(x) le32_to_cpu(*((__le32 *) \ - (AE_F_SET(x) ? x + 19 : x + 13))) -#define PREP_IE_METRIC(x) le32_to_cpu(*((__le32 *) \ - (AE_F_SET(x) ? x + 23 : x + 17))) -#define PREP_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) -#define PREP_IE_DST_DSN(x) le32_to_cpu(*((__le32 *) \ - (AE_F_SET(x) ? x + 33 : x + 27))) - -#define PERR_IE_DST_ADDR(x) (x + 2) -#define PERR_IE_DST_DSN(x) le32_to_cpu(*((__le32 *) (x + 8))) +#define AE_F (1<<6) +#define AE_F_SET(x) (*x & AE_F) +#define PREQ_IE_FLAGS(x) (*(x)) +#define PREQ_IE_HOPCOUNT(x) (*(x + 1)) +#define PREQ_IE_TTL(x) (*(x + 2)) +#define PREQ_IE_PREQ_ID(x) u32_field_get(x, 3, 0) +#define PREQ_IE_ORIG_ADDR(x) (x + 7) +#define PREQ_IE_ORIG_DSN(x) u32_field_get(x, 13, 0); +#define PREQ_IE_LIFETIME(x) u32_field_get(x, 17, AE_F_SET(x)); +#define PREQ_IE_METRIC(x) u32_field_get(x, 21, AE_F_SET(x)); +#define PREQ_IE_DST_F(x) (*(AE_F_SET(x) ? x + 32 : x + 26)) +#define PREQ_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 33 : x + 27) +#define PREQ_IE_DST_DSN(x) u32_field_get(x, 33, AE_F_SET(x)); + + +#define PREP_IE_FLAGS(x) PREQ_IE_FLAGS(x) +#define PREP_IE_HOPCOUNT(x) PREQ_IE_HOPCOUNT(x) +#define PREP_IE_TTL(x) PREQ_IE_TTL(x) +#define PREP_IE_ORIG_ADDR(x) (x + 3) +#define PREP_IE_ORIG_DSN(x) u32_field_get(x, 9, 0); +#define PREP_IE_LIFETIME(x) u32_field_get(x, 13, AE_F_SET(x)); +#define PREP_IE_METRIC(x) u32_field_get(x, 17, AE_F_SET(x)); +#define PREP_IE_DST_ADDR(x) (AE_F_SET(x) ? x + 27 : x + 21) +#define PREP_IE_DST_DSN(x) u32_field_get(x, 27, AE_F_SET(x)); + +#define PERR_IE_DST_ADDR(x) (x + 2) +#define PERR_IE_DST_DSN(x) u32_field_get(x, 8, 0); #define TU_TO_EXP_TIME(x) (jiffies + msecs_to_jiffies(x * 1024 / 1000)) #define MSEC_TO_TU(x) (x*1000/1024) -- cgit v1.2.3-59-g8ed1b From 2a8ca29a88e3858685c463ffd19e11c20d14c73a Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Fri, 29 Feb 2008 17:51:25 -0800 Subject: mac80211: fix mesh_path and sta_info get_by_idx functions Skip properly entries whose dev does not match. Signed-off-by: Luis Carlos Cobo Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/mesh_pathtbl.c | 7 +++++-- net/mac80211/sta_info.c | 5 +++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 135022d7ee57..5845dc21ce85 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -98,7 +98,7 @@ struct mesh_path *mesh_path_lookup(u8 *dst, struct net_device *dev) /** * mesh_path_lookup_by_idx - look up a path in the mesh path table by its index * @idx: index - * @dev: local interface + * @dev: local interface, or NULL for all entries * * Returns: pointer to the mesh path structure, or NULL if not found. * @@ -111,7 +111,9 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev) int i; int j = 0; - for_each_mesh_entry(mesh_paths, p, node, i) + for_each_mesh_entry(mesh_paths, p, node, i) { + if (dev && node->mpath->dev != dev) + continue; if (j++ == idx) { if (MPATH_EXPIRED(node->mpath)) { spin_lock_bh(&node->mpath->state_lock); @@ -121,6 +123,7 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, struct net_device *dev) } return node->mpath; } + } return NULL; } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index e27f896dae53..3b84c16cf054 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -115,12 +115,13 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, int i = 0; list_for_each_entry_rcu(sta, &local->sta_list, list) { + if (dev && dev != sta->sdata->dev) + continue; if (i < idx) { ++i; continue; - } else if (!dev || dev == sta->sdata->dev) { - return sta; } + return sta; } return NULL; -- cgit v1.2.3-59-g8ed1b From 69d3b6f491545d326135a1def4e290cd577c9a36 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 5 Mar 2008 10:58:40 +0100 Subject: mac80211: fix hardware scan completion The mac80211 MLME requires restarting timers after a scan completes but this wasn't done when hardware scan offload was added, so add it now. Signed-off-by: Johannes Berg Tested-by: Bill Moss Cc: Reinette Chatre Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 75ced9a5476c..bece28b3eba5 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -3576,6 +3576,13 @@ static void ieee80211_send_nullfunc(struct ieee80211_local *local, } +static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) +{ + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + ieee80211_vif_is_mesh(&sdata->vif)) + ieee80211_sta_timer((unsigned long)sdata); +} + void ieee80211_scan_completed(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); @@ -3589,6 +3596,12 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) if (local->sta_hw_scanning) { local->sta_hw_scanning = 0; + /* Restart STA timer for HW scan case */ + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) + ieee80211_restart_sta_timer(sdata); + rcu_read_unlock(); + goto done; } @@ -3615,14 +3628,12 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) if (sdata->dev == local->mdev) continue; - if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { - if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) - ieee80211_send_nullfunc(local, sdata, 0); - ieee80211_sta_timer((unsigned long)sdata); - } + /* Tell AP we're back */ + if (sdata->vif.type == IEEE80211_IF_TYPE_STA && + sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) + ieee80211_send_nullfunc(local, sdata, 0); - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) - ieee80211_sta_timer((unsigned long)sdata); + ieee80211_restart_sta_timer(sdata); netif_wake_queue(sdata->dev); } -- cgit v1.2.3-59-g8ed1b From 8c8696553aa3895c2ad4289537e4af45a8877b62 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 6 Mar 2008 15:05:07 -0800 Subject: [TIPC]: Removal of message header option code This patch removes code associated with optional, user-specified fields of the TIPC message header. Such fields were never utilized by TIPC, and have now been removed from the protocol specification. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- include/net/tipc/tipc_port.h | 7 ------- net/tipc/core.c | 1 - net/tipc/msg.h | 23 ----------------------- net/tipc/port.c | 7 ------- 4 files changed, 38 deletions(-) (limited to 'net') diff --git a/include/net/tipc/tipc_port.h b/include/net/tipc/tipc_port.h index cfc4ba46de8f..c9b36b77a0b9 100644 --- a/include/net/tipc/tipc_port.h +++ b/include/net/tipc/tipc_port.h @@ -86,13 +86,6 @@ u32 tipc_createport_raw(void *usr_handle, void (*wakeup)(struct tipc_port *), const u32 importance); -/* - * tipc_set_msg_option(): port must be locked. - */ -int tipc_set_msg_option(struct tipc_port *tp_ptr, - const char *opt, - const u32 len); - int tipc_reject_msg(struct sk_buff *buf, u32 err); int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode); diff --git a/net/tipc/core.c b/net/tipc/core.c index d2d7d32c02c7..9a5eb97684a2 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -277,7 +277,6 @@ EXPORT_SYMBOL(tipc_register_media); /* TIPC API for external APIs (see tipc_port.h) */ EXPORT_SYMBOL(tipc_createport_raw); -EXPORT_SYMBOL(tipc_set_msg_option); EXPORT_SYMBOL(tipc_reject_msg); EXPORT_SYMBOL(tipc_send_buf_fast); EXPORT_SYMBOL(tipc_acknowledge); diff --git a/net/tipc/msg.h b/net/tipc/msg.h index e9ef6df26562..12f8945e8a54 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -190,18 +190,6 @@ static inline void msg_set_lookup_scope(struct tipc_msg *m, u32 n) msg_set_bits(m, 1, 19, 0x3, n); } -static inline void msg_set_options(struct tipc_msg *m, const char *opt, u32 sz) -{ - u32 hsz = msg_hdr_sz(m); - char *to = (char *)&m->hdr[hsz/4]; - - if ((hsz < DIR_MSG_H_SIZE) || ((hsz + sz) > MAX_H_SIZE)) - return; - msg_set_bits(m, 1, 16, 0x7, (hsz - 28)/4); - msg_set_hdr_sz(m, hsz + sz); - memcpy(to, opt, sz); -} - static inline u32 msg_bcast_ack(struct tipc_msg *m) { return msg_bits(m, 1, 0, 0xffff); @@ -330,17 +318,6 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) return (struct tipc_msg *)msg_data(m); } -static inline void msg_expand(struct tipc_msg *m, u32 destnode) -{ - if (!msg_short(m)) - return; - msg_set_hdr_sz(m, LONG_H_SIZE); - msg_set_orignode(m, msg_prevnode(m)); - msg_set_destnode(m, destnode); - memset(&m->hdr[8], 0, 12); -} - - /* TIPC internal message header format, version 2 diff --git a/net/tipc/port.c b/net/tipc/port.c index f508614ca59b..2a16ca43e953 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -413,13 +413,6 @@ static struct sk_buff *port_build_proto_msg(u32 destport, u32 destnode, return buf; } -int tipc_set_msg_option(struct tipc_port *tp_ptr, const char *opt, const u32 sz) -{ - msg_expand(&tp_ptr->phdr, msg_destnode(&tp_ptr->phdr)); - msg_set_options(&tp_ptr->phdr, opt, sz); - return TIPC_OK; -} - int tipc_reject_msg(struct sk_buff *buf, u32 err) { struct tipc_msg *msg = buf_msg(buf); -- cgit v1.2.3-59-g8ed1b From e247a8f5d018740220c66bd5df1928d21d277d63 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 6 Mar 2008 15:05:38 -0800 Subject: [TIPC]: Add argument validation for shutdown() This patch validates that the "how" argument to shutdown() is SHUT_RDWR, since this is the only form that TIPC supports. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/socket.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 9ae8e9f74028..3220d5cb5b5d 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1419,7 +1419,7 @@ exit: /** * shutdown - shutdown socket connection * @sock: socket structure - * @how: direction to close (unused; always treated as read + write) + * @how: direction to close (must be SHUT_RDWR) * * Terminates connection (if necessary), then purges socket's receive queue. * @@ -1432,7 +1432,8 @@ static int shutdown(struct socket *sock, int how) struct sk_buff *buf; int res; - /* Could return -EINVAL for an invalid "how", but why bother? */ + if (how != SHUT_RDWR) + return -EINVAL; if (mutex_lock_interruptible(&tsock->lock)) return -ERESTARTSYS; -- cgit v1.2.3-59-g8ed1b From 0e0609bbd2ab39a5964a70b409a5567ebbaf3700 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 6 Mar 2008 15:06:06 -0800 Subject: [TIPC]: Eliminate "sparse" symbol warnings This patch eliminates warnings about undeclared symbols. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- include/net/tipc/tipc_bearer.h | 9 +++++++++ net/tipc/core.c | 8 -------- net/tipc/core.h | 6 ++++++ 3 files changed, 15 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/net/tipc/tipc_bearer.h b/include/net/tipc/tipc_bearer.h index 2151a80cdf30..ee2f304e4919 100644 --- a/include/net/tipc/tipc_bearer.h +++ b/include/net/tipc/tipc_bearer.h @@ -99,6 +99,9 @@ struct tipc_bearer { char name[TIPC_MAX_BEARER_NAME]; }; +/* + * TIPC routines available to supported media types + */ int tipc_register_media(u32 media_type, char *media_name, @@ -123,6 +126,12 @@ void tipc_continue(struct tipc_bearer *tb_ptr); int tipc_enable_bearer(const char *bearer_name, u32 bcast_scope, u32 priority); int tipc_disable_bearer(const char *name); +/* + * Routines made available to TIPC by supported media types + */ + +int tipc_eth_media_start(void); +void tipc_eth_media_stop(void); #endif diff --git a/net/tipc/core.c b/net/tipc/core.c index 9a5eb97684a2..b41b0ac67c0b 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -48,14 +48,6 @@ #include "subscr.h" #include "config.h" -int tipc_eth_media_start(void); -void tipc_eth_media_stop(void); -int tipc_handler_start(void); -void tipc_handler_stop(void); -int tipc_socket_init(void); -void tipc_socket_stop(void); -int tipc_netlink_start(void); -void tipc_netlink_stop(void); #define TIPC_MOD_VER "1.6.2" diff --git a/net/tipc/core.h b/net/tipc/core.h index feabca580820..3fe9b70331d9 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -180,6 +180,12 @@ extern int tipc_core_start(void); extern void tipc_core_stop(void); extern int tipc_core_start_net(void); extern void tipc_core_stop_net(void); +extern int tipc_handler_start(void); +extern void tipc_handler_stop(void); +extern int tipc_netlink_start(void); +extern void tipc_netlink_stop(void); +extern int tipc_socket_init(void); +extern void tipc_socket_stop(void); static inline int delimit(int val, int min, int max) { -- cgit v1.2.3-59-g8ed1b From 06d82c9191261942ce7873ce4a8735fd2a15e662 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 6 Mar 2008 15:06:55 -0800 Subject: [TIPC]: Minor cleanup of message header code This patch eliminates some unused or duplicate message header symbols, and fixes up the comments and/or location of a few other symbols. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/link.c | 16 ++++++++-------- net/tipc/msg.c | 16 ++++++++-------- net/tipc/msg.h | 19 ++++++++----------- net/tipc/port.c | 5 +++-- 4 files changed, 27 insertions(+), 29 deletions(-) (limited to 'net') diff --git a/net/tipc/link.c b/net/tipc/link.c index cefa99824c58..a42f43430101 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -2832,15 +2832,15 @@ static void link_set_supervision_props(struct link *l_ptr, u32 tolerance) void tipc_link_set_queue_limits(struct link *l_ptr, u32 window) { /* Data messages from this node, inclusive FIRST_FRAGM */ - l_ptr->queue_limit[DATA_LOW] = window; - l_ptr->queue_limit[DATA_MEDIUM] = (window / 3) * 4; - l_ptr->queue_limit[DATA_HIGH] = (window / 3) * 5; - l_ptr->queue_limit[DATA_CRITICAL] = (window / 3) * 6; + l_ptr->queue_limit[TIPC_LOW_IMPORTANCE] = window; + l_ptr->queue_limit[TIPC_MEDIUM_IMPORTANCE] = (window / 3) * 4; + l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE] = (window / 3) * 5; + l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE] = (window / 3) * 6; /* Transiting data messages,inclusive FIRST_FRAGM */ - l_ptr->queue_limit[DATA_LOW + 4] = 300; - l_ptr->queue_limit[DATA_MEDIUM + 4] = 600; - l_ptr->queue_limit[DATA_HIGH + 4] = 900; - l_ptr->queue_limit[DATA_CRITICAL + 4] = 1200; + l_ptr->queue_limit[TIPC_LOW_IMPORTANCE + 4] = 300; + l_ptr->queue_limit[TIPC_MEDIUM_IMPORTANCE + 4] = 600; + l_ptr->queue_limit[TIPC_HIGH_IMPORTANCE + 4] = 900; + l_ptr->queue_limit[TIPC_CRITICAL_IMPORTANCE + 4] = 1200; l_ptr->queue_limit[CONN_MANAGER] = 1200; l_ptr->queue_limit[ROUTE_DISTRIBUTOR] = 1200; l_ptr->queue_limit[CHANGEOVER_PROTOCOL] = 2500; diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 782485468fb2..696a8633df75 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -73,10 +73,10 @@ void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str tipc_printf(buf, "NO(%u/%u):",msg_long_msgno(msg), msg_fragm_no(msg)); break; - case DATA_LOW: - case DATA_MEDIUM: - case DATA_HIGH: - case DATA_CRITICAL: + case TIPC_LOW_IMPORTANCE: + case TIPC_MEDIUM_IMPORTANCE: + case TIPC_HIGH_IMPORTANCE: + case TIPC_CRITICAL_IMPORTANCE: tipc_printf(buf, "DAT%u:", msg_user(msg)); if (msg_short(msg)) { tipc_printf(buf, "CON:"); @@ -229,10 +229,10 @@ void tipc_msg_print(struct print_buf *buf, struct tipc_msg *msg, const char *str switch (usr) { case CONN_MANAGER: case NAME_DISTRIBUTOR: - case DATA_LOW: - case DATA_MEDIUM: - case DATA_HIGH: - case DATA_CRITICAL: + case TIPC_LOW_IMPORTANCE: + case TIPC_MEDIUM_IMPORTANCE: + case TIPC_HIGH_IMPORTANCE: + case TIPC_CRITICAL_IMPORTANCE: if (msg_short(msg)) break; /* No error */ switch (msg_errcode(msg)) { diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 12f8945e8a54..5cf76a4f28e4 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -40,18 +40,16 @@ #include "core.h" #define TIPC_VERSION 2 -#define DATA_LOW TIPC_LOW_IMPORTANCE -#define DATA_MEDIUM TIPC_MEDIUM_IMPORTANCE -#define DATA_HIGH TIPC_HIGH_IMPORTANCE -#define DATA_CRITICAL TIPC_CRITICAL_IMPORTANCE -#define SHORT_H_SIZE 24 /* Connected,in cluster */ + +#define SHORT_H_SIZE 24 /* Connected, in-cluster messages */ #define DIR_MSG_H_SIZE 32 /* Directly addressed messages */ -#define CONN_MSG_H_SIZE 36 /* Routed connected msgs*/ -#define LONG_H_SIZE 40 /* Named Messages */ +#define LONG_H_SIZE 40 /* Named messages */ #define MCAST_H_SIZE 44 /* Multicast messages */ -#define MAX_H_SIZE 60 /* Inclusive full options */ +#define INT_H_SIZE 40 /* Internal messages */ +#define MIN_H_SIZE 24 /* Smallest legal TIPC header size */ +#define MAX_H_SIZE 60 /* Largest possible TIPC header size */ + #define MAX_MSG_SIZE (MAX_H_SIZE + TIPC_MAX_USER_MSG_SIZE) -#define LINK_CONFIG 13 /* @@ -97,7 +95,7 @@ static inline u32 msg_user(struct tipc_msg *m) static inline u32 msg_isdata(struct tipc_msg *m) { - return (msg_user(m) <= DATA_CRITICAL); + return (msg_user(m) <= TIPC_CRITICAL_IMPORTANCE); } static inline void msg_set_user(struct tipc_msg *m, u32 n) @@ -365,7 +363,6 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) #define NAME_DISTRIBUTOR 11 #define MSG_FRAGMENTER 12 #define LINK_CONFIG 13 -#define INT_H_SIZE 40 #define DSC_H_SIZE 40 /* diff --git a/net/tipc/port.c b/net/tipc/port.c index 2a16ca43e953..e2646a96935d 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -242,7 +242,8 @@ u32 tipc_createport_raw(void *usr_handle, p_ptr->publ.max_pkt = MAX_PKT_DEFAULT; p_ptr->publ.ref = ref; msg = &p_ptr->publ.phdr; - msg_init(msg, DATA_LOW, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE, 0); + msg_init(msg, TIPC_LOW_IMPORTANCE, TIPC_NAMED_MSG, TIPC_OK, LONG_H_SIZE, + 0); msg_set_orignode(msg, tipc_own_addr); msg_set_prevnode(msg, tipc_own_addr); msg_set_origport(msg, ref); @@ -625,7 +626,7 @@ void tipc_port_recv_proto_msg(struct sk_buff *buf) msg_orignode(msg), msg_destport(msg), tipc_own_addr, - DATA_HIGH, + TIPC_HIGH_IMPORTANCE, TIPC_CONN_MSG, err, 0, -- cgit v1.2.3-59-g8ed1b From 37695420a233aa8aef40c68cb338ad09e0241ec3 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 6 Mar 2008 15:07:42 -0800 Subject: [TIPC]: Use correct bitmask when setting version This patch ensures that the 3-bit version field of the TIPC message header is masked correctly when written into a message. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/msg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 5cf76a4f28e4..88a2ee03bb2a 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -85,7 +85,7 @@ static inline u32 msg_version(struct tipc_msg *m) static inline void msg_set_version(struct tipc_msg *m) { - msg_set_bits(m, 0, 29, 0xf, TIPC_VERSION); + msg_set_bits(m, 0, 29, 7, TIPC_VERSION); } static inline u32 msg_user(struct tipc_msg *m) -- cgit v1.2.3-59-g8ed1b From c0cb7ef08667374f0cbe8c94c819f74a6c935135 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 6 Mar 2008 15:08:10 -0800 Subject: [TIPC]: Enhancements to message header writing This patch makes two enhancements to the routine used to set bit fields within a TIPC message header: 1) It now ignores any bits of the new field value that are not covered by the mask being used. (Previously, if the new value exceeded the size of the mask the extra bits could corrupt other fields in the message header word being updated.) 2) The code has been optimized to minimize the number of run-time endianness conversion operations by leveraging the fact that the mask (and, in some cases, the value as well) is constant and the necessary conversion can be performed by the compiler. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/msg.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 88a2ee03bb2a..6ad070d87702 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -70,8 +70,10 @@ static inline void msg_set_bits(struct tipc_msg *m, u32 w, u32 pos, u32 mask, u32 val) { val = (val & mask) << pos; - m->hdr[w] &= ~htonl(mask << pos); - m->hdr[w] |= htonl(val); + val = htonl(val); + mask = htonl(mask << pos); + m->hdr[w] &= ~mask; + m->hdr[w] |= val; } /* -- cgit v1.2.3-59-g8ed1b From ba0fa4599484b98dbb21d279fbfdb40e9c07d30d Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 6 Mar 2008 15:08:40 -0800 Subject: [TIPC]: Update version to 1.6.3 This patch updates TIPC's version number to 1.6.3. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/tipc/core.c b/net/tipc/core.c index b41b0ac67c0b..740aac5cdfb6 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -49,7 +49,7 @@ #include "config.h" -#define TIPC_MOD_VER "1.6.2" +#define TIPC_MOD_VER "1.6.3" #ifndef CONFIG_TIPC_ZONES #define CONFIG_TIPC_ZONES 3 -- cgit v1.2.3-59-g8ed1b From db8dac20d5199307dcfcf4e01dac4bda5edf9e89 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 6 Mar 2008 16:22:02 -0800 Subject: [UDP]: Revert udplite and code split. This reverts commit db1ed684f6c430c4cdad67d058688b8a1b5e607c ("[IPV6] UDP: Rename IPv6 UDP files."), commit 8be8af8fa4405652e6c0797db5465a4be8afb998 ("[IPV4] UDP: Move IPv4-specific bits to other file.") and commit e898d4db2749c6052072e9bc4448e396cbdeb06a ("[UDP]: Allow users to configure UDP-Lite."). First, udplite is of such small cost, and it is a core protocol just like TCP and normal UDP are. We spent enormous amounts of effort to make udplite share as much code with core UDP as possible. All of that work is less valuable if we're just going to slap a config option on udplite support. It is also causing build failures, as reported on linux-next, showing that the changeset was not tested very well. In fact, this is the second build failure resulting from the udplite change. Finally, the config options provided was a bool, instead of a modular option. Meaning the udplite code does not even get build tested by allmodconfig builds, and furthermore the user is not presented with a reasonable modular build option which is particularly needed by distribution vendors. Signed-off-by: David S. Miller --- include/linux/udp.h | 10 - include/net/ipv6.h | 5 - include/net/transp_v6.h | 5 - include/net/udplite.h | 9 +- net/ipv4/Kconfig | 10 - net/ipv4/Makefile | 3 +- net/ipv4/af_inet.c | 7 +- net/ipv4/proc.c | 5 +- net/ipv4/udp.c | 1090 +++++++++++++++++++++++++++++++++++++++++++- net/ipv4/udp_ipv4.c | 1134 ---------------------------------------------- net/ipv4/udplite.c | 121 +++++ net/ipv4/udplite_ipv4.c | 121 ----- net/ipv6/Makefile | 3 +- net/ipv6/af_inet6.c | 14 - net/ipv6/ipv6_sockglue.c | 6 +- net/ipv6/proc.c | 6 - net/ipv6/udp.c | 1065 +++++++++++++++++++++++++++++++++++++++++++ net/ipv6/udp_ipv6.c | 1065 ------------------------------------------- net/ipv6/udplite.c | 125 +++++ net/ipv6/udplite_ipv6.c | 125 ----- 20 files changed, 2404 insertions(+), 2525 deletions(-) delete mode 100644 net/ipv4/udp_ipv4.c create mode 100644 net/ipv4/udplite.c delete mode 100644 net/ipv4/udplite_ipv4.c create mode 100644 net/ipv6/udp.c delete mode 100644 net/ipv6/udp_ipv6.c create mode 100644 net/ipv6/udplite.c delete mode 100644 net/ipv6/udplite_ipv6.c (limited to 'net') diff --git a/include/linux/udp.h b/include/linux/udp.h index 4144664d69d9..1e7b7cb5703b 100644 --- a/include/linux/udp.h +++ b/include/linux/udp.h @@ -70,10 +70,8 @@ struct udp_sock { #define UDPLITE_BIT 0x1 /* set by udplite proto init function */ #define UDPLITE_SEND_CC 0x2 /* set via udplite setsockopt */ #define UDPLITE_RECV_CC 0x4 /* set via udplite setsocktopt */ -#ifdef CONFIG_IP_UDPLITE __u8 pcflag; /* marks socket as UDP-Lite if > 0 */ __u8 unused[3]; -#endif /* * For encapsulation sockets. */ @@ -85,15 +83,7 @@ static inline struct udp_sock *udp_sk(const struct sock *sk) return (struct udp_sock *)sk; } -#ifdef CONFIG_IP_UDPLITE #define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag) -#define IS_PROTO_UDPLITE(__proto) ((__proto) == IPPROTO_UDPLITE) -#define IS_SOL_UDPFAMILY(level) ((level) == SOL_UDP || (level) == SOL_UDPLITE) -#else -#define IS_UDPLITE(__sk) 0 -#define IS_PROTO_UDPLITE(__proto) 0 -#define IS_SOL_UDPFAMILY(level) ((level) == SOL_UDP) -#endif #endif diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 5f6df50a33a9..8db06af1efbb 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -599,13 +599,8 @@ extern int tcp6_proc_init(void); extern void tcp6_proc_exit(void); extern int udp6_proc_init(void); extern void udp6_proc_exit(void); -#ifdef CONFIG_IP_UDPLITE extern int udplite6_proc_init(void); extern void udplite6_proc_exit(void); -#else -static inline int udplite6_proc_init(void) { return 0; } -static inline void udplite6_proc_exit(void) { } -#endif extern int ipv6_misc_proc_init(void); extern void ipv6_misc_proc_exit(void); extern int snmp6_register_dev(struct inet6_dev *idev); diff --git a/include/net/transp_v6.h b/include/net/transp_v6.h index 902e6c6bc793..27394e0447d8 100644 --- a/include/net/transp_v6.h +++ b/include/net/transp_v6.h @@ -27,13 +27,8 @@ extern int rawv6_init(void); extern void rawv6_exit(void); extern int udpv6_init(void); extern void udpv6_exit(void); -#ifdef CONFIG_IP_UDPLITE extern int udplitev6_init(void); extern void udplitev6_exit(void); -#else -static inline int udplitev6_init(void) { return 0; } -static inline void udplitev6_exit(void) { } -#endif extern int tcpv6_init(void); extern void tcpv6_exit(void); diff --git a/include/net/udplite.h b/include/net/udplite.h index 01ddb2c20264..b76b2e377af4 100644 --- a/include/net/udplite.h +++ b/include/net/udplite.h @@ -25,9 +25,7 @@ static __inline__ int udplite_getfrag(void *from, char *to, int offset, /* Designate sk as UDP-Lite socket */ static inline int udplite_sk_init(struct sock *sk) { -#ifdef CONFIG_IP_UDPLITE udp_sk(sk)->pcflag = UDPLITE_BIT; -#endif return 0; } @@ -71,7 +69,7 @@ static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) { int cscov = up->len; -#ifdef CONFIG_IP_UDPLITE + /* * Sender has set `partial coverage' option on UDP-Lite socket */ @@ -95,15 +93,13 @@ static inline int udplite_sender_cscov(struct udp_sock *up, struct udphdr *uh) * illegal, we fall back to the defaults here. */ } -#endif return cscov; } static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) { - __wsum csum = 0; -#ifdef CONFIG_IP_UDPLITE int cscov = udplite_sender_cscov(udp_sk(sk), udp_hdr(skb)); + __wsum csum = 0; skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ @@ -116,7 +112,6 @@ static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) if ((cscov -= len) <= 0) break; } -#endif return csum; } diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 5098fd2ff4d0..9c7e5ffb223d 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -632,15 +632,5 @@ config TCP_MD5SIG If unsure, say N. -config IP_UDPLITE - bool "IP: UDP-Lite Protocol (RFC 3828)" - default n - ---help--- - UDP-Lite (RFC 3828) is a UDP-like protocol with variable-length - checksum. Read for - details. - - If unsure, say N. - source "net/ipv4/ipvs/Kconfig" diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index d5226241d5ed..ad40ef3f9ebc 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -8,7 +8,7 @@ obj-y := route.o inetpeer.o protocol.o \ inet_timewait_sock.o inet_connection_sock.o \ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ tcp_minisocks.o tcp_cong.o \ - datagram.o raw.o udp.o udp_ipv4.o \ + datagram.o raw.o udp.o udplite.o \ arp.o icmp.o devinet.o af_inet.o igmp.o \ fib_frontend.o fib_semantics.o \ inet_fragment.o @@ -49,7 +49,6 @@ obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o -obj-$(CONFIG_IP_UDPLITE) += udplite_ipv4.o obj-$(CONFIG_NETLABEL) += cipso_ipv4.o obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 25871c6c7444..4cb8a1385539 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1317,18 +1317,15 @@ static int __init init_ipv4_mibs(void) if (snmp_mib_init((void **)udp_statistics, sizeof(struct udp_mib)) < 0) goto err_udp_mib; -#ifdef CONFIG_IP_UDPLITE if (snmp_mib_init((void **)udplite_statistics, sizeof(struct udp_mib)) < 0) goto err_udplite_mib; -#endif + tcp_mib_init(); return 0; -#ifdef CONFIG_IP_UDPLITE err_udplite_mib: -#endif snmp_mib_free((void **)udp_statistics); err_udp_mib: snmp_mib_free((void **)tcp_statistics); @@ -1426,10 +1423,8 @@ static int __init inet_init(void) /* Setup UDP memory threshold */ udp_init(); -#ifdef CONFIG_IP_UDPLITE /* Add UDP-Lite (RFC 3828) */ udplite4_register(); -#endif /* * Set the ICMP layer up diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index d75ddb7fa4b8..d63474c6b400 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -59,9 +59,7 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) atomic_read(&tcp_memory_allocated)); seq_printf(seq, "UDP: inuse %d mem %d\n", sock_prot_inuse_get(&udp_prot), atomic_read(&udp_memory_allocated)); -#ifdef CONFIG_IP_UDPLITE seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse_get(&udplite_prot)); -#endif seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse_get(&raw_prot)); seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues(&init_net), ip_frag_mem(&init_net)); @@ -351,7 +349,6 @@ static int snmp_seq_show(struct seq_file *seq, void *v) snmp_fold_field((void **)udp_statistics, snmp4_udp_list[i].entry)); -#ifdef CONFIG_IP_UDPLITE /* the UDP and UDP-Lite MIBs are the same */ seq_puts(seq, "\nUdpLite:"); for (i = 0; snmp4_udp_list[i].name != NULL; i++) @@ -362,7 +359,7 @@ static int snmp_seq_show(struct seq_file *seq, void *v) seq_printf(seq, " %lu", snmp_fold_field((void **)udplite_statistics, snmp4_udp_list[i].entry)); -#endif + seq_putc(seq, '\n'); return 0; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index c53d7673b57d..7ea1b67b6de1 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -246,6 +246,553 @@ int udp_get_port(struct sock *sk, unsigned short snum, return __udp_lib_get_port(sk, snum, udp_hash, scmp); } +int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) +{ + struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); + + return ( !ipv6_only_sock(sk2) && + (!inet1->rcv_saddr || !inet2->rcv_saddr || + inet1->rcv_saddr == inet2->rcv_saddr )); +} + +static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) +{ + return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); +} + +/* UDP is nearly always wildcards out the wazoo, it makes no sense to try + * harder than this. -DaveM + */ +static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, + __be16 sport, __be32 daddr, __be16 dport, + int dif, struct hlist_head udptable[]) +{ + struct sock *sk, *result = NULL; + struct hlist_node *node; + unsigned short hnum = ntohs(dport); + int badness = -1; + + read_lock(&udp_hash_lock); + sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { + struct inet_sock *inet = inet_sk(sk); + + if (sk->sk_net == net && sk->sk_hash == hnum && + !ipv6_only_sock(sk)) { + int score = (sk->sk_family == PF_INET ? 1 : 0); + if (inet->rcv_saddr) { + if (inet->rcv_saddr != daddr) + continue; + score+=2; + } + if (inet->daddr) { + if (inet->daddr != saddr) + continue; + score+=2; + } + if (inet->dport) { + if (inet->dport != sport) + continue; + score+=2; + } + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) + continue; + score+=2; + } + if (score == 9) { + result = sk; + break; + } else if (score > badness) { + result = sk; + badness = score; + } + } + } + if (result) + sock_hold(result); + read_unlock(&udp_hash_lock); + return result; +} + +static inline struct sock *udp_v4_mcast_next(struct sock *sk, + __be16 loc_port, __be32 loc_addr, + __be16 rmt_port, __be32 rmt_addr, + int dif) +{ + struct hlist_node *node; + struct sock *s = sk; + unsigned short hnum = ntohs(loc_port); + + sk_for_each_from(s, node) { + struct inet_sock *inet = inet_sk(s); + + if (s->sk_hash != hnum || + (inet->daddr && inet->daddr != rmt_addr) || + (inet->dport != rmt_port && inet->dport) || + (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || + ipv6_only_sock(s) || + (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) + continue; + if (!ip_mc_sf_allow(s, loc_addr, rmt_addr, dif)) + continue; + goto found; + } + s = NULL; +found: + return s; +} + +/* + * This routine is called by the ICMP module when it gets some + * sort of error condition. If err < 0 then the socket should + * be closed and the error returned to the user. If err > 0 + * it's just the icmp type << 8 | icmp code. + * Header points to the ip header of the error packet. We move + * on past this. Then (as it used to claim before adjustment) + * header points to the first 8 bytes of the udp header. We need + * to find the appropriate port. + */ + +void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) +{ + struct inet_sock *inet; + struct iphdr *iph = (struct iphdr*)skb->data; + struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2)); + const int type = icmp_hdr(skb)->type; + const int code = icmp_hdr(skb)->code; + struct sock *sk; + int harderr; + int err; + + sk = __udp4_lib_lookup(skb->dev->nd_net, iph->daddr, uh->dest, + iph->saddr, uh->source, skb->dev->ifindex, udptable); + if (sk == NULL) { + ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); + return; /* No socket for error */ + } + + err = 0; + harderr = 0; + inet = inet_sk(sk); + + switch (type) { + default: + case ICMP_TIME_EXCEEDED: + err = EHOSTUNREACH; + break; + case ICMP_SOURCE_QUENCH: + goto out; + case ICMP_PARAMETERPROB: + err = EPROTO; + harderr = 1; + break; + case ICMP_DEST_UNREACH: + if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ + if (inet->pmtudisc != IP_PMTUDISC_DONT) { + err = EMSGSIZE; + harderr = 1; + break; + } + goto out; + } + err = EHOSTUNREACH; + if (code <= NR_ICMP_UNREACH) { + harderr = icmp_err_convert[code].fatal; + err = icmp_err_convert[code].errno; + } + break; + } + + /* + * RFC1122: OK. Passes ICMP errors back to application, as per + * 4.1.3.3. + */ + if (!inet->recverr) { + if (!harderr || sk->sk_state != TCP_ESTABLISHED) + goto out; + } else { + ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1)); + } + sk->sk_err = err; + sk->sk_error_report(sk); +out: + sock_put(sk); +} + +void udp_err(struct sk_buff *skb, u32 info) +{ + __udp4_lib_err(skb, info, udp_hash); +} + +/* + * Throw away all pending data and cancel the corking. Socket is locked. + */ +static void udp_flush_pending_frames(struct sock *sk) +{ + struct udp_sock *up = udp_sk(sk); + + if (up->pending) { + up->len = 0; + up->pending = 0; + ip_flush_pending_frames(sk); + } +} + +/** + * udp4_hwcsum_outgoing - handle outgoing HW checksumming + * @sk: socket we are sending on + * @skb: sk_buff containing the filled-in UDP header + * (checksum field must be zeroed out) + */ +static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, + __be32 src, __be32 dst, int len ) +{ + unsigned int offset; + struct udphdr *uh = udp_hdr(skb); + __wsum csum = 0; + + if (skb_queue_len(&sk->sk_write_queue) == 1) { + /* + * Only one fragment on the socket. + */ + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct udphdr, check); + uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); + } else { + /* + * HW-checksum won't work as there are two or more + * fragments on the socket so that all csums of sk_buffs + * should be together + */ + offset = skb_transport_offset(skb); + skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); + + skb->ip_summed = CHECKSUM_NONE; + + skb_queue_walk(&sk->sk_write_queue, skb) { + csum = csum_add(csum, skb->csum); + } + + uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + } +} + +/* + * Push out all pending data as one UDP datagram. Socket is locked. + */ +static int udp_push_pending_frames(struct sock *sk) +{ + struct udp_sock *up = udp_sk(sk); + struct inet_sock *inet = inet_sk(sk); + struct flowi *fl = &inet->cork.fl; + struct sk_buff *skb; + struct udphdr *uh; + int err = 0; + int is_udplite = IS_UDPLITE(sk); + __wsum csum = 0; + + /* Grab the skbuff where UDP header space exists. */ + if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) + goto out; + + /* + * Create a UDP header + */ + uh = udp_hdr(skb); + uh->source = fl->fl_ip_sport; + uh->dest = fl->fl_ip_dport; + uh->len = htons(up->len); + uh->check = 0; + + if (is_udplite) /* UDP-Lite */ + csum = udplite_csum_outgoing(sk, skb); + + else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ + + skb->ip_summed = CHECKSUM_NONE; + goto send; + + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ + + udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); + goto send; + + } else /* `normal' UDP */ + csum = udp_csum_outgoing(sk, skb); + + /* add protocol-dependent pseudo-header */ + uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, + sk->sk_protocol, csum ); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + +send: + err = ip_push_pending_frames(sk); +out: + up->len = 0; + up->pending = 0; + if (!err) + UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); + return err; +} + +int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len) +{ + struct inet_sock *inet = inet_sk(sk); + struct udp_sock *up = udp_sk(sk); + int ulen = len; + struct ipcm_cookie ipc; + struct rtable *rt = NULL; + int free = 0; + int connected = 0; + __be32 daddr, faddr, saddr; + __be16 dport; + u8 tos; + int err, is_udplite = IS_UDPLITE(sk); + int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; + int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); + + if (len > 0xFFFF) + return -EMSGSIZE; + + /* + * Check the flags. + */ + + if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */ + return -EOPNOTSUPP; + + ipc.opt = NULL; + + if (up->pending) { + /* + * There are pending frames. + * The socket lock must be held while it's corked. + */ + lock_sock(sk); + if (likely(up->pending)) { + if (unlikely(up->pending != AF_INET)) { + release_sock(sk); + return -EINVAL; + } + goto do_append_data; + } + release_sock(sk); + } + ulen += sizeof(struct udphdr); + + /* + * Get and verify the address. + */ + if (msg->msg_name) { + struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name; + if (msg->msg_namelen < sizeof(*usin)) + return -EINVAL; + if (usin->sin_family != AF_INET) { + if (usin->sin_family != AF_UNSPEC) + return -EAFNOSUPPORT; + } + + daddr = usin->sin_addr.s_addr; + dport = usin->sin_port; + if (dport == 0) + return -EINVAL; + } else { + if (sk->sk_state != TCP_ESTABLISHED) + return -EDESTADDRREQ; + daddr = inet->daddr; + dport = inet->dport; + /* Open fast path for connected socket. + Route will not be used, if at least one option is set. + */ + connected = 1; + } + ipc.addr = inet->saddr; + + ipc.oif = sk->sk_bound_dev_if; + if (msg->msg_controllen) { + err = ip_cmsg_send(msg, &ipc); + if (err) + return err; + if (ipc.opt) + free = 1; + connected = 0; + } + if (!ipc.opt) + ipc.opt = inet->opt; + + saddr = ipc.addr; + ipc.addr = faddr = daddr; + + if (ipc.opt && ipc.opt->srr) { + if (!daddr) + return -EINVAL; + faddr = ipc.opt->faddr; + connected = 0; + } + tos = RT_TOS(inet->tos); + if (sock_flag(sk, SOCK_LOCALROUTE) || + (msg->msg_flags & MSG_DONTROUTE) || + (ipc.opt && ipc.opt->is_strictroute)) { + tos |= RTO_ONLINK; + connected = 0; + } + + if (ipv4_is_multicast(daddr)) { + if (!ipc.oif) + ipc.oif = inet->mc_index; + if (!saddr) + saddr = inet->mc_addr; + connected = 0; + } + + if (connected) + rt = (struct rtable*)sk_dst_check(sk, 0); + + if (rt == NULL) { + struct flowi fl = { .oif = ipc.oif, + .nl_u = { .ip4_u = + { .daddr = faddr, + .saddr = saddr, + .tos = tos } }, + .proto = sk->sk_protocol, + .uli_u = { .ports = + { .sport = inet->sport, + .dport = dport } } }; + security_sk_classify_flow(sk, &fl); + err = ip_route_output_flow(&init_net, &rt, &fl, sk, 1); + if (err) { + if (err == -ENETUNREACH) + IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); + goto out; + } + + err = -EACCES; + if ((rt->rt_flags & RTCF_BROADCAST) && + !sock_flag(sk, SOCK_BROADCAST)) + goto out; + if (connected) + sk_dst_set(sk, dst_clone(&rt->u.dst)); + } + + if (msg->msg_flags&MSG_CONFIRM) + goto do_confirm; +back_from_confirm: + + saddr = rt->rt_src; + if (!ipc.addr) + daddr = ipc.addr = rt->rt_dst; + + lock_sock(sk); + if (unlikely(up->pending)) { + /* The socket is already corked while preparing it. */ + /* ... which is an evident application bug. --ANK */ + release_sock(sk); + + LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); + err = -EINVAL; + goto out; + } + /* + * Now cork the socket to pend data. + */ + inet->cork.fl.fl4_dst = daddr; + inet->cork.fl.fl_ip_dport = dport; + inet->cork.fl.fl4_src = saddr; + inet->cork.fl.fl_ip_sport = inet->sport; + up->pending = AF_INET; + +do_append_data: + up->len += ulen; + getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, + sizeof(struct udphdr), &ipc, rt, + corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); + if (err) + udp_flush_pending_frames(sk); + else if (!corkreq) + err = udp_push_pending_frames(sk); + else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) + up->pending = 0; + release_sock(sk); + +out: + ip_rt_put(rt); + if (free) + kfree(ipc.opt); + if (!err) + return len; + /* + * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting + * ENOBUFS might not be good (it's not tunable per se), but otherwise + * we don't have a good statistic (IpOutDiscards but it can be too many + * things). We could add another new stat but at least for now that + * seems like overkill. + */ + if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { + UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); + } + return err; + +do_confirm: + dst_confirm(&rt->u.dst); + if (!(msg->msg_flags&MSG_PROBE) || len) + goto back_from_confirm; + err = 0; + goto out; +} + +int udp_sendpage(struct sock *sk, struct page *page, int offset, + size_t size, int flags) +{ + struct udp_sock *up = udp_sk(sk); + int ret; + + if (!up->pending) { + struct msghdr msg = { .msg_flags = flags|MSG_MORE }; + + /* Call udp_sendmsg to specify destination address which + * sendpage interface can't pass. + * This will succeed only when the socket is connected. + */ + ret = udp_sendmsg(NULL, sk, &msg, 0); + if (ret < 0) + return ret; + } + + lock_sock(sk); + + if (unlikely(!up->pending)) { + release_sock(sk); + + LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 3\n"); + return -EINVAL; + } + + ret = ip_append_page(sk, page, offset, size, flags); + if (ret == -EOPNOTSUPP) { + release_sock(sk); + return sock_no_sendpage(sk->sk_socket, page, offset, + size, flags); + } + if (ret < 0) { + udp_flush_pending_frames(sk); + goto out; + } + + up->len += size; + if (!(up->corkflag || (flags&MSG_MORE))) + ret = udp_push_pending_frames(sk); + if (!ret) + ret = size; +out: + release_sock(sk); + return ret; +} + /* * IOCTL requests applicable to the UDP protocol */ @@ -286,6 +833,107 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) return 0; } +/* + * This should be easy, if there is something there we + * return it, otherwise we block. + */ + +int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, + size_t len, int noblock, int flags, int *addr_len) +{ + struct inet_sock *inet = inet_sk(sk); + struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; + struct sk_buff *skb; + unsigned int ulen, copied; + int peeked; + int err; + int is_udplite = IS_UDPLITE(sk); + + /* + * Check any passed addresses + */ + if (addr_len) + *addr_len=sizeof(*sin); + + if (flags & MSG_ERRQUEUE) + return ip_recv_error(sk, msg, len); + +try_again: + skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), + &peeked, &err); + if (!skb) + goto out; + + ulen = skb->len - sizeof(struct udphdr); + copied = len; + if (copied > ulen) + copied = ulen; + else if (copied < ulen) + msg->msg_flags |= MSG_TRUNC; + + /* + * If checksum is needed at all, try to do it while copying the + * data. If the data is truncated, or if we only want a partial + * coverage checksum (UDP-Lite), do it before the copy. + */ + + if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { + if (udp_lib_checksum_complete(skb)) + goto csum_copy_err; + } + + if (skb_csum_unnecessary(skb)) + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied ); + else { + err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); + + if (err == -EINVAL) + goto csum_copy_err; + } + + if (err) + goto out_free; + + if (!peeked) + UDP_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); + + sock_recv_timestamp(msg, sk, skb); + + /* Copy the address. */ + if (sin) + { + sin->sin_family = AF_INET; + sin->sin_port = udp_hdr(skb)->source; + sin->sin_addr.s_addr = ip_hdr(skb)->saddr; + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); + } + if (inet->cmsg_flags) + ip_cmsg_recv(msg, skb); + + err = copied; + if (flags & MSG_TRUNC) + err = ulen; + +out_free: + lock_sock(sk); + skb_free_datagram(sk, skb); + release_sock(sk); +out: + return err; + +csum_copy_err: + lock_sock(sk); + if (!skb_kill_datagram(sk, skb, flags)) + UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); + release_sock(sk); + + if (noblock) + return -EAGAIN; + goto try_again; +} + + int udp_disconnect(struct sock *sk, int flags) { struct inet_sock *inet = inet_sk(sk); @@ -308,6 +956,319 @@ int udp_disconnect(struct sock *sk, int flags) return 0; } +/* returns: + * -1: error + * 0: success + * >0: "udp encap" protocol resubmission + * + * Note that in the success and error cases, the skb is assumed to + * have either been requeued or freed. + */ +int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) +{ + struct udp_sock *up = udp_sk(sk); + int rc; + int is_udplite = IS_UDPLITE(sk); + + /* + * Charge it to the socket, dropping if the queue is full. + */ + if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) + goto drop; + nf_reset(skb); + + if (up->encap_type) { + /* + * This is an encapsulation socket so pass the skb to + * the socket's udp_encap_rcv() hook. Otherwise, just + * fall through and pass this up the UDP socket. + * up->encap_rcv() returns the following value: + * =0 if skb was successfully passed to the encap + * handler or was discarded by it. + * >0 if skb should be passed on to UDP. + * <0 if skb should be resubmitted as proto -N + */ + + /* if we're overly short, let UDP handle it */ + if (skb->len > sizeof(struct udphdr) && + up->encap_rcv != NULL) { + int ret; + + ret = (*up->encap_rcv)(sk, skb); + if (ret <= 0) { + UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, + is_udplite); + return -ret; + } + } + + /* FALLTHROUGH -- it's a UDP Packet */ + } + + /* + * UDP-Lite specific tests, ignored on UDP sockets + */ + if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { + + /* + * MIB statistics other than incrementing the error count are + * disabled for the following two types of errors: these depend + * on the application settings, not on the functioning of the + * protocol stack as such. + * + * RFC 3828 here recommends (sec 3.3): "There should also be a + * way ... to ... at least let the receiving application block + * delivery of packets with coverage values less than a value + * provided by the application." + */ + if (up->pcrlen == 0) { /* full coverage was set */ + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " + "%d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); + goto drop; + } + /* The next case involves violating the min. coverage requested + * by the receiver. This is subtle: if receiver wants x and x is + * greater than the buffersize/MTU then receiver will complain + * that it wants x while sender emits packets of smaller size y. + * Therefore the above ...()->partial_cov statement is essential. + */ + if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { + LIMIT_NETDEBUG(KERN_WARNING + "UDPLITE: coverage %d too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); + goto drop; + } + } + + if (sk->sk_filter) { + if (udp_lib_checksum_complete(skb)) + goto drop; + } + + if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { + /* Note that an ENOMEM error is charged twice */ + if (rc == -ENOMEM) + UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); + goto drop; + } + + return 0; + +drop: + UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); + kfree_skb(skb); + return -1; +} + +/* + * Multicasts and broadcasts go to each listener. + * + * Note: called only from the BH handler context, + * so we don't need to lock the hashes. + */ +static int __udp4_lib_mcast_deliver(struct sk_buff *skb, + struct udphdr *uh, + __be32 saddr, __be32 daddr, + struct hlist_head udptable[]) +{ + struct sock *sk; + int dif; + + read_lock(&udp_hash_lock); + sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); + dif = skb->dev->ifindex; + sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); + if (sk) { + struct sock *sknext = NULL; + + do { + struct sk_buff *skb1 = skb; + + sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr, + uh->source, saddr, dif); + if (sknext) + skb1 = skb_clone(skb, GFP_ATOMIC); + + if (skb1) { + int ret = 0; + + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + ret = udp_queue_rcv_skb(sk, skb1); + else + sk_add_backlog(sk, skb1); + bh_unlock_sock(sk); + + if (ret > 0) + /* we should probably re-process instead + * of dropping packets here. */ + kfree_skb(skb1); + } + sk = sknext; + } while (sknext); + } else + kfree_skb(skb); + read_unlock(&udp_hash_lock); + return 0; +} + +/* Initialize UDP checksum. If exited with zero value (success), + * CHECKSUM_UNNECESSARY means, that no more checks are required. + * Otherwise, csum completion requires chacksumming packet body, + * including udp header and folding it to skb->csum. + */ +static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, + int proto) +{ + const struct iphdr *iph; + int err; + + UDP_SKB_CB(skb)->partial_cov = 0; + UDP_SKB_CB(skb)->cscov = skb->len; + + if (proto == IPPROTO_UDPLITE) { + err = udplite_checksum_init(skb, uh); + if (err) + return err; + } + + iph = ip_hdr(skb); + if (uh->check == 0) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else if (skb->ip_summed == CHECKSUM_COMPLETE) { + if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, + proto, skb->csum)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + if (!skb_csum_unnecessary(skb)) + skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, + skb->len, proto, 0); + /* Probably, we should checksum udp header (it should be in cache + * in any case) and data in tiny packets (< rx copybreak). + */ + + return 0; +} + +/* + * All we need to do is get the socket, and then do a checksum. + */ + +int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], + int proto) +{ + struct sock *sk; + struct udphdr *uh = udp_hdr(skb); + unsigned short ulen; + struct rtable *rt = (struct rtable*)skb->dst; + __be32 saddr = ip_hdr(skb)->saddr; + __be32 daddr = ip_hdr(skb)->daddr; + + /* + * Validate the packet. + */ + if (!pskb_may_pull(skb, sizeof(struct udphdr))) + goto drop; /* No space for header. */ + + ulen = ntohs(uh->len); + if (ulen > skb->len) + goto short_packet; + + if (proto == IPPROTO_UDP) { + /* UDP validates ulen. */ + if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) + goto short_packet; + uh = udp_hdr(skb); + } + + if (udp4_csum_init(skb, uh, proto)) + goto csum_error; + + if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) + return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); + + sk = __udp4_lib_lookup(skb->dev->nd_net, saddr, uh->source, daddr, + uh->dest, inet_iif(skb), udptable); + + if (sk != NULL) { + int ret = 0; + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + ret = udp_queue_rcv_skb(sk, skb); + else + sk_add_backlog(sk, skb); + bh_unlock_sock(sk); + sock_put(sk); + + /* a return value > 0 means to resubmit the input, but + * it wants the return to be -protocol, or 0 + */ + if (ret > 0) + return -ret; + return 0; + } + + if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto drop; + nf_reset(skb); + + /* No socket. Drop packet silently, if checksum is wrong */ + if (udp_lib_checksum_complete(skb)) + goto csum_error; + + UDP_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); + + /* + * Hmm. We got an UDP packet to a port to which we + * don't wanna listen. Ignore it. + */ + kfree_skb(skb); + return 0; + +short_packet: + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", + proto == IPPROTO_UDPLITE ? "-Lite" : "", + NIPQUAD(saddr), + ntohs(uh->source), + ulen, + skb->len, + NIPQUAD(daddr), + ntohs(uh->dest)); + goto drop; + +csum_error: + /* + * RFC1122: OK. Discards the bad packet silently (as far as + * the network is concerned, anyway) as per 4.1.3.4 (MUST). + */ + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", + proto == IPPROTO_UDPLITE ? "-Lite" : "", + NIPQUAD(saddr), + ntohs(uh->source), + NIPQUAD(daddr), + ntohs(uh->dest), + ulen); +drop: + UDP_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); + kfree_skb(skb); + return 0; +} + +int udp_rcv(struct sk_buff *skb) +{ + return __udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP); +} + +int udp_destroy_sock(struct sock *sk) +{ + lock_sock(sk); + udp_flush_pending_frames(sk); + release_sock(sk); + return 0; +} + /* * Socket option code for UDP */ @@ -318,9 +1279,7 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, struct udp_sock *up = udp_sk(sk); int val; int err = 0; -#ifdef CONFIG_IP_UDPLITE int is_udplite = IS_UDPLITE(sk); -#endif if (optlenpcrlen = val; up->pcflag |= UDPLITE_RECV_CC; break; -#endif default: err = -ENOPROTOOPT; @@ -392,6 +1349,26 @@ int udp_lib_setsockopt(struct sock *sk, int level, int optname, return err; } +int udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_push_pending_frames); + return ip_setsockopt(sk, level, optname, optval, optlen); +} + +#ifdef CONFIG_COMPAT +int compat_udp_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_push_pending_frames); + return compat_ip_setsockopt(sk, level, optname, optval, optlen); +} +#endif + int udp_lib_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { @@ -436,6 +1413,23 @@ int udp_lib_getsockopt(struct sock *sk, int level, int optname, return 0; } +int udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_getsockopt(sk, level, optname, optval, optlen); + return ip_getsockopt(sk, level, optname, optval, optlen); +} + +#ifdef CONFIG_COMPAT +int compat_udp_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_getsockopt(sk, level, optname, optval, optlen); + return compat_ip_getsockopt(sk, level, optname, optval, optlen); +} +#endif /** * udp_poll - wait for a UDP event. * @file - file struct @@ -480,6 +1474,36 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) } +DEFINE_PROTO_INUSE(udp) + +struct proto udp_prot = { + .name = "UDP", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip4_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .destroy = udp_destroy_sock, + .setsockopt = udp_setsockopt, + .getsockopt = udp_getsockopt, + .sendmsg = udp_sendmsg, + .recvmsg = udp_recvmsg, + .sendpage = udp_sendpage, + .backlog_rcv = udp_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udp_v4_get_port, + .memory_allocated = &udp_memory_allocated, + .sysctl_mem = sysctl_udp_mem, + .sysctl_wmem = &sysctl_udp_wmem_min, + .sysctl_rmem = &sysctl_udp_rmem_min, + .obj_size = sizeof(struct udp_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udp_setsockopt, + .compat_getsockopt = compat_udp_getsockopt, +#endif + REF_PROTO_INUSE(udp) +}; /* ------------------------------------------------------------------------ */ #ifdef CONFIG_PROC_FS @@ -612,6 +1636,62 @@ void udp_proc_unregister(struct udp_seq_afinfo *afinfo) proc_net_remove(&init_net, afinfo->name); memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } + +/* ------------------------------------------------------------------------ */ +static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket) +{ + struct inet_sock *inet = inet_sk(sp); + __be32 dest = inet->daddr; + __be32 src = inet->rcv_saddr; + __u16 destp = ntohs(inet->dport); + __u16 srcp = ntohs(inet->sport); + + sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" + " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p", + bucket, src, srcp, dest, destp, sp->sk_state, + atomic_read(&sp->sk_wmem_alloc), + atomic_read(&sp->sk_rmem_alloc), + 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), + atomic_read(&sp->sk_refcnt), sp); +} + +int udp4_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_printf(seq, "%-127s\n", + " sl local_address rem_address st tx_queue " + "rx_queue tr tm->when retrnsmt uid timeout " + "inode"); + else { + char tmpbuf[129]; + struct udp_iter_state *state = seq->private; + + udp4_format_sock(v, tmpbuf, state->bucket); + seq_printf(seq, "%-127s\n", tmpbuf); + } + return 0; +} + +/* ------------------------------------------------------------------------ */ +static struct file_operations udp4_seq_fops; +static struct udp_seq_afinfo udp4_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udp", + .family = AF_INET, + .hashtable = udp_hash, + .seq_show = udp4_seq_show, + .seq_fops = &udp4_seq_fops, +}; + +int __init udp4_proc_init(void) +{ + return udp_proc_register(&udp4_seq_afinfo); +} + +void udp4_proc_exit(void) +{ + udp_proc_unregister(&udp4_seq_afinfo); +} #endif /* CONFIG_PROC_FS */ void __init udp_init(void) @@ -638,6 +1718,8 @@ EXPORT_SYMBOL(udp_hash); EXPORT_SYMBOL(udp_hash_lock); EXPORT_SYMBOL(udp_ioctl); EXPORT_SYMBOL(udp_get_port); +EXPORT_SYMBOL(udp_prot); +EXPORT_SYMBOL(udp_sendmsg); EXPORT_SYMBOL(udp_lib_getsockopt); EXPORT_SYMBOL(udp_lib_setsockopt); EXPORT_SYMBOL(udp_poll); diff --git a/net/ipv4/udp_ipv4.c b/net/ipv4/udp_ipv4.c deleted file mode 100644 index fd14c2c50ed4..000000000000 --- a/net/ipv4/udp_ipv4.c +++ /dev/null @@ -1,1134 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * UDP for IPv4. - * - * For full credits, see net/ipv4/udp.c. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "udp_impl.h" - -int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) -{ - struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); - - return ( !ipv6_only_sock(sk2) && - (!inet1->rcv_saddr || !inet2->rcv_saddr || - inet1->rcv_saddr == inet2->rcv_saddr )); -} - -static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) -{ - return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); -} - -/* UDP is nearly always wildcards out the wazoo, it makes no sense to try - * harder than this. -DaveM - */ -static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, - __be16 sport, __be32 daddr, __be16 dport, - int dif, struct hlist_head udptable[]) -{ - struct sock *sk, *result = NULL; - struct hlist_node *node; - unsigned short hnum = ntohs(dport); - int badness = -1; - - read_lock(&udp_hash_lock); - sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { - struct inet_sock *inet = inet_sk(sk); - - if (sk->sk_net == net && sk->sk_hash == hnum && - !ipv6_only_sock(sk)) { - int score = (sk->sk_family == PF_INET ? 1 : 0); - if (inet->rcv_saddr) { - if (inet->rcv_saddr != daddr) - continue; - score+=2; - } - if (inet->daddr) { - if (inet->daddr != saddr) - continue; - score+=2; - } - if (inet->dport) { - if (inet->dport != sport) - continue; - score+=2; - } - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - continue; - score+=2; - } - if (score == 9) { - result = sk; - break; - } else if (score > badness) { - result = sk; - badness = score; - } - } - } - if (result) - sock_hold(result); - read_unlock(&udp_hash_lock); - return result; -} - -static inline struct sock *udp_v4_mcast_next(struct sock *sk, - __be16 loc_port, __be32 loc_addr, - __be16 rmt_port, __be32 rmt_addr, - int dif) -{ - struct hlist_node *node; - struct sock *s = sk; - unsigned short hnum = ntohs(loc_port); - - sk_for_each_from(s, node) { - struct inet_sock *inet = inet_sk(s); - - if (s->sk_hash != hnum || - (inet->daddr && inet->daddr != rmt_addr) || - (inet->dport != rmt_port && inet->dport) || - (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || - ipv6_only_sock(s) || - (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) - continue; - if (!ip_mc_sf_allow(s, loc_addr, rmt_addr, dif)) - continue; - goto found; - } - s = NULL; -found: - return s; -} - -/* - * This routine is called by the ICMP module when it gets some - * sort of error condition. If err < 0 then the socket should - * be closed and the error returned to the user. If err > 0 - * it's just the icmp type << 8 | icmp code. - * Header points to the ip header of the error packet. We move - * on past this. Then (as it used to claim before adjustment) - * header points to the first 8 bytes of the udp header. We need - * to find the appropriate port. - */ - -void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) -{ - struct inet_sock *inet; - struct iphdr *iph = (struct iphdr*)skb->data; - struct udphdr *uh = (struct udphdr*)(skb->data+(iph->ihl<<2)); - const int type = icmp_hdr(skb)->type; - const int code = icmp_hdr(skb)->code; - struct sock *sk; - int harderr; - int err; - - sk = __udp4_lib_lookup(skb->dev->nd_net, iph->daddr, uh->dest, - iph->saddr, uh->source, skb->dev->ifindex, udptable); - if (sk == NULL) { - ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); - return; /* No socket for error */ - } - - err = 0; - harderr = 0; - inet = inet_sk(sk); - - switch (type) { - default: - case ICMP_TIME_EXCEEDED: - err = EHOSTUNREACH; - break; - case ICMP_SOURCE_QUENCH: - goto out; - case ICMP_PARAMETERPROB: - err = EPROTO; - harderr = 1; - break; - case ICMP_DEST_UNREACH: - if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ - if (inet->pmtudisc != IP_PMTUDISC_DONT) { - err = EMSGSIZE; - harderr = 1; - break; - } - goto out; - } - err = EHOSTUNREACH; - if (code <= NR_ICMP_UNREACH) { - harderr = icmp_err_convert[code].fatal; - err = icmp_err_convert[code].errno; - } - break; - } - - /* - * RFC1122: OK. Passes ICMP errors back to application, as per - * 4.1.3.3. - */ - if (!inet->recverr) { - if (!harderr || sk->sk_state != TCP_ESTABLISHED) - goto out; - } else { - ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1)); - } - sk->sk_err = err; - sk->sk_error_report(sk); -out: - sock_put(sk); -} - -void udp_err(struct sk_buff *skb, u32 info) -{ - __udp4_lib_err(skb, info, udp_hash); -} - -/* - * Throw away all pending data and cancel the corking. Socket is locked. - */ -static void udp_flush_pending_frames(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - - if (up->pending) { - up->len = 0; - up->pending = 0; - ip_flush_pending_frames(sk); - } -} - -/** - * udp4_hwcsum_outgoing - handle outgoing HW checksumming - * @sk: socket we are sending on - * @skb: sk_buff containing the filled-in UDP header - * (checksum field must be zeroed out) - */ -static void udp4_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, - __be32 src, __be32 dst, int len ) -{ - unsigned int offset; - struct udphdr *uh = udp_hdr(skb); - __wsum csum = 0; - - if (skb_queue_len(&sk->sk_write_queue) == 1) { - /* - * Only one fragment on the socket. - */ - skb->csum_start = skb_transport_header(skb) - skb->head; - skb->csum_offset = offsetof(struct udphdr, check); - uh->check = ~csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, 0); - } else { - /* - * HW-checksum won't work as there are two or more - * fragments on the socket so that all csums of sk_buffs - * should be together - */ - offset = skb_transport_offset(skb); - skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); - - skb->ip_summed = CHECKSUM_NONE; - - skb_queue_walk(&sk->sk_write_queue, skb) { - csum = csum_add(csum, skb->csum); - } - - uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - } -} - -/* - * Push out all pending data as one UDP datagram. Socket is locked. - */ -static int udp_push_pending_frames(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct flowi *fl = &inet->cork.fl; - struct sk_buff *skb; - struct udphdr *uh; - int err = 0; - int is_udplite = IS_UDPLITE(sk); - __wsum csum = 0; - - /* Grab the skbuff where UDP header space exists. */ - if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) - goto out; - - /* - * Create a UDP header - */ - uh = udp_hdr(skb); - uh->source = fl->fl_ip_sport; - uh->dest = fl->fl_ip_dport; - uh->len = htons(up->len); - uh->check = 0; - - if (is_udplite) /* UDP-Lite */ - csum = udplite_csum_outgoing(sk, skb); - - else if (sk->sk_no_check == UDP_CSUM_NOXMIT) { /* UDP csum disabled */ - - skb->ip_summed = CHECKSUM_NONE; - goto send; - - } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ - - udp4_hwcsum_outgoing(sk, skb, fl->fl4_src,fl->fl4_dst, up->len); - goto send; - - } else /* `normal' UDP */ - csum = udp_csum_outgoing(sk, skb); - - /* add protocol-dependent pseudo-header */ - uh->check = csum_tcpudp_magic(fl->fl4_src, fl->fl4_dst, up->len, - sk->sk_protocol, csum ); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - -send: - err = ip_push_pending_frames(sk); -out: - up->len = 0; - up->pending = 0; - if (!err) - UDP_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); - return err; -} - -int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - size_t len) -{ - struct inet_sock *inet = inet_sk(sk); - struct udp_sock *up = udp_sk(sk); - int ulen = len; - struct ipcm_cookie ipc; - struct rtable *rt = NULL; - int free = 0; - int connected = 0; - __be32 daddr, faddr, saddr; - __be16 dport; - u8 tos; - int err, is_udplite = IS_UDPLITE(sk); - int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; - int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); - - if (len > 0xFFFF) - return -EMSGSIZE; - - /* - * Check the flags. - */ - - if (msg->msg_flags&MSG_OOB) /* Mirror BSD error message compatibility */ - return -EOPNOTSUPP; - - ipc.opt = NULL; - - if (up->pending) { - /* - * There are pending frames. - * The socket lock must be held while it's corked. - */ - lock_sock(sk); - if (likely(up->pending)) { - if (unlikely(up->pending != AF_INET)) { - release_sock(sk); - return -EINVAL; - } - goto do_append_data; - } - release_sock(sk); - } - ulen += sizeof(struct udphdr); - - /* - * Get and verify the address. - */ - if (msg->msg_name) { - struct sockaddr_in * usin = (struct sockaddr_in*)msg->msg_name; - if (msg->msg_namelen < sizeof(*usin)) - return -EINVAL; - if (usin->sin_family != AF_INET) { - if (usin->sin_family != AF_UNSPEC) - return -EAFNOSUPPORT; - } - - daddr = usin->sin_addr.s_addr; - dport = usin->sin_port; - if (dport == 0) - return -EINVAL; - } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - daddr = inet->daddr; - dport = inet->dport; - /* Open fast path for connected socket. - Route will not be used, if at least one option is set. - */ - connected = 1; - } - ipc.addr = inet->saddr; - - ipc.oif = sk->sk_bound_dev_if; - if (msg->msg_controllen) { - err = ip_cmsg_send(msg, &ipc); - if (err) - return err; - if (ipc.opt) - free = 1; - connected = 0; - } - if (!ipc.opt) - ipc.opt = inet->opt; - - saddr = ipc.addr; - ipc.addr = faddr = daddr; - - if (ipc.opt && ipc.opt->srr) { - if (!daddr) - return -EINVAL; - faddr = ipc.opt->faddr; - connected = 0; - } - tos = RT_TOS(inet->tos); - if (sock_flag(sk, SOCK_LOCALROUTE) || - (msg->msg_flags & MSG_DONTROUTE) || - (ipc.opt && ipc.opt->is_strictroute)) { - tos |= RTO_ONLINK; - connected = 0; - } - - if (ipv4_is_multicast(daddr)) { - if (!ipc.oif) - ipc.oif = inet->mc_index; - if (!saddr) - saddr = inet->mc_addr; - connected = 0; - } - - if (connected) - rt = (struct rtable*)sk_dst_check(sk, 0); - - if (rt == NULL) { - struct flowi fl = { .oif = ipc.oif, - .nl_u = { .ip4_u = - { .daddr = faddr, - .saddr = saddr, - .tos = tos } }, - .proto = sk->sk_protocol, - .uli_u = { .ports = - { .sport = inet->sport, - .dport = dport } } }; - security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(&init_net, &rt, &fl, sk, 1); - if (err) { - if (err == -ENETUNREACH) - IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); - goto out; - } - - err = -EACCES; - if ((rt->rt_flags & RTCF_BROADCAST) && - !sock_flag(sk, SOCK_BROADCAST)) - goto out; - if (connected) - sk_dst_set(sk, dst_clone(&rt->u.dst)); - } - - if (msg->msg_flags&MSG_CONFIRM) - goto do_confirm; -back_from_confirm: - - saddr = rt->rt_src; - if (!ipc.addr) - daddr = ipc.addr = rt->rt_dst; - - lock_sock(sk); - if (unlikely(up->pending)) { - /* The socket is already corked while preparing it. */ - /* ... which is an evident application bug. --ANK */ - release_sock(sk); - - LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); - err = -EINVAL; - goto out; - } - /* - * Now cork the socket to pend data. - */ - inet->cork.fl.fl4_dst = daddr; - inet->cork.fl.fl_ip_dport = dport; - inet->cork.fl.fl4_src = saddr; - inet->cork.fl.fl_ip_sport = inet->sport; - up->pending = AF_INET; - -do_append_data: - up->len += ulen; - getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; - err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, - sizeof(struct udphdr), &ipc, rt, - corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); - if (err) - udp_flush_pending_frames(sk); - else if (!corkreq) - err = udp_push_pending_frames(sk); - else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) - up->pending = 0; - release_sock(sk); - -out: - ip_rt_put(rt); - if (free) - kfree(ipc.opt); - if (!err) - return len; - /* - * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting - * ENOBUFS might not be good (it's not tunable per se), but otherwise - * we don't have a good statistic (IpOutDiscards but it can be too many - * things). We could add another new stat but at least for now that - * seems like overkill. - */ - if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); - } - return err; - -do_confirm: - dst_confirm(&rt->u.dst); - if (!(msg->msg_flags&MSG_PROBE) || len) - goto back_from_confirm; - err = 0; - goto out; -} - -int udp_sendpage(struct sock *sk, struct page *page, int offset, - size_t size, int flags) -{ - struct udp_sock *up = udp_sk(sk); - int ret; - - if (!up->pending) { - struct msghdr msg = { .msg_flags = flags|MSG_MORE }; - - /* Call udp_sendmsg to specify destination address which - * sendpage interface can't pass. - * This will succeed only when the socket is connected. - */ - ret = udp_sendmsg(NULL, sk, &msg, 0); - if (ret < 0) - return ret; - } - - lock_sock(sk); - - if (unlikely(!up->pending)) { - release_sock(sk); - - LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 3\n"); - return -EINVAL; - } - - ret = ip_append_page(sk, page, offset, size, flags); - if (ret == -EOPNOTSUPP) { - release_sock(sk); - return sock_no_sendpage(sk->sk_socket, page, offset, - size, flags); - } - if (ret < 0) { - udp_flush_pending_frames(sk); - goto out; - } - - up->len += size; - if (!(up->corkflag || (flags&MSG_MORE))) - ret = udp_push_pending_frames(sk); - if (!ret) - ret = size; -out: - release_sock(sk); - return ret; -} - -/* - * This should be easy, if there is something there we - * return it, otherwise we block. - */ - -int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, - size_t len, int noblock, int flags, int *addr_len) -{ - struct inet_sock *inet = inet_sk(sk); - struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; - struct sk_buff *skb; - unsigned int ulen, copied; - int peeked; - int err; - int is_udplite = IS_UDPLITE(sk); - - /* - * Check any passed addresses - */ - if (addr_len) - *addr_len=sizeof(*sin); - - if (flags & MSG_ERRQUEUE) - return ip_recv_error(sk, msg, len); - -try_again: - skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, &err); - if (!skb) - goto out; - - ulen = skb->len - sizeof(struct udphdr); - copied = len; - if (copied > ulen) - copied = ulen; - else if (copied < ulen) - msg->msg_flags |= MSG_TRUNC; - - /* - * If checksum is needed at all, try to do it while copying the - * data. If the data is truncated, or if we only want a partial - * coverage checksum (UDP-Lite), do it before the copy. - */ - - if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { - if (udp_lib_checksum_complete(skb)) - goto csum_copy_err; - } - - if (skb_csum_unnecessary(skb)) - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), - msg->msg_iov, copied ); - else { - err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); - - if (err == -EINVAL) - goto csum_copy_err; - } - - if (err) - goto out_free; - - if (!peeked) - UDP_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); - - sock_recv_timestamp(msg, sk, skb); - - /* Copy the address. */ - if (sin) - { - sin->sin_family = AF_INET; - sin->sin_port = udp_hdr(skb)->source; - sin->sin_addr.s_addr = ip_hdr(skb)->saddr; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - } - if (inet->cmsg_flags) - ip_cmsg_recv(msg, skb); - - err = copied; - if (flags & MSG_TRUNC) - err = ulen; - -out_free: - lock_sock(sk); - skb_free_datagram(sk, skb); - release_sock(sk); -out: - return err; - -csum_copy_err: - lock_sock(sk); - if (!skb_kill_datagram(sk, skb, flags)) - UDP_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); - release_sock(sk); - - if (noblock) - return -EAGAIN; - goto try_again; -} - - -/* returns: - * -1: error - * 0: success - * >0: "udp encap" protocol resubmission - * - * Note that in the success and error cases, the skb is assumed to - * have either been requeued or freed. - */ -int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) -{ - struct udp_sock *up = udp_sk(sk); - int rc; - int is_udplite = IS_UDPLITE(sk); - - /* - * Charge it to the socket, dropping if the queue is full. - */ - if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) - goto drop; - nf_reset(skb); - - if (up->encap_type) { - /* - * This is an encapsulation socket so pass the skb to - * the socket's udp_encap_rcv() hook. Otherwise, just - * fall through and pass this up the UDP socket. - * up->encap_rcv() returns the following value: - * =0 if skb was successfully passed to the encap - * handler or was discarded by it. - * >0 if skb should be passed on to UDP. - * <0 if skb should be resubmitted as proto -N - */ - - /* if we're overly short, let UDP handle it */ - if (skb->len > sizeof(struct udphdr) && - up->encap_rcv != NULL) { - int ret; - - ret = (*up->encap_rcv)(sk, skb); - if (ret <= 0) { - UDP_INC_STATS_BH(UDP_MIB_INDATAGRAMS, - is_udplite); - return -ret; - } - } - - /* FALLTHROUGH -- it's a UDP Packet */ - } - - /* - * UDP-Lite specific tests, ignored on UDP sockets - */ - if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { - - /* - * MIB statistics other than incrementing the error count are - * disabled for the following two types of errors: these depend - * on the application settings, not on the functioning of the - * protocol stack as such. - * - * RFC 3828 here recommends (sec 3.3): "There should also be a - * way ... to ... at least let the receiving application block - * delivery of packets with coverage values less than a value - * provided by the application." - */ - if (up->pcrlen == 0) { /* full coverage was set */ - LIMIT_NETDEBUG(KERN_WARNING "UDPLITE: partial coverage " - "%d while full coverage %d requested\n", - UDP_SKB_CB(skb)->cscov, skb->len); - goto drop; - } - /* The next case involves violating the min. coverage requested - * by the receiver. This is subtle: if receiver wants x and x is - * greater than the buffersize/MTU then receiver will complain - * that it wants x while sender emits packets of smaller size y. - * Therefore the above ...()->partial_cov statement is essential. - */ - if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { - LIMIT_NETDEBUG(KERN_WARNING - "UDPLITE: coverage %d too small, need min %d\n", - UDP_SKB_CB(skb)->cscov, up->pcrlen); - goto drop; - } - } - - if (sk->sk_filter) { - if (udp_lib_checksum_complete(skb)) - goto drop; - } - - if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { - /* Note that an ENOMEM error is charged twice */ - if (rc == -ENOMEM) - UDP_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); - goto drop; - } - - return 0; - -drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); - kfree_skb(skb); - return -1; -} - -/* - * Multicasts and broadcasts go to each listener. - * - * Note: called only from the BH handler context, - * so we don't need to lock the hashes. - */ -static int __udp4_lib_mcast_deliver(struct sk_buff *skb, - struct udphdr *uh, - __be32 saddr, __be32 daddr, - struct hlist_head udptable[]) -{ - struct sock *sk; - int dif; - - read_lock(&udp_hash_lock); - sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); - dif = skb->dev->ifindex; - sk = udp_v4_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); - if (sk) { - struct sock *sknext = NULL; - - do { - struct sk_buff *skb1 = skb; - - sknext = udp_v4_mcast_next(sk_next(sk), uh->dest, daddr, - uh->source, saddr, dif); - if (sknext) - skb1 = skb_clone(skb, GFP_ATOMIC); - - if (skb1) { - int ret = 0; - - bh_lock_sock_nested(sk); - if (!sock_owned_by_user(sk)) - ret = udp_queue_rcv_skb(sk, skb1); - else - sk_add_backlog(sk, skb1); - bh_unlock_sock(sk); - - if (ret > 0) - /* we should probably re-process instead - * of dropping packets here. */ - kfree_skb(skb1); - } - sk = sknext; - } while (sknext); - } else - kfree_skb(skb); - read_unlock(&udp_hash_lock); - return 0; -} - -/* Initialize UDP checksum. If exited with zero value (success), - * CHECKSUM_UNNECESSARY means, that no more checks are required. - * Otherwise, csum completion requires chacksumming packet body, - * including udp header and folding it to skb->csum. - */ -static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, - int proto) -{ - const struct iphdr *iph; - int err; - - UDP_SKB_CB(skb)->partial_cov = 0; - UDP_SKB_CB(skb)->cscov = skb->len; - - if (IS_PROTO_UDPLITE(proto)) { - err = udplite_checksum_init(skb, uh); - if (err) - return err; - } - - iph = ip_hdr(skb); - if (uh->check == 0) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - } else if (skb->ip_summed == CHECKSUM_COMPLETE) { - if (!csum_tcpudp_magic(iph->saddr, iph->daddr, skb->len, - proto, skb->csum)) - skb->ip_summed = CHECKSUM_UNNECESSARY; - } - if (!skb_csum_unnecessary(skb)) - skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, - skb->len, proto, 0); - /* Probably, we should checksum udp header (it should be in cache - * in any case) and data in tiny packets (< rx copybreak). - */ - - return 0; -} - -/* - * All we need to do is get the socket, and then do a checksum. - */ - -int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], - int proto) -{ - struct sock *sk; - struct udphdr *uh = udp_hdr(skb); - unsigned short ulen; - struct rtable *rt = skb->rtable; - __be32 saddr = ip_hdr(skb)->saddr; - __be32 daddr = ip_hdr(skb)->daddr; - - /* - * Validate the packet. - */ - if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto drop; /* No space for header. */ - - ulen = ntohs(uh->len); - if (ulen > skb->len) - goto short_packet; - - if (IS_PROTO_UDPLITE(proto)) { - /* UDP validates ulen. */ - if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) - goto short_packet; - uh = udp_hdr(skb); - } - - if (udp4_csum_init(skb, uh, proto)) - goto csum_error; - - if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) - return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); - - sk = __udp4_lib_lookup(skb->dev->nd_net, saddr, uh->source, daddr, - uh->dest, inet_iif(skb), udptable); - - if (sk != NULL) { - int ret = 0; - bh_lock_sock_nested(sk); - if (!sock_owned_by_user(sk)) - ret = udp_queue_rcv_skb(sk, skb); - else - sk_add_backlog(sk, skb); - bh_unlock_sock(sk); - sock_put(sk); - - /* a return value > 0 means to resubmit the input, but - * it wants the return to be -protocol, or 0 - */ - if (ret > 0) - return -ret; - return 0; - } - - if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) - goto drop; - nf_reset(skb); - - /* No socket. Drop packet silently, if checksum is wrong */ - if (udp_lib_checksum_complete(skb)) - goto csum_error; - - UDP_INC_STATS_BH(UDP_MIB_NOPORTS, IS_PROTO_UDPLITE(proto)); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - - /* - * Hmm. We got an UDP packet to a port to which we - * don't wanna listen. Ignore it. - */ - kfree_skb(skb); - return 0; - -short_packet: - LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", - IS_PROTO_UDPLITE(proto) ? "-Lite" : "", - NIPQUAD(saddr), - ntohs(uh->source), - ulen, - skb->len, - NIPQUAD(daddr), - ntohs(uh->dest)); - goto drop; - -csum_error: - /* - * RFC1122: OK. Discards the bad packet silently (as far as - * the network is concerned, anyway) as per 4.1.3.4 (MUST). - */ - LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", - IS_PROTO_UDPLITE(proto) ? "-Lite" : "", - NIPQUAD(saddr), - ntohs(uh->source), - NIPQUAD(daddr), - ntohs(uh->dest), - ulen); -drop: - UDP_INC_STATS_BH(UDP_MIB_INERRORS, IS_PROTO_UDPLITE(proto)); - kfree_skb(skb); - return 0; -} - -int udp_rcv(struct sk_buff *skb) -{ - return __udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP); -} - -int udp_destroy_sock(struct sock *sk) -{ - lock_sock(sk); - udp_flush_pending_frames(sk); - release_sock(sk); - return 0; -} - -int udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_push_pending_frames); - return ip_setsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_push_pending_frames); - return compat_ip_setsockopt(sk, level, optname, optval, optlen); -} -#endif - -int udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return ip_getsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return compat_ip_getsockopt(sk, level, optname, optval, optlen); -} -#endif - -/* ------------------------------------------------------------------------ */ -DEFINE_PROTO_INUSE(udp) - -struct proto udp_prot = { - .name = "UDP", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip4_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .destroy = udp_destroy_sock, - .setsockopt = udp_setsockopt, - .getsockopt = udp_getsockopt, - .sendmsg = udp_sendmsg, - .recvmsg = udp_recvmsg, - .sendpage = udp_sendpage, - .backlog_rcv = udp_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udp_v4_get_port, - .memory_allocated = &udp_memory_allocated, - .sysctl_mem = sysctl_udp_mem, - .sysctl_wmem = &sysctl_udp_wmem_min, - .sysctl_rmem = &sysctl_udp_rmem_min, - .obj_size = sizeof(struct udp_sock), -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udp_setsockopt, - .compat_getsockopt = compat_udp_getsockopt, -#endif - REF_PROTO_INUSE(udp) -}; - -/* ------------------------------------------------------------------------ */ -static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket) -{ - struct inet_sock *inet = inet_sk(sp); - __be32 dest = inet->daddr; - __be32 src = inet->rcv_saddr; - __u16 destp = ntohs(inet->dport); - __u16 srcp = ntohs(inet->sport); - - sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p", - bucket, src, srcp, dest, destp, sp->sk_state, - atomic_read(&sp->sk_wmem_alloc), - atomic_read(&sp->sk_rmem_alloc), - 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp); -} - -int udp4_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_printf(seq, "%-127s\n", - " sl local_address rem_address st tx_queue " - "rx_queue tr tm->when retrnsmt uid timeout " - "inode"); - else { - char tmpbuf[129]; - struct udp_iter_state *state = seq->private; - - udp4_format_sock(v, tmpbuf, state->bucket); - seq_printf(seq, "%-127s\n", tmpbuf); - } - return 0; -} - -/* ------------------------------------------------------------------------ */ -#ifdef CONFIG_PROC_FS -static struct file_operations udp4_seq_fops; -static struct udp_seq_afinfo udp4_seq_afinfo = { - .owner = THIS_MODULE, - .name = "udp", - .family = AF_INET, - .hashtable = udp_hash, - .seq_show = udp4_seq_show, - .seq_fops = &udp4_seq_fops, -}; - -int __init udp4_proc_init(void) -{ - return udp_proc_register(&udp4_seq_afinfo); -} - -void udp4_proc_exit(void) -{ - udp_proc_unregister(&udp4_seq_afinfo); -} -#endif /* CONFIG_PROC_FS */ - -EXPORT_SYMBOL(udp_prot); -EXPORT_SYMBOL(udp_sendmsg); - diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c new file mode 100644 index 000000000000..d49c6d68c8a9 --- /dev/null +++ b/net/ipv4/udplite.c @@ -0,0 +1,121 @@ +/* + * UDPLITE An implementation of the UDP-Lite protocol (RFC 3828). + * + * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $ + * + * Authors: Gerrit Renker + * + * Changes: + * Fixes: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "udp_impl.h" +DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; + +struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; + +int udplite_get_port(struct sock *sk, unsigned short p, + int (*c)(const struct sock *, const struct sock *)) +{ + return __udp_lib_get_port(sk, p, udplite_hash, c); +} + +static int udplite_v4_get_port(struct sock *sk, unsigned short snum) +{ + return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); +} + +static int udplite_rcv(struct sk_buff *skb) +{ + return __udp4_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); +} + +static void udplite_err(struct sk_buff *skb, u32 info) +{ + __udp4_lib_err(skb, info, udplite_hash); +} + +static struct net_protocol udplite_protocol = { + .handler = udplite_rcv, + .err_handler = udplite_err, + .no_policy = 1, +}; + +DEFINE_PROTO_INUSE(udplite) + +struct proto udplite_prot = { + .name = "UDP-Lite", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip4_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .init = udplite_sk_init, + .destroy = udp_destroy_sock, + .setsockopt = udp_setsockopt, + .getsockopt = udp_getsockopt, + .sendmsg = udp_sendmsg, + .recvmsg = udp_recvmsg, + .sendpage = udp_sendpage, + .backlog_rcv = udp_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udplite_v4_get_port, + .obj_size = sizeof(struct udp_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udp_setsockopt, + .compat_getsockopt = compat_udp_getsockopt, +#endif + REF_PROTO_INUSE(udplite) +}; + +static struct inet_protosw udplite4_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDPLITE, + .prot = &udplite_prot, + .ops = &inet_dgram_ops, + .capability = -1, + .no_check = 0, /* must checksum (RFC 3828) */ + .flags = INET_PROTOSW_PERMANENT, +}; + +#ifdef CONFIG_PROC_FS +static struct file_operations udplite4_seq_fops; +static struct udp_seq_afinfo udplite4_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udplite", + .family = AF_INET, + .hashtable = udplite_hash, + .seq_show = udp4_seq_show, + .seq_fops = &udplite4_seq_fops, +}; +#endif + +void __init udplite4_register(void) +{ + if (proto_register(&udplite_prot, 1)) + goto out_register_err; + + if (inet_add_protocol(&udplite_protocol, IPPROTO_UDPLITE) < 0) + goto out_unregister_proto; + + inet_register_protosw(&udplite4_protosw); + +#ifdef CONFIG_PROC_FS + if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ + printk(KERN_ERR "%s: Cannot register /proc!\n", __func__); +#endif + return; + +out_unregister_proto: + proto_unregister(&udplite_prot); +out_register_err: + printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __func__); +} + +EXPORT_SYMBOL(udplite_hash); +EXPORT_SYMBOL(udplite_prot); +EXPORT_SYMBOL(udplite_get_port); diff --git a/net/ipv4/udplite_ipv4.c b/net/ipv4/udplite_ipv4.c deleted file mode 100644 index d49c6d68c8a9..000000000000 --- a/net/ipv4/udplite_ipv4.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * UDPLITE An implementation of the UDP-Lite protocol (RFC 3828). - * - * Version: $Id: udplite.c,v 1.25 2006/10/19 07:22:36 gerrit Exp $ - * - * Authors: Gerrit Renker - * - * Changes: - * Fixes: - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include "udp_impl.h" -DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; - -struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; - -int udplite_get_port(struct sock *sk, unsigned short p, - int (*c)(const struct sock *, const struct sock *)) -{ - return __udp_lib_get_port(sk, p, udplite_hash, c); -} - -static int udplite_v4_get_port(struct sock *sk, unsigned short snum) -{ - return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); -} - -static int udplite_rcv(struct sk_buff *skb) -{ - return __udp4_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); -} - -static void udplite_err(struct sk_buff *skb, u32 info) -{ - __udp4_lib_err(skb, info, udplite_hash); -} - -static struct net_protocol udplite_protocol = { - .handler = udplite_rcv, - .err_handler = udplite_err, - .no_policy = 1, -}; - -DEFINE_PROTO_INUSE(udplite) - -struct proto udplite_prot = { - .name = "UDP-Lite", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip4_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .init = udplite_sk_init, - .destroy = udp_destroy_sock, - .setsockopt = udp_setsockopt, - .getsockopt = udp_getsockopt, - .sendmsg = udp_sendmsg, - .recvmsg = udp_recvmsg, - .sendpage = udp_sendpage, - .backlog_rcv = udp_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udplite_v4_get_port, - .obj_size = sizeof(struct udp_sock), -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udp_setsockopt, - .compat_getsockopt = compat_udp_getsockopt, -#endif - REF_PROTO_INUSE(udplite) -}; - -static struct inet_protosw udplite4_protosw = { - .type = SOCK_DGRAM, - .protocol = IPPROTO_UDPLITE, - .prot = &udplite_prot, - .ops = &inet_dgram_ops, - .capability = -1, - .no_check = 0, /* must checksum (RFC 3828) */ - .flags = INET_PROTOSW_PERMANENT, -}; - -#ifdef CONFIG_PROC_FS -static struct file_operations udplite4_seq_fops; -static struct udp_seq_afinfo udplite4_seq_afinfo = { - .owner = THIS_MODULE, - .name = "udplite", - .family = AF_INET, - .hashtable = udplite_hash, - .seq_show = udp4_seq_show, - .seq_fops = &udplite4_seq_fops, -}; -#endif - -void __init udplite4_register(void) -{ - if (proto_register(&udplite_prot, 1)) - goto out_register_err; - - if (inet_add_protocol(&udplite_protocol, IPPROTO_UDPLITE) < 0) - goto out_unregister_proto; - - inet_register_protosw(&udplite4_protosw); - -#ifdef CONFIG_PROC_FS - if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ - printk(KERN_ERR "%s: Cannot register /proc!\n", __func__); -#endif - return; - -out_unregister_proto: - proto_unregister(&udplite_prot); -out_register_err: - printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __func__); -} - -EXPORT_SYMBOL(udplite_hash); -EXPORT_SYMBOL(udplite_prot); -EXPORT_SYMBOL(udplite_get_port); diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index 107051f7c227..ae14617e607f 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -6,7 +6,7 @@ obj-$(CONFIG_IPV6) += ipv6.o ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ addrlabel.o \ - route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp_ipv6.o \ + route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \ raw.o protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \ exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o @@ -17,7 +17,6 @@ ipv6-$(CONFIG_NETFILTER) += netfilter.o ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o ipv6-$(CONFIG_PROC_FS) += proc.o ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o -ipv6-$(CONFIG_IP_UDPLITE) += udplite_ipv6.o ipv6-objs += $(ipv6-y) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index afe9276d0420..730a861b8f41 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -813,16 +813,12 @@ static int __init init_ipv6_mibs(void) goto err_icmpmsg_mib; if (snmp_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib)) < 0) goto err_udp_mib; -#ifdef CONFIG_IP_UDPLITE if (snmp_mib_init((void **)udplite_stats_in6, sizeof (struct udp_mib)) < 0) goto err_udplite_mib; -#endif return 0; -#ifdef CONFIG_IP_UDPLITE err_udplite_mib: -#endif snmp_mib_free((void **)udp_stats_in6); err_udp_mib: snmp_mib_free((void **)icmpv6msg_statistics); @@ -841,9 +837,7 @@ static void cleanup_ipv6_mibs(void) snmp_mib_free((void **)icmpv6_statistics); snmp_mib_free((void **)icmpv6msg_statistics); snmp_mib_free((void **)udp_stats_in6); -#ifdef CONFIG_IP_UDPLITE snmp_mib_free((void **)udplite_stats_in6); -#endif } static int inet6_net_init(struct net *net) @@ -888,11 +882,9 @@ static int __init inet6_init(void) if (err) goto out_unregister_tcp_proto; -#ifdef CONFIG_IP_UDPLITE err = proto_register(&udplitev6_prot, 1); if (err) goto out_unregister_udp_proto; -#endif err = proto_register(&rawv6_prot, 1); if (err) @@ -1063,10 +1055,8 @@ out_sock_register_fail: out_unregister_raw_proto: proto_unregister(&rawv6_prot); out_unregister_udplite_proto: -#ifdef CONFIG_IP_UDPLITE proto_unregister(&udplitev6_prot); out_unregister_udp_proto: -#endif proto_unregister(&udpv6_prot); out_unregister_tcp_proto: proto_unregister(&tcpv6_prot); @@ -1085,9 +1075,7 @@ static void __exit inet6_exit(void) ipv6_sysctl_unregister(); #endif udpv6_exit(); -#ifdef CONFIG_IP_UDPLITE udplitev6_exit(); -#endif tcpv6_exit(); /* Cleanup code parts. */ @@ -1117,9 +1105,7 @@ static void __exit inet6_exit(void) unregister_pernet_subsys(&inet6_net_ops); cleanup_ipv6_mibs(); proto_unregister(&rawv6_prot); -#ifdef CONFIG_IP_UDPLITE proto_unregister(&udplitev6_prot); -#endif proto_unregister(&udpv6_prot); proto_unregister(&tcpv6_prot); } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 3bbfdff698d2..5eea6fa506e5 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -127,9 +127,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, struct sk_buff *pktopt; if (sk->sk_protocol != IPPROTO_UDP && -#ifdef CONFIG_IP_UDPLITE sk->sk_protocol != IPPROTO_UDPLITE && -#endif sk->sk_protocol != IPPROTO_TCP) break; @@ -169,7 +167,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, } else { struct proto *prot = &udp_prot; - if (IS_PROTO_UDPLITE(sk->sk_protocol)) + if (sk->sk_protocol == IPPROTO_UDPLITE) prot = &udplite_prot; local_bh_disable(); sock_prot_inuse_add(sk->sk_prot, -1); @@ -734,9 +732,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, switch (optname) { case IPV6_ADDRFORM: if (sk->sk_protocol != IPPROTO_UDP && -#ifdef CONFIG_IP_UDPLITE sk->sk_protocol != IPPROTO_UDPLITE && -#endif sk->sk_protocol != IPPROTO_TCP) return -EINVAL; if (sk->sk_state != TCP_ESTABLISHED) diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 2453f2229ef7..8a5be290c710 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -39,10 +39,8 @@ static int sockstat6_seq_show(struct seq_file *seq, void *v) sock_prot_inuse_get(&tcpv6_prot)); seq_printf(seq, "UDP6: inuse %d\n", sock_prot_inuse_get(&udpv6_prot)); -#ifdef CONFIG_IP_UDPLITE seq_printf(seq, "UDPLITE6: inuse %d\n", sock_prot_inuse_get(&udplitev6_prot)); -#endif seq_printf(seq, "RAW6: inuse %d\n", sock_prot_inuse_get(&rawv6_prot)); seq_printf(seq, "FRAG6: inuse %d memory %d\n", @@ -113,7 +111,6 @@ static struct snmp_mib snmp6_udp6_list[] = { SNMP_MIB_SENTINEL }; -#ifdef CONFIG_IP_UDPLITE static struct snmp_mib snmp6_udplite6_list[] = { SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), @@ -121,7 +118,6 @@ static struct snmp_mib snmp6_udplite6_list[] = { SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), SNMP_MIB_SENTINEL }; -#endif static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, void **mib) { @@ -180,9 +176,7 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) snmp6_seq_show_item(seq, (void **)icmpv6_statistics, snmp6_icmp6_list); snmp6_seq_show_icmpv6msg(seq, (void **)icmpv6msg_statistics); snmp6_seq_show_item(seq, (void **)udp_stats_in6, snmp6_udp6_list); -#ifdef CONFIG_IP_UDPLITE snmp6_seq_show_item(seq, (void **)udplite_stats_in6, snmp6_udplite6_list); -#endif } return 0; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c new file mode 100644 index 000000000000..53739de829db --- /dev/null +++ b/net/ipv6/udp.c @@ -0,0 +1,1065 @@ +/* + * UDP over IPv6 + * Linux INET6 implementation + * + * Authors: + * Pedro Roque + * + * Based on linux/ipv4/udp.c + * + * $Id: udp.c,v 1.65 2002/02/01 22:01:04 davem Exp $ + * + * Fixes: + * Hideaki YOSHIFUJI : sin6_scope_id support + * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which + * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind + * a single port at the same time. + * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data + * YOSHIFUJI Hideaki @USAGI: convert /proc/net/udp6 to seq_file. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "udp_impl.h" + +static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) +{ + return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); +} + +static struct sock *__udp6_lib_lookup(struct net *net, + struct in6_addr *saddr, __be16 sport, + struct in6_addr *daddr, __be16 dport, + int dif, struct hlist_head udptable[]) +{ + struct sock *sk, *result = NULL; + struct hlist_node *node; + unsigned short hnum = ntohs(dport); + int badness = -1; + + read_lock(&udp_hash_lock); + sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { + struct inet_sock *inet = inet_sk(sk); + + if (sk->sk_net == net && sk->sk_hash == hnum && + sk->sk_family == PF_INET6) { + struct ipv6_pinfo *np = inet6_sk(sk); + int score = 0; + if (inet->dport) { + if (inet->dport != sport) + continue; + score++; + } + if (!ipv6_addr_any(&np->rcv_saddr)) { + if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) + continue; + score++; + } + if (!ipv6_addr_any(&np->daddr)) { + if (!ipv6_addr_equal(&np->daddr, saddr)) + continue; + score++; + } + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) + continue; + score++; + } + if (score == 4) { + result = sk; + break; + } else if (score > badness) { + result = sk; + badness = score; + } + } + } + if (result) + sock_hold(result); + read_unlock(&udp_hash_lock); + return result; +} + +/* + * This should be easy, if there is something there we + * return it, otherwise we block. + */ + +int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len, + int noblock, int flags, int *addr_len) +{ + struct ipv6_pinfo *np = inet6_sk(sk); + struct inet_sock *inet = inet_sk(sk); + struct sk_buff *skb; + unsigned int ulen, copied; + int peeked; + int err; + int is_udplite = IS_UDPLITE(sk); + + if (addr_len) + *addr_len=sizeof(struct sockaddr_in6); + + if (flags & MSG_ERRQUEUE) + return ipv6_recv_error(sk, msg, len); + +try_again: + skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), + &peeked, &err); + if (!skb) + goto out; + + ulen = skb->len - sizeof(struct udphdr); + copied = len; + if (copied > ulen) + copied = ulen; + else if (copied < ulen) + msg->msg_flags |= MSG_TRUNC; + + /* + * If checksum is needed at all, try to do it while copying the + * data. If the data is truncated, or if we only want a partial + * coverage checksum (UDP-Lite), do it before the copy. + */ + + if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { + if (udp_lib_checksum_complete(skb)) + goto csum_copy_err; + } + + if (skb_csum_unnecessary(skb)) + err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), + msg->msg_iov, copied ); + else { + err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); + if (err == -EINVAL) + goto csum_copy_err; + } + if (err) + goto out_free; + + if (!peeked) + UDP6_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); + + sock_recv_timestamp(msg, sk, skb); + + /* Copy the address. */ + if (msg->msg_name) { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *) msg->msg_name; + sin6->sin6_family = AF_INET6; + sin6->sin6_port = udp_hdr(skb)->source; + sin6->sin6_flowinfo = 0; + sin6->sin6_scope_id = 0; + + if (skb->protocol == htons(ETH_P_IP)) + ipv6_addr_set(&sin6->sin6_addr, 0, 0, + htonl(0xffff), ip_hdr(skb)->saddr); + else { + ipv6_addr_copy(&sin6->sin6_addr, + &ipv6_hdr(skb)->saddr); + if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) + sin6->sin6_scope_id = IP6CB(skb)->iif; + } + + } + if (skb->protocol == htons(ETH_P_IP)) { + if (inet->cmsg_flags) + ip_cmsg_recv(msg, skb); + } else { + if (np->rxopt.all) + datagram_recv_ctl(sk, msg, skb); + } + + err = copied; + if (flags & MSG_TRUNC) + err = ulen; + +out_free: + lock_sock(sk); + skb_free_datagram(sk, skb); + release_sock(sk); +out: + return err; + +csum_copy_err: + lock_sock(sk); + if (!skb_kill_datagram(sk, skb, flags)) + UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); + release_sock(sk); + + if (flags & MSG_DONTWAIT) + return -EAGAIN; + goto try_again; +} + +void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + int type, int code, int offset, __be32 info, + struct hlist_head udptable[] ) +{ + struct ipv6_pinfo *np; + struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; + struct in6_addr *saddr = &hdr->saddr; + struct in6_addr *daddr = &hdr->daddr; + struct udphdr *uh = (struct udphdr*)(skb->data+offset); + struct sock *sk; + int err; + + sk = __udp6_lib_lookup(skb->dev->nd_net, daddr, uh->dest, + saddr, uh->source, inet6_iif(skb), udptable); + if (sk == NULL) + return; + + np = inet6_sk(sk); + + if (!icmpv6_err_convert(type, code, &err) && !np->recverr) + goto out; + + if (sk->sk_state != TCP_ESTABLISHED && !np->recverr) + goto out; + + if (np->recverr) + ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1)); + + sk->sk_err = err; + sk->sk_error_report(sk); +out: + sock_put(sk); +} + +static __inline__ void udpv6_err(struct sk_buff *skb, + struct inet6_skb_parm *opt, int type, + int code, int offset, __be32 info ) +{ + __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); +} + +int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) +{ + struct udp_sock *up = udp_sk(sk); + int rc; + int is_udplite = IS_UDPLITE(sk); + + if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) + goto drop; + + /* + * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). + */ + if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { + + if (up->pcrlen == 0) { /* full coverage was set */ + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage" + " %d while full coverage %d requested\n", + UDP_SKB_CB(skb)->cscov, skb->len); + goto drop; + } + if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { + LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: coverage %d " + "too small, need min %d\n", + UDP_SKB_CB(skb)->cscov, up->pcrlen); + goto drop; + } + } + + if (sk->sk_filter) { + if (udp_lib_checksum_complete(skb)) + goto drop; + } + + if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { + /* Note that an ENOMEM error is charged twice */ + if (rc == -ENOMEM) + UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); + goto drop; + } + + return 0; +drop: + UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); + kfree_skb(skb); + return -1; +} + +static struct sock *udp_v6_mcast_next(struct sock *sk, + __be16 loc_port, struct in6_addr *loc_addr, + __be16 rmt_port, struct in6_addr *rmt_addr, + int dif) +{ + struct hlist_node *node; + struct sock *s = sk; + unsigned short num = ntohs(loc_port); + + sk_for_each_from(s, node) { + struct inet_sock *inet = inet_sk(s); + + if (s->sk_hash == num && s->sk_family == PF_INET6) { + struct ipv6_pinfo *np = inet6_sk(s); + if (inet->dport) { + if (inet->dport != rmt_port) + continue; + } + if (!ipv6_addr_any(&np->daddr) && + !ipv6_addr_equal(&np->daddr, rmt_addr)) + continue; + + if (s->sk_bound_dev_if && s->sk_bound_dev_if != dif) + continue; + + if (!ipv6_addr_any(&np->rcv_saddr)) { + if (!ipv6_addr_equal(&np->rcv_saddr, loc_addr)) + continue; + } + if (!inet6_mc_check(s, loc_addr, rmt_addr)) + continue; + return s; + } + } + return NULL; +} + +/* + * Note: called only from the BH handler context, + * so we don't need to lock the hashes. + */ +static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, + struct in6_addr *daddr, struct hlist_head udptable[]) +{ + struct sock *sk, *sk2; + const struct udphdr *uh = udp_hdr(skb); + int dif; + + read_lock(&udp_hash_lock); + sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); + dif = inet6_iif(skb); + sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); + if (!sk) { + kfree_skb(skb); + goto out; + } + + sk2 = sk; + while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, + uh->source, saddr, dif))) { + struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); + if (buff) { + bh_lock_sock_nested(sk2); + if (!sock_owned_by_user(sk2)) + udpv6_queue_rcv_skb(sk2, buff); + else + sk_add_backlog(sk2, buff); + bh_unlock_sock(sk2); + } + } + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + udpv6_queue_rcv_skb(sk, skb); + else + sk_add_backlog(sk, skb); + bh_unlock_sock(sk); +out: + read_unlock(&udp_hash_lock); + return 0; +} + +static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, + int proto) +{ + int err; + + UDP_SKB_CB(skb)->partial_cov = 0; + UDP_SKB_CB(skb)->cscov = skb->len; + + if (proto == IPPROTO_UDPLITE) { + err = udplite_checksum_init(skb, uh); + if (err) + return err; + } + + if (uh->check == 0) { + /* RFC 2460 section 8.1 says that we SHOULD log + this error. Well, it is reasonable. + */ + LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); + return 1; + } + if (skb->ip_summed == CHECKSUM_COMPLETE && + !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, + skb->len, proto, skb->csum)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + if (!skb_csum_unnecessary(skb)) + skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + skb->len, proto, 0)); + + return 0; +} + +int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], + int proto) +{ + struct sock *sk; + struct udphdr *uh; + struct net_device *dev = skb->dev; + struct in6_addr *saddr, *daddr; + u32 ulen = 0; + + if (!pskb_may_pull(skb, sizeof(struct udphdr))) + goto short_packet; + + saddr = &ipv6_hdr(skb)->saddr; + daddr = &ipv6_hdr(skb)->daddr; + uh = udp_hdr(skb); + + ulen = ntohs(uh->len); + if (ulen > skb->len) + goto short_packet; + + if (proto == IPPROTO_UDP) { + /* UDP validates ulen. */ + + /* Check for jumbo payload */ + if (ulen == 0) + ulen = skb->len; + + if (ulen < sizeof(*uh)) + goto short_packet; + + if (ulen < skb->len) { + if (pskb_trim_rcsum(skb, ulen)) + goto short_packet; + saddr = &ipv6_hdr(skb)->saddr; + daddr = &ipv6_hdr(skb)->daddr; + uh = udp_hdr(skb); + } + } + + if (udp6_csum_init(skb, uh, proto)) + goto discard; + + /* + * Multicast receive code + */ + if (ipv6_addr_is_multicast(daddr)) + return __udp6_lib_mcast_deliver(skb, saddr, daddr, udptable); + + /* Unicast */ + + /* + * check socket cache ... must talk to Alan about his plans + * for sock caches... i'll skip this for now. + */ + sk = __udp6_lib_lookup(skb->dev->nd_net, saddr, uh->source, + daddr, uh->dest, inet6_iif(skb), udptable); + + if (sk == NULL) { + if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto discard; + + if (udp_lib_checksum_complete(skb)) + goto discard; + UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); + + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); + + kfree_skb(skb); + return 0; + } + + /* deliver */ + + bh_lock_sock_nested(sk); + if (!sock_owned_by_user(sk)) + udpv6_queue_rcv_skb(sk, skb); + else + sk_add_backlog(sk, skb); + bh_unlock_sock(sk); + sock_put(sk); + return 0; + +short_packet: + LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", + proto == IPPROTO_UDPLITE ? "-Lite" : "", + ulen, skb->len); + +discard: + UDP6_INC_STATS_BH(UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); + kfree_skb(skb); + return 0; +} + +static __inline__ int udpv6_rcv(struct sk_buff *skb) +{ + return __udp6_lib_rcv(skb, udp_hash, IPPROTO_UDP); +} + +/* + * Throw away all pending data and cancel the corking. Socket is locked. + */ +static void udp_v6_flush_pending_frames(struct sock *sk) +{ + struct udp_sock *up = udp_sk(sk); + + if (up->pending) { + up->len = 0; + up->pending = 0; + ip6_flush_pending_frames(sk); + } +} + +/* + * Sending + */ + +static int udp_v6_push_pending_frames(struct sock *sk) +{ + struct sk_buff *skb; + struct udphdr *uh; + struct udp_sock *up = udp_sk(sk); + struct inet_sock *inet = inet_sk(sk); + struct flowi *fl = &inet->cork.fl; + int err = 0; + int is_udplite = IS_UDPLITE(sk); + __wsum csum = 0; + + /* Grab the skbuff where UDP header space exists. */ + if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) + goto out; + + /* + * Create a UDP header + */ + uh = udp_hdr(skb); + uh->source = fl->fl_ip_sport; + uh->dest = fl->fl_ip_dport; + uh->len = htons(up->len); + uh->check = 0; + + if (is_udplite) + csum = udplite_csum_outgoing(sk, skb); + else + csum = udp_csum_outgoing(sk, skb); + + /* add protocol-dependent pseudo-header */ + uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, + up->len, fl->proto, csum ); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + + err = ip6_push_pending_frames(sk); +out: + up->len = 0; + up->pending = 0; + if (!err) + UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); + return err; +} + +int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, + struct msghdr *msg, size_t len) +{ + struct ipv6_txoptions opt_space; + struct udp_sock *up = udp_sk(sk); + struct inet_sock *inet = inet_sk(sk); + struct ipv6_pinfo *np = inet6_sk(sk); + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name; + struct in6_addr *daddr, *final_p = NULL, final; + struct ipv6_txoptions *opt = NULL; + struct ip6_flowlabel *flowlabel = NULL; + struct flowi fl; + struct dst_entry *dst; + int addr_len = msg->msg_namelen; + int ulen = len; + int hlimit = -1; + int tclass = -1; + int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; + int err; + int connected = 0; + int is_udplite = IS_UDPLITE(sk); + int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); + + /* destination address check */ + if (sin6) { + if (addr_len < offsetof(struct sockaddr, sa_data)) + return -EINVAL; + + switch (sin6->sin6_family) { + case AF_INET6: + if (addr_len < SIN6_LEN_RFC2133) + return -EINVAL; + daddr = &sin6->sin6_addr; + break; + case AF_INET: + goto do_udp_sendmsg; + case AF_UNSPEC: + msg->msg_name = sin6 = NULL; + msg->msg_namelen = addr_len = 0; + daddr = NULL; + break; + default: + return -EINVAL; + } + } else if (!up->pending) { + if (sk->sk_state != TCP_ESTABLISHED) + return -EDESTADDRREQ; + daddr = &np->daddr; + } else + daddr = NULL; + + if (daddr) { + if (ipv6_addr_v4mapped(daddr)) { + struct sockaddr_in sin; + sin.sin_family = AF_INET; + sin.sin_port = sin6 ? sin6->sin6_port : inet->dport; + sin.sin_addr.s_addr = daddr->s6_addr32[3]; + msg->msg_name = &sin; + msg->msg_namelen = sizeof(sin); +do_udp_sendmsg: + if (__ipv6_only_sock(sk)) + return -ENETUNREACH; + return udp_sendmsg(iocb, sk, msg, len); + } + } + + if (up->pending == AF_INET) + return udp_sendmsg(iocb, sk, msg, len); + + /* Rough check on arithmetic overflow, + better check is made in ip6_append_data(). + */ + if (len > INT_MAX - sizeof(struct udphdr)) + return -EMSGSIZE; + + if (up->pending) { + /* + * There are pending frames. + * The socket lock must be held while it's corked. + */ + lock_sock(sk); + if (likely(up->pending)) { + if (unlikely(up->pending != AF_INET6)) { + release_sock(sk); + return -EAFNOSUPPORT; + } + dst = NULL; + goto do_append_data; + } + release_sock(sk); + } + ulen += sizeof(struct udphdr); + + memset(&fl, 0, sizeof(fl)); + + if (sin6) { + if (sin6->sin6_port == 0) + return -EINVAL; + + fl.fl_ip_dport = sin6->sin6_port; + daddr = &sin6->sin6_addr; + + if (np->sndflow) { + fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; + if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { + flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); + if (flowlabel == NULL) + return -EINVAL; + daddr = &flowlabel->dst; + } + } + + /* + * Otherwise it will be difficult to maintain + * sk->sk_dst_cache. + */ + if (sk->sk_state == TCP_ESTABLISHED && + ipv6_addr_equal(daddr, &np->daddr)) + daddr = &np->daddr; + + if (addr_len >= sizeof(struct sockaddr_in6) && + sin6->sin6_scope_id && + ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) + fl.oif = sin6->sin6_scope_id; + } else { + if (sk->sk_state != TCP_ESTABLISHED) + return -EDESTADDRREQ; + + fl.fl_ip_dport = inet->dport; + daddr = &np->daddr; + fl.fl6_flowlabel = np->flow_label; + connected = 1; + } + + if (!fl.oif) + fl.oif = sk->sk_bound_dev_if; + + if (msg->msg_controllen) { + opt = &opt_space; + memset(opt, 0, sizeof(struct ipv6_txoptions)); + opt->tot_len = sizeof(*opt); + + err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass); + if (err < 0) { + fl6_sock_release(flowlabel); + return err; + } + if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { + flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); + if (flowlabel == NULL) + return -EINVAL; + } + if (!(opt->opt_nflen|opt->opt_flen)) + opt = NULL; + connected = 0; + } + if (opt == NULL) + opt = np->opt; + if (flowlabel) + opt = fl6_merge_options(&opt_space, flowlabel, opt); + opt = ipv6_fixup_options(&opt_space, opt); + + fl.proto = sk->sk_protocol; + ipv6_addr_copy(&fl.fl6_dst, daddr); + if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) + ipv6_addr_copy(&fl.fl6_src, &np->saddr); + fl.fl_ip_sport = inet->sport; + + /* merge ip6_build_xmit from ip6_output */ + if (opt && opt->srcrt) { + struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; + ipv6_addr_copy(&final, &fl.fl6_dst); + ipv6_addr_copy(&fl.fl6_dst, rt0->addr); + final_p = &final; + connected = 0; + } + + if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) { + fl.oif = np->mcast_oif; + connected = 0; + } + + security_sk_classify_flow(sk, &fl); + + err = ip6_sk_dst_lookup(sk, &dst, &fl); + if (err) + goto out; + if (final_p) + ipv6_addr_copy(&fl.fl6_dst, final_p); + + if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) { + if (err == -EREMOTE) + err = ip6_dst_blackhole(sk, &dst, &fl); + if (err < 0) + goto out; + } + + if (hlimit < 0) { + if (ipv6_addr_is_multicast(&fl.fl6_dst)) + hlimit = np->mcast_hops; + else + hlimit = np->hop_limit; + if (hlimit < 0) + hlimit = dst_metric(dst, RTAX_HOPLIMIT); + if (hlimit < 0) + hlimit = ipv6_get_hoplimit(dst->dev); + } + + if (tclass < 0) { + tclass = np->tclass; + if (tclass < 0) + tclass = 0; + } + + if (msg->msg_flags&MSG_CONFIRM) + goto do_confirm; +back_from_confirm: + + lock_sock(sk); + if (unlikely(up->pending)) { + /* The socket is already corked while preparing it. */ + /* ... which is an evident application bug. --ANK */ + release_sock(sk); + + LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); + err = -EINVAL; + goto out; + } + + up->pending = AF_INET6; + +do_append_data: + up->len += ulen; + getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; + err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, + sizeof(struct udphdr), hlimit, tclass, opt, &fl, + (struct rt6_info*)dst, + corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); + if (err) + udp_v6_flush_pending_frames(sk); + else if (!corkreq) + err = udp_v6_push_pending_frames(sk); + else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) + up->pending = 0; + + if (dst) { + if (connected) { + ip6_dst_store(sk, dst, + ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? + &np->daddr : NULL, +#ifdef CONFIG_IPV6_SUBTREES + ipv6_addr_equal(&fl.fl6_src, &np->saddr) ? + &np->saddr : +#endif + NULL); + } else { + dst_release(dst); + } + } + + if (err > 0) + err = np->recverr ? net_xmit_errno(err) : 0; + release_sock(sk); +out: + fl6_sock_release(flowlabel); + if (!err) + return len; + /* + * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting + * ENOBUFS might not be good (it's not tunable per se), but otherwise + * we don't have a good statistic (IpOutDiscards but it can be too many + * things). We could add another new stat but at least for now that + * seems like overkill. + */ + if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { + UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); + } + return err; + +do_confirm: + dst_confirm(dst); + if (!(msg->msg_flags&MSG_PROBE) || len) + goto back_from_confirm; + err = 0; + goto out; +} + +int udpv6_destroy_sock(struct sock *sk) +{ + lock_sock(sk); + udp_v6_flush_pending_frames(sk); + release_sock(sk); + + inet6_destroy_sock(sk); + + return 0; +} + +/* + * Socket option code for UDP + */ +int udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_v6_push_pending_frames); + return ipv6_setsockopt(sk, level, optname, optval, optlen); +} + +#ifdef CONFIG_COMPAT +int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, + char __user *optval, int optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_setsockopt(sk, level, optname, optval, optlen, + udp_v6_push_pending_frames); + return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); +} +#endif + +int udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_getsockopt(sk, level, optname, optval, optlen); + return ipv6_getsockopt(sk, level, optname, optval, optlen); +} + +#ifdef CONFIG_COMPAT +int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, + char __user *optval, int __user *optlen) +{ + if (level == SOL_UDP || level == SOL_UDPLITE) + return udp_lib_getsockopt(sk, level, optname, optval, optlen); + return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); +} +#endif + +static struct inet6_protocol udpv6_protocol = { + .handler = udpv6_rcv, + .err_handler = udpv6_err, + .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, +}; + +/* ------------------------------------------------------------------------ */ +#ifdef CONFIG_PROC_FS + +static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket) +{ + struct inet_sock *inet = inet_sk(sp); + struct ipv6_pinfo *np = inet6_sk(sp); + struct in6_addr *dest, *src; + __u16 destp, srcp; + + dest = &np->daddr; + src = &np->rcv_saddr; + destp = ntohs(inet->dport); + srcp = ntohs(inet->sport); + seq_printf(seq, + "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " + "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p\n", + bucket, + src->s6_addr32[0], src->s6_addr32[1], + src->s6_addr32[2], src->s6_addr32[3], srcp, + dest->s6_addr32[0], dest->s6_addr32[1], + dest->s6_addr32[2], dest->s6_addr32[3], destp, + sp->sk_state, + atomic_read(&sp->sk_wmem_alloc), + atomic_read(&sp->sk_rmem_alloc), + 0, 0L, 0, + sock_i_uid(sp), 0, + sock_i_ino(sp), + atomic_read(&sp->sk_refcnt), sp); +} + +int udp6_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) + seq_printf(seq, + " sl " + "local_address " + "remote_address " + "st tx_queue rx_queue tr tm->when retrnsmt" + " uid timeout inode\n"); + else + udp6_sock_seq_show(seq, v, ((struct udp_iter_state *)seq->private)->bucket); + return 0; +} + +static struct file_operations udp6_seq_fops; +static struct udp_seq_afinfo udp6_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udp6", + .family = AF_INET6, + .hashtable = udp_hash, + .seq_show = udp6_seq_show, + .seq_fops = &udp6_seq_fops, +}; + +int __init udp6_proc_init(void) +{ + return udp_proc_register(&udp6_seq_afinfo); +} + +void udp6_proc_exit(void) { + udp_proc_unregister(&udp6_seq_afinfo); +} +#endif /* CONFIG_PROC_FS */ + +/* ------------------------------------------------------------------------ */ + +DEFINE_PROTO_INUSE(udpv6) + +struct proto udpv6_prot = { + .name = "UDPv6", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip6_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .destroy = udpv6_destroy_sock, + .setsockopt = udpv6_setsockopt, + .getsockopt = udpv6_getsockopt, + .sendmsg = udpv6_sendmsg, + .recvmsg = udpv6_recvmsg, + .backlog_rcv = udpv6_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udp_v6_get_port, + .memory_allocated = &udp_memory_allocated, + .sysctl_mem = sysctl_udp_mem, + .sysctl_wmem = &sysctl_udp_wmem_min, + .sysctl_rmem = &sysctl_udp_rmem_min, + .obj_size = sizeof(struct udp6_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udpv6_setsockopt, + .compat_getsockopt = compat_udpv6_getsockopt, +#endif + REF_PROTO_INUSE(udpv6) +}; + +static struct inet_protosw udpv6_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDP, + .prot = &udpv6_prot, + .ops = &inet6_dgram_ops, + .capability =-1, + .no_check = UDP_CSUM_DEFAULT, + .flags = INET_PROTOSW_PERMANENT, +}; + + +int __init udpv6_init(void) +{ + int ret; + + ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP); + if (ret) + goto out; + + ret = inet6_register_protosw(&udpv6_protosw); + if (ret) + goto out_udpv6_protocol; +out: + return ret; + +out_udpv6_protocol: + inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); + goto out; +} + +void udpv6_exit(void) +{ + inet6_unregister_protosw(&udpv6_protosw); + inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); +} diff --git a/net/ipv6/udp_ipv6.c b/net/ipv6/udp_ipv6.c deleted file mode 100644 index 55feac7ba717..000000000000 --- a/net/ipv6/udp_ipv6.c +++ /dev/null @@ -1,1065 +0,0 @@ -/* - * UDP over IPv6 - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Based on linux/ipv4/udp.c - * - * $Id: udp.c,v 1.65 2002/02/01 22:01:04 davem Exp $ - * - * Fixes: - * Hideaki YOSHIFUJI : sin6_scope_id support - * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which - * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind - * a single port at the same time. - * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data - * YOSHIFUJI Hideaki @USAGI: convert /proc/net/udp6 to seq_file. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "udp_impl.h" - -static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) -{ - return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); -} - -static struct sock *__udp6_lib_lookup(struct net *net, - struct in6_addr *saddr, __be16 sport, - struct in6_addr *daddr, __be16 dport, - int dif, struct hlist_head udptable[]) -{ - struct sock *sk, *result = NULL; - struct hlist_node *node; - unsigned short hnum = ntohs(dport); - int badness = -1; - - read_lock(&udp_hash_lock); - sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { - struct inet_sock *inet = inet_sk(sk); - - if (sk->sk_net == net && sk->sk_hash == hnum && - sk->sk_family == PF_INET6) { - struct ipv6_pinfo *np = inet6_sk(sk); - int score = 0; - if (inet->dport) { - if (inet->dport != sport) - continue; - score++; - } - if (!ipv6_addr_any(&np->rcv_saddr)) { - if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) - continue; - score++; - } - if (!ipv6_addr_any(&np->daddr)) { - if (!ipv6_addr_equal(&np->daddr, saddr)) - continue; - score++; - } - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - continue; - score++; - } - if (score == 4) { - result = sk; - break; - } else if (score > badness) { - result = sk; - badness = score; - } - } - } - if (result) - sock_hold(result); - read_unlock(&udp_hash_lock); - return result; -} - -/* - * This should be easy, if there is something there we - * return it, otherwise we block. - */ - -int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, - struct msghdr *msg, size_t len, - int noblock, int flags, int *addr_len) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct sk_buff *skb; - unsigned int ulen, copied; - int peeked; - int err; - int is_udplite = IS_UDPLITE(sk); - - if (addr_len) - *addr_len=sizeof(struct sockaddr_in6); - - if (flags & MSG_ERRQUEUE) - return ipv6_recv_error(sk, msg, len); - -try_again: - skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, &err); - if (!skb) - goto out; - - ulen = skb->len - sizeof(struct udphdr); - copied = len; - if (copied > ulen) - copied = ulen; - else if (copied < ulen) - msg->msg_flags |= MSG_TRUNC; - - /* - * If checksum is needed at all, try to do it while copying the - * data. If the data is truncated, or if we only want a partial - * coverage checksum (UDP-Lite), do it before the copy. - */ - - if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) { - if (udp_lib_checksum_complete(skb)) - goto csum_copy_err; - } - - if (skb_csum_unnecessary(skb)) - err = skb_copy_datagram_iovec(skb, sizeof(struct udphdr), - msg->msg_iov, copied ); - else { - err = skb_copy_and_csum_datagram_iovec(skb, sizeof(struct udphdr), msg->msg_iov); - if (err == -EINVAL) - goto csum_copy_err; - } - if (err) - goto out_free; - - if (!peeked) - UDP6_INC_STATS_USER(UDP_MIB_INDATAGRAMS, is_udplite); - - sock_recv_timestamp(msg, sk, skb); - - /* Copy the address. */ - if (msg->msg_name) { - struct sockaddr_in6 *sin6; - - sin6 = (struct sockaddr_in6 *) msg->msg_name; - sin6->sin6_family = AF_INET6; - sin6->sin6_port = udp_hdr(skb)->source; - sin6->sin6_flowinfo = 0; - sin6->sin6_scope_id = 0; - - if (skb->protocol == htons(ETH_P_IP)) - ipv6_addr_set(&sin6->sin6_addr, 0, 0, - htonl(0xffff), ip_hdr(skb)->saddr); - else { - ipv6_addr_copy(&sin6->sin6_addr, - &ipv6_hdr(skb)->saddr); - if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) - sin6->sin6_scope_id = IP6CB(skb)->iif; - } - - } - if (skb->protocol == htons(ETH_P_IP)) { - if (inet->cmsg_flags) - ip_cmsg_recv(msg, skb); - } else { - if (np->rxopt.all) - datagram_recv_ctl(sk, msg, skb); - } - - err = copied; - if (flags & MSG_TRUNC) - err = ulen; - -out_free: - lock_sock(sk); - skb_free_datagram(sk, skb); - release_sock(sk); -out: - return err; - -csum_copy_err: - lock_sock(sk); - if (!skb_kill_datagram(sk, skb, flags)) - UDP6_INC_STATS_USER(UDP_MIB_INERRORS, is_udplite); - release_sock(sk); - - if (flags & MSG_DONTWAIT) - return -EAGAIN; - goto try_again; -} - -void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info, - struct hlist_head udptable[] ) -{ - struct ipv6_pinfo *np; - struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; - struct in6_addr *saddr = &hdr->saddr; - struct in6_addr *daddr = &hdr->daddr; - struct udphdr *uh = (struct udphdr*)(skb->data+offset); - struct sock *sk; - int err; - - sk = __udp6_lib_lookup(skb->dev->nd_net, daddr, uh->dest, - saddr, uh->source, inet6_iif(skb), udptable); - if (sk == NULL) - return; - - np = inet6_sk(sk); - - if (!icmpv6_err_convert(type, code, &err) && !np->recverr) - goto out; - - if (sk->sk_state != TCP_ESTABLISHED && !np->recverr) - goto out; - - if (np->recverr) - ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1)); - - sk->sk_err = err; - sk->sk_error_report(sk); -out: - sock_put(sk); -} - -static __inline__ void udpv6_err(struct sk_buff *skb, - struct inet6_skb_parm *opt, int type, - int code, int offset, __be32 info ) -{ - __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); -} - -int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) -{ - struct udp_sock *up = udp_sk(sk); - int rc; - int is_udplite = IS_UDPLITE(sk); - - if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) - goto drop; - - /* - * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). - */ - if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { - - if (up->pcrlen == 0) { /* full coverage was set */ - LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: partial coverage" - " %d while full coverage %d requested\n", - UDP_SKB_CB(skb)->cscov, skb->len); - goto drop; - } - if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { - LIMIT_NETDEBUG(KERN_WARNING "UDPLITE6: coverage %d " - "too small, need min %d\n", - UDP_SKB_CB(skb)->cscov, up->pcrlen); - goto drop; - } - } - - if (sk->sk_filter) { - if (udp_lib_checksum_complete(skb)) - goto drop; - } - - if ((rc = sock_queue_rcv_skb(sk,skb)) < 0) { - /* Note that an ENOMEM error is charged twice */ - if (rc == -ENOMEM) - UDP6_INC_STATS_BH(UDP_MIB_RCVBUFERRORS, is_udplite); - goto drop; - } - - return 0; -drop: - UDP6_INC_STATS_BH(UDP_MIB_INERRORS, is_udplite); - kfree_skb(skb); - return -1; -} - -static struct sock *udp_v6_mcast_next(struct sock *sk, - __be16 loc_port, struct in6_addr *loc_addr, - __be16 rmt_port, struct in6_addr *rmt_addr, - int dif) -{ - struct hlist_node *node; - struct sock *s = sk; - unsigned short num = ntohs(loc_port); - - sk_for_each_from(s, node) { - struct inet_sock *inet = inet_sk(s); - - if (s->sk_hash == num && s->sk_family == PF_INET6) { - struct ipv6_pinfo *np = inet6_sk(s); - if (inet->dport) { - if (inet->dport != rmt_port) - continue; - } - if (!ipv6_addr_any(&np->daddr) && - !ipv6_addr_equal(&np->daddr, rmt_addr)) - continue; - - if (s->sk_bound_dev_if && s->sk_bound_dev_if != dif) - continue; - - if (!ipv6_addr_any(&np->rcv_saddr)) { - if (!ipv6_addr_equal(&np->rcv_saddr, loc_addr)) - continue; - } - if (!inet6_mc_check(s, loc_addr, rmt_addr)) - continue; - return s; - } - } - return NULL; -} - -/* - * Note: called only from the BH handler context, - * so we don't need to lock the hashes. - */ -static int __udp6_lib_mcast_deliver(struct sk_buff *skb, struct in6_addr *saddr, - struct in6_addr *daddr, struct hlist_head udptable[]) -{ - struct sock *sk, *sk2; - const struct udphdr *uh = udp_hdr(skb); - int dif; - - read_lock(&udp_hash_lock); - sk = sk_head(&udptable[ntohs(uh->dest) & (UDP_HTABLE_SIZE - 1)]); - dif = inet6_iif(skb); - sk = udp_v6_mcast_next(sk, uh->dest, daddr, uh->source, saddr, dif); - if (!sk) { - kfree_skb(skb); - goto out; - } - - sk2 = sk; - while ((sk2 = udp_v6_mcast_next(sk_next(sk2), uh->dest, daddr, - uh->source, saddr, dif))) { - struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); - if (buff) { - bh_lock_sock_nested(sk2); - if (!sock_owned_by_user(sk2)) - udpv6_queue_rcv_skb(sk2, buff); - else - sk_add_backlog(sk2, buff); - bh_unlock_sock(sk2); - } - } - bh_lock_sock_nested(sk); - if (!sock_owned_by_user(sk)) - udpv6_queue_rcv_skb(sk, skb); - else - sk_add_backlog(sk, skb); - bh_unlock_sock(sk); -out: - read_unlock(&udp_hash_lock); - return 0; -} - -static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, - int proto) -{ - int err; - - UDP_SKB_CB(skb)->partial_cov = 0; - UDP_SKB_CB(skb)->cscov = skb->len; - - if (IS_PROTO_UDPLITE(proto)) { - err = udplite_checksum_init(skb, uh); - if (err) - return err; - } - - if (uh->check == 0) { - /* RFC 2460 section 8.1 says that we SHOULD log - this error. Well, it is reasonable. - */ - LIMIT_NETDEBUG(KERN_INFO "IPv6: udp checksum is 0\n"); - return 1; - } - if (skb->ip_summed == CHECKSUM_COMPLETE && - !csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, - skb->len, proto, skb->csum)) - skb->ip_summed = CHECKSUM_UNNECESSARY; - - if (!skb_csum_unnecessary(skb)) - skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - skb->len, proto, 0)); - - return 0; -} - -int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], - int proto) -{ - struct sock *sk; - struct udphdr *uh; - struct net_device *dev = skb->dev; - struct in6_addr *saddr, *daddr; - u32 ulen = 0; - - if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto short_packet; - - saddr = &ipv6_hdr(skb)->saddr; - daddr = &ipv6_hdr(skb)->daddr; - uh = udp_hdr(skb); - - ulen = ntohs(uh->len); - if (ulen > skb->len) - goto short_packet; - - if (proto == IPPROTO_UDP) { - /* UDP validates ulen. */ - - /* Check for jumbo payload */ - if (ulen == 0) - ulen = skb->len; - - if (ulen < sizeof(*uh)) - goto short_packet; - - if (ulen < skb->len) { - if (pskb_trim_rcsum(skb, ulen)) - goto short_packet; - saddr = &ipv6_hdr(skb)->saddr; - daddr = &ipv6_hdr(skb)->daddr; - uh = udp_hdr(skb); - } - } - - if (udp6_csum_init(skb, uh, proto)) - goto discard; - - /* - * Multicast receive code - */ - if (ipv6_addr_is_multicast(daddr)) - return __udp6_lib_mcast_deliver(skb, saddr, daddr, udptable); - - /* Unicast */ - - /* - * check socket cache ... must talk to Alan about his plans - * for sock caches... i'll skip this for now. - */ - sk = __udp6_lib_lookup(skb->dev->nd_net, saddr, uh->source, - daddr, uh->dest, inet6_iif(skb), udptable); - - if (sk == NULL) { - if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) - goto discard; - - if (udp_lib_checksum_complete(skb)) - goto discard; - UDP6_INC_STATS_BH(UDP_MIB_NOPORTS, IS_PROTO_UDPLITE(proto)); - - icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, dev); - - kfree_skb(skb); - return 0; - } - - /* deliver */ - - bh_lock_sock_nested(sk); - if (!sock_owned_by_user(sk)) - udpv6_queue_rcv_skb(sk, skb); - else - sk_add_backlog(sk, skb); - bh_unlock_sock(sk); - sock_put(sk); - return 0; - -short_packet: - LIMIT_NETDEBUG(KERN_DEBUG "UDP%sv6: short packet: %d/%u\n", - IS_PROTO_UDPLITE(proto) ? "-Lite" : "", - ulen, skb->len); - -discard: - UDP6_INC_STATS_BH(UDP_MIB_INERRORS, IS_PROTO_UDPLITE(proto)); - kfree_skb(skb); - return 0; -} - -static __inline__ int udpv6_rcv(struct sk_buff *skb) -{ - return __udp6_lib_rcv(skb, udp_hash, IPPROTO_UDP); -} - -/* - * Throw away all pending data and cancel the corking. Socket is locked. - */ -static void udp_v6_flush_pending_frames(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - - if (up->pending) { - up->len = 0; - up->pending = 0; - ip6_flush_pending_frames(sk); - } -} - -/* - * Sending - */ - -static int udp_v6_push_pending_frames(struct sock *sk) -{ - struct sk_buff *skb; - struct udphdr *uh; - struct udp_sock *up = udp_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct flowi *fl = &inet->cork.fl; - int err = 0; - int is_udplite = IS_UDPLITE(sk); - __wsum csum = 0; - - /* Grab the skbuff where UDP header space exists. */ - if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) - goto out; - - /* - * Create a UDP header - */ - uh = udp_hdr(skb); - uh->source = fl->fl_ip_sport; - uh->dest = fl->fl_ip_dport; - uh->len = htons(up->len); - uh->check = 0; - - if (is_udplite) - csum = udplite_csum_outgoing(sk, skb); - else - csum = udp_csum_outgoing(sk, skb); - - /* add protocol-dependent pseudo-header */ - uh->check = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, - up->len, fl->proto, csum ); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - - err = ip6_push_pending_frames(sk); -out: - up->len = 0; - up->pending = 0; - if (!err) - UDP6_INC_STATS_USER(UDP_MIB_OUTDATAGRAMS, is_udplite); - return err; -} - -int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, - struct msghdr *msg, size_t len) -{ - struct ipv6_txoptions opt_space; - struct udp_sock *up = udp_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name; - struct in6_addr *daddr, *final_p = NULL, final; - struct ipv6_txoptions *opt = NULL; - struct ip6_flowlabel *flowlabel = NULL; - struct flowi fl; - struct dst_entry *dst; - int addr_len = msg->msg_namelen; - int ulen = len; - int hlimit = -1; - int tclass = -1; - int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; - int err; - int connected = 0; - int is_udplite = IS_UDPLITE(sk); - int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); - - /* destination address check */ - if (sin6) { - if (addr_len < offsetof(struct sockaddr, sa_data)) - return -EINVAL; - - switch (sin6->sin6_family) { - case AF_INET6: - if (addr_len < SIN6_LEN_RFC2133) - return -EINVAL; - daddr = &sin6->sin6_addr; - break; - case AF_INET: - goto do_udp_sendmsg; - case AF_UNSPEC: - msg->msg_name = sin6 = NULL; - msg->msg_namelen = addr_len = 0; - daddr = NULL; - break; - default: - return -EINVAL; - } - } else if (!up->pending) { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - daddr = &np->daddr; - } else - daddr = NULL; - - if (daddr) { - if (ipv6_addr_v4mapped(daddr)) { - struct sockaddr_in sin; - sin.sin_family = AF_INET; - sin.sin_port = sin6 ? sin6->sin6_port : inet->dport; - sin.sin_addr.s_addr = daddr->s6_addr32[3]; - msg->msg_name = &sin; - msg->msg_namelen = sizeof(sin); -do_udp_sendmsg: - if (__ipv6_only_sock(sk)) - return -ENETUNREACH; - return udp_sendmsg(iocb, sk, msg, len); - } - } - - if (up->pending == AF_INET) - return udp_sendmsg(iocb, sk, msg, len); - - /* Rough check on arithmetic overflow, - better check is made in ip6_append_data(). - */ - if (len > INT_MAX - sizeof(struct udphdr)) - return -EMSGSIZE; - - if (up->pending) { - /* - * There are pending frames. - * The socket lock must be held while it's corked. - */ - lock_sock(sk); - if (likely(up->pending)) { - if (unlikely(up->pending != AF_INET6)) { - release_sock(sk); - return -EAFNOSUPPORT; - } - dst = NULL; - goto do_append_data; - } - release_sock(sk); - } - ulen += sizeof(struct udphdr); - - memset(&fl, 0, sizeof(fl)); - - if (sin6) { - if (sin6->sin6_port == 0) - return -EINVAL; - - fl.fl_ip_dport = sin6->sin6_port; - daddr = &sin6->sin6_addr; - - if (np->sndflow) { - fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; - if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) { - flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); - if (flowlabel == NULL) - return -EINVAL; - daddr = &flowlabel->dst; - } - } - - /* - * Otherwise it will be difficult to maintain - * sk->sk_dst_cache. - */ - if (sk->sk_state == TCP_ESTABLISHED && - ipv6_addr_equal(daddr, &np->daddr)) - daddr = &np->daddr; - - if (addr_len >= sizeof(struct sockaddr_in6) && - sin6->sin6_scope_id && - ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) - fl.oif = sin6->sin6_scope_id; - } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - - fl.fl_ip_dport = inet->dport; - daddr = &np->daddr; - fl.fl6_flowlabel = np->flow_label; - connected = 1; - } - - if (!fl.oif) - fl.oif = sk->sk_bound_dev_if; - - if (msg->msg_controllen) { - opt = &opt_space; - memset(opt, 0, sizeof(struct ipv6_txoptions)); - opt->tot_len = sizeof(*opt); - - err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass); - if (err < 0) { - fl6_sock_release(flowlabel); - return err; - } - if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { - flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel); - if (flowlabel == NULL) - return -EINVAL; - } - if (!(opt->opt_nflen|opt->opt_flen)) - opt = NULL; - connected = 0; - } - if (opt == NULL) - opt = np->opt; - if (flowlabel) - opt = fl6_merge_options(&opt_space, flowlabel, opt); - opt = ipv6_fixup_options(&opt_space, opt); - - fl.proto = sk->sk_protocol; - ipv6_addr_copy(&fl.fl6_dst, daddr); - if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) - ipv6_addr_copy(&fl.fl6_src, &np->saddr); - fl.fl_ip_sport = inet->sport; - - /* merge ip6_build_xmit from ip6_output */ - if (opt && opt->srcrt) { - struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt; - ipv6_addr_copy(&final, &fl.fl6_dst); - ipv6_addr_copy(&fl.fl6_dst, rt0->addr); - final_p = &final; - connected = 0; - } - - if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) { - fl.oif = np->mcast_oif; - connected = 0; - } - - security_sk_classify_flow(sk, &fl); - - err = ip6_sk_dst_lookup(sk, &dst, &fl); - if (err) - goto out; - if (final_p) - ipv6_addr_copy(&fl.fl6_dst, final_p); - - if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) { - if (err == -EREMOTE) - err = ip6_dst_blackhole(sk, &dst, &fl); - if (err < 0) - goto out; - } - - if (hlimit < 0) { - if (ipv6_addr_is_multicast(&fl.fl6_dst)) - hlimit = np->mcast_hops; - else - hlimit = np->hop_limit; - if (hlimit < 0) - hlimit = dst_metric(dst, RTAX_HOPLIMIT); - if (hlimit < 0) - hlimit = ipv6_get_hoplimit(dst->dev); - } - - if (tclass < 0) { - tclass = np->tclass; - if (tclass < 0) - tclass = 0; - } - - if (msg->msg_flags&MSG_CONFIRM) - goto do_confirm; -back_from_confirm: - - lock_sock(sk); - if (unlikely(up->pending)) { - /* The socket is already corked while preparing it. */ - /* ... which is an evident application bug. --ANK */ - release_sock(sk); - - LIMIT_NETDEBUG(KERN_DEBUG "udp cork app bug 2\n"); - err = -EINVAL; - goto out; - } - - up->pending = AF_INET6; - -do_append_data: - up->len += ulen; - getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; - err = ip6_append_data(sk, getfrag, msg->msg_iov, ulen, - sizeof(struct udphdr), hlimit, tclass, opt, &fl, - (struct rt6_info*)dst, - corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); - if (err) - udp_v6_flush_pending_frames(sk); - else if (!corkreq) - err = udp_v6_push_pending_frames(sk); - else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) - up->pending = 0; - - if (dst) { - if (connected) { - ip6_dst_store(sk, dst, - ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ? - &np->daddr : NULL, -#ifdef CONFIG_IPV6_SUBTREES - ipv6_addr_equal(&fl.fl6_src, &np->saddr) ? - &np->saddr : -#endif - NULL); - } else { - dst_release(dst); - } - } - - if (err > 0) - err = np->recverr ? net_xmit_errno(err) : 0; - release_sock(sk); -out: - fl6_sock_release(flowlabel); - if (!err) - return len; - /* - * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting - * ENOBUFS might not be good (it's not tunable per se), but otherwise - * we don't have a good statistic (IpOutDiscards but it can be too many - * things). We could add another new stat but at least for now that - * seems like overkill. - */ - if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP6_INC_STATS_USER(UDP_MIB_SNDBUFERRORS, is_udplite); - } - return err; - -do_confirm: - dst_confirm(dst); - if (!(msg->msg_flags&MSG_PROBE) || len) - goto back_from_confirm; - err = 0; - goto out; -} - -int udpv6_destroy_sock(struct sock *sk) -{ - lock_sock(sk); - udp_v6_flush_pending_frames(sk); - release_sock(sk); - - inet6_destroy_sock(sk); - - return 0; -} - -/* - * Socket option code for UDP - */ -int udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_v6_push_pending_frames); - return ipv6_setsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, int optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_v6_push_pending_frames); - return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); -} -#endif - -int udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return ipv6_getsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (IS_SOL_UDPFAMILY(level)) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); -} -#endif - -static struct inet6_protocol udpv6_protocol = { - .handler = udpv6_rcv, - .err_handler = udpv6_err, - .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, -}; - -/* ------------------------------------------------------------------------ */ -#ifdef CONFIG_PROC_FS - -static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket) -{ - struct inet_sock *inet = inet_sk(sp); - struct ipv6_pinfo *np = inet6_sk(sp); - struct in6_addr *dest, *src; - __u16 destp, srcp; - - dest = &np->daddr; - src = &np->rcv_saddr; - destp = ntohs(inet->dport); - srcp = ntohs(inet->sport); - seq_printf(seq, - "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p\n", - bucket, - src->s6_addr32[0], src->s6_addr32[1], - src->s6_addr32[2], src->s6_addr32[3], srcp, - dest->s6_addr32[0], dest->s6_addr32[1], - dest->s6_addr32[2], dest->s6_addr32[3], destp, - sp->sk_state, - atomic_read(&sp->sk_wmem_alloc), - atomic_read(&sp->sk_rmem_alloc), - 0, 0L, 0, - sock_i_uid(sp), 0, - sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp); -} - -int udp6_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_printf(seq, - " sl " - "local_address " - "remote_address " - "st tx_queue rx_queue tr tm->when retrnsmt" - " uid timeout inode\n"); - else - udp6_sock_seq_show(seq, v, ((struct udp_iter_state *)seq->private)->bucket); - return 0; -} - -static struct file_operations udp6_seq_fops; -static struct udp_seq_afinfo udp6_seq_afinfo = { - .owner = THIS_MODULE, - .name = "udp6", - .family = AF_INET6, - .hashtable = udp_hash, - .seq_show = udp6_seq_show, - .seq_fops = &udp6_seq_fops, -}; - -int __init udp6_proc_init(void) -{ - return udp_proc_register(&udp6_seq_afinfo); -} - -void udp6_proc_exit(void) { - udp_proc_unregister(&udp6_seq_afinfo); -} -#endif /* CONFIG_PROC_FS */ - -/* ------------------------------------------------------------------------ */ - -DEFINE_PROTO_INUSE(udpv6) - -struct proto udpv6_prot = { - .name = "UDPv6", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip6_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .destroy = udpv6_destroy_sock, - .setsockopt = udpv6_setsockopt, - .getsockopt = udpv6_getsockopt, - .sendmsg = udpv6_sendmsg, - .recvmsg = udpv6_recvmsg, - .backlog_rcv = udpv6_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udp_v6_get_port, - .memory_allocated = &udp_memory_allocated, - .sysctl_mem = sysctl_udp_mem, - .sysctl_wmem = &sysctl_udp_wmem_min, - .sysctl_rmem = &sysctl_udp_rmem_min, - .obj_size = sizeof(struct udp6_sock), -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udpv6_setsockopt, - .compat_getsockopt = compat_udpv6_getsockopt, -#endif - REF_PROTO_INUSE(udpv6) -}; - -static struct inet_protosw udpv6_protosw = { - .type = SOCK_DGRAM, - .protocol = IPPROTO_UDP, - .prot = &udpv6_prot, - .ops = &inet6_dgram_ops, - .capability =-1, - .no_check = UDP_CSUM_DEFAULT, - .flags = INET_PROTOSW_PERMANENT, -}; - - -int __init udpv6_init(void) -{ - int ret; - - ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP); - if (ret) - goto out; - - ret = inet6_register_protosw(&udpv6_protosw); - if (ret) - goto out_udpv6_protocol; -out: - return ret; - -out_udpv6_protocol: - inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); - goto out; -} - -void udpv6_exit(void) -{ - inet6_unregister_protosw(&udpv6_protosw); - inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); -} diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c new file mode 100644 index 000000000000..87d4202522ee --- /dev/null +++ b/net/ipv6/udplite.c @@ -0,0 +1,125 @@ +/* + * UDPLITEv6 An implementation of the UDP-Lite protocol over IPv6. + * See also net/ipv4/udplite.c + * + * Version: $Id: udplite.c,v 1.9 2006/10/19 08:28:10 gerrit Exp $ + * + * Authors: Gerrit Renker + * + * Changes: + * Fixes: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include "udp_impl.h" + +DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6) __read_mostly; + +static int udplitev6_rcv(struct sk_buff *skb) +{ + return __udp6_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); +} + +static void udplitev6_err(struct sk_buff *skb, + struct inet6_skb_parm *opt, + int type, int code, int offset, __be32 info) +{ + __udp6_lib_err(skb, opt, type, code, offset, info, udplite_hash); +} + +static struct inet6_protocol udplitev6_protocol = { + .handler = udplitev6_rcv, + .err_handler = udplitev6_err, + .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, +}; + +static int udplite_v6_get_port(struct sock *sk, unsigned short snum) +{ + return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal); +} + +DEFINE_PROTO_INUSE(udplitev6) + +struct proto udplitev6_prot = { + .name = "UDPLITEv6", + .owner = THIS_MODULE, + .close = udp_lib_close, + .connect = ip6_datagram_connect, + .disconnect = udp_disconnect, + .ioctl = udp_ioctl, + .init = udplite_sk_init, + .destroy = udpv6_destroy_sock, + .setsockopt = udpv6_setsockopt, + .getsockopt = udpv6_getsockopt, + .sendmsg = udpv6_sendmsg, + .recvmsg = udpv6_recvmsg, + .backlog_rcv = udpv6_queue_rcv_skb, + .hash = udp_lib_hash, + .unhash = udp_lib_unhash, + .get_port = udplite_v6_get_port, + .obj_size = sizeof(struct udp6_sock), +#ifdef CONFIG_COMPAT + .compat_setsockopt = compat_udpv6_setsockopt, + .compat_getsockopt = compat_udpv6_getsockopt, +#endif + REF_PROTO_INUSE(udplitev6) +}; + +static struct inet_protosw udplite6_protosw = { + .type = SOCK_DGRAM, + .protocol = IPPROTO_UDPLITE, + .prot = &udplitev6_prot, + .ops = &inet6_dgram_ops, + .capability = -1, + .no_check = 0, + .flags = INET_PROTOSW_PERMANENT, +}; + +int __init udplitev6_init(void) +{ + int ret; + + ret = inet6_add_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); + if (ret) + goto out; + + ret = inet6_register_protosw(&udplite6_protosw); + if (ret) + goto out_udplitev6_protocol; +out: + return ret; + +out_udplitev6_protocol: + inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); + goto out; +} + +void udplitev6_exit(void) +{ + inet6_unregister_protosw(&udplite6_protosw); + inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); +} + +#ifdef CONFIG_PROC_FS +static struct file_operations udplite6_seq_fops; +static struct udp_seq_afinfo udplite6_seq_afinfo = { + .owner = THIS_MODULE, + .name = "udplite6", + .family = AF_INET6, + .hashtable = udplite_hash, + .seq_show = udp6_seq_show, + .seq_fops = &udplite6_seq_fops, +}; + +int __init udplite6_proc_init(void) +{ + return udp_proc_register(&udplite6_seq_afinfo); +} + +void udplite6_proc_exit(void) +{ + udp_proc_unregister(&udplite6_seq_afinfo); +} +#endif diff --git a/net/ipv6/udplite_ipv6.c b/net/ipv6/udplite_ipv6.c deleted file mode 100644 index 87d4202522ee..000000000000 --- a/net/ipv6/udplite_ipv6.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * UDPLITEv6 An implementation of the UDP-Lite protocol over IPv6. - * See also net/ipv4/udplite.c - * - * Version: $Id: udplite.c,v 1.9 2006/10/19 08:28:10 gerrit Exp $ - * - * Authors: Gerrit Renker - * - * Changes: - * Fixes: - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include "udp_impl.h" - -DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6) __read_mostly; - -static int udplitev6_rcv(struct sk_buff *skb) -{ - return __udp6_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); -} - -static void udplitev6_err(struct sk_buff *skb, - struct inet6_skb_parm *opt, - int type, int code, int offset, __be32 info) -{ - __udp6_lib_err(skb, opt, type, code, offset, info, udplite_hash); -} - -static struct inet6_protocol udplitev6_protocol = { - .handler = udplitev6_rcv, - .err_handler = udplitev6_err, - .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, -}; - -static int udplite_v6_get_port(struct sock *sk, unsigned short snum) -{ - return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal); -} - -DEFINE_PROTO_INUSE(udplitev6) - -struct proto udplitev6_prot = { - .name = "UDPLITEv6", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip6_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .init = udplite_sk_init, - .destroy = udpv6_destroy_sock, - .setsockopt = udpv6_setsockopt, - .getsockopt = udpv6_getsockopt, - .sendmsg = udpv6_sendmsg, - .recvmsg = udpv6_recvmsg, - .backlog_rcv = udpv6_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udplite_v6_get_port, - .obj_size = sizeof(struct udp6_sock), -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udpv6_setsockopt, - .compat_getsockopt = compat_udpv6_getsockopt, -#endif - REF_PROTO_INUSE(udplitev6) -}; - -static struct inet_protosw udplite6_protosw = { - .type = SOCK_DGRAM, - .protocol = IPPROTO_UDPLITE, - .prot = &udplitev6_prot, - .ops = &inet6_dgram_ops, - .capability = -1, - .no_check = 0, - .flags = INET_PROTOSW_PERMANENT, -}; - -int __init udplitev6_init(void) -{ - int ret; - - ret = inet6_add_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); - if (ret) - goto out; - - ret = inet6_register_protosw(&udplite6_protosw); - if (ret) - goto out_udplitev6_protocol; -out: - return ret; - -out_udplitev6_protocol: - inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); - goto out; -} - -void udplitev6_exit(void) -{ - inet6_unregister_protosw(&udplite6_protosw); - inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); -} - -#ifdef CONFIG_PROC_FS -static struct file_operations udplite6_seq_fops; -static struct udp_seq_afinfo udplite6_seq_afinfo = { - .owner = THIS_MODULE, - .name = "udplite6", - .family = AF_INET6, - .hashtable = udplite_hash, - .seq_show = udp6_seq_show, - .seq_fops = &udplite6_seq_fops, -}; - -int __init udplite6_proc_init(void) -{ - return udp_proc_register(&udplite6_seq_afinfo); -} - -void udplite6_proc_exit(void) -{ - udp_proc_unregister(&udplite6_seq_afinfo); -} -#endif -- cgit v1.2.3-59-g8ed1b From 8a3edd800dcdf949953777c73abf54de261574e8 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 7 Mar 2008 11:14:16 -0800 Subject: [NETNS][IPV6] fix some missing namespace This patch adds some missing namespace Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv6/ip6_output.c | 10 ++++++---- net/ipv6/ipv6_sockglue.c | 3 ++- net/ipv6/route.c | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 937018529d18..98762fde2b65 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -404,6 +404,7 @@ int ip6_forward(struct sk_buff *skb) struct dst_entry *dst = skb->dst; struct ipv6hdr *hdr = ipv6_hdr(skb); struct inet6_skb_parm *opt = IP6CB(skb); + struct net *net = dst->dev->nd_net; if (ipv6_devconf.forwarding == 0) goto error; @@ -450,7 +451,7 @@ int ip6_forward(struct sk_buff *skb) /* XXX: idev->cnf.proxy_ndp? */ if (ipv6_devconf.proxy_ndp && - pneigh_lookup(&nd_tbl, &init_net, &hdr->daddr, skb->dev, 0)) { + pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) { int proxied = ip6_forward_proxy_check(skb); if (proxied > 0) return ip6_input(skb); @@ -911,9 +912,10 @@ static int ip6_dst_lookup_tail(struct sock *sk, struct dst_entry **dst, struct flowi *fl) { int err; + struct net *net = sk->sk_net; if (*dst == NULL) - *dst = ip6_route_output(sk->sk_net, sk, fl); + *dst = ip6_route_output(net, sk, fl); if ((err = (*dst)->error)) goto out_err_release; @@ -939,7 +941,7 @@ static int ip6_dst_lookup_tail(struct sock *sk, struct flowi fl_gw; int redirect; - ifp = ipv6_get_ifaddr(&init_net, &fl->fl6_src, + ifp = ipv6_get_ifaddr(net, &fl->fl6_src, (*dst)->dev, 1); redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC); @@ -954,7 +956,7 @@ static int ip6_dst_lookup_tail(struct sock *sk, dst_release(*dst); memcpy(&fl_gw, fl, sizeof(struct flowi)); memset(&fl_gw.fl6_dst, 0, sizeof(struct in6_addr)); - *dst = ip6_route_output(sk->sk_net, sk, &fl_gw); + *dst = ip6_route_output(net, sk, &fl_gw); if ((err = (*dst)->error)) goto out_err_release; } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 5eea6fa506e5..c11c76cab371 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -107,6 +107,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { struct ipv6_pinfo *np = inet6_sk(sk); + struct net *net = sk->sk_net; int val, valbool; int retv = -ENOPROTOOPT; @@ -432,7 +433,7 @@ done: if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) goto e_inval; - if (__dev_get_by_index(&init_net, val) == NULL) { + if (__dev_get_by_index(net, val) == NULL) { retv = -ENODEV; break; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 15e9a86f28c8..a4b5aee0f68a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2261,7 +2261,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void skb_reset_mac_header(skb); skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); - rt = (struct rt6_info*) ip6_route_output(&init_net, NULL, &fl); + rt = (struct rt6_info*) ip6_route_output(net, NULL, &fl); skb->dst = &rt->u.dst; err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, -- cgit v1.2.3-59-g8ed1b From a18bc6959d9793c8352d2177b456d93868953874 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 7 Mar 2008 11:14:49 -0800 Subject: [NETNS][IPV6] ndisc - make ndisc handle multiple network namespaces Make ndisc handle multiple network namespaces: Remove references to init_net, add network namespace parameters and add pernet_operations for ndisc Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index e0d023360a88..a539b9ea53fd 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -541,7 +541,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, }; /* for anycast or proxy, solicited_addr != src_addr */ - ifp = ipv6_get_ifaddr(&init_net, solicited_addr, dev, 1); + ifp = ipv6_get_ifaddr(dev->nd_net, solicited_addr, dev, 1); if (ifp) { src_addr = solicited_addr; if (ifp->flags & IFA_F_OPTIMISTIC) @@ -601,7 +601,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, * suppress the inclusion of the sllao. */ if (send_sllao) { - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(&init_net, saddr, + struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev->nd_net, saddr, dev, 1); if (ifp) { if (ifp->flags & IFA_F_OPTIMISTIC) { @@ -639,7 +639,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; int probes = atomic_read(&neigh->probes); - if (skb && ipv6_chk_addr(&init_net, &ipv6_hdr(skb)->saddr, dev, 1)) + if (skb && ipv6_chk_addr(dev->nd_net, &ipv6_hdr(skb)->saddr, dev, 1)) saddr = &ipv6_hdr(skb)->saddr; if ((probes -= neigh->parms->ucast_probes) < 0) { @@ -727,7 +727,8 @@ static void ndisc_recv_ns(struct sk_buff *skb) inc = ipv6_addr_is_multicast(daddr); - if ((ifp = ipv6_get_ifaddr(&init_net, &msg->target, dev, 1)) != NULL) { + ifp = ipv6_get_ifaddr(dev->nd_net, &msg->target, dev, 1); + if (ifp) { if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { if (dad) { @@ -775,7 +776,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) if (ipv6_chk_acast_addr(dev, &msg->target) || (idev->cnf.forwarding && (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && - (pneigh = pneigh_lookup(&nd_tbl, &init_net, + (pneigh = pneigh_lookup(&nd_tbl, dev->nd_net, &msg->target, dev, 0)) != NULL)) { if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && skb->pkt_type != PACKET_HOST && @@ -885,7 +886,8 @@ static void ndisc_recv_na(struct sk_buff *skb) return; } } - if ((ifp = ipv6_get_ifaddr(&init_net, &msg->target, dev, 1))) { + ifp = ipv6_get_ifaddr(dev->nd_net, &msg->target, dev, 1); + if (ifp) { if (ifp->flags & IFA_F_TENTATIVE) { addrconf_dad_failure(ifp); return; @@ -916,7 +918,7 @@ static void ndisc_recv_na(struct sk_buff *skb) */ if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp && - pneigh_lookup(&nd_tbl, &init_net, &msg->target, dev, 0)) { + pneigh_lookup(&nd_tbl, dev->nd_net, &msg->target, dev, 0)) { /* XXX: idev->cnf.prixy_ndp */ goto out; } @@ -1006,6 +1008,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) struct sk_buff *skb; struct nlmsghdr *nlh; struct nduseroptmsg *ndmsg; + struct net *net = ra->dev->nd_net; int err; int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg) + (opt->nd_opt_len << 3)); @@ -1035,7 +1038,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) &ipv6_hdr(ra)->saddr); nlmsg_end(skb, nlh); - err = rtnl_notify(skb, &init_net, 0, RTNLGRP_ND_USEROPT, NULL, + err = rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC); if (err < 0) goto errout; @@ -1046,7 +1049,7 @@ nla_put_failure: nlmsg_free(skb); err = -EMSGSIZE; errout: - rtnl_set_sk_err(&init_net, RTNLGRP_ND_USEROPT, err); + rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); } static void ndisc_router_discovery(struct sk_buff *skb) @@ -1600,9 +1603,6 @@ static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; struct net *net = dev->nd_net; - if (dev->nd_net != &init_net) - return NOTIFY_DONE; - switch (event) { case NETDEV_CHANGEADDR: neigh_changeaddr(&nd_tbl, dev); -- cgit v1.2.3-59-g8ed1b From 1762f7e88eb34f653b4a915be99a102e347dd45e Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 7 Mar 2008 11:15:34 -0800 Subject: [NETNS][IPV6] ndisc - make socket control per namespace Make ndisc socket control per namespace. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/netns/ipv6.h | 1 + net/ipv6/ndisc.c | 77 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 90e6e24df858..b773256d0d1d 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -51,5 +51,6 @@ struct netns_ipv6 { struct fib_rules_ops *fib6_rules_ops; #endif struct sock **icmp_sk; + struct sock *ndisc_sk; }; #endif diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index a539b9ea53fd..24e76ed98884 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -89,8 +89,6 @@ #include #include -static struct socket *ndisc_socket; - static u32 ndisc_hash(const void *pkey, const struct net_device *dev); static int ndisc_constructor(struct neighbour *neigh); static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); @@ -449,7 +447,8 @@ static void __ndisc_send(struct net_device *dev, { struct flowi fl; struct dst_entry *dst; - struct sock *sk = ndisc_socket->sk; + struct net *net = dev->nd_net; + struct sock *sk = net->ipv6.ndisc_sk; struct sk_buff *skb; struct icmp6hdr *hdr; struct inet6_dev *idev; @@ -459,8 +458,7 @@ static void __ndisc_send(struct net_device *dev, type = icmp6h->icmp6_type; - icmpv6_flow_init(ndisc_socket->sk, &fl, type, - saddr, daddr, dev->ifindex); + icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex); dst = icmp6_dst_alloc(dev, neigh, daddr); if (!dst) @@ -1394,13 +1392,14 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, struct in6_addr *target) { - struct sock *sk = ndisc_socket->sk; + struct net_device *dev = skb->dev; + struct net *net = dev->nd_net; + struct sock *sk = net->ipv6.ndisc_sk; int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); struct sk_buff *buff; struct icmp6hdr *icmph; struct in6_addr saddr_buf; struct in6_addr *addrp; - struct net_device *dev; struct rt6_info *rt; struct dst_entry *dst; struct inet6_dev *idev; @@ -1411,8 +1410,6 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, int hlen; u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; - dev = skb->dev; - if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { ND_PRINTK2(KERN_WARNING "ICMPv6 Redirect: no link-local address on %s\n", @@ -1427,10 +1424,10 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, return; } - icmpv6_flow_init(ndisc_socket->sk, &fl, NDISC_REDIRECT, + icmpv6_flow_init(sk, &fl, NDISC_REDIRECT, &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); - dst = ip6_route_output(&init_net, NULL, &fl); + dst = ip6_route_output(net, NULL, &fl); if (dst == NULL) return; @@ -1719,22 +1716,24 @@ static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name, #endif -int __init ndisc_init(void) +static int ndisc_net_init(struct net *net) { + struct socket *sock; struct ipv6_pinfo *np; struct sock *sk; int err; - err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &ndisc_socket); + err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock); if (err < 0) { ND_PRINTK0(KERN_ERR "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n", err); - ndisc_socket = NULL; /* For safety. */ return err; } - sk = ndisc_socket->sk; + net->ipv6.ndisc_sk = sk = sock->sk; + sk_change_net(sk, net); + np = inet6_sk(sk); sk->sk_allocation = GFP_ATOMIC; np->hop_limit = 255; @@ -1742,21 +1741,52 @@ int __init ndisc_init(void) np->mc_loop = 0; sk->sk_prot->unhash(sk); + return 0; +} + +static void ndisc_net_exit(struct net *net) +{ + sk_release_kernel(net->ipv6.ndisc_sk); +} + +static struct pernet_operations ndisc_net_ops = { + .init = ndisc_net_init, + .exit = ndisc_net_exit, +}; + +int __init ndisc_init(void) +{ + int err; + + err = register_pernet_subsys(&ndisc_net_ops); + if (err) + return err; /* * Initialize the neighbour table */ - neigh_table_init(&nd_tbl); #ifdef CONFIG_SYSCTL - neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, - "ipv6", - &ndisc_ifinfo_sysctl_change, - &ndisc_ifinfo_sysctl_strategy); + err = neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, + NET_IPV6_NEIGH, "ipv6", + &ndisc_ifinfo_sysctl_change, + &ndisc_ifinfo_sysctl_strategy); + if (err) + goto out_unregister_pernet; #endif + err = register_netdevice_notifier(&ndisc_netdev_notifier); + if (err) + goto out_unregister_sysctl; +out: + return err; - register_netdevice_notifier(&ndisc_netdev_notifier); - return 0; +out_unregister_sysctl: +#ifdef CONFIG_SYSCTL + neigh_sysctl_unregister(&nd_tbl.parms); +out_unregister_pernet: +#endif + unregister_pernet_subsys(&ndisc_net_ops); + goto out; } void ndisc_cleanup(void) @@ -1766,6 +1796,5 @@ void ndisc_cleanup(void) neigh_sysctl_unregister(&nd_tbl.parms); #endif neigh_table_clear(&nd_tbl); - sock_release(ndisc_socket); - ndisc_socket = NULL; /* For safety. */ + unregister_pernet_subsys(&ndisc_net_ops); } -- cgit v1.2.3-59-g8ed1b From 93ec926b075d14bb7edcbc054e92199e9ad4ad1d Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 7 Mar 2008 11:16:02 -0800 Subject: [NETNS][IPV6] tcp6 - make socket control per namespace Instead of having a tcp6_socket global to all the namespace, there is tcp6 socket control per namespace. That is consistent with which namespace sent a RST and allows to pass the socket to the underlying function to retrieve the network namespace. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/netns/ipv6.h | 1 + net/ipv6/tcp_ipv6.c | 43 +++++++++++++++++++++++++++++++++---------- 2 files changed, 34 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index b773256d0d1d..ddb9ccddcc4d 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -52,5 +52,6 @@ struct netns_ipv6 { #endif struct sock **icmp_sk; struct sock *ndisc_sk; + struct sock *tcp_sk; }; #endif diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index b47cce8fea44..7954b4e99c4f 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -69,9 +69,6 @@ #include #include -/* Socket used for sending RSTs and ACKs */ -static struct socket *tcp6_socket; - static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb); static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req); static void tcp_v6_send_check(struct sock *sk, int len, @@ -1075,10 +1072,11 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) * Underlying function will use this to retrieve the network * namespace */ - if (!ip6_dst_lookup(tcp6_socket->sk, &buff->dst, &fl)) { + if (!ip6_dst_lookup(init_net.ipv6.tcp_sk, &buff->dst, &fl)) { if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { - ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0); + ip6_xmit(init_net.ipv6.tcp_sk, + buff, &fl, NULL, 0); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); return; @@ -1175,9 +1173,10 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, fl.fl_ip_sport = t1->source; security_skb_classify_flow(skb, &fl); - if (!ip6_dst_lookup(tcp6_socket->sk, &buff->dst, &fl)) { + if (!ip6_dst_lookup(init_net.ipv6.tcp_sk, &buff->dst, &fl)) { if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { - ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0); + ip6_xmit(init_net.ipv6.tcp_sk, + buff, &fl, NULL, 0); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); return; } @@ -2198,6 +2197,31 @@ static struct inet_protosw tcpv6_protosw = { INET_PROTOSW_ICSK, }; +static int tcpv6_net_init(struct net *net) +{ + int err; + struct socket *sock; + struct sock *sk; + + err = inet_csk_ctl_sock_create(&sock, PF_INET6, SOCK_RAW, IPPROTO_TCP); + if (err) + return err; + + net->ipv6.tcp_sk = sk = sock->sk; + sk_change_net(sk, net); + return err; +} + +static void tcpv6_net_exit(struct net *net) +{ + sk_release_kernel(net->ipv6.tcp_sk); +} + +static struct pernet_operations tcpv6_net_ops = { + .init = tcpv6_net_init, + .exit = tcpv6_net_exit, +}; + int __init tcpv6_init(void) { int ret; @@ -2211,8 +2235,7 @@ int __init tcpv6_init(void) if (ret) goto out_tcpv6_protocol; - ret = inet_csk_ctl_sock_create(&tcp6_socket, PF_INET6, - SOCK_RAW, IPPROTO_TCP); + ret = register_pernet_subsys(&tcpv6_net_ops); if (ret) goto out_tcpv6_protosw; out: @@ -2227,7 +2250,7 @@ out_tcpv6_protosw: void tcpv6_exit(void) { - sock_release(tcp6_socket); + unregister_pernet_subsys(&tcpv6_net_ops); inet6_unregister_protosw(&tcpv6_protosw); inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP); } -- cgit v1.2.3-59-g8ed1b From e504799276e53045a9b597f24c1b456552482f63 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 7 Mar 2008 11:16:26 -0800 Subject: [NETNS][IPV6] tcp6 - handle several network namespace We have the right network namespace at the right place now. So make use of this information to make tcp6 per network namespace Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- net/ipv6/tcp_ipv6.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 7954b4e99c4f..caf0cc1c00e1 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -988,6 +988,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) struct tcphdr *th = tcp_hdr(skb), *t1; struct sk_buff *buff; struct flowi fl; + struct net *net = skb->dst->dev->nd_net; + struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(*th); #ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *key; @@ -1072,11 +1074,10 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) * Underlying function will use this to retrieve the network * namespace */ - if (!ip6_dst_lookup(init_net.ipv6.tcp_sk, &buff->dst, &fl)) { + if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) { if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { - ip6_xmit(init_net.ipv6.tcp_sk, - buff, &fl, NULL, 0); + ip6_xmit(ctl_sk, buff, &fl, NULL, 0); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); return; @@ -1092,6 +1093,8 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, struct tcphdr *th = tcp_hdr(skb), *t1; struct sk_buff *buff; struct flowi fl; + struct net *net = skb->dev->nd_net; + struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(struct tcphdr); __be32 *topt; #ifdef CONFIG_TCP_MD5SIG @@ -1173,10 +1176,9 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, fl.fl_ip_sport = t1->source; security_skb_classify_flow(skb, &fl); - if (!ip6_dst_lookup(init_net.ipv6.tcp_sk, &buff->dst, &fl)) { + if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) { if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { - ip6_xmit(init_net.ipv6.tcp_sk, - buff, &fl, NULL, 0); + ip6_xmit(ctl_sk, buff, &fl, NULL, 0); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); return; } -- cgit v1.2.3-59-g8ed1b From b8ad0cbc58f703972e9e37c4e2a8081dd7e6a551 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 7 Mar 2008 11:16:55 -0800 Subject: [NETNS][IPV6] mcast - handle several network namespace This patch make use of the network namespace information at the right places to handle the multicast for several network namespaces. It makes the socket control to be per namespace too. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/netns/ipv6.h | 1 + net/ipv6/mcast.c | 116 +++++++++++++++++++++++++++++++---------------- net/ipv6/udp.c | 3 ++ 3 files changed, 82 insertions(+), 38 deletions(-) (limited to 'net') diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index ddb9ccddcc4d..ac053be6c256 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -53,5 +53,6 @@ struct netns_ipv6 { struct sock **icmp_sk; struct sock *ndisc_sk; struct sock *tcp_sk; + struct sock *igmp_sk; }; #endif diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 197ca390a15d..f2879056fab0 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -126,8 +126,6 @@ static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; /* Big mc list lock for all the sockets */ static DEFINE_RWLOCK(ipv6_sk_mc_lock); -static struct socket *igmp6_socket; - int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr); static void igmp6_join_group(struct ifmcaddr6 *ma); @@ -183,6 +181,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) struct net_device *dev = NULL; struct ipv6_mc_socklist *mc_lst; struct ipv6_pinfo *np = inet6_sk(sk); + struct net *net = sk->sk_net; int err; if (!ipv6_addr_is_multicast(addr)) @@ -208,14 +207,14 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) if (ifindex == 0) { struct rt6_info *rt; - rt = rt6_lookup(&init_net, addr, NULL, 0, 0); + rt = rt6_lookup(net, addr, NULL, 0, 0); if (rt) { dev = rt->rt6i_dev; dev_hold(dev); dst_release(&rt->u.dst); } } else - dev = dev_get_by_index(&init_net, ifindex); + dev = dev_get_by_index(net, ifindex); if (dev == NULL) { sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); @@ -256,6 +255,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_mc_socklist *mc_lst, **lnk; + struct net *net = sk->sk_net; write_lock_bh(&ipv6_sk_mc_lock); for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) { @@ -266,7 +266,8 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) *lnk = mc_lst->next; write_unlock_bh(&ipv6_sk_mc_lock); - if ((dev = dev_get_by_index(&init_net, mc_lst->ifindex)) != NULL) { + dev = dev_get_by_index(net, mc_lst->ifindex); + if (dev != NULL) { struct inet6_dev *idev = in6_dev_get(dev); (void) ip6_mc_leave_src(sk, mc_lst, idev); @@ -286,7 +287,9 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) return -EADDRNOTAVAIL; } -static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) +static struct inet6_dev *ip6_mc_find_dev(struct net *net, + struct in6_addr *group, + int ifindex) { struct net_device *dev = NULL; struct inet6_dev *idev = NULL; @@ -294,14 +297,14 @@ static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) if (ifindex == 0) { struct rt6_info *rt; - rt = rt6_lookup(&init_net, group, NULL, 0, 0); + rt = rt6_lookup(net, group, NULL, 0, 0); if (rt) { dev = rt->rt6i_dev; dev_hold(dev); dst_release(&rt->u.dst); } } else - dev = dev_get_by_index(&init_net, ifindex); + dev = dev_get_by_index(net, ifindex); if (!dev) return NULL; @@ -324,6 +327,7 @@ void ipv6_sock_mc_close(struct sock *sk) { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_mc_socklist *mc_lst; + struct net *net = sk->sk_net; write_lock_bh(&ipv6_sk_mc_lock); while ((mc_lst = np->ipv6_mc_list) != NULL) { @@ -332,7 +336,7 @@ void ipv6_sock_mc_close(struct sock *sk) np->ipv6_mc_list = mc_lst->next; write_unlock_bh(&ipv6_sk_mc_lock); - dev = dev_get_by_index(&init_net, mc_lst->ifindex); + dev = dev_get_by_index(net, mc_lst->ifindex); if (dev) { struct inet6_dev *idev = in6_dev_get(dev); @@ -361,6 +365,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, struct inet6_dev *idev; struct ipv6_pinfo *inet6 = inet6_sk(sk); struct ip6_sf_socklist *psl; + struct net *net = sk->sk_net; int i, j, rv; int leavegroup = 0; int pmclocked = 0; @@ -376,7 +381,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, if (!ipv6_addr_is_multicast(group)) return -EINVAL; - idev = ip6_mc_find_dev(group, pgsr->gsr_interface); + idev = ip6_mc_find_dev(net, group, pgsr->gsr_interface); if (!idev) return -ENODEV; dev = idev->dev; @@ -500,6 +505,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) struct inet6_dev *idev; struct ipv6_pinfo *inet6 = inet6_sk(sk); struct ip6_sf_socklist *newpsl, *psl; + struct net *net = sk->sk_net; int leavegroup = 0; int i, err; @@ -511,7 +517,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) gsf->gf_fmode != MCAST_EXCLUDE) return -EINVAL; - idev = ip6_mc_find_dev(group, gsf->gf_interface); + idev = ip6_mc_find_dev(net, group, gsf->gf_interface); if (!idev) return -ENODEV; @@ -592,13 +598,14 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, struct net_device *dev; struct ipv6_pinfo *inet6 = inet6_sk(sk); struct ip6_sf_socklist *psl; + struct net *net = sk->sk_net; group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr; if (!ipv6_addr_is_multicast(group)) return -EINVAL; - idev = ip6_mc_find_dev(group, gsf->gf_interface); + idev = ip6_mc_find_dev(net, group, gsf->gf_interface); if (!idev) return -ENODEV; @@ -1393,7 +1400,8 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted) static struct sk_buff *mld_newpack(struct net_device *dev, int size) { - struct sock *sk = igmp6_socket->sk; + struct net *net = dev->nd_net; + struct sock *sk = net->ipv6.igmp_sk; struct sk_buff *skb; struct mld2_report *pmr; struct in6_addr addr_buf; @@ -1440,6 +1448,7 @@ static void mld_sendpack(struct sk_buff *skb) (struct mld2_report *)skb_transport_header(skb); int payload_len, mldlen; struct inet6_dev *idev = in6_dev_get(skb->dev); + struct net *net = skb->dev->nd_net; int err; struct flowi fl; @@ -1459,7 +1468,7 @@ static void mld_sendpack(struct sk_buff *skb) goto err_out; } - icmpv6_flow_init(igmp6_socket->sk, &fl, ICMPV6_MLD2_REPORT, + icmpv6_flow_init(net->ipv6.igmp_sk, &fl, ICMPV6_MLD2_REPORT, &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, skb->dev->ifindex); @@ -1753,7 +1762,8 @@ static void mld_send_cr(struct inet6_dev *idev) static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) { - struct sock *sk = igmp6_socket->sk; + struct net *net = dev->nd_net; + struct sock *sk = net->ipv6.igmp_sk; struct inet6_dev *idev; struct sk_buff *skb; struct icmp6hdr *hdr; @@ -1824,7 +1834,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) goto err_out; } - icmpv6_flow_init(igmp6_socket->sk, &fl, type, + icmpv6_flow_init(sk, &fl, type, &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, skb->dev->ifindex); @@ -2334,6 +2344,7 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev) #ifdef CONFIG_PROC_FS struct igmp6_mc_iter_state { + struct seq_net_private p; struct net_device *dev; struct inet6_dev *idev; }; @@ -2344,9 +2355,10 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) { struct ifmcaddr6 *im = NULL; struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); + struct net *net = state->p.net; state->idev = NULL; - for_each_netdev(&init_net, state->dev) { + for_each_netdev(net, state->dev) { struct inet6_dev *idev; idev = in6_dev_get(state->dev); if (!idev) @@ -2448,8 +2460,8 @@ static const struct seq_operations igmp6_mc_seq_ops = { static int igmp6_mc_seq_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &igmp6_mc_seq_ops, - sizeof(struct igmp6_mc_iter_state)); + return seq_open_net(inode, file, &igmp6_mc_seq_ops, + sizeof(struct igmp6_mc_iter_state)); } static const struct file_operations igmp6_mc_seq_fops = { @@ -2457,10 +2469,11 @@ static const struct file_operations igmp6_mc_seq_fops = { .open = igmp6_mc_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; struct igmp6_mcf_iter_state { + struct seq_net_private p; struct net_device *dev; struct inet6_dev *idev; struct ifmcaddr6 *im; @@ -2473,10 +2486,11 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) struct ip6_sf_list *psf = NULL; struct ifmcaddr6 *im = NULL; struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); + struct net *net = state->p.net; state->idev = NULL; state->im = NULL; - for_each_netdev(&init_net, state->dev) { + for_each_netdev(net, state->dev) { struct inet6_dev *idev; idev = in6_dev_get(state->dev); if (unlikely(idev == NULL)) @@ -2608,8 +2622,8 @@ static const struct seq_operations igmp6_mcf_seq_ops = { static int igmp6_mcf_seq_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &igmp6_mcf_seq_ops, - sizeof(struct igmp6_mcf_iter_state)); + return seq_open_net(inode, file, &igmp6_mcf_seq_ops, + sizeof(struct igmp6_mcf_iter_state)); } static const struct file_operations igmp6_mcf_seq_fops = { @@ -2617,26 +2631,27 @@ static const struct file_operations igmp6_mcf_seq_fops = { .open = igmp6_mcf_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; #endif -int __init igmp6_init(void) +static int igmp6_net_init(struct net *net) { struct ipv6_pinfo *np; + struct socket *sock; struct sock *sk; int err; - err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket); + err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock); if (err < 0) { printk(KERN_ERR "Failed to initialize the IGMP6 control socket (err %d).\n", err); - igmp6_socket = NULL; /* For safety. */ - return err; + goto out; } - sk = igmp6_socket->sk; + net->ipv6.igmp_sk = sk = sock->sk; + sk_change_net(sk, net); sk->sk_allocation = GFP_ATOMIC; sk->sk_prot->unhash(sk); @@ -2644,20 +2659,45 @@ int __init igmp6_init(void) np->hop_limit = 1; #ifdef CONFIG_PROC_FS - proc_net_fops_create(&init_net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops); - proc_net_fops_create(&init_net, "mcfilter6", S_IRUGO, &igmp6_mcf_seq_fops); + err = -ENOMEM; + if (!proc_net_fops_create(net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops)) + goto out_sock_create; + if (!proc_net_fops_create(net, "mcfilter6", S_IRUGO, + &igmp6_mcf_seq_fops)) { + proc_net_remove(net, "igmp6"); + goto out_sock_create; + } #endif - return 0; + err = 0; +out: + return err; + +out_sock_create: + sk_release_kernel(net->ipv6.igmp_sk); + goto out; } -void igmp6_cleanup(void) +static void igmp6_net_exit(struct net *net) { - sock_release(igmp6_socket); - igmp6_socket = NULL; /* for safety */ - + sk_release_kernel(net->ipv6.igmp_sk); #ifdef CONFIG_PROC_FS - proc_net_remove(&init_net, "mcfilter6"); - proc_net_remove(&init_net, "igmp6"); + proc_net_remove(net, "mcfilter6"); + proc_net_remove(net, "igmp6"); #endif } + +static struct pernet_operations igmp6_net_ops = { + .init = igmp6_net_init, + .exit = igmp6_net_exit, +}; + +int __init igmp6_init(void) +{ + return register_pernet_subsys(&igmp6_net_ops); +} + +void igmp6_cleanup(void) +{ + unregister_pernet_subsys(&igmp6_net_ops); +} diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 53739de829db..d6e311f6c8eb 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -323,6 +323,9 @@ static struct sock *udp_v6_mcast_next(struct sock *sk, sk_for_each_from(s, node) { struct inet_sock *inet = inet_sk(s); + if (s->sk_net != sk->sk_net) + continue; + if (s->sk_hash == num && s->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(s); if (inet->dport) { -- cgit v1.2.3-59-g8ed1b From e5f98f2df903af627a9b9ac55b9352fd54fc431a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 5 Mar 2008 20:39:31 +0100 Subject: mac80211: don't call conf_tx under RCU lock Reinette pointed out that with the sta_info RCU-ification the behaviour here changed and the conf_tx callback is now invoked under RCU read lock. That is not necessary so this patch restores the original behaviour Signed-off-by: Johannes Berg Tested-by: Reinette Chatre Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index bece28b3eba5..8b991ebcbb4e 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1930,16 +1930,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { sta->flags |= WLAN_STA_WME; + rcu_read_unlock(); ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, elems.wmm_param_len); - } + } else + rcu_read_unlock(); /* set AID, ieee80211_set_associated() will tell the driver */ bss_conf->aid = aid; ieee80211_set_associated(dev, ifsta, 1); - rcu_read_unlock(); - ieee80211_associated(dev, ifsta); } -- cgit v1.2.3-59-g8ed1b From 7524d7d6de5d5d3f081de8cf5479819fad339661 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 4 Mar 2008 15:26:14 -0800 Subject: the scheduled ieee80211 softmac removal Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: John W. Linville --- Documentation/feature-removal-schedule.txt | 8 - MAINTAINERS | 6 - include/net/ieee80211softmac.h | 373 ---------------- include/net/ieee80211softmac_wx.h | 99 ----- net/ieee80211/Kconfig | 1 - net/ieee80211/Makefile | 1 - net/ieee80211/softmac/Kconfig | 12 - net/ieee80211/softmac/Makefile | 9 - net/ieee80211/softmac/ieee80211softmac_assoc.c | 489 -------------------- net/ieee80211/softmac/ieee80211softmac_auth.c | 413 ----------------- net/ieee80211/softmac/ieee80211softmac_event.c | 189 -------- net/ieee80211/softmac/ieee80211softmac_io.c | 488 -------------------- net/ieee80211/softmac/ieee80211softmac_module.c | 568 ------------------------ net/ieee80211/softmac/ieee80211softmac_priv.h | 244 ---------- net/ieee80211/softmac/ieee80211softmac_scan.c | 254 ----------- net/ieee80211/softmac/ieee80211softmac_wx.c | 508 --------------------- 16 files changed, 3662 deletions(-) delete mode 100644 include/net/ieee80211softmac.h delete mode 100644 include/net/ieee80211softmac_wx.h delete mode 100644 net/ieee80211/softmac/Kconfig delete mode 100644 net/ieee80211/softmac/Makefile delete mode 100644 net/ieee80211/softmac/ieee80211softmac_assoc.c delete mode 100644 net/ieee80211/softmac/ieee80211softmac_auth.c delete mode 100644 net/ieee80211/softmac/ieee80211softmac_event.c delete mode 100644 net/ieee80211/softmac/ieee80211softmac_io.c delete mode 100644 net/ieee80211/softmac/ieee80211softmac_module.c delete mode 100644 net/ieee80211/softmac/ieee80211softmac_priv.h delete mode 100644 net/ieee80211/softmac/ieee80211softmac_scan.c delete mode 100644 net/ieee80211/softmac/ieee80211softmac_wx.c (limited to 'net') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index dade1d14f5b2..2cf4d7ad7b0b 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -230,14 +230,6 @@ Who: Jean Delvare --------------------------- -What: ieee80211 softmac wireless networking component -When: 2.6.26 (or after removal of bcm43xx and port of zd1211rw to mac80211) -Files: net/ieee80211/softmac -Why: No in-kernel drivers will depend on it any longer. -Who: John W. Linville - ---------------------------- - What: rc80211-simple rate control algorithm for mac80211 When: 2.6.26 Files: net/mac80211/rc80211-simple.c diff --git a/MAINTAINERS b/MAINTAINERS index 38b767611bbf..b9fc1f620f29 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3548,12 +3548,6 @@ M: mhoffman@lightlink.com L: lm-sensors@lm-sensors.org S: Maintained -SOFTMAC LAYER (IEEE 802.11) -P: Daniel Drake -M: dsd@gentoo.org -L: linux-wireless@vger.kernel.org -S: Obsolete - SOFTWARE RAID (Multiple Disks) SUPPORT P: Ingo Molnar M: mingo@redhat.com diff --git a/include/net/ieee80211softmac.h b/include/net/ieee80211softmac.h deleted file mode 100644 index 1ef6282fdded..000000000000 --- a/include/net/ieee80211softmac.h +++ /dev/null @@ -1,373 +0,0 @@ -/* - * ieee80211softmac.h - public interface to the softmac - * - * Copyright (c) 2005 Johannes Berg - * Joseph Jezak - * Larry Finger - * Danny van Dyk - * Michael Buesch - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. - */ - -#ifndef IEEE80211SOFTMAC_H_ -#define IEEE80211SOFTMAC_H_ - -#include -#include -#include -#include -#include - -/* Once the API is considered more or less stable, - * this should be incremented on API incompatible changes. - */ -#define IEEE80211SOFTMAC_API 0 - -#define IEEE80211SOFTMAC_MAX_RATES_LEN 8 -#define IEEE80211SOFTMAC_MAX_EX_RATES_LEN 255 - -struct ieee80211softmac_ratesinfo { - u8 count; - u8 rates[IEEE80211SOFTMAC_MAX_RATES_LEN + IEEE80211SOFTMAC_MAX_EX_RATES_LEN]; -}; - -/* internal structures */ -struct ieee80211softmac_network; -struct ieee80211softmac_scaninfo; - -struct ieee80211softmac_essid { - u8 len; - char data[IW_ESSID_MAX_SIZE+1]; -}; - -struct ieee80211softmac_wpa { - char *IE; - int IElen; - int IEbuflen; -}; - -/* - * Information about association - */ -struct ieee80211softmac_assoc_info { - - struct mutex mutex; - - /* - * This is the requested ESSID. It is written - * only by the WX handlers. - * - */ - struct ieee80211softmac_essid req_essid; - /* - * the ESSID of the network we're currently - * associated (or trying) to. This is - * updated to the network's actual ESSID - * even if the requested ESSID was 'ANY' - */ - struct ieee80211softmac_essid associate_essid; - - /* BSSID we're trying to associate to */ - char bssid[ETH_ALEN]; - - /* some flags. - * static_essid is valid if the essid is constant, - * this is for use by the wx handlers only. - * - * associating is true, if the network has been - * auth'ed on and we are in the process of associating. - * - * bssvalid is true if we found a matching network - * and saved it's BSSID into the bssid above. - * - * bssfixed is used for SIOCSIWAP. - */ - u8 static_essid; - u8 short_preamble_available; - u8 associating; - u8 associated; - u8 assoc_wait; - u8 bssvalid; - u8 bssfixed; - - /* Scan retries remaining */ - int scan_retry; - - struct delayed_work work; - struct delayed_work timeout; -}; - -struct ieee80211softmac_bss_info { - /* Rates supported by the network */ - struct ieee80211softmac_ratesinfo supported_rates; - - /* This indicates whether frames can currently be transmitted with - * short preamble (only use this variable during TX at CCK rates) */ - u8 short_preamble:1; - - /* This indicates whether protection (e.g. self-CTS) should be used - * when transmitting with OFDM modulation */ - u8 use_protection:1; -}; - -enum { - IEEE80211SOFTMAC_AUTH_OPEN_REQUEST = 1, - IEEE80211SOFTMAC_AUTH_OPEN_RESPONSE = 2, -}; - -enum { - IEEE80211SOFTMAC_AUTH_SHARED_REQUEST = 1, - IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE = 2, - IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE = 3, - IEEE80211SOFTMAC_AUTH_SHARED_PASS = 4, -}; - -/* We should make these tunable - * AUTH_TIMEOUT seems really long, but that's what it is in BSD */ -#define IEEE80211SOFTMAC_AUTH_TIMEOUT (12 * HZ) -#define IEEE80211SOFTMAC_AUTH_RETRY_LIMIT 5 -#define IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT 3 - -struct ieee80211softmac_txrates { - /* The Bit-Rate to be used for multicast frames. */ - u8 mcast_rate; - - /* The Bit-Rate to be used for multicast management frames. */ - u8 mgt_mcast_rate; - - /* The Bit-Rate to be used for any other (normal) data packet. */ - u8 default_rate; - /* The Bit-Rate to be used for default fallback - * (If the device supports fallback and hardware-retry) - */ - u8 default_fallback; - - /* This is the rate that the user asked for */ - u8 user_rate; -}; - -/* Bits for txrates_change callback. */ -#define IEEE80211SOFTMAC_TXRATECHG_DEFAULT (1 << 0) /* default_rate */ -#define IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK (1 << 1) /* default_fallback */ -#define IEEE80211SOFTMAC_TXRATECHG_MCAST (1 << 2) /* mcast_rate */ -#define IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST (1 << 3) /* mgt_mcast_rate */ - -#define IEEE80211SOFTMAC_BSSINFOCHG_RATES (1 << 0) /* supported_rates */ -#define IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE (1 << 1) /* short_preamble */ -#define IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION (1 << 2) /* use_protection */ - -struct ieee80211softmac_device { - /* 802.11 structure for data stuff */ - struct ieee80211_device *ieee; - struct net_device *dev; - - /* only valid if associated, then holds the Association ID */ - u16 association_id; - - /* the following methods are callbacks that the driver - * using this framework has to assign - */ - - /* always assign these */ - void (*set_bssid_filter)(struct net_device *dev, const u8 *bssid); - void (*set_channel)(struct net_device *dev, u8 channel); - - /* assign if you need it, informational only */ - void (*link_change)(struct net_device *dev); - - /* If the hardware can do scanning, assign _all_ three of these callbacks. - * When the scan finishes, call ieee80211softmac_scan_finished(). - */ - - /* when called, start_scan is guaranteed to not be called again - * until you call ieee80211softmac_scan_finished. - * Return 0 if scanning could start, error otherwise. - * SOFTMAC AUTHORS: don't call this, use ieee80211softmac_start_scan */ - int (*start_scan)(struct net_device *dev); - /* this should block until after ieee80211softmac_scan_finished was called - * SOFTMAC AUTHORS: don't call this, use ieee80211softmac_wait_for_scan */ - void (*wait_for_scan)(struct net_device *dev); - /* stop_scan aborts a scan, but is asynchronous. - * if you want to wait for it too, use wait_for_scan - * SOFTMAC AUTHORS: don't call this, use ieee80211softmac_stop_scan */ - void (*stop_scan)(struct net_device *dev); - - /* we'll need something about beacons here too, for AP or ad-hoc modes */ - - /* Transmission rates to be used by the driver. - * The SoftMAC figures out the best possible rates. - * The driver just needs to read them. - */ - struct ieee80211softmac_txrates txrates; - - /* If the driver needs to do stuff on TX rate changes, assign this - * callback. See IEEE80211SOFTMAC_TXRATECHG for change flags. */ - void (*txrates_change)(struct net_device *dev, - u32 changes); - - /* If the driver needs to do stuff when BSS properties change, assign - * this callback. see IEEE80211SOFTMAC_BSSINFOCHG for change flags. */ - void (*bssinfo_change)(struct net_device *dev, - u32 changes); - - /* private stuff follows */ - /* this lock protects this structure */ - spinlock_t lock; - - struct workqueue_struct *wq; - - u8 running; /* SoftMAC started? */ - u8 scanning; - - struct ieee80211softmac_scaninfo *scaninfo; - struct ieee80211softmac_assoc_info associnfo; - struct ieee80211softmac_bss_info bssinfo; - - struct list_head auth_queue; - struct list_head events; - - struct ieee80211softmac_ratesinfo ratesinfo; - int txrate_badness; - - /* WPA stuff */ - struct ieee80211softmac_wpa wpa; - - /* we need to keep a list of network structs we copied */ - struct list_head network_list; - - /* This must be the last item so that it points to the data - * allocated beyond this structure by alloc_ieee80211 */ - u8 priv[0]; -}; - -extern void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm); - -static inline void * ieee80211softmac_priv(struct net_device *dev) -{ - return ((struct ieee80211softmac_device *)ieee80211_priv(dev))->priv; -} - -extern struct net_device * alloc_ieee80211softmac(int sizeof_priv); -extern void free_ieee80211softmac(struct net_device *dev); - -/* Call this function if you detect a lost TX fragment. - * (If the device indicates failure of ACK RX, for example.) - * It is wise to call this function if you are able to detect lost packets, - * because it contributes to the TX Rates auto adjustment. - */ -extern void ieee80211softmac_fragment_lost(struct net_device *dev, - u16 wireless_sequence_number); -/* Call this function before _start to tell the softmac what rates - * the hw supports. The rates parameter is copied, so you can - * free it right after calling this function. - * Note that the rates need to be sorted. */ -extern void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates); - -/* Finds the highest rate which is: - * 1. Present in ri (optionally a basic rate) - * 2. Supported by the device - * 3. Less than or equal to the user-defined rate - */ -extern u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac, - struct ieee80211softmac_ratesinfo *ri, int basic_only); - -/* Helper function which advises you the rate at which a frame should be - * transmitted at. */ -static inline u8 ieee80211softmac_suggest_txrate(struct ieee80211softmac_device *mac, - int is_multicast, - int is_mgt) -{ - struct ieee80211softmac_txrates *txrates = &mac->txrates; - - if (!mac->associnfo.associated) - return txrates->mgt_mcast_rate; - - /* We are associated, sending unicast frame */ - if (!is_multicast) - return txrates->default_rate; - - /* We are associated, sending multicast frame */ - if (is_mgt) - return txrates->mgt_mcast_rate; - else - return txrates->mcast_rate; -} - -/* Helper function which advises you when it is safe to transmit with short - * preamble. - * You should only call this function when transmitting at CCK rates. */ -static inline int ieee80211softmac_short_preamble_ok(struct ieee80211softmac_device *mac, - int is_multicast, - int is_mgt) -{ - return (is_multicast && is_mgt) ? 0 : mac->bssinfo.short_preamble; -} - -/* Helper function which advises you whether protection (e.g. self-CTS) is - * needed. 1 = protection needed, 0 = no protection needed - * Only use this function when transmitting with OFDM modulation. */ -static inline int ieee80211softmac_protection_needed(struct ieee80211softmac_device *mac) -{ - return mac->bssinfo.use_protection; -} - -/* Start the SoftMAC. Call this after you initialized the device - * and it is ready to run. - */ -extern void ieee80211softmac_start(struct net_device *dev); -/* Stop the SoftMAC. Call this before you shutdown the device. */ -extern void ieee80211softmac_stop(struct net_device *dev); - -/* - * Event system - */ - -/* valid event types */ -#define IEEE80211SOFTMAC_EVENT_ANY -1 /*private use only*/ -#define IEEE80211SOFTMAC_EVENT_SCAN_FINISHED 0 -#define IEEE80211SOFTMAC_EVENT_ASSOCIATED 1 -#define IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED 2 -#define IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT 3 -#define IEEE80211SOFTMAC_EVENT_AUTHENTICATED 4 -#define IEEE80211SOFTMAC_EVENT_AUTH_FAILED 5 -#define IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT 6 -#define IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND 7 -#define IEEE80211SOFTMAC_EVENT_DISASSOCIATED 8 -/* keep this updated! */ -#define IEEE80211SOFTMAC_EVENT_LAST 8 -/* - * If you want to be notified of certain events, you can call - * ieee80211softmac_notify[_atomic] with - * - event set to one of the constants below - * - fun set to a function pointer of the appropriate type - * - context set to the context data you want passed - * The return value is 0, or an error. - */ -typedef void (*notify_function_ptr)(struct net_device *dev, int event_type, void *context); - -#define ieee80211softmac_notify(dev, event, fun, context) ieee80211softmac_notify_gfp(dev, event, fun, context, GFP_KERNEL); -#define ieee80211softmac_notify_atomic(dev, event, fun, context) ieee80211softmac_notify_gfp(dev, event, fun, context, GFP_ATOMIC); - -extern int ieee80211softmac_notify_gfp(struct net_device *dev, - int event, notify_function_ptr fun, void *context, gfp_t gfp_mask); - -/* To clear pending work (for ifconfig down, etc.) */ -extern void -ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm); - -#endif /* IEEE80211SOFTMAC_H_ */ diff --git a/include/net/ieee80211softmac_wx.h b/include/net/ieee80211softmac_wx.h deleted file mode 100644 index 4ee3ad57283f..000000000000 --- a/include/net/ieee80211softmac_wx.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * This file contains the prototypes for the wireless extension - * handlers that the softmac API provides. Include this file to - * use the wx handlers, you can assign these directly. - * - * Copyright (c) 2005 Johannes Berg - * Joseph Jezak - * Larry Finger - * Danny van Dyk - * Michael Buesch - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. - */ - -#ifndef _IEEE80211SOFTMAC_WX_H -#define _IEEE80211SOFTMAC_WX_H - -#include -#include - -extern int -ieee80211softmac_wx_trigger_scan(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra); - -extern int -ieee80211softmac_wx_get_scan_results(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra); - -extern int -ieee80211softmac_wx_set_essid(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra); - -extern int -ieee80211softmac_wx_get_essid(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra); - -extern int -ieee80211softmac_wx_set_rate(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra); - -extern int -ieee80211softmac_wx_get_rate(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra); - -extern int -ieee80211softmac_wx_get_wap(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra); - -extern int -ieee80211softmac_wx_set_wap(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra); - -extern int -ieee80211softmac_wx_set_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra); - -extern int -ieee80211softmac_wx_get_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra); -extern int -ieee80211softmac_wx_set_mlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra); -#endif /* _IEEE80211SOFTMAC_WX */ diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig index bd501046c9c0..94ed7d3cd9da 100644 --- a/net/ieee80211/Kconfig +++ b/net/ieee80211/Kconfig @@ -71,4 +71,3 @@ config IEEE80211_CRYPT_TKIP This can be compiled as a module and it will be called "ieee80211_crypt_tkip". -source "net/ieee80211/softmac/Kconfig" diff --git a/net/ieee80211/Makefile b/net/ieee80211/Makefile index 796a7c76ee48..f988417121da 100644 --- a/net/ieee80211/Makefile +++ b/net/ieee80211/Makefile @@ -10,4 +10,3 @@ ieee80211-objs := \ ieee80211_wx.o \ ieee80211_geo.o -obj-$(CONFIG_IEEE80211_SOFTMAC) += softmac/ diff --git a/net/ieee80211/softmac/Kconfig b/net/ieee80211/softmac/Kconfig deleted file mode 100644 index 2811651cb134..000000000000 --- a/net/ieee80211/softmac/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config IEEE80211_SOFTMAC - tristate "Software MAC add-on to the IEEE 802.11 networking stack" - depends on IEEE80211 && EXPERIMENTAL - select WIRELESS_EXT - select IEEE80211_CRYPT_WEP - ---help--- - This option enables the hardware independent software MAC addon - for the IEEE 802.11 networking stack. - -config IEEE80211_SOFTMAC_DEBUG - bool "Enable full debugging output" - depends on IEEE80211_SOFTMAC diff --git a/net/ieee80211/softmac/Makefile b/net/ieee80211/softmac/Makefile deleted file mode 100644 index bfcb391bb2c7..000000000000 --- a/net/ieee80211/softmac/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -obj-$(CONFIG_IEEE80211_SOFTMAC) += ieee80211softmac.o -ieee80211softmac-objs := \ - ieee80211softmac_io.o \ - ieee80211softmac_auth.o \ - ieee80211softmac_module.o \ - ieee80211softmac_scan.o \ - ieee80211softmac_wx.o \ - ieee80211softmac_assoc.o \ - ieee80211softmac_event.o diff --git a/net/ieee80211/softmac/ieee80211softmac_assoc.c b/net/ieee80211/softmac/ieee80211softmac_assoc.c deleted file mode 100644 index c4d122ddd72c..000000000000 --- a/net/ieee80211/softmac/ieee80211softmac_assoc.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * This file contains the softmac's association logic. - * - * Copyright (c) 2005, 2006 Johannes Berg - * Joseph Jezak - * Larry Finger - * Danny van Dyk - * Michael Buesch - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. - */ - -#include "ieee80211softmac_priv.h" - -/* - * Overview - * - * Before you can associate, you have to authenticate. - * - */ - -/* Sends out an association request to the desired AP */ -static void -ieee80211softmac_assoc(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net) -{ - unsigned long flags; - - /* Switch to correct channel for this network */ - mac->set_channel(mac->dev, net->channel); - - /* Send association request */ - ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_ASSOC_REQ, 0); - - dprintk(KERN_INFO PFX "sent association request!\n"); - - spin_lock_irqsave(&mac->lock, flags); - mac->associnfo.associated = 0; /* just to make sure */ - - /* Set a timer for timeout */ - /* FIXME: make timeout configurable */ - if (likely(mac->running)) - queue_delayed_work(mac->wq, &mac->associnfo.timeout, 5 * HZ); - spin_unlock_irqrestore(&mac->lock, flags); -} - -void -ieee80211softmac_assoc_timeout(struct work_struct *work) -{ - struct ieee80211softmac_device *mac = - container_of(work, struct ieee80211softmac_device, - associnfo.timeout.work); - struct ieee80211softmac_network *n; - - mutex_lock(&mac->associnfo.mutex); - /* we might race against ieee80211softmac_handle_assoc_response, - * so make sure only one of us does something */ - if (!mac->associnfo.associating) - goto out; - mac->associnfo.associating = 0; - mac->associnfo.bssvalid = 0; - mac->associnfo.associated = 0; - - n = ieee80211softmac_get_network_by_bssid_locked(mac, mac->associnfo.bssid); - - dprintk(KERN_INFO PFX "assoc request timed out!\n"); - ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_TIMEOUT, n); -out: - mutex_unlock(&mac->associnfo.mutex); -} - -void -ieee80211softmac_disassoc(struct ieee80211softmac_device *mac) -{ - unsigned long flags; - - spin_lock_irqsave(&mac->lock, flags); - if (mac->associnfo.associating) - cancel_delayed_work(&mac->associnfo.timeout); - - netif_carrier_off(mac->dev); - - mac->associnfo.associated = 0; - mac->associnfo.bssvalid = 0; - mac->associnfo.associating = 0; - ieee80211softmac_init_bss(mac); - ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_DISASSOCIATED, NULL); - spin_unlock_irqrestore(&mac->lock, flags); -} - -/* Sends out a disassociation request to the desired AP */ -void -ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason) -{ - struct ieee80211softmac_network *found; - - if (mac->associnfo.bssvalid && mac->associnfo.associated) { - found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid); - if (found) - ieee80211softmac_send_mgt_frame(mac, found, IEEE80211_STYPE_DISASSOC, reason); - } - - ieee80211softmac_disassoc(mac); -} - -static inline int -we_support_all_basic_rates(struct ieee80211softmac_device *mac, u8 *from, u8 from_len) -{ - int idx; - u8 rate; - - for (idx = 0; idx < (from_len); idx++) { - rate = (from)[idx]; - if (!(rate & IEEE80211_BASIC_RATE_MASK)) - continue; - rate &= ~IEEE80211_BASIC_RATE_MASK; - if (!ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate)) - return 0; - } - return 1; -} - -static int -network_matches_request(struct ieee80211softmac_device *mac, struct ieee80211_network *net) -{ - /* we cannot associate to networks whose name we don't know */ - if (ieee80211_is_empty_essid(net->ssid, net->ssid_len)) - return 0; - /* do not associate to a network whose BSSBasicRateSet we cannot support */ - if (!we_support_all_basic_rates(mac, net->rates, net->rates_len)) - return 0; - /* do we really need to check the ex rates? */ - if (!we_support_all_basic_rates(mac, net->rates_ex, net->rates_ex_len)) - return 0; - - /* assume that users know what they're doing ... - * (note we don't let them select a net we're incompatible with) */ - if (mac->associnfo.bssfixed) { - return !memcmp(mac->associnfo.bssid, net->bssid, ETH_ALEN); - } - - /* if 'ANY' network requested, take any that doesn't have privacy enabled */ - if (mac->associnfo.req_essid.len == 0 - && !(net->capability & WLAN_CAPABILITY_PRIVACY)) - return 1; - if (net->ssid_len != mac->associnfo.req_essid.len) - return 0; - if (!memcmp(net->ssid, mac->associnfo.req_essid.data, mac->associnfo.req_essid.len)) - return 1; - return 0; -} - -static void -ieee80211softmac_assoc_notify_scan(struct net_device *dev, int event_type, void *context) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - ieee80211softmac_assoc_work(&mac->associnfo.work.work); -} - -static void -ieee80211softmac_assoc_notify_auth(struct net_device *dev, int event_type, void *context) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - - switch (event_type) { - case IEEE80211SOFTMAC_EVENT_AUTHENTICATED: - ieee80211softmac_assoc_work(&mac->associnfo.work.work); - break; - case IEEE80211SOFTMAC_EVENT_AUTH_FAILED: - case IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT: - ieee80211softmac_disassoc(mac); - break; - } -} - -/* This function is called to handle userspace requests (asynchronously) */ -void -ieee80211softmac_assoc_work(struct work_struct *work) -{ - struct ieee80211softmac_device *mac = - container_of(work, struct ieee80211softmac_device, - associnfo.work.work); - struct ieee80211softmac_network *found = NULL; - struct ieee80211_network *net = NULL, *best = NULL; - int bssvalid; - unsigned long flags; - - mutex_lock(&mac->associnfo.mutex); - - if (!mac->associnfo.associating) - goto out; - - /* ieee80211_disassoc might clear this */ - bssvalid = mac->associnfo.bssvalid; - - /* meh */ - if (mac->associnfo.associated) - ieee80211softmac_send_disassoc_req(mac, WLAN_REASON_DISASSOC_STA_HAS_LEFT); - - /* try to find the requested network in our list, if we found one already */ - if (bssvalid || mac->associnfo.bssfixed) - found = ieee80211softmac_get_network_by_bssid(mac, mac->associnfo.bssid); - - /* Search the ieee80211 networks for this network if we didn't find it by bssid, - * but only if we've scanned at least once (to get a better list of networks to - * select from). If we have not scanned before, the !found logic below will be - * invoked and will scan. */ - if (!found && (mac->associnfo.scan_retry < IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT)) - { - s8 rssi = -128; /* if I don't initialise, gcc emits an invalid warning - because it cannot follow the best pointer logic. */ - spin_lock_irqsave(&mac->ieee->lock, flags); - list_for_each_entry(net, &mac->ieee->network_list, list) { - /* we're supposed to find the network with - * the best signal here, as we're asked to join - * any network with a specific ESSID, and many - * different ones could have that. - * - * I'll for now just go with the reported rssi. - * - * We also should take into account the rateset - * here to find the best BSSID to try. - */ - if (network_matches_request(mac, net)) { - if (!best) { - best = net; - rssi = best->stats.rssi; - continue; - } - /* we already had a matching network, so - * compare their properties to get the - * better of the two ... (see above) - */ - if (rssi < net->stats.rssi) { - best = net; - rssi = best->stats.rssi; - } - } - } - /* if we unlock here, we might get interrupted and the `best' - * pointer could go stale */ - if (best) { - found = ieee80211softmac_create_network(mac, best); - /* if found is still NULL, then we got -ENOMEM somewhere */ - if (found) - ieee80211softmac_add_network(mac, found); - } - spin_unlock_irqrestore(&mac->ieee->lock, flags); - } - - if (!found) { - if (mac->associnfo.scan_retry > 0) { - mac->associnfo.scan_retry--; - - /* We know of no such network. Let's scan. - * NB: this also happens if we had no memory to copy the network info... - * Maybe we can hope to have more memory after scanning finishes ;) - */ - dprintk(KERN_INFO PFX "Associate: Scanning for networks first.\n"); - ieee80211softmac_notify(mac->dev, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, ieee80211softmac_assoc_notify_scan, NULL); - if (ieee80211softmac_start_scan(mac)) { - dprintk(KERN_INFO PFX "Associate: failed to initiate scan. Is device up?\n"); - } - goto out; - } else { - mac->associnfo.associating = 0; - mac->associnfo.associated = 0; - - dprintk(KERN_INFO PFX "Unable to find matching network after scan!\n"); - /* reset the retry counter for the next user request since we - * break out and don't reschedule ourselves after this point. */ - mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT; - ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_NET_NOT_FOUND, NULL); - goto out; - } - } - - /* reset the retry counter for the next user request since we - * now found a net and will try to associate to it, but not - * schedule this function again. */ - mac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT; - mac->associnfo.bssvalid = 1; - memcpy(mac->associnfo.bssid, found->bssid, ETH_ALEN); - /* copy the ESSID for displaying it */ - mac->associnfo.associate_essid.len = found->essid.len; - memcpy(mac->associnfo.associate_essid.data, found->essid.data, IW_ESSID_MAX_SIZE + 1); - - /* we found a network! authenticate (if necessary) and associate to it. */ - if (found->authenticating) { - dprintk(KERN_INFO PFX "Already requested authentication, waiting...\n"); - if(!mac->associnfo.assoc_wait) { - mac->associnfo.assoc_wait = 1; - ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL); - } - goto out; - } - if (!found->authenticated && !found->authenticating) { - /* This relies on the fact that _auth_req only queues the work, - * otherwise adding the notification would be racy. */ - if (!ieee80211softmac_auth_req(mac, found)) { - if(!mac->associnfo.assoc_wait) { - dprintk(KERN_INFO PFX "Cannot associate without being authenticated, requested authentication\n"); - mac->associnfo.assoc_wait = 1; - ieee80211softmac_notify_internal(mac, IEEE80211SOFTMAC_EVENT_ANY, found, ieee80211softmac_assoc_notify_auth, NULL, GFP_KERNEL); - } - } else { - printkl(KERN_WARNING PFX "Not authenticated, but requesting authentication failed. Giving up to associate\n"); - mac->associnfo.assoc_wait = 0; - ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, found); - } - goto out; - } - /* finally! now we can start associating */ - mac->associnfo.assoc_wait = 0; - ieee80211softmac_assoc(mac, found); - -out: - mutex_unlock(&mac->associnfo.mutex); -} - -/* call this to do whatever is necessary when we're associated */ -static void -ieee80211softmac_associated(struct ieee80211softmac_device *mac, - struct ieee80211_assoc_response * resp, - struct ieee80211softmac_network *net) -{ - u16 cap = le16_to_cpu(resp->capability); - u8 erp_value = net->erp_value; - - mac->associnfo.associating = 0; - mac->bssinfo.supported_rates = net->supported_rates; - ieee80211softmac_recalc_txrates(mac); - - mac->associnfo.associated = 1; - - mac->associnfo.short_preamble_available = - (cap & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0; - ieee80211softmac_process_erp(mac, erp_value); - - if (mac->set_bssid_filter) - mac->set_bssid_filter(mac->dev, net->bssid); - memcpy(mac->ieee->bssid, net->bssid, ETH_ALEN); - netif_carrier_on(mac->dev); - - mac->association_id = le16_to_cpup(&resp->aid); -} - -/* received frame handling functions */ -int -ieee80211softmac_handle_assoc_response(struct net_device * dev, - struct ieee80211_assoc_response * resp, - struct ieee80211_network * _ieee80211_network) -{ - /* NOTE: the network parameter has to be mostly ignored by - * this code because it is the ieee80211's pointer - * to the struct, not ours (we made a copy) - */ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - u16 status = le16_to_cpup(&resp->status); - struct ieee80211softmac_network *network = NULL; - unsigned long flags; - DECLARE_MAC_BUF(mac2); - - if (unlikely(!mac->running)) - return -ENODEV; - - spin_lock_irqsave(&mac->lock, flags); - - if (!mac->associnfo.associating) { - /* we race against the timeout function, so make sure - * only one of us can do work */ - spin_unlock_irqrestore(&mac->lock, flags); - return 0; - } - network = ieee80211softmac_get_network_by_bssid_locked(mac, resp->header.addr3); - - /* someone sending us things without us knowing him? Ignore. */ - if (!network) { - dprintk(KERN_INFO PFX "Received unrequested assocation response from %s\n", - print_mac(mac2, resp->header.addr3)); - spin_unlock_irqrestore(&mac->lock, flags); - return 0; - } - - /* now that we know it was for us, we can cancel the timeout */ - cancel_delayed_work(&mac->associnfo.timeout); - - /* if the association response included an ERP IE, update our saved - * copy */ - if (_ieee80211_network->flags & NETWORK_HAS_ERP_VALUE) - network->erp_value = _ieee80211_network->erp_value; - - switch (status) { - case 0: - dprintk(KERN_INFO PFX "associated!\n"); - ieee80211softmac_associated(mac, resp, network); - ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATED, network); - break; - case WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH: - if (!network->auth_desynced_once) { - /* there seem to be a few rare cases where our view of - * the world is obscured, or buggy APs that don't DEAUTH - * us properly. So we handle that, but allow it only once. - */ - printkl(KERN_INFO PFX "We were not authenticated during association, retrying...\n"); - network->authenticated = 0; - /* we don't want to do this more than once ... */ - network->auth_desynced_once = 1; - queue_delayed_work(mac->wq, &mac->associnfo.work, 0); - break; - } - default: - dprintk(KERN_INFO PFX "associating failed (reason: 0x%x)!\n", status); - mac->associnfo.associating = 0; - mac->associnfo.bssvalid = 0; - mac->associnfo.associated = 0; - ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_ASSOCIATE_FAILED, network); - } - - spin_unlock_irqrestore(&mac->lock, flags); - return 0; -} - -void -ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac) -{ - unsigned long flags; - - spin_lock_irqsave(&mac->lock, flags); - mac->associnfo.associating = 1; - queue_delayed_work(mac->wq, &mac->associnfo.work, 0); - spin_unlock_irqrestore(&mac->lock, flags); -} - -int -ieee80211softmac_handle_disassoc(struct net_device * dev, - struct ieee80211_disassoc *disassoc) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - - if (unlikely(!mac->running)) - return -ENODEV; - - if (memcmp(disassoc->header.addr2, mac->associnfo.bssid, ETH_ALEN)) - return 0; - - if (memcmp(disassoc->header.addr1, mac->dev->dev_addr, ETH_ALEN)) - return 0; - - dprintk(KERN_INFO PFX "got disassoc frame\n"); - ieee80211softmac_disassoc(mac); - - ieee80211softmac_try_reassoc(mac); - - return 0; -} - -int -ieee80211softmac_handle_reassoc_req(struct net_device * dev, - struct ieee80211_reassoc_request * resp) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - struct ieee80211softmac_network *network; - - if (unlikely(!mac->running)) - return -ENODEV; - - network = ieee80211softmac_get_network_by_bssid(mac, resp->header.addr3); - if (!network) { - dprintkl(KERN_INFO PFX "reassoc request from unknown network\n"); - return 0; - } - queue_delayed_work(mac->wq, &mac->associnfo.work, 0); - - return 0; -} diff --git a/net/ieee80211/softmac/ieee80211softmac_auth.c b/net/ieee80211/softmac/ieee80211softmac_auth.c deleted file mode 100644 index 1a96c2572578..000000000000 --- a/net/ieee80211/softmac/ieee80211softmac_auth.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * This file contains the softmac's authentication logic. - * - * Copyright (c) 2005, 2006 Johannes Berg - * Joseph Jezak - * Larry Finger - * Danny van Dyk - * Michael Buesch - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. - */ - -#include "ieee80211softmac_priv.h" - -static void ieee80211softmac_auth_queue(struct work_struct *work); - -/* Queues an auth request to the desired AP */ -int -ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, - struct ieee80211softmac_network *net) -{ - struct ieee80211softmac_auth_queue_item *auth; - unsigned long flags; - DECLARE_MAC_BUF(mac2); - - if (net->authenticating || net->authenticated) - return 0; - net->authenticating = 1; - - /* Add the network if it's not already added */ - ieee80211softmac_add_network(mac, net); - - dprintk(KERN_NOTICE PFX "Queueing Authentication Request to %s\n", print_mac(mac2, net->bssid)); - /* Queue the auth request */ - auth = (struct ieee80211softmac_auth_queue_item *) - kmalloc(sizeof(struct ieee80211softmac_auth_queue_item), GFP_KERNEL); - if(auth == NULL) - return -ENOMEM; - - auth->net = net; - auth->mac = mac; - auth->retry = IEEE80211SOFTMAC_AUTH_RETRY_LIMIT; - auth->state = IEEE80211SOFTMAC_AUTH_OPEN_REQUEST; - INIT_DELAYED_WORK(&auth->work, ieee80211softmac_auth_queue); - - /* Lock (for list) */ - spin_lock_irqsave(&mac->lock, flags); - - /* add to list */ - list_add_tail(&auth->list, &mac->auth_queue); - queue_delayed_work(mac->wq, &auth->work, 0); - spin_unlock_irqrestore(&mac->lock, flags); - - return 0; -} - - -/* Sends an auth request to the desired AP and handles timeouts */ -static void -ieee80211softmac_auth_queue(struct work_struct *work) -{ - struct ieee80211softmac_device *mac; - struct ieee80211softmac_auth_queue_item *auth; - struct ieee80211softmac_network *net; - unsigned long flags; - DECLARE_MAC_BUF(mac2); - - auth = container_of(work, struct ieee80211softmac_auth_queue_item, - work.work); - net = auth->net; - mac = auth->mac; - - if(auth->retry > 0) { - /* Switch to correct channel for this network */ - mac->set_channel(mac->dev, net->channel); - - /* Lock and set flags */ - spin_lock_irqsave(&mac->lock, flags); - if (unlikely(!mac->running)) { - /* Prevent reschedule on workqueue flush */ - spin_unlock_irqrestore(&mac->lock, flags); - return; - } - net->authenticated = 0; - /* add a timeout call so we eventually give up waiting for an auth reply */ - queue_delayed_work(mac->wq, &auth->work, IEEE80211SOFTMAC_AUTH_TIMEOUT); - auth->retry--; - spin_unlock_irqrestore(&mac->lock, flags); - if (ieee80211softmac_send_mgt_frame(mac, auth->net, IEEE80211_STYPE_AUTH, auth->state)) - dprintk(KERN_NOTICE PFX "Sending Authentication Request to %s failed (this shouldn't happen, wait for the timeout).\n", - print_mac(mac2, net->bssid)); - else - dprintk(KERN_NOTICE PFX "Sent Authentication Request to %s.\n", print_mac(mac2, net->bssid)); - return; - } - - printkl(KERN_WARNING PFX "Authentication timed out with %s\n", print_mac(mac2, net->bssid)); - /* Remove this item from the queue */ - spin_lock_irqsave(&mac->lock, flags); - net->authenticating = 0; - ieee80211softmac_call_events_locked(mac, IEEE80211SOFTMAC_EVENT_AUTH_TIMEOUT, net); - cancel_delayed_work(&auth->work); /* just to make sure... */ - list_del(&auth->list); - spin_unlock_irqrestore(&mac->lock, flags); - /* Free it */ - kfree(auth); -} - -/* Sends a response to an auth challenge (for shared key auth). */ -static void -ieee80211softmac_auth_challenge_response(struct work_struct *work) -{ - struct ieee80211softmac_auth_queue_item *aq = - container_of(work, struct ieee80211softmac_auth_queue_item, - work.work); - - /* Send our response */ - ieee80211softmac_send_mgt_frame(aq->mac, aq->net, IEEE80211_STYPE_AUTH, aq->state); -} - -/* Handle the auth response from the AP - * This should be registered with ieee80211 as handle_auth - */ -int -ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth) -{ - - struct list_head *list_ptr; - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - struct ieee80211softmac_auth_queue_item *aq = NULL; - struct ieee80211softmac_network *net = NULL; - unsigned long flags; - u8 * data; - DECLARE_MAC_BUF(mac2); - - if (unlikely(!mac->running)) - return -ENODEV; - - /* Find correct auth queue item */ - spin_lock_irqsave(&mac->lock, flags); - list_for_each(list_ptr, &mac->auth_queue) { - aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list); - net = aq->net; - if (!memcmp(net->bssid, auth->header.addr2, ETH_ALEN)) - break; - else - aq = NULL; - } - spin_unlock_irqrestore(&mac->lock, flags); - - /* Make sure that we've got an auth queue item for this request */ - if(aq == NULL) - { - dprintkl(KERN_DEBUG PFX "Authentication response received from %s but no queue item exists.\n", print_mac(mac2, auth->header.addr2)); - /* Error #? */ - return -1; - } - - /* Check for out of order authentication */ - if(!net->authenticating) - { - dprintkl(KERN_DEBUG PFX "Authentication response received from %s but did not request authentication.\n",print_mac(mac2, auth->header.addr2)); - return -1; - } - - /* Parse the auth packet */ - switch(le16_to_cpu(auth->algorithm)) { - case WLAN_AUTH_OPEN: - /* Check the status code of the response */ - - switch(le16_to_cpu(auth->status)) { - case WLAN_STATUS_SUCCESS: - /* Update the status to Authenticated */ - spin_lock_irqsave(&mac->lock, flags); - net->authenticating = 0; - net->authenticated = 1; - spin_unlock_irqrestore(&mac->lock, flags); - - /* Send event */ - printkl(KERN_NOTICE PFX "Open Authentication completed with %s\n", print_mac(mac2, net->bssid)); - ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net); - break; - default: - /* Lock and reset flags */ - spin_lock_irqsave(&mac->lock, flags); - net->authenticated = 0; - net->authenticating = 0; - spin_unlock_irqrestore(&mac->lock, flags); - - printkl(KERN_NOTICE PFX "Open Authentication with %s failed, error code: %i\n", - print_mac(mac2, net->bssid), le16_to_cpup(&auth->status)); - /* Count the error? */ - break; - } - goto free_aq; - break; - case WLAN_AUTH_SHARED_KEY: - /* Figure out where we are in the process */ - switch(le16_to_cpu(auth->transaction)) { - case IEEE80211SOFTMAC_AUTH_SHARED_CHALLENGE: - /* Check to make sure we have a challenge IE */ - data = (u8 *)auth->info_element; - if (*data++ != MFIE_TYPE_CHALLENGE) { - printkl(KERN_NOTICE PFX "Shared Key Authentication failed due to a missing challenge.\n"); - break; - } - /* Save the challenge */ - spin_lock_irqsave(&mac->lock, flags); - net->challenge_len = *data++; - if (net->challenge_len > WLAN_AUTH_CHALLENGE_LEN) - net->challenge_len = WLAN_AUTH_CHALLENGE_LEN; - kfree(net->challenge); - net->challenge = kmemdup(data, net->challenge_len, - GFP_ATOMIC); - if (net->challenge == NULL) { - printkl(KERN_NOTICE PFX "Shared Key " - "Authentication failed due to " - "memory shortage.\n"); - spin_unlock_irqrestore(&mac->lock, flags); - break; - } - aq->state = IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE; - - /* We reuse the work struct from the auth request here. - * It is safe to do so as each one is per-request, and - * at this point (dealing with authentication response) - * we have obviously already sent the initial auth - * request. */ - cancel_delayed_work(&aq->work); - INIT_DELAYED_WORK(&aq->work, &ieee80211softmac_auth_challenge_response); - queue_delayed_work(mac->wq, &aq->work, 0); - spin_unlock_irqrestore(&mac->lock, flags); - return 0; - case IEEE80211SOFTMAC_AUTH_SHARED_PASS: - kfree(net->challenge); - net->challenge = NULL; - net->challenge_len = 0; - /* Check the status code of the response */ - switch(auth->status) { - case WLAN_STATUS_SUCCESS: - /* Update the status to Authenticated */ - spin_lock_irqsave(&mac->lock, flags); - net->authenticating = 0; - net->authenticated = 1; - spin_unlock_irqrestore(&mac->lock, flags); - printkl(KERN_NOTICE PFX "Shared Key Authentication completed with %s\n", - print_mac(mac2, net->bssid)); - ieee80211softmac_call_events(mac, IEEE80211SOFTMAC_EVENT_AUTHENTICATED, net); - break; - default: - printkl(KERN_NOTICE PFX "Shared Key Authentication with %s failed, error code: %i\n", - print_mac(mac2, net->bssid), le16_to_cpup(&auth->status)); - /* Lock and reset flags */ - spin_lock_irqsave(&mac->lock, flags); - net->authenticating = 0; - net->authenticated = 0; - spin_unlock_irqrestore(&mac->lock, flags); - /* Count the error? */ - break; - } - goto free_aq; - break; - default: - printkl(KERN_WARNING PFX "Unhandled Authentication Step: %i\n", auth->transaction); - break; - } - goto free_aq; - break; - default: - /* ERROR */ - goto free_aq; - break; - } - return 0; -free_aq: - /* Cancel the timeout */ - spin_lock_irqsave(&mac->lock, flags); - cancel_delayed_work(&aq->work); - /* Remove this item from the queue */ - list_del(&aq->list); - spin_unlock_irqrestore(&mac->lock, flags); - - /* Free it */ - kfree(aq); - return 0; -} - -/* - * Handle deauthorization - */ -static void -ieee80211softmac_deauth_from_net(struct ieee80211softmac_device *mac, - struct ieee80211softmac_network *net) -{ - struct ieee80211softmac_auth_queue_item *aq = NULL; - struct list_head *list_ptr; - unsigned long flags; - - /* deauthentication implies disassociation */ - ieee80211softmac_disassoc(mac); - - /* Lock and reset status flags */ - spin_lock_irqsave(&mac->lock, flags); - net->authenticating = 0; - net->authenticated = 0; - - /* Find correct auth queue item, if it exists */ - list_for_each(list_ptr, &mac->auth_queue) { - aq = list_entry(list_ptr, struct ieee80211softmac_auth_queue_item, list); - if (!memcmp(net->bssid, aq->net->bssid, ETH_ALEN)) - break; - else - aq = NULL; - } - - /* Cancel pending work */ - if(aq != NULL) - /* Not entirely safe? What about running work? */ - cancel_delayed_work(&aq->work); - - /* Free our network ref */ - ieee80211softmac_del_network_locked(mac, net); - if(net->challenge != NULL) - kfree(net->challenge); - kfree(net); - - /* can't transmit data right now... */ - netif_carrier_off(mac->dev); - spin_unlock_irqrestore(&mac->lock, flags); - - ieee80211softmac_try_reassoc(mac); -} - -/* - * Sends a deauth request to the desired AP - */ -int -ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, - struct ieee80211softmac_network *net, int reason) -{ - int ret; - - /* Make sure the network is authenticated */ - if (!net->authenticated) - { - dprintkl(KERN_DEBUG PFX "Can't send deauthentication packet, network is not authenticated.\n"); - /* Error okay? */ - return -EPERM; - } - - /* Send the de-auth packet */ - if((ret = ieee80211softmac_send_mgt_frame(mac, net, IEEE80211_STYPE_DEAUTH, reason))) - return ret; - - ieee80211softmac_deauth_from_net(mac, net); - return 0; -} - -/* - * This should be registered with ieee80211 as handle_deauth - */ -int -ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth) -{ - - struct ieee80211softmac_network *net = NULL; - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - DECLARE_MAC_BUF(mac2); - - if (unlikely(!mac->running)) - return -ENODEV; - - if (!deauth) { - dprintk("deauth without deauth packet. eek!\n"); - return 0; - } - - net = ieee80211softmac_get_network_by_bssid(mac, deauth->header.addr2); - - if (net == NULL) { - dprintkl(KERN_DEBUG PFX "Received deauthentication packet from %s, but that network is unknown.\n", - print_mac(mac2, deauth->header.addr2)); - return 0; - } - - /* Make sure the network is authenticated */ - if(!net->authenticated) - { - dprintkl(KERN_DEBUG PFX "Can't perform deauthentication, network is not authenticated.\n"); - /* Error okay? */ - return -EPERM; - } - - ieee80211softmac_deauth_from_net(mac, net); - - /* let's try to re-associate */ - queue_delayed_work(mac->wq, &mac->associnfo.work, 0); - return 0; -} diff --git a/net/ieee80211/softmac/ieee80211softmac_event.c b/net/ieee80211/softmac/ieee80211softmac_event.c deleted file mode 100644 index 8cef05b60f16..000000000000 --- a/net/ieee80211/softmac/ieee80211softmac_event.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Event system - * Also see comments in public header file and longer explanation below. - * - * Copyright (c) 2005, 2006 Johannes Berg - * Joseph Jezak - * Larry Finger - * Danny van Dyk - * Michael Buesch - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. - */ - -#include "ieee80211softmac_priv.h" - -/* - * Each event has associated to it - * - an event type (see constants in public header) - * - an event context (see below) - * - the function to be called - * - a context (extra parameter to call the function with) - * - and the softmac struct - * - * The event context is private and can only be used from - * within this module. Its meaning varies with the event - * type: - * SCAN_FINISHED, - * DISASSOCIATED: NULL - * ASSOCIATED, - * ASSOCIATE_FAILED, - * ASSOCIATE_TIMEOUT, - * AUTHENTICATED, - * AUTH_FAILED, - * AUTH_TIMEOUT: a pointer to the network struct - * ... - * Code within this module can use the event context to be only - * called when the event is true for that specific context - * as per above table. - * If the event context is NULL, then the notification is always called, - * regardless of the event context. The event context is not passed to - * the callback, it is assumed that the context suffices. - * - * You can also use the event context only by setting the event type - * to -1 (private use only), in which case you'll be notified - * whenever the event context matches. - */ - -static char *event_descriptions[IEEE80211SOFTMAC_EVENT_LAST+1] = { - NULL, /* scan finished */ - NULL, /* associated */ - "associating failed", - "associating timed out", - "authenticated", - "authenticating failed", - "authenticating timed out", - "associating failed because no suitable network was found", - NULL, /* disassociated */ -}; - - -static void -ieee80211softmac_notify_callback(struct work_struct *work) -{ - struct ieee80211softmac_event *pevent = - container_of(work, struct ieee80211softmac_event, work.work); - struct ieee80211softmac_event event = *pevent; - kfree(pevent); - - event.fun(event.mac->dev, event.event_type, event.context); -} - -int -ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac, - int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask) -{ - struct ieee80211softmac_event *eventptr; - unsigned long flags; - - if (event < -1 || event > IEEE80211SOFTMAC_EVENT_LAST) - return -ENOSYS; - - if (!fun) - return -EINVAL; - - eventptr = kmalloc(sizeof(struct ieee80211softmac_event), gfp_mask); - if (!eventptr) - return -ENOMEM; - - eventptr->event_type = event; - INIT_DELAYED_WORK(&eventptr->work, ieee80211softmac_notify_callback); - eventptr->fun = fun; - eventptr->context = context; - eventptr->mac = mac; - eventptr->event_context = event_context; - - spin_lock_irqsave(&mac->lock, flags); - list_add(&eventptr->list, &mac->events); - spin_unlock_irqrestore(&mac->lock, flags); - - return 0; -} - -int -ieee80211softmac_notify_gfp(struct net_device *dev, - int event, notify_function_ptr fun, void *context, gfp_t gfp_mask) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - - if (event < 0 || event > IEEE80211SOFTMAC_EVENT_LAST) - return -ENOSYS; - - return ieee80211softmac_notify_internal(mac, event, NULL, fun, context, gfp_mask); -} -EXPORT_SYMBOL_GPL(ieee80211softmac_notify_gfp); - -/* private -- calling all callbacks that were specified */ -void -ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_ctx) -{ - struct ieee80211softmac_event *eventptr, *tmp; - struct ieee80211softmac_network *network; - - if (event >= 0) { - union iwreq_data wrqu; - int we_event; - char *msg = NULL; - - memset(&wrqu, '\0', sizeof (union iwreq_data)); - - switch(event) { - case IEEE80211SOFTMAC_EVENT_ASSOCIATED: - network = (struct ieee80211softmac_network *)event_ctx; - memcpy(wrqu.ap_addr.sa_data, &network->bssid[0], ETH_ALEN); - /* fall through */ - case IEEE80211SOFTMAC_EVENT_DISASSOCIATED: - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - we_event = SIOCGIWAP; - break; - case IEEE80211SOFTMAC_EVENT_SCAN_FINISHED: - we_event = SIOCGIWSCAN; - break; - default: - msg = event_descriptions[event]; - if (!msg) - msg = "SOFTMAC EVENT BUG"; - wrqu.data.length = strlen(msg); - we_event = IWEVCUSTOM; - break; - } - wireless_send_event(mac->dev, we_event, &wrqu, msg); - } - - if (!list_empty(&mac->events)) - list_for_each_entry_safe(eventptr, tmp, &mac->events, list) { - if ((eventptr->event_type == event || eventptr->event_type == -1) - && (eventptr->event_context == NULL || eventptr->event_context == event_ctx)) { - list_del(&eventptr->list); - /* User may have subscribed to ANY event, so - * we tell them which event triggered it. */ - eventptr->event_type = event; - queue_delayed_work(mac->wq, &eventptr->work, 0); - } - } -} - -void -ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_ctx) -{ - unsigned long flags; - - spin_lock_irqsave(&mac->lock, flags); - ieee80211softmac_call_events_locked(mac, event, event_ctx); - - spin_unlock_irqrestore(&mac->lock, flags); -} diff --git a/net/ieee80211/softmac/ieee80211softmac_io.c b/net/ieee80211/softmac/ieee80211softmac_io.c deleted file mode 100644 index 73b4b13fbd8f..000000000000 --- a/net/ieee80211/softmac/ieee80211softmac_io.c +++ /dev/null @@ -1,488 +0,0 @@ -/* - * Some parts based on code from net80211 - * Copyright (c) 2001 Atsushi Onoe - * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "ieee80211softmac_priv.h" - -/* Helper functions for inserting data into the frames */ - -/* - * Adds an ESSID element to the frame - * - */ -static u8 * -ieee80211softmac_add_essid(u8 *dst, struct ieee80211softmac_essid *essid) -{ - if (essid) { - *dst++ = MFIE_TYPE_SSID; - *dst++ = essid->len; - memcpy(dst, essid->data, essid->len); - return dst+essid->len; - } else { - *dst++ = MFIE_TYPE_SSID; - *dst++ = 0; - return dst; - } -} - -/* Adds Supported Rates and if required Extended Rates Information Element - * to the frame, ASSUMES WE HAVE A SORTED LIST OF RATES */ -static u8 * -ieee80211softmac_frame_add_rates(u8 *dst, const struct ieee80211softmac_ratesinfo *r) -{ - int cck_len, ofdm_len; - *dst++ = MFIE_TYPE_RATES; - - for(cck_len=0; ieee80211_is_cck_rate(r->rates[cck_len]) && (cck_len < r->count);cck_len++); - - if(cck_len > IEEE80211SOFTMAC_MAX_RATES_LEN) - cck_len = IEEE80211SOFTMAC_MAX_RATES_LEN; - *dst++ = cck_len; - memcpy(dst, r->rates, cck_len); - dst += cck_len; - - if(cck_len < r->count){ - for (ofdm_len=0; ieee80211_is_ofdm_rate(r->rates[ofdm_len + cck_len]) && (ofdm_len + cck_len < r->count); ofdm_len++); - if (ofdm_len > 0) { - if (ofdm_len > IEEE80211SOFTMAC_MAX_EX_RATES_LEN) - ofdm_len = IEEE80211SOFTMAC_MAX_EX_RATES_LEN; - *dst++ = MFIE_TYPE_RATES_EX; - *dst++ = ofdm_len; - memcpy(dst, r->rates + cck_len, ofdm_len); - dst += ofdm_len; - } - } - return dst; -} - -/* Allocate a management frame */ -static u8 * -ieee80211softmac_alloc_mgt(u32 size) -{ - u8 * data; - - /* Add the header and FCS to the size */ - size = size + IEEE80211_3ADDR_LEN; - if(size > IEEE80211_DATA_LEN) - return NULL; - /* Allocate the frame */ - data = kzalloc(size, GFP_ATOMIC); - return data; -} - -/* - * Add a 2 Address Header - */ -static void -ieee80211softmac_hdr_2addr(struct ieee80211softmac_device *mac, - struct ieee80211_hdr_2addr *header, u32 type, u8 *dest) -{ - /* Fill in the frame control flags */ - header->frame_ctl = cpu_to_le16(type); - /* Control packets always have WEP turned off */ - if(type > IEEE80211_STYPE_CFENDACK && type < IEEE80211_STYPE_PSPOLL) - header->frame_ctl |= mac->ieee->sec.level ? cpu_to_le16(IEEE80211_FCTL_PROTECTED) : 0; - - /* Fill in the duration */ - header->duration_id = 0; - /* FIXME: How do I find this? - * calculate. But most drivers just fill in 0 (except if it's a station id of course) */ - - /* Fill in the Destination Address */ - if(dest == NULL) - memset(header->addr1, 0xFF, ETH_ALEN); - else - memcpy(header->addr1, dest, ETH_ALEN); - /* Fill in the Source Address */ - memcpy(header->addr2, mac->ieee->dev->dev_addr, ETH_ALEN); - -} - - -/* Add a 3 Address Header */ -static void -ieee80211softmac_hdr_3addr(struct ieee80211softmac_device *mac, - struct ieee80211_hdr_3addr *header, u32 type, u8 *dest, u8 *bssid) -{ - /* This is common with 2addr, so use that instead */ - ieee80211softmac_hdr_2addr(mac, (struct ieee80211_hdr_2addr *)header, type, dest); - - /* Fill in the BSS ID */ - if(bssid == NULL) - memset(header->addr3, 0xFF, ETH_ALEN); - else - memcpy(header->addr3, bssid, ETH_ALEN); - - /* Fill in the sequence # */ - /* FIXME: I need to add this to the softmac struct - * shouldn't the sequence number be in ieee80211? */ -} - -static __le16 -ieee80211softmac_capabilities(struct ieee80211softmac_device *mac, - struct ieee80211softmac_network *net) -{ - __le16 capability = 0; - - /* ESS and IBSS bits are set according to the current mode */ - switch (mac->ieee->iw_mode) { - case IW_MODE_INFRA: - capability = cpu_to_le16(WLAN_CAPABILITY_ESS); - break; - case IW_MODE_ADHOC: - capability = cpu_to_le16(WLAN_CAPABILITY_IBSS); - break; - case IW_MODE_AUTO: - capability = cpu_to_le16(net->capabilities & - (WLAN_CAPABILITY_ESS|WLAN_CAPABILITY_IBSS)); - break; - default: - /* bleh. we don't ever go to these modes */ - printk(KERN_ERR PFX "invalid iw_mode!\n"); - break; - } - - /* CF Pollable / CF Poll Request */ - /* Needs to be implemented, for now, the 0's == not supported */ - - /* Privacy Bit */ - capability |= mac->ieee->sec.level ? - cpu_to_le16(WLAN_CAPABILITY_PRIVACY) : 0; - - /* Short Preamble */ - /* Always supported: we probably won't ever be powering devices which - * dont support this... */ - capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); - - /* PBCC */ - /* Not widely used */ - - /* Channel Agility */ - /* Not widely used */ - - /* Short Slot */ - /* Will be implemented later */ - - /* DSSS-OFDM */ - /* Not widely used */ - - return capability; -} - -/***************************************************************************** - * Create Management packets - *****************************************************************************/ - -/* Creates an association request packet */ -static u32 -ieee80211softmac_assoc_req(struct ieee80211_assoc_request **pkt, - struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net) -{ - u8 *data; - (*pkt) = (struct ieee80211_assoc_request *)ieee80211softmac_alloc_mgt( - 2 + /* Capability Info */ - 2 + /* Listen Interval */ - /* SSID IE */ - 1 + 1 + IW_ESSID_MAX_SIZE + - /* Rates IE */ - 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN + - /* Extended Rates IE */ - 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN + - /* WPA IE if present */ - mac->wpa.IElen - /* Other IE's? Optional? - * Yeah, probably need an extra IE parameter -- lots of vendors like to - * fill in their own IEs */ - ); - if (unlikely((*pkt) == NULL)) - return 0; - ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_ASSOC_REQ, net->bssid, net->bssid); - - /* Fill in the capabilities */ - (*pkt)->capability = ieee80211softmac_capabilities(mac, net); - - /* Fill in Listen Interval (?) */ - (*pkt)->listen_interval = cpu_to_le16(10); - - data = (u8 *)(*pkt)->info_element; - /* Add SSID */ - data = ieee80211softmac_add_essid(data, &net->essid); - /* Add Rates */ - data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo); - /* Add WPA IE */ - if (mac->wpa.IElen && mac->wpa.IE) { - memcpy(data, mac->wpa.IE, mac->wpa.IElen); - data += mac->wpa.IElen; - } - /* Return the number of used bytes */ - return (data - (u8*)(*pkt)); -} - -/* Create a reassociation request packet */ -static u32 -ieee80211softmac_reassoc_req(struct ieee80211_reassoc_request **pkt, - struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net) -{ - u8 *data; - (*pkt) = (struct ieee80211_reassoc_request *)ieee80211softmac_alloc_mgt( - 2 + /* Capability Info */ - 2 + /* Listen Interval */ - ETH_ALEN + /* AP MAC */ - /* SSID IE */ - 1 + 1 + IW_ESSID_MAX_SIZE + - /* Rates IE */ - 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN + - /* Extended Rates IE */ - 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN - /* Other IE's? */ - ); - if (unlikely((*pkt) == NULL)) - return 0; - ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_REASSOC_REQ, net->bssid, net->bssid); - - /* Fill in the capabilities */ - (*pkt)->capability = ieee80211softmac_capabilities(mac, net); - - /* Fill in Listen Interval (?) */ - (*pkt)->listen_interval = cpu_to_le16(10); - /* Fill in the current AP MAC */ - memcpy((*pkt)->current_ap, mac->ieee->bssid, ETH_ALEN); - - data = (u8 *)(*pkt)->info_element; - /* Add SSID */ - data = ieee80211softmac_add_essid(data, &net->essid); - /* Add Rates */ - data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo); - /* Return packet size */ - return (data - (u8 *)(*pkt)); -} - -/* Create an authentication packet */ -static u32 -ieee80211softmac_auth(struct ieee80211_auth **pkt, - struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, - u16 transaction, u16 status, int *encrypt_mpdu) -{ - u8 *data; - int auth_mode = mac->ieee->sec.auth_mode; - int is_shared_response = (auth_mode == WLAN_AUTH_SHARED_KEY - && transaction == IEEE80211SOFTMAC_AUTH_SHARED_RESPONSE); - - /* Allocate Packet */ - (*pkt) = (struct ieee80211_auth *)ieee80211softmac_alloc_mgt( - 2 + /* Auth Algorithm */ - 2 + /* Auth Transaction Seq */ - 2 + /* Status Code */ - /* Challenge Text IE */ - (is_shared_response ? 1 + 1 + net->challenge_len : 0) - ); - if (unlikely((*pkt) == NULL)) - return 0; - ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_AUTH, net->bssid, net->bssid); - - /* Algorithm */ - (*pkt)->algorithm = cpu_to_le16(auth_mode); - /* Transaction */ - (*pkt)->transaction = cpu_to_le16(transaction); - /* Status */ - (*pkt)->status = cpu_to_le16(status); - - data = (u8 *)(*pkt)->info_element; - /* Challenge Text */ - if (is_shared_response) { - *data = MFIE_TYPE_CHALLENGE; - data++; - - /* Copy the challenge in */ - *data = net->challenge_len; - data++; - memcpy(data, net->challenge, net->challenge_len); - data += net->challenge_len; - - /* Make sure this frame gets encrypted with the shared key */ - *encrypt_mpdu = 1; - } else - *encrypt_mpdu = 0; - - /* Return the packet size */ - return (data - (u8 *)(*pkt)); -} - -/* Create a disassocation or deauthentication packet */ -static u32 -ieee80211softmac_disassoc_deauth(struct ieee80211_disassoc **pkt, - struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, - u16 type, u16 reason) -{ - /* Allocate Packet */ - (*pkt) = (struct ieee80211_disassoc *)ieee80211softmac_alloc_mgt(2); - if (unlikely((*pkt) == NULL)) - return 0; - ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), type, net->bssid, net->bssid); - /* Reason */ - (*pkt)->reason = cpu_to_le16(reason); - /* Return the packet size */ - return (2 + IEEE80211_3ADDR_LEN); -} - -/* Create a probe request packet */ -static u32 -ieee80211softmac_probe_req(struct ieee80211_probe_request **pkt, - struct ieee80211softmac_device *mac, struct ieee80211softmac_essid *essid) -{ - u8 *data; - /* Allocate Packet */ - (*pkt) = (struct ieee80211_probe_request *)ieee80211softmac_alloc_mgt( - /* SSID of requested network */ - 1 + 1 + IW_ESSID_MAX_SIZE + - /* Rates IE */ - 1 + 1 + IEEE80211SOFTMAC_MAX_RATES_LEN + - /* Extended Rates IE */ - 1 + 1 + IEEE80211SOFTMAC_MAX_EX_RATES_LEN - ); - if (unlikely((*pkt) == NULL)) - return 0; - ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_REQ, NULL, NULL); - - data = (u8 *)(*pkt)->info_element; - /* Add ESSID (can be NULL) */ - data = ieee80211softmac_add_essid(data, essid); - /* Add Rates */ - data = ieee80211softmac_frame_add_rates(data, &mac->ratesinfo); - /* Return packet size */ - return (data - (u8 *)(*pkt)); -} - -/* Create a probe response packet */ -/* FIXME: Not complete */ -static u32 -ieee80211softmac_probe_resp(struct ieee80211_probe_response **pkt, - struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net) -{ - u8 *data; - /* Allocate Packet */ - (*pkt) = (struct ieee80211_probe_response *)ieee80211softmac_alloc_mgt( - 8 + /* Timestamp */ - 2 + /* Beacon Interval */ - 2 + /* Capability Info */ - /* SSID IE */ - 1 + 1 + IW_ESSID_MAX_SIZE + - 7 + /* FH Parameter Set */ - 2 + /* DS Parameter Set */ - 8 + /* CF Parameter Set */ - 4 /* IBSS Parameter Set */ - ); - if (unlikely((*pkt) == NULL)) - return 0; - ieee80211softmac_hdr_3addr(mac, &((*pkt)->header), IEEE80211_STYPE_PROBE_RESP, net->bssid, net->bssid); - data = (u8 *)(*pkt)->info_element; - - /* Return the packet size */ - return (data - (u8 *)(*pkt)); -} - - -/* Sends a manangement packet - * FIXME: document the use of the arg parameter - * for _AUTH: (transaction #) | (status << 16) - */ -int -ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac, - void *ptrarg, u32 type, u32 arg) -{ - void *pkt = NULL; - u32 pkt_size = 0; - int encrypt_mpdu = 0; - - switch(type) { - case IEEE80211_STYPE_ASSOC_REQ: - pkt_size = ieee80211softmac_assoc_req((struct ieee80211_assoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg); - break; - case IEEE80211_STYPE_REASSOC_REQ: - pkt_size = ieee80211softmac_reassoc_req((struct ieee80211_reassoc_request **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg); - break; - case IEEE80211_STYPE_AUTH: - pkt_size = ieee80211softmac_auth((struct ieee80211_auth **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, (u16)(arg & 0xFFFF), (u16) (arg >> 16), &encrypt_mpdu); - break; - case IEEE80211_STYPE_DISASSOC: - case IEEE80211_STYPE_DEAUTH: - pkt_size = ieee80211softmac_disassoc_deauth((struct ieee80211_disassoc **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg, type, (u16)(arg & 0xFFFF)); - break; - case IEEE80211_STYPE_PROBE_REQ: - pkt_size = ieee80211softmac_probe_req((struct ieee80211_probe_request **)(&pkt), mac, (struct ieee80211softmac_essid *)ptrarg); - break; - case IEEE80211_STYPE_PROBE_RESP: - pkt_size = ieee80211softmac_probe_resp((struct ieee80211_probe_response **)(&pkt), mac, (struct ieee80211softmac_network *)ptrarg); - break; - default: - printkl(KERN_DEBUG PFX "Unsupported Management Frame type: %i\n", type); - return -EINVAL; - }; - - if(pkt_size == 0 || pkt == NULL) { - printkl(KERN_DEBUG PFX "Error, packet is nonexistant or 0 length\n"); - return -ENOMEM; - } - - /* Send the packet to the ieee80211 layer for tx */ - /* we defined softmac->mgmt_xmit for this. Should we keep it - * as it is (that means we'd need to wrap this into a txb), - * modify the prototype (so it matches this function), - * or get rid of it alltogether? - * Does this work for you now? - */ - ieee80211_tx_frame(mac->ieee, (struct ieee80211_hdr *)pkt, - IEEE80211_3ADDR_LEN, pkt_size, encrypt_mpdu); - - kfree(pkt); - return 0; -} - -/* Beacon handling */ -int ieee80211softmac_handle_beacon(struct net_device *dev, - struct ieee80211_beacon *beacon, - struct ieee80211_network *network) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - - /* This might race, but we don't really care and it's not worth - * adding heavyweight locking in this fastpath. - */ - if (mac->associnfo.associated) { - if (memcmp(network->bssid, mac->associnfo.bssid, ETH_ALEN) == 0) - ieee80211softmac_process_erp(mac, network->erp_value); - } - - return 0; -} - diff --git a/net/ieee80211/softmac/ieee80211softmac_module.c b/net/ieee80211/softmac/ieee80211softmac_module.c deleted file mode 100644 index 07505ca859af..000000000000 --- a/net/ieee80211/softmac/ieee80211softmac_module.c +++ /dev/null @@ -1,568 +0,0 @@ -/* - * Contains some basic softmac functions along with module registration code etc. - * - * Copyright (c) 2005, 2006 Johannes Berg - * Joseph Jezak - * Larry Finger - * Danny van Dyk - * Michael Buesch - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. - */ - -#include "ieee80211softmac_priv.h" -#include -#include - -struct net_device *alloc_ieee80211softmac(int sizeof_priv) -{ - struct ieee80211softmac_device *softmac; - struct net_device *dev; - - dev = alloc_ieee80211(sizeof(*softmac) + sizeof_priv); - if (!dev) - return NULL; - softmac = ieee80211_priv(dev); - softmac->wq = create_freezeable_workqueue("softmac"); - if (!softmac->wq) { - free_ieee80211(dev); - return NULL; - } - - softmac->dev = dev; - softmac->ieee = netdev_priv(dev); - spin_lock_init(&softmac->lock); - - softmac->ieee->handle_auth = ieee80211softmac_auth_resp; - softmac->ieee->handle_deauth = ieee80211softmac_deauth_resp; - softmac->ieee->handle_assoc_response = ieee80211softmac_handle_assoc_response; - softmac->ieee->handle_reassoc_request = ieee80211softmac_handle_reassoc_req; - softmac->ieee->handle_disassoc = ieee80211softmac_handle_disassoc; - softmac->ieee->handle_beacon = ieee80211softmac_handle_beacon; - softmac->scaninfo = NULL; - - softmac->associnfo.scan_retry = IEEE80211SOFTMAC_ASSOC_SCAN_RETRY_LIMIT; - - /* TODO: initialise all the other callbacks in the ieee struct - * (once they're written) - */ - - INIT_LIST_HEAD(&softmac->auth_queue); - INIT_LIST_HEAD(&softmac->network_list); - INIT_LIST_HEAD(&softmac->events); - - mutex_init(&softmac->associnfo.mutex); - INIT_DELAYED_WORK(&softmac->associnfo.work, ieee80211softmac_assoc_work); - INIT_DELAYED_WORK(&softmac->associnfo.timeout, ieee80211softmac_assoc_timeout); - softmac->start_scan = ieee80211softmac_start_scan_implementation; - softmac->wait_for_scan = ieee80211softmac_wait_for_scan_implementation; - softmac->stop_scan = ieee80211softmac_stop_scan_implementation; - - /* to start with, we can't send anything ... */ - netif_carrier_off(dev); - - return dev; -} -EXPORT_SYMBOL_GPL(alloc_ieee80211softmac); - -/* Clears the pending work queue items, stops all scans, etc. */ -void -ieee80211softmac_clear_pending_work(struct ieee80211softmac_device *sm) -{ - unsigned long flags; - struct ieee80211softmac_event *eventptr, *eventtmp; - struct ieee80211softmac_auth_queue_item *authptr, *authtmp; - struct ieee80211softmac_network *netptr, *nettmp; - - ieee80211softmac_stop_scan(sm); - ieee80211softmac_wait_for_scan(sm); - - spin_lock_irqsave(&sm->lock, flags); - sm->running = 0; - - /* Free all pending assoc work items */ - cancel_delayed_work(&sm->associnfo.work); - - /* Free all pending scan work items */ - if(sm->scaninfo != NULL) - cancel_delayed_work(&sm->scaninfo->softmac_scan); - - /* Free all pending auth work items */ - list_for_each_entry(authptr, &sm->auth_queue, list) - cancel_delayed_work(&authptr->work); - - /* delete all pending event calls and work items */ - list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) - cancel_delayed_work(&eventptr->work); - - spin_unlock_irqrestore(&sm->lock, flags); - flush_workqueue(sm->wq); - - /* now we should be save and no longer need locking... */ - spin_lock_irqsave(&sm->lock, flags); - /* Free all pending auth work items */ - list_for_each_entry_safe(authptr, authtmp, &sm->auth_queue, list) { - list_del(&authptr->list); - kfree(authptr); - } - - /* delete all pending event calls and work items */ - list_for_each_entry_safe(eventptr, eventtmp, &sm->events, list) { - list_del(&eventptr->list); - kfree(eventptr); - } - - /* Free all networks */ - list_for_each_entry_safe(netptr, nettmp, &sm->network_list, list) { - ieee80211softmac_del_network_locked(sm, netptr); - if(netptr->challenge != NULL) - kfree(netptr->challenge); - kfree(netptr); - } - - spin_unlock_irqrestore(&sm->lock, flags); -} -EXPORT_SYMBOL_GPL(ieee80211softmac_clear_pending_work); - -void free_ieee80211softmac(struct net_device *dev) -{ - struct ieee80211softmac_device *sm = ieee80211_priv(dev); - ieee80211softmac_clear_pending_work(sm); - kfree(sm->scaninfo); - kfree(sm->wpa.IE); - destroy_workqueue(sm->wq); - free_ieee80211(dev); -} -EXPORT_SYMBOL_GPL(free_ieee80211softmac); - -static void ieee80211softmac_start_check_rates(struct ieee80211softmac_device *mac) -{ - struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo; - /* I took out the sorting check, we're seperating by modulation now. */ - if (ri->count) - return; - /* otherwise assume we hav'em all! */ - if (mac->ieee->modulation & IEEE80211_CCK_MODULATION) { - ri->rates[ri->count++] = IEEE80211_CCK_RATE_1MB; - ri->rates[ri->count++] = IEEE80211_CCK_RATE_2MB; - ri->rates[ri->count++] = IEEE80211_CCK_RATE_5MB; - ri->rates[ri->count++] = IEEE80211_CCK_RATE_11MB; - } - if (mac->ieee->modulation & IEEE80211_OFDM_MODULATION) { - ri->rates[ri->count++] = IEEE80211_OFDM_RATE_6MB; - ri->rates[ri->count++] = IEEE80211_OFDM_RATE_9MB; - ri->rates[ri->count++] = IEEE80211_OFDM_RATE_12MB; - ri->rates[ri->count++] = IEEE80211_OFDM_RATE_18MB; - ri->rates[ri->count++] = IEEE80211_OFDM_RATE_24MB; - ri->rates[ri->count++] = IEEE80211_OFDM_RATE_36MB; - ri->rates[ri->count++] = IEEE80211_OFDM_RATE_48MB; - ri->rates[ri->count++] = IEEE80211_OFDM_RATE_54MB; - } -} - -int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate) -{ - int search; - u8 search_rate; - - for (search = 0; search < ri->count; search++) { - search_rate = ri->rates[search]; - search_rate &= ~IEEE80211_BASIC_RATE_MASK; - if (rate == search_rate) - return 1; - } - - return 0; -} - -u8 ieee80211softmac_highest_supported_rate(struct ieee80211softmac_device *mac, - struct ieee80211softmac_ratesinfo *ri, int basic_only) -{ - u8 user_rate = mac->txrates.user_rate; - int i; - - if (ri->count == 0) - return IEEE80211_CCK_RATE_1MB; - - for (i = ri->count - 1; i >= 0; i--) { - u8 rate = ri->rates[i]; - if (basic_only && !(rate & IEEE80211_BASIC_RATE_MASK)) - continue; - rate &= ~IEEE80211_BASIC_RATE_MASK; - if (rate > user_rate) - continue; - if (ieee80211softmac_ratesinfo_rate_supported(&mac->ratesinfo, rate)) - return rate; - } - - /* If we haven't found a suitable rate by now, just trust the user */ - return user_rate; -} -EXPORT_SYMBOL_GPL(ieee80211softmac_highest_supported_rate); - -void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac, - u8 erp_value) -{ - int use_protection; - int short_preamble; - u32 changes = 0; - - /* Barker preamble mode */ - short_preamble = ((erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0 - && mac->associnfo.short_preamble_available) ? 1 : 0; - - /* Protection needed? */ - use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; - - if (mac->bssinfo.short_preamble != short_preamble) { - changes |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE; - mac->bssinfo.short_preamble = short_preamble; - } - - if (mac->bssinfo.use_protection != use_protection) { - changes |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION; - mac->bssinfo.use_protection = use_protection; - } - - if (mac->bssinfo_change && changes) - mac->bssinfo_change(mac->dev, changes); -} - -void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac) -{ - struct ieee80211softmac_txrates *txrates = &mac->txrates; - u32 change = 0; - - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; - txrates->default_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 0); - - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; - txrates->default_fallback = lower_rate(mac, txrates->default_rate); - - change |= IEEE80211SOFTMAC_TXRATECHG_MCAST; - txrates->mcast_rate = ieee80211softmac_highest_supported_rate(mac, &mac->bssinfo.supported_rates, 1); - - if (mac->txrates_change) - mac->txrates_change(mac->dev, change); - -} - -void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac) -{ - struct ieee80211_device *ieee = mac->ieee; - u32 change = 0; - struct ieee80211softmac_txrates *txrates = &mac->txrates; - struct ieee80211softmac_bss_info *bssinfo = &mac->bssinfo; - - /* TODO: We need some kind of state machine to lower the default rates - * if we loose too many packets. - */ - /* Change the default txrate to the highest possible value. - * The txrate machine will lower it, if it is too high. - */ - if (ieee->modulation & IEEE80211_OFDM_MODULATION) - txrates->user_rate = IEEE80211_OFDM_RATE_24MB; - else - txrates->user_rate = IEEE80211_CCK_RATE_11MB; - - txrates->default_rate = IEEE80211_CCK_RATE_1MB; - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; - - txrates->default_fallback = IEEE80211_CCK_RATE_1MB; - change |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; - - txrates->mcast_rate = IEEE80211_CCK_RATE_1MB; - change |= IEEE80211SOFTMAC_TXRATECHG_MCAST; - - txrates->mgt_mcast_rate = IEEE80211_CCK_RATE_1MB; - change |= IEEE80211SOFTMAC_TXRATECHG_MGT_MCAST; - - if (mac->txrates_change) - mac->txrates_change(mac->dev, change); - - change = 0; - - bssinfo->supported_rates.count = 0; - memset(bssinfo->supported_rates.rates, 0, - sizeof(bssinfo->supported_rates.rates)); - change |= IEEE80211SOFTMAC_BSSINFOCHG_RATES; - - bssinfo->short_preamble = 0; - change |= IEEE80211SOFTMAC_BSSINFOCHG_SHORT_PREAMBLE; - - bssinfo->use_protection = 0; - change |= IEEE80211SOFTMAC_BSSINFOCHG_PROTECTION; - - if (mac->bssinfo_change) - mac->bssinfo_change(mac->dev, change); - - mac->running = 1; -} - -void ieee80211softmac_start(struct net_device *dev) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - - ieee80211softmac_start_check_rates(mac); - ieee80211softmac_init_bss(mac); -} -EXPORT_SYMBOL_GPL(ieee80211softmac_start); - -void ieee80211softmac_stop(struct net_device *dev) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - - ieee80211softmac_clear_pending_work(mac); -} -EXPORT_SYMBOL_GPL(ieee80211softmac_stop); - -void ieee80211softmac_set_rates(struct net_device *dev, u8 count, u8 *rates) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&mac->lock, flags); - memcpy(mac->ratesinfo.rates, rates, count); - mac->ratesinfo.count = count; - spin_unlock_irqrestore(&mac->lock, flags); -} -EXPORT_SYMBOL_GPL(ieee80211softmac_set_rates); - -static u8 raise_rate(struct ieee80211softmac_device *mac, u8 rate) -{ - int i; - struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo; - - for (i=0; icount-1; i++) { - if (ri->rates[i] == rate) - return ri->rates[i+1]; - } - /* I guess we can't go any higher... */ - return ri->rates[ri->count]; -} - -u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta) -{ - int i; - struct ieee80211softmac_ratesinfo *ri = &mac->ratesinfo; - - for (i=delta; icount; i++) { - if (ri->rates[i] == rate) - return ri->rates[i-delta]; - } - /* I guess we can't go any lower... */ - return ri->rates[0]; -} - -static void ieee80211softmac_add_txrates_badness(struct ieee80211softmac_device *mac, - int amount) -{ - u8 default_rate = mac->txrates.default_rate; - u8 default_fallback = mac->txrates.default_fallback; - u32 changes = 0; - - //TODO: This is highly experimental code. - // Maybe the dynamic rate selection does not work - // and it has to be removed again. - -printk("badness %d\n", mac->txrate_badness); - mac->txrate_badness += amount; - if (mac->txrate_badness <= -1000) { - /* Very small badness. Try a faster bitrate. */ - default_rate = raise_rate(mac, default_rate); - changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; - default_fallback = get_fallback_rate(mac, default_rate); - changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; - mac->txrate_badness = 0; -printk("Bitrate raised to %u\n", default_rate); - } else if (mac->txrate_badness >= 10000) { - /* Very high badness. Try a slower bitrate. */ - default_rate = lower_rate(mac, default_rate); - changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT; - default_fallback = get_fallback_rate(mac, default_rate); - changes |= IEEE80211SOFTMAC_TXRATECHG_DEFAULT_FBACK; - mac->txrate_badness = 0; -printk("Bitrate lowered to %u\n", default_rate); - } - - mac->txrates.default_rate = default_rate; - mac->txrates.default_fallback = default_fallback; - - if (changes && mac->txrates_change) - mac->txrates_change(mac->dev, changes); -} - -void ieee80211softmac_fragment_lost(struct net_device *dev, - u16 wl_seq) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - unsigned long flags; - - spin_lock_irqsave(&mac->lock, flags); - ieee80211softmac_add_txrates_badness(mac, 1000); - //TODO - - spin_unlock_irqrestore(&mac->lock, flags); -} -EXPORT_SYMBOL_GPL(ieee80211softmac_fragment_lost); - -static int rate_cmp(const void *a_, const void *b_) { - u8 *a, *b; - a = (u8*)a_; - b = (u8*)b_; - return ((*a & ~IEEE80211_BASIC_RATE_MASK) - (*b & ~IEEE80211_BASIC_RATE_MASK)); -} - -/* Allocate a softmac network struct and fill it from a network */ -struct ieee80211softmac_network * -ieee80211softmac_create_network(struct ieee80211softmac_device *mac, - struct ieee80211_network *net) -{ - struct ieee80211softmac_network *softnet; - softnet = kzalloc(sizeof(struct ieee80211softmac_network), GFP_ATOMIC); - if(softnet == NULL) - return NULL; - memcpy(softnet->bssid, net->bssid, ETH_ALEN); - softnet->channel = net->channel; - softnet->essid.len = net->ssid_len; - memcpy(softnet->essid.data, net->ssid, softnet->essid.len); - - /* copy rates over */ - softnet->supported_rates.count = net->rates_len; - memcpy(&softnet->supported_rates.rates[0], net->rates, net->rates_len); - memcpy(&softnet->supported_rates.rates[softnet->supported_rates.count], net->rates_ex, net->rates_ex_len); - softnet->supported_rates.count += net->rates_ex_len; - sort(softnet->supported_rates.rates, softnet->supported_rates.count, sizeof(softnet->supported_rates.rates[0]), rate_cmp, NULL); - - /* we save the ERP value because it is needed at association time, and - * many AP's do not include an ERP IE in the association response. */ - softnet->erp_value = net->erp_value; - - softnet->capabilities = net->capability; - return softnet; -} - - -/* Add a network to the list, while locked */ -void -ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac, - struct ieee80211softmac_network *add_net) -{ - struct ieee80211softmac_network *softmac_net; - - list_for_each_entry(softmac_net, &mac->network_list, list) { - if(!memcmp(softmac_net->bssid, add_net->bssid, ETH_ALEN)) - return; - } - list_add(&(add_net->list), &mac->network_list); -} - -/* Add a network to the list, with locking */ -void -ieee80211softmac_add_network(struct ieee80211softmac_device *mac, - struct ieee80211softmac_network *add_net) -{ - unsigned long flags; - spin_lock_irqsave(&mac->lock, flags); - ieee80211softmac_add_network_locked(mac, add_net); - spin_unlock_irqrestore(&mac->lock, flags); -} - - -/* Delete a network from the list, while locked*/ -void -ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac, - struct ieee80211softmac_network *del_net) -{ - list_del(&(del_net->list)); -} - -/* Delete a network from the list with locking */ -void -ieee80211softmac_del_network(struct ieee80211softmac_device *mac, - struct ieee80211softmac_network *del_net) -{ - unsigned long flags; - spin_lock_irqsave(&mac->lock, flags); - ieee80211softmac_del_network_locked(mac, del_net); - spin_unlock_irqrestore(&mac->lock, flags); -} - -/* Get a network from the list by MAC while locked */ -struct ieee80211softmac_network * -ieee80211softmac_get_network_by_bssid_locked(struct ieee80211softmac_device *mac, - u8 *bssid) -{ - struct ieee80211softmac_network *softmac_net; - - list_for_each_entry(softmac_net, &mac->network_list, list) { - if(!memcmp(softmac_net->bssid, bssid, ETH_ALEN)) - return softmac_net; - } - return NULL; -} - -/* Get a network from the list by BSSID with locking */ -struct ieee80211softmac_network * -ieee80211softmac_get_network_by_bssid(struct ieee80211softmac_device *mac, - u8 *bssid) -{ - unsigned long flags; - struct ieee80211softmac_network *softmac_net; - - spin_lock_irqsave(&mac->lock, flags); - softmac_net = ieee80211softmac_get_network_by_bssid_locked(mac, bssid); - spin_unlock_irqrestore(&mac->lock, flags); - return softmac_net; -} - -/* Get a network from the list by ESSID while locked */ -struct ieee80211softmac_network * -ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac, - struct ieee80211softmac_essid *essid) -{ - struct ieee80211softmac_network *softmac_net; - - list_for_each_entry(softmac_net, &mac->network_list, list) { - if (softmac_net->essid.len == essid->len && - !memcmp(softmac_net->essid.data, essid->data, essid->len)) - return softmac_net; - } - return NULL; -} - -/* Get a network from the list by ESSID with locking */ -struct ieee80211softmac_network * -ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac, - struct ieee80211softmac_essid *essid) -{ - unsigned long flags; - struct ieee80211softmac_network *softmac_net = NULL; - - spin_lock_irqsave(&mac->lock, flags); - softmac_net = ieee80211softmac_get_network_by_essid_locked(mac, essid); - spin_unlock_irqrestore(&mac->lock, flags); - return softmac_net; -} - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Johannes Berg"); -MODULE_AUTHOR("Joseph Jezak"); -MODULE_AUTHOR("Larry Finger"); -MODULE_AUTHOR("Danny van Dyk"); -MODULE_AUTHOR("Michael Buesch"); -MODULE_DESCRIPTION("802.11 software MAC"); diff --git a/net/ieee80211/softmac/ieee80211softmac_priv.h b/net/ieee80211/softmac/ieee80211softmac_priv.h deleted file mode 100644 index f9232c8f6bdc..000000000000 --- a/net/ieee80211/softmac/ieee80211softmac_priv.h +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Internal softmac API definitions. - * - * Copyright (c) 2005, 2006 Johannes Berg - * Joseph Jezak - * Larry Finger - * Danny van Dyk - * Michael Buesch - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. - */ - -#ifndef IEEE80211SOFTMAC_PRIV_H_ -#define IEEE80211SOFTMAC_PRIV_H_ - -#include -#include -#include -#include - - -#define PFX "SoftMAC: " - -#ifdef assert -# undef assert -#endif -#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG -#define assert(expr) \ - do { \ - if (unlikely(!(expr))) { \ - printkl(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", #expr, \ - __FILE__, __LINE__, __func__); \ - } \ - } while (0) -#else -#define assert(expr) do {} while (0) -#endif - -/* rate limited printk(). */ -#ifdef printkl -# undef printkl -#endif -#define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0) -/* rate limited printk() for debugging */ -#ifdef dprintkl -# undef dprintkl -#endif -#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG -# define dprintkl printkl -#else -# define dprintkl(f, x...) do { /* nothing */ } while (0) -#endif - -/* debugging printk() */ -#ifdef dprintk -# undef dprintk -#endif -#ifdef CONFIG_IEEE80211_SOFTMAC_DEBUG -# define dprintk(f, x...) do { printk(f ,##x); } while (0) -#else -# define dprintk(f, x...) do { /* nothing */ } while (0) -#endif - -/* private definitions and prototypes */ - -/*** prototypes from _scan.c */ -void ieee80211softmac_scan(struct work_struct *work); -/* for internal use if scanning is needed */ -int ieee80211softmac_start_scan(struct ieee80211softmac_device *mac); -void ieee80211softmac_stop_scan(struct ieee80211softmac_device *mac); -void ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *mac); - -/* for use by _module.c to assign to the callbacks */ -int ieee80211softmac_start_scan_implementation(struct net_device *dev); -void ieee80211softmac_stop_scan_implementation(struct net_device *dev); -void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev); - -/*** Network prototypes from _module.c */ -struct ieee80211softmac_network * ieee80211softmac_create_network( - struct ieee80211softmac_device *mac, struct ieee80211_network *net); -void ieee80211softmac_add_network_locked(struct ieee80211softmac_device *mac, - struct ieee80211softmac_network *net); -void ieee80211softmac_add_network(struct ieee80211softmac_device *mac, - struct ieee80211softmac_network *net); -void ieee80211softmac_del_network_locked(struct ieee80211softmac_device *mac, - struct ieee80211softmac_network *net); -void ieee80211softmac_del_network(struct ieee80211softmac_device *mac, - struct ieee80211softmac_network *net); -struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid_locked( - struct ieee80211softmac_device *mac, u8 *ea); -struct ieee80211softmac_network * ieee80211softmac_get_network_by_bssid( - struct ieee80211softmac_device *mac, u8 *ea); -struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid_locked( - struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len); -struct ieee80211softmac_network * ieee80211softmac_get_network_by_ssid( - struct ieee80211softmac_device *mac, u8 *ssid, u8 ssid_len); -struct ieee80211softmac_network * -ieee80211softmac_get_network_by_essid_locked(struct ieee80211softmac_device *mac, - struct ieee80211softmac_essid *essid); -struct ieee80211softmac_network * -ieee80211softmac_get_network_by_essid(struct ieee80211softmac_device *mac, - struct ieee80211softmac_essid *essid); - -/* Rates related */ -void ieee80211softmac_process_erp(struct ieee80211softmac_device *mac, - u8 erp_value); -int ieee80211softmac_ratesinfo_rate_supported(struct ieee80211softmac_ratesinfo *ri, u8 rate); -u8 ieee80211softmac_lower_rate_delta(struct ieee80211softmac_device *mac, u8 rate, int delta); -void ieee80211softmac_init_bss(struct ieee80211softmac_device *mac); -void ieee80211softmac_recalc_txrates(struct ieee80211softmac_device *mac); -static inline u8 lower_rate(struct ieee80211softmac_device *mac, u8 rate) { - return ieee80211softmac_lower_rate_delta(mac, rate, 1); -} - -static inline u8 get_fallback_rate(struct ieee80211softmac_device *mac, u8 rate) -{ - return ieee80211softmac_lower_rate_delta(mac, rate, 2); -} - - -/*** prototypes from _io.c */ -int ieee80211softmac_send_mgt_frame(struct ieee80211softmac_device *mac, - void* ptrarg, u32 type, u32 arg); -int ieee80211softmac_handle_beacon(struct net_device *dev, - struct ieee80211_beacon *beacon, - struct ieee80211_network *network); - -/*** prototypes from _auth.c */ -/* do these have to go into the public header? */ -int ieee80211softmac_auth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net); -int ieee80211softmac_deauth_req(struct ieee80211softmac_device *mac, struct ieee80211softmac_network *net, int reason); - -/* for use by _module.c to assign to the callbacks */ -int ieee80211softmac_auth_resp(struct net_device *dev, struct ieee80211_auth *auth); -int ieee80211softmac_deauth_resp(struct net_device *dev, struct ieee80211_deauth *deauth); - -/*** prototypes from _assoc.c */ -void ieee80211softmac_assoc_work(struct work_struct *work); -int ieee80211softmac_handle_assoc_response(struct net_device * dev, - struct ieee80211_assoc_response * resp, - struct ieee80211_network * network); -int ieee80211softmac_handle_disassoc(struct net_device * dev, - struct ieee80211_disassoc * disassoc); -int ieee80211softmac_handle_reassoc_req(struct net_device * dev, - struct ieee80211_reassoc_request * reassoc); -void ieee80211softmac_assoc_timeout(struct work_struct *work); -void ieee80211softmac_send_disassoc_req(struct ieee80211softmac_device *mac, u16 reason); -void ieee80211softmac_disassoc(struct ieee80211softmac_device *mac); - -/* some helper functions */ -static inline int ieee80211softmac_scan_handlers_check_self(struct ieee80211softmac_device *sm) -{ - return (sm->start_scan == ieee80211softmac_start_scan_implementation) && - (sm->stop_scan == ieee80211softmac_stop_scan_implementation) && - (sm->wait_for_scan == ieee80211softmac_wait_for_scan_implementation); -} - -static inline int ieee80211softmac_scan_sanity_check(struct ieee80211softmac_device *sm) -{ - return ((sm->start_scan != ieee80211softmac_start_scan_implementation) && - (sm->stop_scan != ieee80211softmac_stop_scan_implementation) && - (sm->wait_for_scan != ieee80211softmac_wait_for_scan_implementation) - ) || ieee80211softmac_scan_handlers_check_self(sm); -} - -#define IEEE80211SOFTMAC_PROBE_DELAY HZ/50 -#define IEEE80211SOFTMAC_WORKQUEUE_NAME_LEN (17 + IFNAMSIZ) - -struct ieee80211softmac_network { - struct list_head list; /* List */ - /* Network information copied from ieee80211_network */ - u8 bssid[ETH_ALEN]; - u8 channel; - struct ieee80211softmac_essid essid; - - struct ieee80211softmac_ratesinfo supported_rates; - - /* SoftMAC specific */ - u16 authenticating:1, /* Status Flags */ - authenticated:1, - auth_desynced_once:1; - - u8 erp_value; /* Saved ERP value */ - u16 capabilities; /* Capabilities bitfield */ - u8 challenge_len; /* Auth Challenge length */ - char *challenge; /* Challenge Text */ -}; - -/* structure used to keep track of networks we're auth'ing to */ -struct ieee80211softmac_auth_queue_item { - struct list_head list; /* List head */ - struct ieee80211softmac_network *net; /* Network to auth */ - struct ieee80211softmac_device *mac; /* SoftMAC device */ - u8 retry; /* Retry limit */ - u8 state; /* Auth State */ - struct delayed_work work; /* Work queue */ -}; - -/* scanning information */ -struct ieee80211softmac_scaninfo { - u8 current_channel_idx, - number_channels; - struct ieee80211_channel *channels; - u8 started:1, - stop:1; - u8 skip_flags; - struct completion finished; - struct delayed_work softmac_scan; - struct ieee80211softmac_device *mac; -}; - -/* private event struct */ -struct ieee80211softmac_event { - struct list_head list; - int event_type; - void *event_context; - struct delayed_work work; - notify_function_ptr fun; - void *context; - struct ieee80211softmac_device *mac; -}; - -void ieee80211softmac_call_events(struct ieee80211softmac_device *mac, int event, void *event_context); -void ieee80211softmac_call_events_locked(struct ieee80211softmac_device *mac, int event, void *event_context); -int ieee80211softmac_notify_internal(struct ieee80211softmac_device *mac, - int event, void *event_context, notify_function_ptr fun, void *context, gfp_t gfp_mask); - -void ieee80211softmac_try_reassoc(struct ieee80211softmac_device *mac); - -#endif /* IEEE80211SOFTMAC_PRIV_H_ */ diff --git a/net/ieee80211/softmac/ieee80211softmac_scan.c b/net/ieee80211/softmac/ieee80211softmac_scan.c deleted file mode 100644 index bfab8d7db88f..000000000000 --- a/net/ieee80211/softmac/ieee80211softmac_scan.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Scanning routines. - * - * These are not exported because they're assigned to the function pointers. - * - * Copyright (c) 2005, 2006 Johannes Berg - * Joseph Jezak - * Larry Finger - * Danny van Dyk - * Michael Buesch - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. - */ - -#include -#include "ieee80211softmac_priv.h" - -/* internal, use to trigger scanning if needed. - * Returns -EBUSY if already scanning, - * result of start_scan otherwise */ -int -ieee80211softmac_start_scan(struct ieee80211softmac_device *sm) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&sm->lock, flags); - if (sm->scanning) - { - spin_unlock_irqrestore(&sm->lock, flags); - return -EINPROGRESS; - } - sm->scanning = 1; - spin_unlock_irqrestore(&sm->lock, flags); - - ret = sm->start_scan(sm->dev); - if (ret) { - spin_lock_irqsave(&sm->lock, flags); - sm->scanning = 0; - spin_unlock_irqrestore(&sm->lock, flags); - } - return ret; -} - -void -ieee80211softmac_stop_scan(struct ieee80211softmac_device *sm) -{ - unsigned long flags; - - spin_lock_irqsave(&sm->lock, flags); - - if (!sm->scanning) { - spin_unlock_irqrestore(&sm->lock, flags); - return; - } - - spin_unlock_irqrestore(&sm->lock, flags); - sm->stop_scan(sm->dev); -} - -void -ieee80211softmac_wait_for_scan(struct ieee80211softmac_device *sm) -{ - unsigned long flags; - - spin_lock_irqsave(&sm->lock, flags); - - if (!sm->scanning) { - spin_unlock_irqrestore(&sm->lock, flags); - return; - } - - spin_unlock_irqrestore(&sm->lock, flags); - sm->wait_for_scan(sm->dev); -} - - -/* internal scanning implementation follows */ -void ieee80211softmac_scan(struct work_struct *work) -{ - int invalid_channel; - u8 current_channel_idx; - struct ieee80211softmac_scaninfo *si = - container_of(work, struct ieee80211softmac_scaninfo, - softmac_scan.work); - struct ieee80211softmac_device *sm = si->mac; - unsigned long flags; - - while (!(si->stop) && (si->current_channel_idx < si->number_channels)) { - current_channel_idx = si->current_channel_idx; - si->current_channel_idx++; /* go to the next channel */ - - invalid_channel = (si->skip_flags & si->channels[current_channel_idx].flags); - - if (!invalid_channel) { - sm->set_channel(sm->dev, si->channels[current_channel_idx].channel); - // FIXME make this user configurable (active/passive) - if(ieee80211softmac_send_mgt_frame(sm, NULL, IEEE80211_STYPE_PROBE_REQ, 0)) - printkl(KERN_DEBUG PFX "Sending Probe Request Failed\n"); - - /* also send directed management frame for the network we're looking for */ - // TODO: is this if correct, or should we do this only if scanning from assoc request? - if (sm->associnfo.req_essid.len) - ieee80211softmac_send_mgt_frame(sm, &sm->associnfo.req_essid, IEEE80211_STYPE_PROBE_REQ, 0); - - spin_lock_irqsave(&sm->lock, flags); - if (unlikely(!sm->running)) { - /* Prevent reschedule on workqueue flush */ - spin_unlock_irqrestore(&sm->lock, flags); - break; - } - queue_delayed_work(sm->wq, &si->softmac_scan, IEEE80211SOFTMAC_PROBE_DELAY); - spin_unlock_irqrestore(&sm->lock, flags); - return; - } else { - dprintk(PFX "Not probing Channel %d (not allowed here)\n", si->channels[current_channel_idx].channel); - } - } - - spin_lock_irqsave(&sm->lock, flags); - cancel_delayed_work(&si->softmac_scan); - si->started = 0; - spin_unlock_irqrestore(&sm->lock, flags); - - dprintk(PFX "Scanning finished: scanned %d channels starting with channel %d\n", - sm->scaninfo->number_channels, sm->scaninfo->channels[0].channel); - ieee80211softmac_scan_finished(sm); - complete_all(&sm->scaninfo->finished); -} - -static inline struct ieee80211softmac_scaninfo *allocate_scaninfo(struct ieee80211softmac_device *mac) -{ - /* ugh. can we call this without having the spinlock held? */ - struct ieee80211softmac_scaninfo *info = kmalloc(sizeof(struct ieee80211softmac_scaninfo), GFP_ATOMIC); - if (unlikely(!info)) - return NULL; - INIT_DELAYED_WORK(&info->softmac_scan, ieee80211softmac_scan); - info->mac = mac; - init_completion(&info->finished); - return info; -} - -int ieee80211softmac_start_scan_implementation(struct net_device *dev) -{ - struct ieee80211softmac_device *sm = ieee80211_priv(dev); - unsigned long flags; - - if (!(dev->flags & IFF_UP)) - return -ENODEV; - - assert(ieee80211softmac_scan_handlers_check_self(sm)); - if (!ieee80211softmac_scan_handlers_check_self(sm)) - return -EINVAL; - - spin_lock_irqsave(&sm->lock, flags); - /* it looks like we need to hold the lock here - * to make sure we don't allocate two of these... */ - if (unlikely(!sm->scaninfo)) - sm->scaninfo = allocate_scaninfo(sm); - if (unlikely(!sm->scaninfo)) { - spin_unlock_irqrestore(&sm->lock, flags); - return -ENOMEM; - } - - sm->scaninfo->skip_flags = IEEE80211_CH_INVALID; - if (0 /* not scanning in IEEE802.11b */)//TODO - sm->scaninfo->skip_flags |= IEEE80211_CH_B_ONLY; - if (0 /* IEEE802.11a */) {//TODO - sm->scaninfo->channels = sm->ieee->geo.a; - sm->scaninfo->number_channels = sm->ieee->geo.a_channels; - } else { - sm->scaninfo->channels = sm->ieee->geo.bg; - sm->scaninfo->number_channels = sm->ieee->geo.bg_channels; - } - sm->scaninfo->current_channel_idx = 0; - sm->scaninfo->started = 1; - sm->scaninfo->stop = 0; - INIT_COMPLETION(sm->scaninfo->finished); - queue_delayed_work(sm->wq, &sm->scaninfo->softmac_scan, 0); - spin_unlock_irqrestore(&sm->lock, flags); - return 0; -} - -void ieee80211softmac_stop_scan_implementation(struct net_device *dev) -{ - struct ieee80211softmac_device *sm = ieee80211_priv(dev); - unsigned long flags; - - assert(ieee80211softmac_scan_handlers_check_self(sm)); - if (!ieee80211softmac_scan_handlers_check_self(sm)) - return; - - spin_lock_irqsave(&sm->lock, flags); - assert(sm->scaninfo != NULL); - if (sm->scaninfo) { - if (sm->scaninfo->started) - sm->scaninfo->stop = 1; - else - complete_all(&sm->scaninfo->finished); - } - spin_unlock_irqrestore(&sm->lock, flags); -} - -void ieee80211softmac_wait_for_scan_implementation(struct net_device *dev) -{ - struct ieee80211softmac_device *sm = ieee80211_priv(dev); - unsigned long flags; - - assert(ieee80211softmac_scan_handlers_check_self(sm)); - if (!ieee80211softmac_scan_handlers_check_self(sm)) - return; - - spin_lock_irqsave(&sm->lock, flags); - if (!sm->scaninfo->started) { - spin_unlock_irqrestore(&sm->lock, flags); - return; - } - spin_unlock_irqrestore(&sm->lock, flags); - wait_for_completion(&sm->scaninfo->finished); -} - -/* this is what drivers (that do scanning) call when they're done */ -void ieee80211softmac_scan_finished(struct ieee80211softmac_device *sm) -{ - unsigned long flags; - - spin_lock_irqsave(&sm->lock, flags); - sm->scanning = 0; - spin_unlock_irqrestore(&sm->lock, flags); - - if (sm->associnfo.bssvalid) { - struct ieee80211softmac_network *net; - - net = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid); - if (net) - sm->set_channel(sm->dev, net->channel); - } - ieee80211softmac_call_events(sm, IEEE80211SOFTMAC_EVENT_SCAN_FINISHED, NULL); -} -EXPORT_SYMBOL_GPL(ieee80211softmac_scan_finished); diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c deleted file mode 100644 index e01b59aedc54..000000000000 --- a/net/ieee80211/softmac/ieee80211softmac_wx.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * This file contains our _wx handlers. Make sure you EXPORT_SYMBOL_GPL them - * - * Copyright (c) 2005, 2006 Johannes Berg - * Joseph Jezak - * Larry Finger - * Danny van Dyk - * Michael Buesch - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. - */ - -#include "ieee80211softmac_priv.h" - -#include -/* for is_broadcast_ether_addr and is_zero_ether_addr */ -#include - -int -ieee80211softmac_wx_trigger_scan(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); - return ieee80211softmac_start_scan(sm); -} -EXPORT_SYMBOL_GPL(ieee80211softmac_wx_trigger_scan); - - -/* if we're still scanning, return -EAGAIN so that userspace tools - * can get the complete scan results, otherwise return 0. */ -int -ieee80211softmac_wx_get_scan_results(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - unsigned long flags; - struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); - - spin_lock_irqsave(&sm->lock, flags); - if (sm->scanning) { - spin_unlock_irqrestore(&sm->lock, flags); - return -EAGAIN; - } - spin_unlock_irqrestore(&sm->lock, flags); - return ieee80211_wx_get_scan(sm->ieee, info, data, extra); -} -EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_scan_results); - -int -ieee80211softmac_wx_set_essid(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); - struct ieee80211softmac_auth_queue_item *authptr; - int length = 0; - DECLARE_MAC_BUF(mac); - -check_assoc_again: - mutex_lock(&sm->associnfo.mutex); - if((sm->associnfo.associating || sm->associnfo.associated) && - (data->essid.flags && data->essid.length)) { - dprintk(KERN_INFO PFX "Canceling existing associate request!\n"); - /* Cancel assoc work */ - cancel_delayed_work(&sm->associnfo.work); - /* We don't have to do this, but it's a little cleaner */ - list_for_each_entry(authptr, &sm->auth_queue, list) - cancel_delayed_work(&authptr->work); - sm->associnfo.bssvalid = 0; - sm->associnfo.bssfixed = 0; - sm->associnfo.associating = 0; - sm->associnfo.associated = 0; - /* We must unlock to avoid deadlocks with the assoc workqueue - * on the associnfo.mutex */ - mutex_unlock(&sm->associnfo.mutex); - flush_workqueue(sm->wq); - /* Avoid race! Check assoc status again. Maybe someone started an - * association while we flushed. */ - goto check_assoc_again; - } - - sm->associnfo.static_essid = 0; - sm->associnfo.assoc_wait = 0; - - if (data->essid.flags && data->essid.length) { - length = min((int)data->essid.length, IW_ESSID_MAX_SIZE); - if (length) { - memcpy(sm->associnfo.req_essid.data, extra, length); - sm->associnfo.static_essid = 1; - } - } - - /* set our requested ESSID length. - * If applicable, we have already copied the data in */ - sm->associnfo.req_essid.len = length; - - sm->associnfo.associating = 1; - /* queue lower level code to do work (if necessary) */ - queue_delayed_work(sm->wq, &sm->associnfo.work, 0); - - mutex_unlock(&sm->associnfo.mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_essid); - -int -ieee80211softmac_wx_get_essid(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct ieee80211softmac_device *sm = ieee80211_priv(net_dev); - - mutex_lock(&sm->associnfo.mutex); - /* If all fails, return ANY (empty) */ - data->essid.length = 0; - data->essid.flags = 0; /* active */ - - /* If we have a statically configured ESSID then return it */ - if (sm->associnfo.static_essid) { - data->essid.length = sm->associnfo.req_essid.len; - data->essid.flags = 1; /* active */ - memcpy(extra, sm->associnfo.req_essid.data, sm->associnfo.req_essid.len); - dprintk(KERN_INFO PFX "Getting essid from req_essid\n"); - } else if (sm->associnfo.associated || sm->associnfo.associating) { - /* If we're associating/associated, return that */ - data->essid.length = sm->associnfo.associate_essid.len; - data->essid.flags = 1; /* active */ - memcpy(extra, sm->associnfo.associate_essid.data, sm->associnfo.associate_essid.len); - dprintk(KERN_INFO PFX "Getting essid from associate_essid\n"); - } - mutex_unlock(&sm->associnfo.mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_essid); - -int -ieee80211softmac_wx_set_rate(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); - struct ieee80211_device *ieee = mac->ieee; - unsigned long flags; - s32 in_rate = data->bitrate.value; - u8 rate; - int is_ofdm = 0; - int err = -EINVAL; - - if (in_rate == -1) { - if (ieee->modulation & IEEE80211_OFDM_MODULATION) - in_rate = 24000000; - else - in_rate = 11000000; - } - - switch (in_rate) { - case 1000000: - rate = IEEE80211_CCK_RATE_1MB; - break; - case 2000000: - rate = IEEE80211_CCK_RATE_2MB; - break; - case 5500000: - rate = IEEE80211_CCK_RATE_5MB; - break; - case 11000000: - rate = IEEE80211_CCK_RATE_11MB; - break; - case 6000000: - rate = IEEE80211_OFDM_RATE_6MB; - is_ofdm = 1; - break; - case 9000000: - rate = IEEE80211_OFDM_RATE_9MB; - is_ofdm = 1; - break; - case 12000000: - rate = IEEE80211_OFDM_RATE_12MB; - is_ofdm = 1; - break; - case 18000000: - rate = IEEE80211_OFDM_RATE_18MB; - is_ofdm = 1; - break; - case 24000000: - rate = IEEE80211_OFDM_RATE_24MB; - is_ofdm = 1; - break; - case 36000000: - rate = IEEE80211_OFDM_RATE_36MB; - is_ofdm = 1; - break; - case 48000000: - rate = IEEE80211_OFDM_RATE_48MB; - is_ofdm = 1; - break; - case 54000000: - rate = IEEE80211_OFDM_RATE_54MB; - is_ofdm = 1; - break; - default: - goto out; - } - - spin_lock_irqsave(&mac->lock, flags); - - /* Check if correct modulation for this PHY. */ - if (is_ofdm && !(ieee->modulation & IEEE80211_OFDM_MODULATION)) - goto out_unlock; - - mac->txrates.user_rate = rate; - ieee80211softmac_recalc_txrates(mac); - err = 0; - -out_unlock: - spin_unlock_irqrestore(&mac->lock, flags); -out: - return err; -} -EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_rate); - -int -ieee80211softmac_wx_get_rate(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); - unsigned long flags; - int err = -EINVAL; - - spin_lock_irqsave(&mac->lock, flags); - - if (unlikely(!mac->running)) { - err = -ENODEV; - goto out_unlock; - } - - switch (mac->txrates.default_rate) { - case IEEE80211_CCK_RATE_1MB: - data->bitrate.value = 1000000; - break; - case IEEE80211_CCK_RATE_2MB: - data->bitrate.value = 2000000; - break; - case IEEE80211_CCK_RATE_5MB: - data->bitrate.value = 5500000; - break; - case IEEE80211_CCK_RATE_11MB: - data->bitrate.value = 11000000; - break; - case IEEE80211_OFDM_RATE_6MB: - data->bitrate.value = 6000000; - break; - case IEEE80211_OFDM_RATE_9MB: - data->bitrate.value = 9000000; - break; - case IEEE80211_OFDM_RATE_12MB: - data->bitrate.value = 12000000; - break; - case IEEE80211_OFDM_RATE_18MB: - data->bitrate.value = 18000000; - break; - case IEEE80211_OFDM_RATE_24MB: - data->bitrate.value = 24000000; - break; - case IEEE80211_OFDM_RATE_36MB: - data->bitrate.value = 36000000; - break; - case IEEE80211_OFDM_RATE_48MB: - data->bitrate.value = 48000000; - break; - case IEEE80211_OFDM_RATE_54MB: - data->bitrate.value = 54000000; - break; - default: - assert(0); - goto out_unlock; - } - err = 0; -out_unlock: - spin_unlock_irqrestore(&mac->lock, flags); - - return err; -} -EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_rate); - -int -ieee80211softmac_wx_get_wap(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); - int err = 0; - - mutex_lock(&mac->associnfo.mutex); - if (mac->associnfo.bssvalid) - memcpy(data->ap_addr.sa_data, mac->associnfo.bssid, ETH_ALEN); - else - memset(data->ap_addr.sa_data, 0xff, ETH_ALEN); - data->ap_addr.sa_family = ARPHRD_ETHER; - mutex_unlock(&mac->associnfo.mutex); - - return err; -} -EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_wap); - -int -ieee80211softmac_wx_set_wap(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); - - /* sanity check */ - if (data->ap_addr.sa_family != ARPHRD_ETHER) { - return -EINVAL; - } - - mutex_lock(&mac->associnfo.mutex); - if (is_broadcast_ether_addr(data->ap_addr.sa_data)) { - /* the bssid we have is not to be fixed any longer, - * and we should reassociate to the best AP. */ - mac->associnfo.bssfixed = 0; - /* force reassociation */ - mac->associnfo.bssvalid = 0; - if (mac->associnfo.associated) - queue_delayed_work(mac->wq, &mac->associnfo.work, 0); - } else if (is_zero_ether_addr(data->ap_addr.sa_data)) { - /* the bssid we have is no longer fixed */ - mac->associnfo.bssfixed = 0; - } else { - if (!memcmp(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN)) { - if (mac->associnfo.associating || mac->associnfo.associated) { - /* bssid unchanged and associated or associating - just return */ - goto out; - } - } else { - /* copy new value in data->ap_addr.sa_data to bssid */ - memcpy(mac->associnfo.bssid, data->ap_addr.sa_data, ETH_ALEN); - } - /* tell the other code that this bssid should be used no matter what */ - mac->associnfo.bssfixed = 1; - /* queue associate if new bssid or (old one again and not associated) */ - queue_delayed_work(mac->wq, &mac->associnfo.work, 0); - } - - out: - mutex_unlock(&mac->associnfo.mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_wap); - -int -ieee80211softmac_wx_set_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - unsigned long flags; - int err = 0; - char *buf; - int i; - - mutex_lock(&mac->associnfo.mutex); - spin_lock_irqsave(&mac->lock, flags); - /* bleh. shouldn't be locked for that kmalloc... */ - - if (wrqu->data.length) { - if ((wrqu->data.length < 2) || (extra[1]+2 != wrqu->data.length)) { - /* this is an IE, so the length must be - * correct. Is it possible though that - * more than one IE is passed in? - */ - err = -EINVAL; - goto out; - } - if (mac->wpa.IEbuflen <= wrqu->data.length) { - buf = kmalloc(wrqu->data.length, GFP_ATOMIC); - if (!buf) { - err = -ENOMEM; - goto out; - } - kfree(mac->wpa.IE); - mac->wpa.IE = buf; - mac->wpa.IEbuflen = wrqu->data.length; - } - memcpy(mac->wpa.IE, extra, wrqu->data.length); - dprintk(KERN_INFO PFX "generic IE set to "); - for (i=0;idata.length;i++) - dprintk("%.2x", (u8)mac->wpa.IE[i]); - dprintk("\n"); - mac->wpa.IElen = wrqu->data.length; - } else { - kfree(mac->wpa.IE); - mac->wpa.IE = NULL; - mac->wpa.IElen = 0; - mac->wpa.IEbuflen = 0; - } - - out: - spin_unlock_irqrestore(&mac->lock, flags); - mutex_unlock(&mac->associnfo.mutex); - - return err; -} -EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_genie); - -int -ieee80211softmac_wx_get_genie(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - unsigned long flags; - int err = 0; - int space = wrqu->data.length; - - mutex_lock(&mac->associnfo.mutex); - spin_lock_irqsave(&mac->lock, flags); - - wrqu->data.length = 0; - - if (mac->wpa.IE && mac->wpa.IElen) { - wrqu->data.length = mac->wpa.IElen; - if (mac->wpa.IElen <= space) - memcpy(extra, mac->wpa.IE, mac->wpa.IElen); - else - err = -E2BIG; - } - spin_unlock_irqrestore(&mac->lock, flags); - mutex_unlock(&mac->associnfo.mutex); - - return err; -} -EXPORT_SYMBOL_GPL(ieee80211softmac_wx_get_genie); - -int -ieee80211softmac_wx_set_mlme(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, - char *extra) -{ - struct ieee80211softmac_device *mac = ieee80211_priv(dev); - struct iw_mlme *mlme = (struct iw_mlme *)extra; - u16 reason = mlme->reason_code; - struct ieee80211softmac_network *net; - int err = -EINVAL; - - mutex_lock(&mac->associnfo.mutex); - - if (memcmp(mac->associnfo.bssid, mlme->addr.sa_data, ETH_ALEN)) { - printk(KERN_DEBUG PFX "wx_set_mlme: requested operation on net we don't use\n"); - goto out; - } - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - net = ieee80211softmac_get_network_by_bssid_locked(mac, mlme->addr.sa_data); - if (!net) { - printk(KERN_DEBUG PFX "wx_set_mlme: we should know the net here...\n"); - goto out; - } - err = ieee80211softmac_deauth_req(mac, net, reason); - goto out; - case IW_MLME_DISASSOC: - ieee80211softmac_send_disassoc_req(mac, reason); - mac->associnfo.associated = 0; - mac->associnfo.associating = 0; - err = 0; - goto out; - default: - err = -EOPNOTSUPP; - } - -out: - mutex_unlock(&mac->associnfo.mutex); - - return err; -} -EXPORT_SYMBOL_GPL(ieee80211softmac_wx_set_mlme); -- cgit v1.2.3-59-g8ed1b From d9357136ac4729f589543afb6b1d17d443ae4f71 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 4 Mar 2008 15:26:15 -0800 Subject: the scheduled rc80211-simple.c removal Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: John W. Linville --- Documentation/feature-removal-schedule.txt | 10 - net/mac80211/Kconfig | 19 -- net/mac80211/Makefile | 2 - net/mac80211/ieee80211.c | 9 +- net/mac80211/ieee80211_rate.h | 15 -- net/mac80211/rc80211_simple.c | 394 ----------------------------- 6 files changed, 1 insertion(+), 448 deletions(-) delete mode 100644 net/mac80211/rc80211_simple.c (limited to 'net') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 2cf4d7ad7b0b..7279595b96c3 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -230,16 +230,6 @@ Who: Jean Delvare --------------------------- -What: rc80211-simple rate control algorithm for mac80211 -When: 2.6.26 -Files: net/mac80211/rc80211-simple.c -Why: This algorithm was provided for reference but always exhibited bad - responsiveness and performance and has some serious flaws. It has been - replaced by rc80211-pid. -Who: Stefano Brivio - ---------------------------- - What (Why): - include/linux/netfilter_ipv4/ipt_TOS.h ipt_tos.h header files (superseded by xt_TOS/xt_tos target & match) diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 3c3f62faae1e..520a5180a4f6 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -32,15 +32,6 @@ config MAC80211_RC_DEFAULT_PID default rate control algorithm. You should choose this unless you know what you are doing. -config MAC80211_RC_DEFAULT_SIMPLE - bool "Simple rate control algorithm" - select MAC80211_RC_SIMPLE - ---help--- - Select the simple rate control as the default rate - control algorithm. Note that this is a non-responsive, - dumb algorithm. You should choose the PID rate control - instead. - config MAC80211_RC_DEFAULT_NONE bool "No default algorithm" depends on EMBEDDED @@ -57,7 +48,6 @@ comment "build the algorithm into mac80211." config MAC80211_RC_DEFAULT string default "pid" if MAC80211_RC_DEFAULT_PID - default "simple" if MAC80211_RC_DEFAULT_SIMPLE default "" config MAC80211_RC_PID @@ -70,15 +60,6 @@ config MAC80211_RC_PID Say Y or M unless you're sure you want to use a different rate control algorithm. -config MAC80211_RC_SIMPLE - tristate "Simple rate control algorithm (DEPRECATED)" - ---help--- - This option enables a very simple, non-responsive TX - rate control algorithm. This algorithm is deprecated - and will be removed from the kernel in the near future. - It has been replaced by the PID algorithm. - - Say N unless you know what you are doing. endmenu config MAC80211_MESH diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 829ce4256b76..70f4b26c2d87 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -44,9 +44,7 @@ mac80211-$(CONFIG_MAC80211_MESH) += \ # Build rate control algorithm(s) -CFLAGS_rc80211_simple.o += -DRC80211_SIMPLE_COMPILE CFLAGS_rc80211_pid_algo.o += -DRC80211_PID_COMPILE -mac80211-$(CONFIG_MAC80211_RC_SIMPLE) += rc80211_simple.o mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc-pid-$(CONFIG_MAC80211_RC_PID)) # Modular rate algorithms are assigned to mac80211-m - make separate modules diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 484b063a3538..55b63712e48c 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -1803,13 +1803,9 @@ static int __init ieee80211_init(void) BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb)); - ret = rc80211_simple_init(); - if (ret) - goto out; - ret = rc80211_pid_init(); if (ret) - goto out_cleanup_simple; + goto out; ret = ieee80211_wme_register(); if (ret) { @@ -1824,15 +1820,12 @@ static int __init ieee80211_init(void) out_cleanup_pid: rc80211_pid_exit(); - out_cleanup_simple: - rc80211_simple_exit(); out: return ret; } static void __exit ieee80211_exit(void) { - rc80211_simple_exit(); rc80211_pid_exit(); if (mesh_allocated) diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h index bfd0a1982e4a..5b45f33cb766 100644 --- a/net/mac80211/ieee80211_rate.h +++ b/net/mac80211/ieee80211_rate.h @@ -171,21 +171,6 @@ void rate_control_deinitialize(struct ieee80211_local *local); /* Rate control algorithms */ -#if defined(RC80211_SIMPLE_COMPILE) || \ - (defined(CONFIG_MAC80211_RC_SIMPLE) && \ - !defined(CONFIG_MAC80211_RC_SIMPLE_MODULE)) -extern int rc80211_simple_init(void); -extern void rc80211_simple_exit(void); -#else -static inline int rc80211_simple_init(void) -{ - return 0; -} -static inline void rc80211_simple_exit(void) -{ -} -#endif - #if defined(RC80211_PID_COMPILE) || \ (defined(CONFIG_MAC80211_RC_PID) && \ !defined(CONFIG_MAC80211_RC_PID_MODULE)) diff --git a/net/mac80211/rc80211_simple.c b/net/mac80211/rc80211_simple.c deleted file mode 100644 index 4f72fdca7f12..000000000000 --- a/net/mac80211/rc80211_simple.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright 2002-2005, Instant802 Networks, Inc. - * Copyright 2005, Devicescape Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "ieee80211_i.h" -#include "ieee80211_rate.h" -#include "debugfs.h" - - -/* This is a minimal implementation of TX rate controlling that can be used - * as the default when no improved mechanisms are available. */ - -#define RATE_CONTROL_NUM_DOWN 20 -#define RATE_CONTROL_NUM_UP 15 - -#define RATE_CONTROL_EMERG_DEC 2 -#define RATE_CONTROL_INTERVAL (HZ / 20) -#define RATE_CONTROL_MIN_TX 10 - -static void rate_control_rate_inc(struct ieee80211_local *local, - struct sta_info *sta) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_supported_band *sband; - int i = sta->txrate_idx; - int maxrate; - - sdata = sta->sdata; - if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { - /* forced unicast rate - do not change STA rate */ - return; - } - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1; - - if (i > sband->n_bitrates) - i = sband->n_bitrates - 2; - - while (i + 1 < sband->n_bitrates) { - i++; - if (rate_supported(sta, sband->band, i) && - (maxrate < 0 || i <= maxrate)) { - sta->txrate_idx = i; - break; - } - } -} - - -static void rate_control_rate_dec(struct ieee80211_local *local, - struct sta_info *sta) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_supported_band *sband; - int i = sta->txrate_idx; - - sdata = sta->sdata; - if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { - /* forced unicast rate - do not change STA rate */ - return; - } - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - if (i > sband->n_bitrates) - i = sband->n_bitrates; - - while (i > 0) { - i--; - if (rate_supported(sta, sband->band, i)) { - sta->txrate_idx = i; - break; - } - } -} - -struct global_rate_control { - int dummy; -}; - -struct sta_rate_control { - unsigned long last_rate_change; - u32 tx_num_failures; - u32 tx_num_xmit; - - unsigned long avg_rate_update; - u32 tx_avg_rate_sum; - u32 tx_avg_rate_num; - -#ifdef CONFIG_MAC80211_DEBUGFS - struct dentry *tx_avg_rate_sum_dentry; - struct dentry *tx_avg_rate_num_dentry; -#endif -}; - - -static void rate_control_simple_tx_status(void *priv, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *status) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct sta_info *sta; - struct sta_rate_control *srctrl; - - rcu_read_lock(); - - sta = sta_info_get(local, hdr->addr1); - - if (!sta) - goto unlock; - - srctrl = sta->rate_ctrl_priv; - srctrl->tx_num_xmit++; - if (status->excessive_retries) { - srctrl->tx_num_failures++; - sta->tx_retry_failed++; - sta->tx_num_consecutive_failures++; - sta->tx_num_mpdu_fail++; - } else { - sta->tx_num_consecutive_failures = 0; - sta->tx_num_mpdu_ok++; - } - sta->tx_retry_count += status->retry_count; - sta->tx_num_mpdu_fail += status->retry_count; - - if (time_after(jiffies, - srctrl->last_rate_change + RATE_CONTROL_INTERVAL) && - srctrl->tx_num_xmit > RATE_CONTROL_MIN_TX) { - u32 per_failed; - srctrl->last_rate_change = jiffies; - - per_failed = (100 * sta->tx_num_mpdu_fail) / - (sta->tx_num_mpdu_fail + sta->tx_num_mpdu_ok); - /* TODO: calculate average per_failed to make adjusting - * parameters easier */ -#if 0 - if (net_ratelimit()) { - printk(KERN_DEBUG "MPDU fail=%d ok=%d per_failed=%d\n", - sta->tx_num_mpdu_fail, sta->tx_num_mpdu_ok, - per_failed); - } -#endif - - /* - * XXX: Make these configurable once we have an - * interface to the rate control algorithms - */ - if (per_failed > RATE_CONTROL_NUM_DOWN) { - rate_control_rate_dec(local, sta); - } else if (per_failed < RATE_CONTROL_NUM_UP) { - rate_control_rate_inc(local, sta); - } - srctrl->tx_avg_rate_sum += status->control.tx_rate->bitrate; - srctrl->tx_avg_rate_num++; - srctrl->tx_num_failures = 0; - srctrl->tx_num_xmit = 0; - } else if (sta->tx_num_consecutive_failures >= - RATE_CONTROL_EMERG_DEC) { - rate_control_rate_dec(local, sta); - } - - if (time_after(jiffies, srctrl->avg_rate_update + 60 * HZ)) { - srctrl->avg_rate_update = jiffies; - if (srctrl->tx_avg_rate_num > 0) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s: STA %s Average rate: " - "%d (%d/%d)\n", - dev->name, print_mac(mac, sta->addr), - srctrl->tx_avg_rate_sum / - srctrl->tx_avg_rate_num, - srctrl->tx_avg_rate_sum, - srctrl->tx_avg_rate_num); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - srctrl->tx_avg_rate_sum = 0; - srctrl->tx_avg_rate_num = 0; - } - } - - unlock: - rcu_read_unlock(); -} - - -static void -rate_control_simple_get_rate(void *priv, struct net_device *dev, - struct ieee80211_supported_band *sband, - struct sk_buff *skb, - struct rate_selection *sel) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct ieee80211_sub_if_data *sdata; - struct sta_info *sta; - int rateidx; - u16 fc; - - rcu_read_lock(); - - sta = sta_info_get(local, hdr->addr1); - - /* Send management frames and broadcast/multicast data using lowest - * rate. */ - fc = le16_to_cpu(hdr->frame_control); - if ((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || - is_multicast_ether_addr(hdr->addr1) || !sta) { - sel->rate = rate_lowest(local, sband, sta); - rcu_read_unlock(); - return; - } - - /* If a forced rate is in effect, select it. */ - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) - sta->txrate_idx = sdata->bss->force_unicast_rateidx; - - rateidx = sta->txrate_idx; - - if (rateidx >= sband->n_bitrates) - rateidx = sband->n_bitrates - 1; - - sta->last_txrate_idx = rateidx; - - rcu_read_unlock(); - - sel->rate = &sband->bitrates[rateidx]; -} - - -static void rate_control_simple_rate_init(void *priv, void *priv_sta, - struct ieee80211_local *local, - struct sta_info *sta) -{ - struct ieee80211_supported_band *sband; - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - /* TODO: This routine should consider using RSSI from previous packets - * as we need to have IEEE 802.1X auth succeed immediately after assoc.. - * Until that method is implemented, we will use the lowest supported rate - * as a workaround, */ - sta->txrate_idx = rate_lowest_index(local, sband, sta); -} - - -static void * rate_control_simple_alloc(struct ieee80211_local *local) -{ - struct global_rate_control *rctrl; - - rctrl = kzalloc(sizeof(*rctrl), GFP_ATOMIC); - - return rctrl; -} - - -static void rate_control_simple_free(void *priv) -{ - struct global_rate_control *rctrl = priv; - kfree(rctrl); -} - - -static void rate_control_simple_clear(void *priv) -{ -} - - -static void * rate_control_simple_alloc_sta(void *priv, gfp_t gfp) -{ - struct sta_rate_control *rctrl; - - rctrl = kzalloc(sizeof(*rctrl), gfp); - - return rctrl; -} - - -static void rate_control_simple_free_sta(void *priv, void *priv_sta) -{ - struct sta_rate_control *rctrl = priv_sta; - kfree(rctrl); -} - -#ifdef CONFIG_MAC80211_DEBUGFS - -static int open_file_generic(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t sta_tx_avg_rate_sum_read(struct file *file, - char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct sta_rate_control *srctrl = file->private_data; - char buf[20]; - - sprintf(buf, "%d\n", srctrl->tx_avg_rate_sum); - return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); -} - -static const struct file_operations sta_tx_avg_rate_sum_ops = { - .read = sta_tx_avg_rate_sum_read, - .open = open_file_generic, -}; - -static ssize_t sta_tx_avg_rate_num_read(struct file *file, - char __user *userbuf, - size_t count, loff_t *ppos) -{ - struct sta_rate_control *srctrl = file->private_data; - char buf[20]; - - sprintf(buf, "%d\n", srctrl->tx_avg_rate_num); - return simple_read_from_buffer(userbuf, count, ppos, buf, strlen(buf)); -} - -static const struct file_operations sta_tx_avg_rate_num_ops = { - .read = sta_tx_avg_rate_num_read, - .open = open_file_generic, -}; - -static void rate_control_simple_add_sta_debugfs(void *priv, void *priv_sta, - struct dentry *dir) -{ - struct sta_rate_control *srctrl = priv_sta; - - srctrl->tx_avg_rate_num_dentry = - debugfs_create_file("rc_simple_sta_tx_avg_rate_num", 0400, - dir, srctrl, &sta_tx_avg_rate_num_ops); - srctrl->tx_avg_rate_sum_dentry = - debugfs_create_file("rc_simple_sta_tx_avg_rate_sum", 0400, - dir, srctrl, &sta_tx_avg_rate_sum_ops); -} - -static void rate_control_simple_remove_sta_debugfs(void *priv, void *priv_sta) -{ - struct sta_rate_control *srctrl = priv_sta; - - debugfs_remove(srctrl->tx_avg_rate_sum_dentry); - debugfs_remove(srctrl->tx_avg_rate_num_dentry); -} -#endif - -static struct rate_control_ops mac80211_rcsimple = { - .name = "simple", - .tx_status = rate_control_simple_tx_status, - .get_rate = rate_control_simple_get_rate, - .rate_init = rate_control_simple_rate_init, - .clear = rate_control_simple_clear, - .alloc = rate_control_simple_alloc, - .free = rate_control_simple_free, - .alloc_sta = rate_control_simple_alloc_sta, - .free_sta = rate_control_simple_free_sta, -#ifdef CONFIG_MAC80211_DEBUGFS - .add_sta_debugfs = rate_control_simple_add_sta_debugfs, - .remove_sta_debugfs = rate_control_simple_remove_sta_debugfs, -#endif -}; - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Simple rate control algorithm"); - -int __init rc80211_simple_init(void) -{ - return ieee80211_rate_control_register(&mac80211_rcsimple); -} - -void rc80211_simple_exit(void) -{ - ieee80211_rate_control_unregister(&mac80211_rcsimple); -} - -#ifdef CONFIG_MAC80211_RC_SIMPLE_MODULE -module_init(rc80211_simple_init); -module_exit(rc80211_simple_exit); -#endif -- cgit v1.2.3-59-g8ed1b From 938b93adb2642885e688390396472d22a7548748 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Tue, 18 Mar 2008 00:59:23 -0700 Subject: [NET]: Add debugging names to __RW_LOCK_UNLOCKED macros. Signed-off-by: Robert P. J. Day Signed-off-by: David S. Miller --- net/ipv4/raw.c | 2 +- net/ipv6/raw.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index a3002fe65b7f..e10ef6c2202a 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -81,7 +81,7 @@ #include static struct raw_hashinfo raw_v4_hashinfo = { - .lock = __RW_LOCK_UNLOCKED(), + .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock), }; void raw_hash_sk(struct sock *sk, struct raw_hashinfo *h) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 8897ccf8086a..d6afa0216759 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -62,7 +62,7 @@ #include static struct raw_hashinfo raw_v6_hashinfo = { - .lock = __RW_LOCK_UNLOCKED(), + .lock = __RW_LOCK_UNLOCKED(raw_v6_hashinfo.lock), }; static void raw_v6_hash(struct sock *sk) -- cgit v1.2.3-59-g8ed1b From 82cc1a7a56872056af0ead6c7d695aa223f36695 Mon Sep 17 00:00:00 2001 From: Peter P Waskiewicz Jr Date: Fri, 21 Mar 2008 03:43:19 -0700 Subject: [NET]: Add per-connection option to set max TSO frame size Update: My mailer ate one of Jarek's feedback mails... Fixed the parameter in netif_set_gso_max_size() to be u32, not u16. Fixed the whitespace issue due to a patch import botch. Changed the types from u32 to unsigned int to be more consistent with other variables in the area. Also brought the patch up to the latest net-2.6.26 tree. Update: Made gso_max_size container 32 bits, not 16. Moved the location of gso_max_size within netdev to be less hotpath. Made more consistent names between the sock and netdev layers, and added a define for the max GSO size. Update: Respun for net-2.6.26 tree. Update: changed max_gso_frame_size and sk_gso_max_size from signed to unsigned - thanks Stephen! This patch adds the ability for device drivers to control the size of the TSO frames being sent to them, per TCP connection. By setting the netdevice's gso_max_size value, the socket layer will set the GSO frame size based on that value. This will propogate into the TCP layer, and send TSO's of that size to the hardware. This can be desirable to help tune the bursty nature of TSO on a per-adapter basis, where one may have 1 GbE and 10 GbE devices coexisting in a system, one running multiqueue and the other not, etc. This can also be desirable for devices that cannot support full 64 KB TSO's, but still want to benefit from some level of segmentation offloading. Signed-off-by: Peter P Waskiewicz Jr Signed-off-by: David S. Miller --- include/linux/netdevice.h | 10 ++++++++++ include/net/sock.h | 2 ++ net/core/dev.c | 1 + net/core/sock.c | 6 ++++-- net/ipv4/tcp_output.c | 4 ++-- 5 files changed, 19 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index a2f003239c85..ced61f87660e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -724,6 +724,10 @@ struct net_device /* rtnetlink link ops */ const struct rtnl_link_ops *rtnl_link_ops; + /* for setting kernel sock attribute on TCP connection setup */ +#define GSO_MAX_SIZE 65536 + unsigned int gso_max_size; + /* The TX queue control structures */ unsigned int egress_subqueue_count; struct net_device_subqueue egress_subqueue[1]; @@ -1475,6 +1479,12 @@ static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) unlikely(skb->ip_summed != CHECKSUM_PARTIAL)); } +static inline void netif_set_gso_max_size(struct net_device *dev, + unsigned int size) +{ + dev->gso_max_size = size; +} + /* On bonding slaves other than the currently active slave, suppress * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and * ARP on active-backup slaves with arp_validate enabled. diff --git a/include/net/sock.h b/include/net/sock.h index 39112e75411c..8358fff002eb 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -151,6 +151,7 @@ struct sock_common { * @sk_no_check: %SO_NO_CHECK setting, wether or not checkup packets * @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO) * @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4) + * @sk_gso_max_size: Maximum GSO segment size to build * @sk_lingertime: %SO_LINGER l_linger setting * @sk_backlog: always used with the per-socket spinlock held * @sk_callback_lock: used with the callbacks in the end of this struct @@ -237,6 +238,7 @@ struct sock { gfp_t sk_allocation; int sk_route_caps; int sk_gso_type; + unsigned int sk_gso_max_size; int sk_rcvlowat; unsigned long sk_flags; unsigned long sk_lingertime; diff --git a/net/core/dev.c b/net/core/dev.c index fcdf03cf3b3f..f973e38b81af 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4021,6 +4021,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, } dev->egress_subqueue_count = queue_count; + dev->gso_max_size = GSO_MAX_SIZE; dev->get_stats = internal_stats; netpoll_netdev_init(dev); diff --git a/net/core/sock.c b/net/core/sock.c index bb5236aee643..b1a6ed4d33c1 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1095,10 +1095,12 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst) if (sk->sk_route_caps & NETIF_F_GSO) sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE; if (sk_can_gso(sk)) { - if (dst->header_len) + if (dst->header_len) { sk->sk_route_caps &= ~NETIF_F_GSO_MASK; - else + } else { sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; + sk->sk_gso_max_size = dst->dev->gso_max_size; + } } } EXPORT_SYMBOL_GPL(sk_setup_caps); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b4e11d834c9f..a627616314ba 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -998,7 +998,7 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed) xmit_size_goal = mss_now; if (doing_tso) { - xmit_size_goal = (65535 - + xmit_size_goal = ((sk->sk_gso_max_size - 1) - inet_csk(sk)->icsk_af_ops->net_header_len - inet_csk(sk)->icsk_ext_hdr_len - tp->tcp_header_len); @@ -1282,7 +1282,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb) limit = min(send_win, cong_win); /* If a full-sized TSO skb can be sent, do it. */ - if (limit >= 65536) + if (limit >= sk->sk_gso_max_size) goto send_now; if (sysctl_tcp_tso_win_divisor) { -- cgit v1.2.3-59-g8ed1b From ea82edf704f6bf3c3a51d0dbee816c5bbc6d3974 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 21 Mar 2008 04:10:53 -0700 Subject: [NETNS][IPV6] mcast - fix compilation warning when procfs is not compiled in When CONFIG_PROC_FS=no, the out_sock_create label is not used because the code using it is disabled and that leads to a warning at compile time. This patch fix that by making a specific function to initialize proc for igmp6, and remove the annoying CONFIG_PROC_FS sections in init/exit function. Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv6/mcast.c | 53 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index f2879056fab0..957ac7e9e929 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2633,6 +2633,41 @@ static const struct file_operations igmp6_mcf_seq_fops = { .llseek = seq_lseek, .release = seq_release_net, }; + +static int igmp6_proc_init(struct net *net) +{ + int err; + + err = -ENOMEM; + if (!proc_net_fops_create(net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops)) + goto out; + if (!proc_net_fops_create(net, "mcfilter6", S_IRUGO, + &igmp6_mcf_seq_fops)) + goto out_proc_net_igmp6; + + err = 0; +out: + return err; + +out_proc_net_igmp6: + proc_net_remove(net, "igmp6"); + goto out; +} + +static void igmp6_proc_exit(struct net *net) +{ + proc_net_remove(net, "mcfilter6"); + proc_net_remove(net, "igmp6"); +} +#else +static int igmp6_proc_init(struct net *net) +{ + return 0; +} +static void igmp6_proc_exit(struct net *net) +{ + ; +} #endif static int igmp6_net_init(struct net *net) @@ -2658,18 +2693,9 @@ static int igmp6_net_init(struct net *net) np = inet6_sk(sk); np->hop_limit = 1; -#ifdef CONFIG_PROC_FS - err = -ENOMEM; - if (!proc_net_fops_create(net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops)) - goto out_sock_create; - if (!proc_net_fops_create(net, "mcfilter6", S_IRUGO, - &igmp6_mcf_seq_fops)) { - proc_net_remove(net, "igmp6"); + err = igmp6_proc_init(net); + if (err) goto out_sock_create; - } -#endif - - err = 0; out: return err; @@ -2681,10 +2707,7 @@ out_sock_create: static void igmp6_net_exit(struct net *net) { sk_release_kernel(net->ipv6.igmp_sk); -#ifdef CONFIG_PROC_FS - proc_net_remove(net, "mcfilter6"); - proc_net_remove(net, "igmp6"); -#endif + igmp6_proc_exit(net); } static struct pernet_operations igmp6_net_ops = { -- cgit v1.2.3-59-g8ed1b From a91275eff43a527e1a25d6d034cbcd19ee323e64 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 21 Mar 2008 04:11:58 -0700 Subject: [NETNS][IPV6] udp - make proc handle the network namespace This patch makes the common udp proc functions to take care of which socket they should show taking into account the namespace it belongs. Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/net/udp.h | 1 + net/ipv4/udp.c | 32 ++++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/udp.h b/include/net/udp.h index c6669c0a74c7..a1b33d667199 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -192,6 +192,7 @@ struct udp_seq_afinfo { }; struct udp_iter_state { + struct net *net; sa_family_t family; struct hlist_head *hashtable; int bucket; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 7ea1b67b6de1..049e92519616 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1512,10 +1512,13 @@ static struct sock *udp_get_first(struct seq_file *seq) { struct sock *sk; struct udp_iter_state *state = seq->private; + struct net *net = state->net; for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { struct hlist_node *node; sk_for_each(sk, node, state->hashtable + state->bucket) { + if (sk->sk_net != net) + continue; if (sk->sk_family == state->family) goto found; } @@ -1528,12 +1531,13 @@ found: static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) { struct udp_iter_state *state = seq->private; + struct net *net = state->net; do { sk = sk_next(sk); try_again: ; - } while (sk && sk->sk_family != state->family); + } while (sk && sk->sk_net != net && sk->sk_family != state->family); if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { sk = sk_head(state->hashtable + state->bucket); @@ -1582,31 +1586,51 @@ static int udp_seq_open(struct inode *inode, struct file *file) { struct udp_seq_afinfo *afinfo = PDE(inode)->data; struct seq_file *seq; + struct net *net; int rc = -ENOMEM; struct udp_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) goto out; + + rc = -ENXIO; + net = get_proc_net(inode); + if (!net) + goto out_kfree; + s->family = afinfo->family; s->hashtable = afinfo->hashtable; s->seq_ops.start = udp_seq_start; s->seq_ops.next = udp_seq_next; s->seq_ops.show = afinfo->seq_show; s->seq_ops.stop = udp_seq_stop; + s->net = net; rc = seq_open(file, &s->seq_ops); if (rc) - goto out_kfree; + goto out_put_net; - seq = file->private_data; + seq = file->private_data; seq->private = s; out: return rc; +out_put_net: + put_net(net); out_kfree: kfree(s); goto out; } +static int udp_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct udp_iter_state *s = seq->private; + + put_net(s->net); + seq_release_private(inode, file); + return 0; +} + /* ------------------------------------------------------------------------ */ int udp_proc_register(struct udp_seq_afinfo *afinfo) { @@ -1619,7 +1643,7 @@ int udp_proc_register(struct udp_seq_afinfo *afinfo) afinfo->seq_fops->open = udp_seq_open; afinfo->seq_fops->read = seq_read; afinfo->seq_fops->llseek = seq_lseek; - afinfo->seq_fops->release = seq_release_private; + afinfo->seq_fops->release = udp_seq_release; p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) -- cgit v1.2.3-59-g8ed1b From 8d9f1744cab50acb0c6c9553be533621e01f178b Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 21 Mar 2008 04:12:54 -0700 Subject: [NETNS][IPV6] tcp - assign the netns for timewait sockets Copy the network namespace from the socket to the timewait socket. Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv4/inet_timewait_sock.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 876169f3a528..717c411a5c6b 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -124,6 +124,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat tw->tw_hash = sk->sk_hash; tw->tw_ipv6only = 0; tw->tw_prot = sk->sk_prot_creator; + tw->tw_net = sk->sk_net; atomic_set(&tw->tw_refcnt, 1); inet_twsk_dead_node_init(tw); __module_get(tw->tw_prot->owner); -- cgit v1.2.3-59-g8ed1b From f40c8174d3c21bf178283f3ef3aa8c7bf238fdec Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 21 Mar 2008 04:13:54 -0700 Subject: [NETNS][IPV4] tcp - make proc handle the network namespaces This patch, like udp proc, makes the proc functions to take care of which namespace the socket belongs. Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/net/tcp.h | 1 + net/ipv4/tcp_ipv4.c | 44 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 36 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/net/tcp.h b/include/net/tcp.h index 11119e33acfe..6b08dab1b1fa 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1328,6 +1328,7 @@ struct tcp_seq_afinfo { }; struct tcp_iter_state { + struct net *net; sa_family_t family; enum tcp_seq_states state; struct sock *syn_wait_sk; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index a79e324638eb..f9b30dc3bd6c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1948,6 +1948,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) struct hlist_node *node; struct sock *sk = cur; struct tcp_iter_state* st = seq->private; + struct net *net = st->net; if (!sk) { st->bucket = 0; @@ -1964,7 +1965,8 @@ static void *listening_get_next(struct seq_file *seq, void *cur) req = req->dl_next; while (1) { while (req) { - if (req->rsk_ops->family == st->family) { + if (req->rsk_ops->family == st->family && + req->sk->sk_net == net) { cur = req; goto out; } @@ -1988,7 +1990,7 @@ get_req: } get_sk: sk_for_each_from(sk, node) { - if (sk->sk_family == st->family) { + if (sk->sk_family == st->family && sk->sk_net == net) { cur = sk; goto out; } @@ -2027,6 +2029,7 @@ static void *listening_get_idx(struct seq_file *seq, loff_t *pos) static void *established_get_first(struct seq_file *seq) { struct tcp_iter_state* st = seq->private; + struct net *net = st->net; void *rc = NULL; for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) { @@ -2037,7 +2040,8 @@ static void *established_get_first(struct seq_file *seq) read_lock_bh(lock); sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) { - if (sk->sk_family != st->family) { + if (sk->sk_family != st->family || + sk->sk_net != net) { continue; } rc = sk; @@ -2046,7 +2050,8 @@ static void *established_get_first(struct seq_file *seq) st->state = TCP_SEQ_STATE_TIME_WAIT; inet_twsk_for_each(tw, node, &tcp_hashinfo.ehash[st->bucket].twchain) { - if (tw->tw_family != st->family) { + if (tw->tw_family != st->family && + tw->tw_net != net) { continue; } rc = tw; @@ -2065,6 +2070,7 @@ static void *established_get_next(struct seq_file *seq, void *cur) struct inet_timewait_sock *tw; struct hlist_node *node; struct tcp_iter_state* st = seq->private; + struct net *net = st->net; ++st->num; @@ -2072,7 +2078,7 @@ static void *established_get_next(struct seq_file *seq, void *cur) tw = cur; tw = tw_next(tw); get_tw: - while (tw && tw->tw_family != st->family) { + while (tw && tw->tw_family != st->family && tw->tw_net != net) { tw = tw_next(tw); } if (tw) { @@ -2093,7 +2099,7 @@ get_tw: sk = sk_next(sk); sk_for_each_from(sk, node) { - if (sk->sk_family == st->family) + if (sk->sk_family == st->family && sk->sk_net == net) goto found; } @@ -2201,6 +2207,7 @@ static int tcp_seq_open(struct inode *inode, struct file *file) struct tcp_seq_afinfo *afinfo = PDE(inode)->data; struct seq_file *seq; struct tcp_iter_state *s; + struct net *net; int rc; if (unlikely(afinfo == NULL)) @@ -2209,24 +2216,43 @@ static int tcp_seq_open(struct inode *inode, struct file *file) s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) return -ENOMEM; + + rc = -ENXIO; + net = get_proc_net(inode); + if (!net) + goto out_kfree; + s->family = afinfo->family; s->seq_ops.start = tcp_seq_start; s->seq_ops.next = tcp_seq_next; s->seq_ops.show = afinfo->seq_show; s->seq_ops.stop = tcp_seq_stop; + s->net = net; rc = seq_open(file, &s->seq_ops); if (rc) - goto out_kfree; - seq = file->private_data; + goto out_put_net; + seq = file->private_data; seq->private = s; out: return rc; +out_put_net: + put_net(net); out_kfree: kfree(s); goto out; } +static int tcp_seq_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct tcp_iter_state *s = seq->private; + + put_net(s->net); + seq_release_private(inode, file); + return 0; +} + int tcp_proc_register(struct tcp_seq_afinfo *afinfo) { int rc = 0; @@ -2238,7 +2264,7 @@ int tcp_proc_register(struct tcp_seq_afinfo *afinfo) afinfo->seq_fops->open = tcp_seq_open; afinfo->seq_fops->read = seq_read; afinfo->seq_fops->llseek = seq_lseek; - afinfo->seq_fops->release = seq_release_private; + afinfo->seq_fops->release = tcp_seq_release; p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) -- cgit v1.2.3-59-g8ed1b From 0c96d8c50bffb7f02690dd8a8cf1adb8e07e100f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 21 Mar 2008 04:14:17 -0700 Subject: [NETNS][IPV6] udp6 - make proc per namespace The proc init/exit functions take a new network namespace parameter in order to register/unregister /proc/net/udp6 for a namespace. Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/net/ipv6.h | 4 ++-- include/net/udp.h | 4 ++-- net/ipv4/udp.c | 12 ++++++------ net/ipv4/udplite.c | 2 +- net/ipv6/af_inet6.c | 19 ++++++++++++------- net/ipv6/udp.c | 8 ++++---- net/ipv6/udplite.c | 4 ++-- 7 files changed, 29 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 8db06af1efbb..e01a563132e8 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -597,8 +597,8 @@ extern int raw6_proc_init(void); extern void raw6_proc_exit(void); extern int tcp6_proc_init(void); extern void tcp6_proc_exit(void); -extern int udp6_proc_init(void); -extern void udp6_proc_exit(void); +extern int udp6_proc_init(struct net *net); +extern void udp6_proc_exit(struct net *net); extern int udplite6_proc_init(void); extern void udplite6_proc_exit(void); extern int ipv6_misc_proc_init(void); diff --git a/include/net/udp.h b/include/net/udp.h index a1b33d667199..b4cbdce883d1 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -200,8 +200,8 @@ struct udp_iter_state { }; #ifdef CONFIG_PROC_FS -extern int udp_proc_register(struct udp_seq_afinfo *afinfo); -extern void udp_proc_unregister(struct udp_seq_afinfo *afinfo); +extern int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo); +extern void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo); extern int udp4_proc_init(void); extern void udp4_proc_exit(void); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 049e92519616..a98c43c0a89c 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1632,7 +1632,7 @@ static int udp_seq_release(struct inode *inode, struct file *file) } /* ------------------------------------------------------------------------ */ -int udp_proc_register(struct udp_seq_afinfo *afinfo) +int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) { struct proc_dir_entry *p; int rc = 0; @@ -1645,7 +1645,7 @@ int udp_proc_register(struct udp_seq_afinfo *afinfo) afinfo->seq_fops->llseek = seq_lseek; afinfo->seq_fops->release = udp_seq_release; - p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops); + p = proc_net_fops_create(net, afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) p->data = afinfo; else @@ -1653,11 +1653,11 @@ int udp_proc_register(struct udp_seq_afinfo *afinfo) return rc; } -void udp_proc_unregister(struct udp_seq_afinfo *afinfo) +void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo) { if (!afinfo) return; - proc_net_remove(&init_net, afinfo->name); + proc_net_remove(net, afinfo->name); memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } @@ -1709,12 +1709,12 @@ static struct udp_seq_afinfo udp4_seq_afinfo = { int __init udp4_proc_init(void) { - return udp_proc_register(&udp4_seq_afinfo); + return udp_proc_register(&init_net, &udp4_seq_afinfo); } void udp4_proc_exit(void) { - udp_proc_unregister(&udp4_seq_afinfo); + udp_proc_unregister(&init_net, &udp4_seq_afinfo); } #endif /* CONFIG_PROC_FS */ diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index d49c6d68c8a9..2469b5104587 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -105,7 +105,7 @@ void __init udplite4_register(void) inet_register_protosw(&udplite4_protosw); #ifdef CONFIG_PROC_FS - if (udp_proc_register(&udplite4_seq_afinfo)) /* udplite4_proc_init() */ + if (udp_proc_register(&init_net, &udplite4_seq_afinfo)) printk(KERN_ERR "%s: Cannot register /proc!\n", __func__); #endif return; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 730a861b8f41..e3e09147d134 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -842,6 +842,8 @@ static void cleanup_ipv6_mibs(void) static int inet6_net_init(struct net *net) { + int err = 0; + net->ipv6.sysctl.bindv6only = 0; net->ipv6.sysctl.flush_delay = 0; net->ipv6.sysctl.ip6_rt_max_size = 4096; @@ -853,12 +855,20 @@ static int inet6_net_init(struct net *net) net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40; net->ipv6.sysctl.icmpv6_time = 1*HZ; - return 0; +#ifdef CONFIG_PROC_FS + err = udp6_proc_init(net); + if (err) + goto out; +out: +#endif + return err; } static void inet6_net_exit(struct net *net) { - return; +#ifdef CONFIG_PROC_FS + udp6_proc_exit(net); +#endif } static struct pernet_operations inet6_net_ops = { @@ -943,8 +953,6 @@ static int __init inet6_init(void) goto proc_raw6_fail; if (tcp6_proc_init()) goto proc_tcp6_fail; - if (udp6_proc_init()) - goto proc_udp6_fail; if (udplite6_proc_init()) goto proc_udplite6_fail; if (ipv6_misc_proc_init()) @@ -1029,8 +1037,6 @@ proc_anycast6_fail: proc_misc6_fail: udplite6_proc_exit(); proc_udplite6_fail: - udp6_proc_exit(); -proc_udp6_fail: tcp6_proc_exit(); proc_tcp6_fail: raw6_proc_exit(); @@ -1092,7 +1098,6 @@ static void __exit inet6_exit(void) ac6_proc_exit(); ipv6_misc_proc_exit(); udplite6_proc_exit(); - udp6_proc_exit(); tcp6_proc_exit(); raw6_proc_exit(); #endif diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index d6e311f6c8eb..af619d48ba80 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -989,13 +989,13 @@ static struct udp_seq_afinfo udp6_seq_afinfo = { .seq_fops = &udp6_seq_fops, }; -int __init udp6_proc_init(void) +int udp6_proc_init(struct net *net) { - return udp_proc_register(&udp6_seq_afinfo); + return udp_proc_register(net, &udp6_seq_afinfo); } -void udp6_proc_exit(void) { - udp_proc_unregister(&udp6_seq_afinfo); +void udp6_proc_exit(struct net *net) { + udp_proc_unregister(net, &udp6_seq_afinfo); } #endif /* CONFIG_PROC_FS */ diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 87d4202522ee..815190be528c 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -115,11 +115,11 @@ static struct udp_seq_afinfo udplite6_seq_afinfo = { int __init udplite6_proc_init(void) { - return udp_proc_register(&udplite6_seq_afinfo); + return udp_proc_register(&init_net, &udplite6_seq_afinfo); } void udplite6_proc_exit(void) { - udp_proc_unregister(&udplite6_seq_afinfo); + udp_proc_unregister(&init_net, &udplite6_seq_afinfo); } #endif -- cgit v1.2.3-59-g8ed1b From 6f8b13bcb3369a5df2e63acc422bed6098f5b8c4 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Fri, 21 Mar 2008 04:14:45 -0700 Subject: [NETNS][IPV6] tcp6 - make proc per namespace Make the proc for tcp6 to be per namespace. Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/net/ipv6.h | 4 ++-- include/net/tcp.h | 4 ++-- net/ipv4/tcp_ipv4.c | 12 ++++++------ net/ipv6/af_inet6.c | 15 ++++++++++----- net/ipv6/tcp_ipv6.c | 8 ++++---- 5 files changed, 24 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index e01a563132e8..e82f1814d96b 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -595,8 +595,8 @@ extern int ac6_proc_init(void); extern void ac6_proc_exit(void); extern int raw6_proc_init(void); extern void raw6_proc_exit(void); -extern int tcp6_proc_init(void); -extern void tcp6_proc_exit(void); +extern int tcp6_proc_init(struct net *net); +extern void tcp6_proc_exit(struct net *net); extern int udp6_proc_init(struct net *net); extern void udp6_proc_exit(struct net *net); extern int udplite6_proc_init(void); diff --git a/include/net/tcp.h b/include/net/tcp.h index 6b08dab1b1fa..847e1634e1f4 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1336,8 +1336,8 @@ struct tcp_iter_state { struct seq_operations seq_ops; }; -extern int tcp_proc_register(struct tcp_seq_afinfo *afinfo); -extern void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo); +extern int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo); +extern void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo); extern struct request_sock_ops tcp_request_sock_ops; extern struct request_sock_ops tcp6_request_sock_ops; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index f9b30dc3bd6c..744bc9d6cebc 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2253,7 +2253,7 @@ static int tcp_seq_release(struct inode *inode, struct file *file) return 0; } -int tcp_proc_register(struct tcp_seq_afinfo *afinfo) +int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo) { int rc = 0; struct proc_dir_entry *p; @@ -2266,7 +2266,7 @@ int tcp_proc_register(struct tcp_seq_afinfo *afinfo) afinfo->seq_fops->llseek = seq_lseek; afinfo->seq_fops->release = tcp_seq_release; - p = proc_net_fops_create(&init_net, afinfo->name, S_IRUGO, afinfo->seq_fops); + p = proc_net_fops_create(net, afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) p->data = afinfo; else @@ -2274,11 +2274,11 @@ int tcp_proc_register(struct tcp_seq_afinfo *afinfo) return rc; } -void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo) +void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo) { if (!afinfo) return; - proc_net_remove(&init_net, afinfo->name); + proc_net_remove(net, afinfo->name); memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } @@ -2419,12 +2419,12 @@ static struct tcp_seq_afinfo tcp4_seq_afinfo = { int __init tcp4_proc_init(void) { - return tcp_proc_register(&tcp4_seq_afinfo); + return tcp_proc_register(&init_net, &tcp4_seq_afinfo); } void tcp4_proc_exit(void) { - tcp_proc_unregister(&tcp4_seq_afinfo); + tcp_proc_unregister(&init_net, &tcp4_seq_afinfo); } #endif /* CONFIG_PROC_FS */ diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index e3e09147d134..f52bdaed8a1b 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -859,15 +859,25 @@ static int inet6_net_init(struct net *net) err = udp6_proc_init(net); if (err) goto out; + err = tcp6_proc_init(net); + if (err) + goto proc_tcp6_fail; out: #endif return err; + +#ifdef CONFIG_PROC_FS +proc_tcp6_fail: + udp6_proc_exit(net); + goto out; +#endif } static void inet6_net_exit(struct net *net) { #ifdef CONFIG_PROC_FS udp6_proc_exit(net); + tcp6_proc_exit(net); #endif } @@ -951,8 +961,6 @@ static int __init inet6_init(void) err = -ENOMEM; if (raw6_proc_init()) goto proc_raw6_fail; - if (tcp6_proc_init()) - goto proc_tcp6_fail; if (udplite6_proc_init()) goto proc_udplite6_fail; if (ipv6_misc_proc_init()) @@ -1037,8 +1045,6 @@ proc_anycast6_fail: proc_misc6_fail: udplite6_proc_exit(); proc_udplite6_fail: - tcp6_proc_exit(); -proc_tcp6_fail: raw6_proc_exit(); proc_raw6_fail: #endif @@ -1098,7 +1104,6 @@ static void __exit inet6_exit(void) ac6_proc_exit(); ipv6_misc_proc_exit(); udplite6_proc_exit(); - tcp6_proc_exit(); raw6_proc_exit(); #endif ipv6_netfilter_fini(); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index caf0cc1c00e1..56d0cea7d578 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2129,14 +2129,14 @@ static struct tcp_seq_afinfo tcp6_seq_afinfo = { .seq_fops = &tcp6_seq_fops, }; -int __init tcp6_proc_init(void) +int tcp6_proc_init(struct net *net) { - return tcp_proc_register(&tcp6_seq_afinfo); + return tcp_proc_register(net, &tcp6_seq_afinfo); } -void tcp6_proc_exit(void) +void tcp6_proc_exit(struct net *net) { - tcp_proc_unregister(&tcp6_seq_afinfo); + tcp_proc_unregister(net, &tcp6_seq_afinfo); } #endif -- cgit v1.2.3-59-g8ed1b From b1153f29ee07dc1a788964409255a4b4fae50b98 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 21 Mar 2008 15:46:12 -0700 Subject: netlink: make socket filters work on netlink Make socket filters work for netlink unicast and notifications. This is useful for applications like Zebra that get overrun with messages that are then ignored. Note: netlink messages are in host byte order, but packet filter state machine operations are done as network byte order. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 524e826bb976..86bd8660a8f2 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -886,6 +886,13 @@ retry: if (netlink_is_kernel(sk)) return netlink_unicast_kernel(sk, skb); + if (sk_filter(sk, skb)) { + int err = skb->len; + kfree_skb(skb); + sock_put(sk); + return err; + } + err = netlink_attachskb(sk, skb, nonblock, &timeo, ssk); if (err == 1) goto retry; @@ -980,6 +987,9 @@ static inline int do_one_broadcast(struct sock *sk, netlink_overrun(sk); /* Clone failed. Notify ALL listeners. */ p->failure = 1; + } else if (sk_filter(sk, p->skb2)) { + kfree_skb(p->skb2); + p->skb2 = NULL; } else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) { netlink_overrun(sk); } else { @@ -1533,8 +1543,13 @@ static int netlink_dump(struct sock *sk) if (len > 0) { mutex_unlock(nlk->cb_mutex); - skb_queue_tail(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk, len); + + if (sk_filter(sk, skb)) + kfree_skb(skb); + else { + skb_queue_tail(&sk->sk_receive_queue, skb); + sk->sk_data_ready(sk, skb->len); + } return 0; } @@ -1544,8 +1559,12 @@ static int netlink_dump(struct sock *sk) memcpy(nlmsg_data(nlh), &len, sizeof(len)); - skb_queue_tail(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk, skb->len); + if (sk_filter(sk, skb)) + kfree_skb(skb); + else { + skb_queue_tail(&sk->sk_receive_queue, skb); + sk->sk_data_ready(sk, skb->len); + } if (cb->done) cb->done(cb); -- cgit v1.2.3-59-g8ed1b From 28518fc1701a757a3df8aa2d2ac2e5d1efd1c3e5 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 21 Mar 2008 15:52:00 -0700 Subject: [NET]: NULL pointer dereference and other nasty things in /proc/net/(tcp|udp)[6] Commits f40c81 ([NETNS][IPV4] tcp - make proc handle the network namespaces) and a91275 ([NETNS][IPV6] udp - make proc handle the network namespace) both introduced bad checks on sockets and tw buckets to belong to proper net namespace. I.e. when checking for socket to belong to given net and family the do { sk = sk_next(sk); } while (sk && sk->sk_net != net && sk->sk_family != family); constructions were used. This is wrong, since as soon as the sk->sk_net fits the net the socket is immediately returned, even if it belongs to other family. As the result four /proc/net/(udp|tcp)[6] entries show wrong info. The udp6 entry even oopses when dereferencing inet6_sk(sk) pointer: static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket) { ... struct ipv6_pinfo *np = inet6_sk(sp); ... dest = &np->daddr; /* will be NULL for AF_INET sockets */ ... seq_printf(... dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], ... Fix it by converting && to ||. Signed-off-by: Pavel Emelyanov Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 4 ++-- net/ipv4/udp.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 744bc9d6cebc..0ba6e911c979 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2050,7 +2050,7 @@ static void *established_get_first(struct seq_file *seq) st->state = TCP_SEQ_STATE_TIME_WAIT; inet_twsk_for_each(tw, node, &tcp_hashinfo.ehash[st->bucket].twchain) { - if (tw->tw_family != st->family && + if (tw->tw_family != st->family || tw->tw_net != net) { continue; } @@ -2078,7 +2078,7 @@ static void *established_get_next(struct seq_file *seq, void *cur) tw = cur; tw = tw_next(tw); get_tw: - while (tw && tw->tw_family != st->family && tw->tw_net != net) { + while (tw && (tw->tw_family != st->family || tw->tw_net != net)) { tw = tw_next(tw); } if (tw) { diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index a98c43c0a89c..fa946829d1e8 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1537,7 +1537,7 @@ static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) sk = sk_next(sk); try_again: ; - } while (sk && sk->sk_net != net && sk->sk_family != state->family); + } while (sk && (sk->sk_net != net || sk->sk_family != state->family)); if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { sk = sk_head(state->hashtable + state->bucket); -- cgit v1.2.3-59-g8ed1b From 539fae89bebd16ebeafd57a87169bc56eb530d76 Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Fri, 21 Mar 2008 16:27:38 -0700 Subject: [TCP]: TCP_DEFER_ACCEPT updates - defer timeout conflicts with max_thresh timeout associated with SO_DEFER_ACCEPT wasn't being honored if it was less than the timeout allowed by the maximum syn-recv queue size algorithm. Fix by using the SO_DEFER_ACCEPT value if the ack has arrived. Signed-off-by: Patrick McManus Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/inet_connection_sock.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index c0e0fa03fce1..f24c7d534081 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -461,8 +461,7 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, reqp=&lopt->syn_table[i]; while ((req = *reqp) != NULL) { if (time_after_eq(now, req->expires)) { - if ((req->retrans < thresh || - (inet_rsk(req)->acked && req->retrans < max_retries)) + if ((req->retrans < (inet_rsk(req)->acked ? max_retries : thresh)) && !req->rsk_ops->rtx_syn_ack(parent, req)) { unsigned long timeo; -- cgit v1.2.3-59-g8ed1b From e4c78840284f3f51b1896cf3936d60a6033c4d2c Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Fri, 21 Mar 2008 16:29:22 -0700 Subject: [TCP]: TCP_DEFER_ACCEPT updates - dont retxmt synack a socket in LISTEN that had completed its 3 way handshake, but not notified userspace because of SO_DEFER_ACCEPT, would retransmit the already acked syn-ack during the time it was waiting for the first data byte from the peer. Signed-off-by: Patrick McManus Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/inet_connection_sock.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index f24c7d534081..8a45be988709 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -461,8 +461,9 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, reqp=&lopt->syn_table[i]; while ((req = *reqp) != NULL) { if (time_after_eq(now, req->expires)) { - if ((req->retrans < (inet_rsk(req)->acked ? max_retries : thresh)) - && !req->rsk_ops->rtx_syn_ack(parent, req)) { + if ((req->retrans < (inet_rsk(req)->acked ? max_retries : thresh)) && + (inet_rsk(req)->acked || + !req->rsk_ops->rtx_syn_ack(parent, req))) { unsigned long timeo; if (req->retrans++ == 0) -- cgit v1.2.3-59-g8ed1b From ec3c0982a2dd1e671bad8e9d26c28dcba0039d87 Mon Sep 17 00:00:00 2001 From: Patrick McManus Date: Fri, 21 Mar 2008 16:33:01 -0700 Subject: [TCP]: TCP_DEFER_ACCEPT updates - process as established Change TCP_DEFER_ACCEPT implementation so that it transitions a connection to ESTABLISHED after handshake is complete instead of leaving it in SYN-RECV until some data arrvies. Place connection in accept queue when first data packet arrives from slow path. Benefits: - established connection is now reset if it never makes it to the accept queue - diagnostic state of established matches with the packet traces showing completed handshake - TCP_DEFER_ACCEPT timeouts are expressed in seconds and can now be enforced with reasonable accuracy instead of rounding up to next exponential back-off of syn-ack retry. Signed-off-by: Patrick McManus Signed-off-by: David S. Miller --- include/linux/tcp.h | 7 +++++++ include/net/request_sock.h | 4 ++-- include/net/tcp.h | 1 + net/ipv4/inet_connection_sock.c | 11 +++------- net/ipv4/tcp.c | 18 +++++++--------- net/ipv4/tcp_input.c | 46 +++++++++++++++++++++++++++++++++++++++++ net/ipv4/tcp_ipv4.c | 8 +++++++ net/ipv4/tcp_minisocks.c | 32 +++++++++++++++++----------- net/ipv4/tcp_timer.c | 5 +++++ 9 files changed, 99 insertions(+), 33 deletions(-) (limited to 'net') diff --git a/include/linux/tcp.h b/include/linux/tcp.h index 08027f1d7f31..d96d9b122304 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h @@ -239,6 +239,11 @@ static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) return (struct tcp_request_sock *)req; } +struct tcp_deferred_accept_info { + struct sock *listen_sk; + struct request_sock *request; +}; + struct tcp_sock { /* inet_connection_sock has to be the first member of tcp_sock */ struct inet_connection_sock inet_conn; @@ -374,6 +379,8 @@ struct tcp_sock { unsigned int keepalive_intvl; /* time interval between keep alive probes */ int linger2; + struct tcp_deferred_accept_info defer_tcp_accept; + unsigned long last_synq_overflow; u32 tso_deferred; diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 040780add355..0369f98e9f3a 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -115,8 +115,8 @@ struct request_sock_queue { struct request_sock *rskq_accept_head; struct request_sock *rskq_accept_tail; rwlock_t syn_wait_lock; - u8 rskq_defer_accept; - /* 3 bytes hole, try to pack */ + u16 rskq_defer_accept; + /* 2 bytes hole, try to pack */ struct listen_sock *listen_opt; }; diff --git a/include/net/tcp.h b/include/net/tcp.h index 847e1634e1f4..67cc3956d29c 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -139,6 +139,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define MAX_TCP_KEEPINTVL 32767 #define MAX_TCP_KEEPCNT 127 #define MAX_TCP_SYNCNT 127 +#define MAX_TCP_ACCEPT_DEFERRED 65535 #define TCP_SYNQ_INTERVAL (HZ/5) /* Period of SYNACK timer */ diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 8a45be988709..cc1a1859a61b 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -414,8 +414,7 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, struct inet_connection_sock *icsk = inet_csk(parent); struct request_sock_queue *queue = &icsk->icsk_accept_queue; struct listen_sock *lopt = queue->listen_opt; - int max_retries = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries; - int thresh = max_retries; + int thresh = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries; unsigned long now = jiffies; struct request_sock **reqp, *req; int i, budget; @@ -451,9 +450,6 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, } } - if (queue->rskq_defer_accept) - max_retries = queue->rskq_defer_accept; - budget = 2 * (lopt->nr_table_entries / (timeout / interval)); i = lopt->clock_hand; @@ -461,9 +457,8 @@ void inet_csk_reqsk_queue_prune(struct sock *parent, reqp=&lopt->syn_table[i]; while ((req = *reqp) != NULL) { if (time_after_eq(now, req->expires)) { - if ((req->retrans < (inet_rsk(req)->acked ? max_retries : thresh)) && - (inet_rsk(req)->acked || - !req->rsk_ops->rtx_syn_ack(parent, req))) { + if (req->retrans < thresh && + !req->rsk_ops->rtx_syn_ack(parent, req)) { unsigned long timeo; if (req->retrans++ == 0) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 071e83a894ad..e0fbc25ca816 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -2105,15 +2105,12 @@ static int do_tcp_setsockopt(struct sock *sk, int level, break; case TCP_DEFER_ACCEPT: - icsk->icsk_accept_queue.rskq_defer_accept = 0; - if (val > 0) { - /* Translate value in seconds to number of - * retransmits */ - while (icsk->icsk_accept_queue.rskq_defer_accept < 32 && - val > ((TCP_TIMEOUT_INIT / HZ) << - icsk->icsk_accept_queue.rskq_defer_accept)) - icsk->icsk_accept_queue.rskq_defer_accept++; - icsk->icsk_accept_queue.rskq_defer_accept++; + if (val < 0) { + err = -EINVAL; + } else { + if (val > MAX_TCP_ACCEPT_DEFERRED) + val = MAX_TCP_ACCEPT_DEFERRED; + icsk->icsk_accept_queue.rskq_defer_accept = val; } break; @@ -2295,8 +2292,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level, val = (val ? : sysctl_tcp_fin_timeout) / HZ; break; case TCP_DEFER_ACCEPT: - val = !icsk->icsk_accept_queue.rskq_defer_accept ? 0 : - ((TCP_TIMEOUT_INIT / HZ) << (icsk->icsk_accept_queue.rskq_defer_accept - 1)); + val = icsk->icsk_accept_queue.rskq_defer_accept; break; case TCP_WINDOW_CLAMP: val = tp->window_clamp; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 9cf446427cc2..6e46b4c0f28c 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4451,6 +4451,49 @@ static void tcp_urg(struct sock *sk, struct sk_buff *skb, struct tcphdr *th) } } +static int tcp_defer_accept_check(struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + + if (tp->defer_tcp_accept.request) { + int queued_data = tp->rcv_nxt - tp->copied_seq; + int hasfin = !skb_queue_empty(&sk->sk_receive_queue) ? + tcp_hdr((struct sk_buff *) + sk->sk_receive_queue.prev)->fin : 0; + + if (queued_data && hasfin) + queued_data--; + + if (queued_data && + tp->defer_tcp_accept.listen_sk->sk_state == TCP_LISTEN) { + if (sock_flag(sk, SOCK_KEEPOPEN)) { + inet_csk_reset_keepalive_timer(sk, + keepalive_time_when(tp)); + } else { + inet_csk_delete_keepalive_timer(sk); + } + + inet_csk_reqsk_queue_add( + tp->defer_tcp_accept.listen_sk, + tp->defer_tcp_accept.request, + sk); + + tp->defer_tcp_accept.listen_sk->sk_data_ready( + tp->defer_tcp_accept.listen_sk, 0); + + sock_put(tp->defer_tcp_accept.listen_sk); + sock_put(sk); + tp->defer_tcp_accept.listen_sk = NULL; + tp->defer_tcp_accept.request = NULL; + } else if (hasfin || + tp->defer_tcp_accept.listen_sk->sk_state != TCP_LISTEN) { + tcp_reset(sk); + return -1; + } + } + return 0; +} + static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen) { struct tcp_sock *tp = tcp_sk(sk); @@ -4811,6 +4854,9 @@ step5: tcp_data_snd_check(sk); tcp_ack_snd_check(sk); + + if (tcp_defer_accept_check(sk)) + return -1; return 0; csum_error: diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0ba6e911c979..167a0f557531 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1920,6 +1920,14 @@ int tcp_v4_destroy_sock(struct sock *sk) sk->sk_sndmsg_page = NULL; } + if (tp->defer_tcp_accept.request) { + reqsk_free(tp->defer_tcp_accept.request); + sock_put(tp->defer_tcp_accept.listen_sk); + sock_put(sk); + tp->defer_tcp_accept.listen_sk = NULL; + tp->defer_tcp_accept.request = NULL; + } + atomic_dec(&tcp_sockets_allocated); return 0; diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 8245247a6ceb..019c8c16e5cc 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -571,10 +571,8 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, does sequence test, SYN is truncated, and thus we consider it a bare ACK. - If icsk->icsk_accept_queue.rskq_defer_accept, we silently drop this - bare ACK. Otherwise, we create an established connection. Both - ends (listening sockets) accept the new incoming connection and try - to talk to each other. 8-) + Both ends (listening sockets) accept the new incoming + connection and try to talk to each other. 8-) Note: This case is both harmless, and rare. Possibility is about the same as us discovering intelligent life on another plant tomorrow. @@ -642,13 +640,6 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, if (!(flg & TCP_FLAG_ACK)) return NULL; - /* If TCP_DEFER_ACCEPT is set, drop bare ACK. */ - if (inet_csk(sk)->icsk_accept_queue.rskq_defer_accept && - TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) { - inet_rsk(req)->acked = 1; - return NULL; - } - /* OK, ACK is valid, create big socket and * feed this segment to it. It will repeat all * the tests. THIS SEGMENT MUST MOVE SOCKET TO @@ -687,7 +678,24 @@ struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, inet_csk_reqsk_queue_unlink(sk, req, prev); inet_csk_reqsk_queue_removed(sk, req); - inet_csk_reqsk_queue_add(sk, req, child); + if (inet_csk(sk)->icsk_accept_queue.rskq_defer_accept && + TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) { + + /* the accept queue handling is done is est recv slow + * path so lets make sure to start there + */ + tcp_sk(child)->pred_flags = 0; + sock_hold(sk); + sock_hold(child); + tcp_sk(child)->defer_tcp_accept.listen_sk = sk; + tcp_sk(child)->defer_tcp_accept.request = req; + + inet_csk_reset_keepalive_timer(child, + inet_csk(sk)->icsk_accept_queue.rskq_defer_accept * HZ); + } else { + inet_csk_reqsk_queue_add(sk, req, child); + } + return child; listen_overflow: diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 803d758a2b12..160d16f9f4fc 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -481,6 +481,11 @@ static void tcp_keepalive_timer (unsigned long data) goto death; } + if (tp->defer_tcp_accept.request && sk->sk_state == TCP_ESTABLISHED) { + tcp_send_active_reset(sk, GFP_ATOMIC); + goto death; + } + if (!sock_flag(sk, SOCK_KEEPOPEN) || sk->sk_state == TCP_CLOSE) goto out; -- cgit v1.2.3-59-g8ed1b From 10fe7d85e2e4042f703a10bed4123f2105eadad2 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sat, 22 Mar 2008 16:35:00 -0700 Subject: [IPV4]: Remove unnecessary check for opt->is_data in ip_options_compile. There is the only way to reach ip_options compile with opt != NULL: ip_options_get_finish opt->is_data = 1; ip_options_compile(opt, NULL) So, checking for is_data inside opt != NULL branch is not needed. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/ip_options.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index df93a9c2efda..7e94bf850a07 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -267,8 +267,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) optptr = iph + sizeof(struct iphdr); opt->is_data = 0; } else { - optptr = opt->is_data ? opt->__data : - (unsigned char *)&(ip_hdr(skb)[1]); + optptr = opt->__data; iph = optptr - sizeof(struct iphdr); } -- cgit v1.2.3-59-g8ed1b From ef722495c8867aacc1db0675a6737e5cf1e72e07 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sat, 22 Mar 2008 16:35:29 -0700 Subject: [IPV4]: Remove unused ip_options->is_data. ip_options->is_data is assigned only and never checked. The structure is not a part of kernel interface to the userspace. So, it is safe to remove this field. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/inet_sock.h | 3 +-- net/ipv4/cipso_ipv4.c | 1 - net/ipv4/ip_options.c | 5 ----- 3 files changed, 1 insertion(+), 8 deletions(-) (limited to 'net') diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index 8660cb0fa0dd..b6db16d2766a 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -43,8 +43,7 @@ struct ip_options { unsigned char srr; unsigned char rr; unsigned char ts; - unsigned char is_data:1, - is_strictroute:1, + unsigned char is_strictroute:1, srr_is_hit:1, is_changed:1, rr_needaddr:1, diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 8cd357f41283..4637ded3dba8 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -1800,7 +1800,6 @@ int cipso_v4_sock_setattr(struct sock *sk, } memcpy(opt->__data, buf, buf_len); opt->optlen = opt_len; - opt->is_data = 1; opt->cipso = sizeof(struct iphdr); kfree(buf); buf = NULL; diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 7e94bf850a07..2fa411381b11 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -45,7 +45,6 @@ void ip_options_build(struct sk_buff * skb, struct ip_options * opt, memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options)); memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen); opt = &(IPCB(skb)->opt); - opt->is_data = 0; if (opt->srr) memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4); @@ -95,8 +94,6 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) memset(dopt, 0, sizeof(struct ip_options)); - dopt->is_data = 1; - sopt = &(IPCB(skb)->opt); if (sopt->optlen == 0) { @@ -265,7 +262,6 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) iph = skb_network_header(skb); opt->optlen = ((struct iphdr *)iph)->ihl*4 - sizeof(struct iphdr); optptr = iph + sizeof(struct iphdr); - opt->is_data = 0; } else { optptr = opt->__data; iph = optptr - sizeof(struct iphdr); @@ -519,7 +515,6 @@ static int ip_options_get_finish(struct ip_options **optp, while (optlen & 3) opt->__data[optlen++] = IPOPT_END; opt->optlen = optlen; - opt->is_data = 1; if (optlen && ip_options_compile(opt, NULL)) { kfree(opt); return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 22aba383ce52f8ca8740f9a74dc66b1b68138813 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sat, 22 Mar 2008 16:36:20 -0700 Subject: [IPV4]: Always pass ip_options pointer into ip_options_compile. This makes code a bit more uniform and straigthforward. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/ip_input.c | 5 +++-- net/ipv4/ip_options.c | 17 +++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index d36e310b314d..e3a0c78fa7bf 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -283,13 +283,14 @@ static inline int ip_rcv_options(struct sk_buff *skb) } iph = ip_hdr(skb); + opt = &(IPCB(skb)->opt); + opt->optlen = iph->ihl*4 - sizeof(struct iphdr); - if (ip_options_compile(NULL, skb)) { + if (ip_options_compile(opt, skb)) { IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); goto drop; } - opt = &(IPCB(skb)->opt); if (unlikely(opt->srr)) { struct in_device *in_dev = in_dev_get(dev); if (in_dev) { diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 2fa411381b11..aeed4e5858ec 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -255,17 +255,14 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) unsigned char * optptr; int optlen; unsigned char * pp_ptr = NULL; - struct rtable *rt = skb ? skb->rtable : NULL; - - if (!opt) { - opt = &(IPCB(skb)->opt); - iph = skb_network_header(skb); - opt->optlen = ((struct iphdr *)iph)->ihl*4 - sizeof(struct iphdr); - optptr = iph + sizeof(struct iphdr); - } else { + struct rtable *rt = NULL; + + if (skb != NULL) { + rt = skb->rtable; + optptr = (unsigned char *)&(ip_hdr(skb)[1]); + } else optptr = opt->__data; - iph = optptr - sizeof(struct iphdr); - } + iph = optptr - sizeof(struct iphdr); for (l = opt->optlen; l > 0; ) { switch (*optptr) { -- cgit v1.2.3-59-g8ed1b From 39d8cda76cfb1178455f9d196b39e773878e6c05 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 22 Mar 2008 16:50:58 -0700 Subject: [SOCK]: Add udp_hash member to struct proto. Inspired by the commit ab1e0a13 ([SOCK] proto: Add hashinfo member to struct proto) from Arnaldo, I made similar thing for UDP/-Lite IPv4 and -v6 protocols. The result is not that exciting, but it removes some levels of indirection in udpxxx_get_port and saves some space in code and text. The first step is to union existing hashinfo and new udp_hash on the struct proto and give a name to this union, since future initialization of tcpxxx_prot, dccp_vx_protinfo and udpxxx_protinfo will cause gcc warning about inability to initialize anonymous member this way. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/net/inet_hashtables.h | 2 +- include/net/sock.h | 5 ++++- net/dccp/ipv4.c | 2 +- net/dccp/ipv6.c | 2 +- net/ipv4/inet_connection_sock.c | 2 +- net/ipv4/inet_hashtables.c | 8 ++++---- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/inet6_hashtables.c | 2 +- net/ipv6/tcp_ipv6.c | 2 +- 9 files changed, 15 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 97dc35ad09be..d99c1ba2ece0 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -223,7 +223,7 @@ static inline int inet_sk_listen_hashfn(const struct sock *sk) /* Caller must disable local BH processing. */ static inline void __inet_inherit_port(struct sock *sk, struct sock *child) { - struct inet_hashinfo *table = sk->sk_prot->hashinfo; + struct inet_hashinfo *table = sk->sk_prot->h.hashinfo; const int bhash = inet_bhashfn(inet_sk(child)->num, table->bhash_size); struct inet_bind_hashbucket *head = &table->bhash[bhash]; struct inet_bind_bucket *tb; diff --git a/include/net/sock.h b/include/net/sock.h index b89680d2693b..c3175c400b79 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -586,7 +586,10 @@ struct proto { struct request_sock_ops *rsk_prot; struct timewait_sock_ops *twsk_prot; - struct inet_hashinfo *hashinfo; + union { + struct inet_hashinfo *hashinfo; + struct hlist_head *udp_hash; + } h; struct module *owner; diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 17ad69e90e48..4ca8b0c93c80 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -941,7 +941,7 @@ static struct proto dccp_v4_prot = { .obj_size = sizeof(struct dccp_sock), .rsk_prot = &dccp_request_sock_ops, .twsk_prot = &dccp_timewait_sock_ops, - .hashinfo = &dccp_hashinfo, + .h.hashinfo = &dccp_hashinfo, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_dccp_setsockopt, .compat_getsockopt = compat_dccp_getsockopt, diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 1a5e50b90677..2fec1af1a8c3 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1126,7 +1126,7 @@ static struct proto dccp_v6_prot = { .obj_size = sizeof(struct dccp6_sock), .rsk_prot = &dccp6_request_sock_ops, .twsk_prot = &dccp6_timewait_sock_ops, - .hashinfo = &dccp_hashinfo, + .h.hashinfo = &dccp_hashinfo, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_dccp_setsockopt, .compat_getsockopt = compat_dccp_getsockopt, diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index cc1a1859a61b..f9c5c4def1ba 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -80,7 +80,7 @@ EXPORT_SYMBOL_GPL(inet_csk_bind_conflict); */ int inet_csk_get_port(struct sock *sk, unsigned short snum) { - struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo; + struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; struct inet_bind_hashbucket *head; struct hlist_node *node; struct inet_bind_bucket *tb; diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 1aba606f6bbb..8cd1ad9b9111 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -68,7 +68,7 @@ void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb, */ static void __inet_put_port(struct sock *sk) { - struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo; + struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; const int bhash = inet_bhashfn(inet_sk(sk)->num, hashinfo->bhash_size); struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash]; struct inet_bind_bucket *tb; @@ -318,7 +318,7 @@ static inline u32 inet_sk_port_offset(const struct sock *sk) void __inet_hash_nolisten(struct sock *sk) { - struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo; + struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; struct hlist_head *list; rwlock_t *lock; struct inet_ehash_bucket *head; @@ -339,7 +339,7 @@ EXPORT_SYMBOL_GPL(__inet_hash_nolisten); static void __inet_hash(struct sock *sk) { - struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo; + struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; struct hlist_head *list; rwlock_t *lock; @@ -372,7 +372,7 @@ EXPORT_SYMBOL_GPL(inet_hash); void inet_unhash(struct sock *sk) { rwlock_t *lock; - struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo; + struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; if (sk_unhashed(sk)) goto out; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 167a0f557531..1a47719a55ad 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2468,7 +2468,7 @@ struct proto tcp_prot = { .obj_size = sizeof(struct tcp_sock), .twsk_prot = &tcp_timewait_sock_ops, .rsk_prot = &tcp_request_sock_ops, - .hashinfo = &tcp_hashinfo, + .h.hashinfo = &tcp_hashinfo, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_tcp_setsockopt, .compat_getsockopt = compat_tcp_getsockopt, diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 99fd25f7f005..c0c8d2d17682 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -24,7 +24,7 @@ void __inet6_hash(struct sock *sk) { - struct inet_hashinfo *hashinfo = sk->sk_prot->hashinfo; + struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; struct hlist_head *list; rwlock_t *lock; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 56d0cea7d578..8dd72966ff78 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2172,7 +2172,7 @@ struct proto tcpv6_prot = { .obj_size = sizeof(struct tcp6_sock), .twsk_prot = &tcp6_timewait_sock_ops, .rsk_prot = &tcp6_request_sock_ops, - .hashinfo = &tcp_hashinfo, + .h.hashinfo = &tcp_hashinfo, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_tcp_setsockopt, .compat_getsockopt = compat_tcp_getsockopt, -- cgit v1.2.3-59-g8ed1b From 6ba5a3c52da00015e739469e3b00cd6d0d4c5c67 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 22 Mar 2008 16:51:21 -0700 Subject: [UDP]: Make full use of proto.h.udp_hash innovation. After this we have only udp_lib_get_port to get the port and two stubs for ipv4 and ipv6. No difference in udp and udplite except for initialized h.udp_hash member. I tried to find a graceful way to drop the only difference between udp_v4_get_port and udp_v6_get_port (i.e. the rcv_saddr comparison routine), but adding one more callback on the struct proto didn't appear such :( Maybe later. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/net/udp.h | 2 ++ net/ipv4/udp.c | 22 ++++++++-------------- net/ipv4/udp_impl.h | 6 +----- net/ipv4/udplite.c | 15 ++------------- net/ipv6/udp.c | 5 +++-- net/ipv6/udp_impl.h | 2 ++ net/ipv6/udplite.c | 8 ++------ 7 files changed, 20 insertions(+), 40 deletions(-) (limited to 'net') diff --git a/include/net/udp.h b/include/net/udp.h index b4cbdce883d1..635940d374ab 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -125,6 +125,8 @@ static inline void udp_lib_close(struct sock *sk, long timeout) sk_common_release(sk); } +extern int udp_lib_get_port(struct sock *sk, unsigned short snum, + int (*)(const struct sock*,const struct sock*)); /* net/ipv4/udp.c */ extern int udp_get_port(struct sock *sk, unsigned short snum, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index fa946829d1e8..8c1f5eaafcd2 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -143,18 +143,17 @@ static inline int __udp_lib_lport_inuse(struct net *net, __u16 num, } /** - * __udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 + * udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 * * @sk: socket struct in question * @snum: port number to look up - * @udptable: hash list table, must be of UDP_HTABLE_SIZE * @saddr_comp: AF-dependent comparison of bound local IP addresses */ -int __udp_lib_get_port(struct sock *sk, unsigned short snum, - struct hlist_head udptable[], +int udp_lib_get_port(struct sock *sk, unsigned short snum, int (*saddr_comp)(const struct sock *sk1, const struct sock *sk2 ) ) { + struct hlist_head *udptable = sk->sk_prot->h.udp_hash; struct hlist_node *node; struct hlist_head *head; struct sock *sk2; @@ -240,13 +239,7 @@ fail: return error; } -int udp_get_port(struct sock *sk, unsigned short snum, - int (*scmp)(const struct sock *, const struct sock *)) -{ - return __udp_lib_get_port(sk, snum, udp_hash, scmp); -} - -int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) +static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) { struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); @@ -255,9 +248,9 @@ int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) inet1->rcv_saddr == inet2->rcv_saddr )); } -static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) +int udp_v4_get_port(struct sock *sk, unsigned short snum) { - return udp_get_port(sk, snum, ipv4_rcv_saddr_equal); + return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal); } /* UDP is nearly always wildcards out the wazoo, it makes no sense to try @@ -1498,6 +1491,7 @@ struct proto udp_prot = { .sysctl_wmem = &sysctl_udp_wmem_min, .sysctl_rmem = &sysctl_udp_rmem_min, .obj_size = sizeof(struct udp_sock), + .h.udp_hash = udp_hash, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_udp_setsockopt, .compat_getsockopt = compat_udp_getsockopt, @@ -1741,12 +1735,12 @@ EXPORT_SYMBOL(udp_disconnect); EXPORT_SYMBOL(udp_hash); EXPORT_SYMBOL(udp_hash_lock); EXPORT_SYMBOL(udp_ioctl); -EXPORT_SYMBOL(udp_get_port); EXPORT_SYMBOL(udp_prot); EXPORT_SYMBOL(udp_sendmsg); EXPORT_SYMBOL(udp_lib_getsockopt); EXPORT_SYMBOL(udp_lib_setsockopt); EXPORT_SYMBOL(udp_poll); +EXPORT_SYMBOL(udp_lib_get_port); #ifdef CONFIG_PROC_FS EXPORT_SYMBOL(udp_proc_register); diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h index 6c55828e41ba..7288bf7977fb 100644 --- a/net/ipv4/udp_impl.h +++ b/net/ipv4/udp_impl.h @@ -8,11 +8,7 @@ extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int ); extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []); -extern int __udp_lib_get_port(struct sock *sk, unsigned short snum, - struct hlist_head udptable[], - int (*)(const struct sock*,const struct sock*)); -extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *); - +extern int udp_v4_get_port(struct sock *sk, unsigned short snum); extern int udp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen); diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 2469b5104587..8d42e344b043 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -17,17 +17,6 @@ DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics) __read_mostly; struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; -int udplite_get_port(struct sock *sk, unsigned short p, - int (*c)(const struct sock *, const struct sock *)) -{ - return __udp_lib_get_port(sk, p, udplite_hash, c); -} - -static int udplite_v4_get_port(struct sock *sk, unsigned short snum) -{ - return udplite_get_port(sk, snum, ipv4_rcv_saddr_equal); -} - static int udplite_rcv(struct sk_buff *skb) { return __udp4_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); @@ -63,8 +52,9 @@ struct proto udplite_prot = { .backlog_rcv = udp_queue_rcv_skb, .hash = udp_lib_hash, .unhash = udp_lib_unhash, - .get_port = udplite_v4_get_port, + .get_port = udp_v4_get_port, .obj_size = sizeof(struct udp_sock), + .h.udp_hash = udplite_hash, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_udp_setsockopt, .compat_getsockopt = compat_udp_getsockopt, @@ -118,4 +108,3 @@ out_register_err: EXPORT_SYMBOL(udplite_hash); EXPORT_SYMBOL(udplite_prot); -EXPORT_SYMBOL(udplite_get_port); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index af619d48ba80..5f5d1218c34e 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -51,9 +51,9 @@ #include #include "udp_impl.h" -static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) +int udp_v6_get_port(struct sock *sk, unsigned short snum) { - return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); + return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal); } static struct sock *__udp6_lib_lookup(struct net *net, @@ -1024,6 +1024,7 @@ struct proto udpv6_prot = { .sysctl_wmem = &sysctl_udp_wmem_min, .sysctl_rmem = &sysctl_udp_rmem_min, .obj_size = sizeof(struct udp6_sock), + .h.udp_hash = udp_hash, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_udpv6_setsockopt, .compat_getsockopt = compat_udpv6_getsockopt, diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h index 21be3a83e7bc..321b81a4d418 100644 --- a/net/ipv6/udp_impl.h +++ b/net/ipv6/udp_impl.h @@ -11,6 +11,8 @@ extern int __udp6_lib_rcv(struct sk_buff *, struct hlist_head [], int ); extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, int , int , int , __be32 , struct hlist_head []); +extern int udp_v6_get_port(struct sock *sk, unsigned short snum); + extern int udpv6_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); extern int udpv6_setsockopt(struct sock *sk, int level, int optname, diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 815190be528c..93e52e0d57f2 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -35,11 +35,6 @@ static struct inet6_protocol udplitev6_protocol = { .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; -static int udplite_v6_get_port(struct sock *sk, unsigned short snum) -{ - return udplite_get_port(sk, snum, ipv6_rcv_saddr_equal); -} - DEFINE_PROTO_INUSE(udplitev6) struct proto udplitev6_prot = { @@ -58,8 +53,9 @@ struct proto udplitev6_prot = { .backlog_rcv = udpv6_queue_rcv_skb, .hash = udp_lib_hash, .unhash = udp_lib_unhash, - .get_port = udplite_v6_get_port, + .get_port = udp_v6_get_port, .obj_size = sizeof(struct udp6_sock), + .h.udp_hash = udplite_hash, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_udpv6_setsockopt, .compat_getsockopt = compat_udpv6_getsockopt, -- cgit v1.2.3-59-g8ed1b From fc8717baa8f52dd8d1b90df9008300ef3ec794ed Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sat, 22 Mar 2008 16:56:51 -0700 Subject: [RAW]: Add raw_hashinfo member on struct proto. Sorry for the patch sequence confusion :| but I found that the similar thing can be done for raw sockets easily too late. Expand the proto.h union with the raw_hashinfo member and use it in raw_prot and rawv6_prot. This allows to drop the protocol specific versions of hash and unhash callbacks. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/net/raw.h | 4 ++-- include/net/sock.h | 2 ++ net/ipv4/raw.c | 22 ++++++++-------------- net/ipv6/raw.c | 16 +++------------- 4 files changed, 15 insertions(+), 29 deletions(-) (limited to 'net') diff --git a/include/net/raw.h b/include/net/raw.h index 1828f81fe374..6c14a656357a 100644 --- a/include/net/raw.h +++ b/include/net/raw.h @@ -53,7 +53,7 @@ int raw_seq_open(struct inode *ino, struct file *file, #endif -void raw_hash_sk(struct sock *sk, struct raw_hashinfo *h); -void raw_unhash_sk(struct sock *sk, struct raw_hashinfo *h); +void raw_hash_sk(struct sock *sk); +void raw_unhash_sk(struct sock *sk); #endif /* _RAW_H */ diff --git a/include/net/sock.h b/include/net/sock.h index c3175c400b79..b433b1ed203d 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -504,6 +504,7 @@ extern int sk_wait_data(struct sock *sk, long *timeo); struct request_sock_ops; struct timewait_sock_ops; struct inet_hashinfo; +struct raw_hashinfo; /* Networking protocol blocks we attach to sockets. * socket layer -> transport layer interface @@ -589,6 +590,7 @@ struct proto { union { struct inet_hashinfo *hashinfo; struct hlist_head *udp_hash; + struct raw_hashinfo *raw_hash; } h; struct module *owner; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index e10ef6c2202a..b433b485a883 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -84,8 +84,9 @@ static struct raw_hashinfo raw_v4_hashinfo = { .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock), }; -void raw_hash_sk(struct sock *sk, struct raw_hashinfo *h) +void raw_hash_sk(struct sock *sk) { + struct raw_hashinfo *h = sk->sk_prot->h.raw_hash; struct hlist_head *head; head = &h->ht[inet_sk(sk)->num & (RAW_HTABLE_SIZE - 1)]; @@ -97,8 +98,10 @@ void raw_hash_sk(struct sock *sk, struct raw_hashinfo *h) } EXPORT_SYMBOL_GPL(raw_hash_sk); -void raw_unhash_sk(struct sock *sk, struct raw_hashinfo *h) +void raw_unhash_sk(struct sock *sk) { + struct raw_hashinfo *h = sk->sk_prot->h.raw_hash; + write_lock_bh(&h->lock); if (sk_del_node_init(sk)) sock_prot_inuse_add(sk->sk_prot, -1); @@ -106,16 +109,6 @@ void raw_unhash_sk(struct sock *sk, struct raw_hashinfo *h) } EXPORT_SYMBOL_GPL(raw_unhash_sk); -static void raw_v4_hash(struct sock *sk) -{ - raw_hash_sk(sk, &raw_v4_hashinfo); -} - -static void raw_v4_unhash(struct sock *sk) -{ - raw_unhash_sk(sk, &raw_v4_hashinfo); -} - static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, unsigned short num, __be32 raddr, __be32 laddr, int dif) { @@ -841,9 +834,10 @@ struct proto raw_prot = { .recvmsg = raw_recvmsg, .bind = raw_bind, .backlog_rcv = raw_rcv_skb, - .hash = raw_v4_hash, - .unhash = raw_v4_unhash, + .hash = raw_hash_sk, + .unhash = raw_unhash_sk, .obj_size = sizeof(struct raw_sock), + .h.raw_hash = &raw_v4_hashinfo, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_raw_setsockopt, .compat_getsockopt = compat_raw_getsockopt, diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index d6afa0216759..a9e4235157a2 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -65,17 +65,6 @@ static struct raw_hashinfo raw_v6_hashinfo = { .lock = __RW_LOCK_UNLOCKED(raw_v6_hashinfo.lock), }; -static void raw_v6_hash(struct sock *sk) -{ - raw_hash_sk(sk, &raw_v6_hashinfo); -} - -static void raw_v6_unhash(struct sock *sk) -{ - raw_unhash_sk(sk, &raw_v6_hashinfo); -} - - static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, unsigned short num, struct in6_addr *loc_addr, struct in6_addr *rmt_addr, int dif) @@ -1201,9 +1190,10 @@ struct proto rawv6_prot = { .recvmsg = rawv6_recvmsg, .bind = rawv6_bind, .backlog_rcv = rawv6_rcv_skb, - .hash = raw_v6_hash, - .unhash = raw_v6_unhash, + .hash = raw_hash_sk, + .unhash = raw_unhash_sk, .obj_size = sizeof(struct raw6_sock), + .h.raw_hash = &raw_v6_hashinfo, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_rawv6_setsockopt, .compat_getsockopt = compat_rawv6_getsockopt, -- cgit v1.2.3-59-g8ed1b From ce259990785595420ace616faece09255bad1163 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sat, 22 Mar 2008 17:42:37 -0700 Subject: [IPV4]: sk parameter is unused in ipv4_dst_blackhole. Just remove it. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/route.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 1051326c36b2..9ba3413a9909 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2520,7 +2520,7 @@ static struct dst_ops ipv4_dst_blackhole_ops = { }; -static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock *sk) +static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp) { struct rtable *ort = *rp; struct rtable *rt = (struct rtable *) @@ -2580,7 +2580,7 @@ int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp, err = __xfrm_lookup((struct dst_entry **)rp, flp, sk, flags ? XFRM_LOOKUP_WAIT : 0); if (err == -EREMOTE) - err = ipv4_dst_blackhole(rp, flp, sk); + err = ipv4_dst_blackhole(rp, flp); return err; } -- cgit v1.2.3-59-g8ed1b From 817bc4db7794d6dc6594265ddea88d2b839cf2f8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sat, 22 Mar 2008 17:43:59 -0700 Subject: [IPV4] route: use read_mostly The route table parameters are set based on system memory and sysctl values that almost never change. Also the genid only changes every 10 minutes. RTprint is defined by never used. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/route.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 9ba3413a9909..2941ef21f203 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -118,21 +118,19 @@ #define RT_GC_TIMEOUT (300*HZ) static int ip_rt_max_size; -static int ip_rt_gc_timeout = RT_GC_TIMEOUT; -static int ip_rt_gc_interval = 60 * HZ; -static int ip_rt_gc_min_interval = HZ / 2; -static int ip_rt_redirect_number = 9; -static int ip_rt_redirect_load = HZ / 50; -static int ip_rt_redirect_silence = ((HZ / 50) << (9 + 1)); -static int ip_rt_error_cost = HZ; -static int ip_rt_error_burst = 5 * HZ; -static int ip_rt_gc_elasticity = 8; -static int ip_rt_mtu_expires = 10 * 60 * HZ; -static int ip_rt_min_pmtu = 512 + 20 + 20; -static int ip_rt_min_advmss = 256; -static int ip_rt_secret_interval = 10 * 60 * HZ; - -#define RTprint(a...) printk(KERN_DEBUG a) +static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT; +static int ip_rt_gc_interval __read_mostly = 60 * HZ; +static int ip_rt_gc_min_interval __read_mostly = HZ / 2; +static int ip_rt_redirect_number __read_mostly = 9; +static int ip_rt_redirect_load __read_mostly = HZ / 50; +static int ip_rt_redirect_silence __read_mostly = ((HZ / 50) << (9 + 1)); +static int ip_rt_error_cost __read_mostly = HZ; +static int ip_rt_error_burst __read_mostly = 5 * HZ; +static int ip_rt_gc_elasticity __read_mostly = 8; +static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; +static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; +static int ip_rt_min_advmss __read_mostly = 256; +static int ip_rt_secret_interval __read_mostly = 10 * 60 * HZ; static void rt_worker_func(struct work_struct *work); static DECLARE_DELAYED_WORK(expires_work, rt_worker_func); @@ -252,10 +250,10 @@ static inline void rt_hash_lock_init(void) } #endif -static struct rt_hash_bucket *rt_hash_table; -static unsigned rt_hash_mask; -static unsigned int rt_hash_log; -static atomic_t rt_genid; +static struct rt_hash_bucket *rt_hash_table __read_mostly; +static unsigned rt_hash_mask __read_mostly; +static unsigned int rt_hash_log __read_mostly; +static atomic_t rt_genid __read_mostly; static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat); #define RT_CACHE_STAT_INC(field) \ -- cgit v1.2.3-59-g8ed1b From 061964fb988ca51087948975da66ff523b3a5852 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Sun, 23 Mar 2008 21:58:44 -0700 Subject: [IPV6]: Remove unused code in ndisc_send_redirect(). This patches removes unused code in ndisc_send_redirect() method in net/ipv6/ndisc.c. Signed-off-by: Rami Rosen Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 24e76ed98884..e7d8e74704c1 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1407,7 +1407,6 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, u8 *opt; int rd_len; int err; - int hlen; u8 ha_buf[MAX_ADDR_LEN], *ha = NULL; if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { @@ -1476,8 +1475,6 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, return; } - hlen = 0; - skb_reserve(buff, LL_RESERVED_SPACE(dev)); ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr, IPPROTO_ICMPV6, len); -- cgit v1.2.3-59-g8ed1b From 2051f11fb86b0056fec440fe7e9fa8370d60a5c6 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sun, 23 Mar 2008 22:21:28 -0700 Subject: [TCP]: Shrink syncookie_secret by 8 byte. the first u32 copied from syncookie_secret is overwritten by the minute-counter four lines below. After adjusting the destination address, the size of syncookie_secret can be reduced accordingly. AFAICS, the only other user of syncookie_secret[] is the ipv6 syncookie support. Because ipv6 syncookies only grab 44 bytes from syncookie_secret[], this shouldn't affect them in any way. With fixes from Glenn Griffin. Signed-off-by: Florian Westphal Acked-by: Glenn Griffin Signed-off-by: David S. Miller --- include/net/tcp.h | 2 +- net/ipv4/syncookies.c | 4 ++-- net/ipv6/syncookies.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/tcp.h b/include/net/tcp.h index 67cc3956d29c..723b36851dde 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -436,7 +436,7 @@ extern int tcp_disconnect(struct sock *sk, int flags); extern void tcp_unhash(struct sock *sk); /* From syncookies.c */ -extern __u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS]; +extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS]; extern struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, struct ip_options *opt); extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index 4704f27f6c0b..abc752d45cf7 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -21,7 +21,7 @@ extern int sysctl_tcp_syncookies; -__u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS]; +__u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS]; EXPORT_SYMBOL(syncookie_secret); static __init int init_syncookies(void) @@ -41,7 +41,7 @@ static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, { __u32 *tmp = __get_cpu_var(cookie_scratch); - memcpy(tmp + 3, syncookie_secret[c], sizeof(syncookie_secret[c])); + memcpy(tmp + 4, syncookie_secret[c], sizeof(syncookie_secret[c])); tmp[0] = (__force u32)saddr; tmp[1] = (__force u32)daddr; tmp[2] = ((__force u32)sport << 16) + (__force u32)dport; diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 827c5aa7524c..3a622e7abc02 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -22,7 +22,7 @@ #include extern int sysctl_tcp_syncookies; -extern __u32 syncookie_secret[2][16-3+SHA_DIGEST_WORDS]; +extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS]; #define COOKIEBITS 24 /* Upper bits store count */ #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1) -- cgit v1.2.3-59-g8ed1b From 2a706ec1881709b8a90d8ccdd1fde40b3cc79364 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Sun, 23 Mar 2008 22:42:34 -0700 Subject: [AF_PACKET]: Remove unused variable. Signed-off-by: Jiri Olsa Signed-off-by: David S. Miller --- net/packet/af_packet.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index b8b827c7062d..a56ed2120e07 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -1658,7 +1658,7 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing int err = 0; if (req->tp_block_nr) { - int i, l; + int i; /* Sanity tests and some calculations */ @@ -1687,7 +1687,6 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req, int closing if (unlikely(!pg_vec)) goto out; - l = 0; for (i = 0; i < req->tp_block_nr; i++) { char *ptr = pg_vec[i]; struct tpacket_hdr *header; -- cgit v1.2.3-59-g8ed1b From 3d3b2d25a4debaff05a9e6f5c55a0d31e4334234 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 23 Mar 2008 22:43:56 -0700 Subject: fib_trie: print information on all routing tables Make /proc/net/fib_trie and /proc/net/fib_triestat display all routing tables, not just local and main. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/fib_trie.c | 179 ++++++++++++++++++++++++++++------------------------ 1 file changed, 95 insertions(+), 84 deletions(-) (limited to 'net') diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 1ff446d0fa8b..a7d089eb042e 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2026,9 +2026,8 @@ struct fib_table *fib_hash_table(u32 id) /* Depth first Trie walk iterator */ struct fib_trie_iter { struct seq_net_private p; - struct trie *trie_local, *trie_main; + struct fib_table *tb; struct tnode *tnode; - struct trie *trie; unsigned index; unsigned depth; }; @@ -2081,31 +2080,26 @@ rescan: static struct node *fib_trie_get_first(struct fib_trie_iter *iter, struct trie *t) { - struct node *n ; + struct node *n; if (!t) return NULL; n = rcu_dereference(t->trie); - - if (!iter) + if (!n) return NULL; - if (n) { - if (IS_TNODE(n)) { - iter->tnode = (struct tnode *) n; - iter->trie = t; - iter->index = 0; - iter->depth = 1; - } else { - iter->tnode = NULL; - iter->trie = t; - iter->index = 0; - iter->depth = 0; - } - return n; + if (IS_TNODE(n)) { + iter->tnode = (struct tnode *) n; + iter->index = 0; + iter->depth = 1; + } else { + iter->tnode = NULL; + iter->index = 0; + iter->depth = 0; } - return NULL; + + return n; } static void trie_collect_stats(struct trie *t, struct trie_stat *s) @@ -2116,8 +2110,7 @@ static void trie_collect_stats(struct trie *t, struct trie_stat *s) memset(s, 0, sizeof(*s)); rcu_read_lock(); - for (n = fib_trie_get_first(&iter, t); n; - n = fib_trie_get_next(&iter)) { + for (n = fib_trie_get_first(&iter, t); n; n = fib_trie_get_next(&iter)) { if (IS_LEAF(n)) { struct leaf *l = (struct leaf *)n; struct leaf_info *li; @@ -2206,36 +2199,48 @@ static void trie_show_usage(struct seq_file *seq, } #endif /* CONFIG_IP_FIB_TRIE_STATS */ -static void fib_trie_show(struct seq_file *seq, const char *name, - struct trie *trie) +static void fib_table_print(struct seq_file *seq, struct fib_table *tb) { - struct trie_stat stat; - - trie_collect_stats(trie, &stat); - seq_printf(seq, "%s:\n", name); - trie_show_stats(seq, &stat); -#ifdef CONFIG_IP_FIB_TRIE_STATS - trie_show_usage(seq, &trie->stats); -#endif + if (tb->tb_id == RT_TABLE_LOCAL) + seq_puts(seq, "Local:\n"); + else if (tb->tb_id == RT_TABLE_MAIN) + seq_puts(seq, "Main:\n"); + else + seq_printf(seq, "Id %d:\n", tb->tb_id); } + static int fib_triestat_seq_show(struct seq_file *seq, void *v) { struct net *net = (struct net *)seq->private; - struct fib_table *tb; + unsigned int h; seq_printf(seq, "Basic info: size of leaf:" " %Zd bytes, size of tnode: %Zd bytes.\n", sizeof(struct leaf), sizeof(struct tnode)); - tb = fib_get_table(net, RT_TABLE_LOCAL); - if (tb) - fib_trie_show(seq, "Local", (struct trie *) tb->tb_data); + for (h = 0; h < FIB_TABLE_HASHSZ; h++) { + struct hlist_head *head = &net->ipv4.fib_table_hash[h]; + struct hlist_node *node; + struct fib_table *tb; + + hlist_for_each_entry_rcu(tb, node, head, tb_hlist) { + struct trie *t = (struct trie *) tb->tb_data; + struct trie_stat stat; + + if (!t) + continue; - tb = fib_get_table(net, RT_TABLE_MAIN); - if (tb) - fib_trie_show(seq, "Main", (struct trie *) tb->tb_data); + fib_table_print(seq, tb); + + trie_collect_stats(t, &stat); + trie_show_stats(seq, &stat); +#ifdef CONFIG_IP_FIB_TRIE_STATS + trie_show_usage(seq, &t->stats); +#endif + } + } return 0; } @@ -2271,23 +2276,30 @@ static const struct file_operations fib_triestat_fops = { .release = fib_triestat_seq_release, }; -static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, - loff_t pos) +static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, loff_t pos) { + struct net *net = iter->p.net; loff_t idx = 0; - struct node *n; + unsigned int h; - for (n = fib_trie_get_first(iter, iter->trie_local); - n; ++idx, n = fib_trie_get_next(iter)) { - if (pos == idx) - return n; - } + for (h = 0; h < FIB_TABLE_HASHSZ; h++) { + struct hlist_head *head = &net->ipv4.fib_table_hash[h]; + struct hlist_node *node; + struct fib_table *tb; - for (n = fib_trie_get_first(iter, iter->trie_main); - n; ++idx, n = fib_trie_get_next(iter)) { - if (pos == idx) - return n; + hlist_for_each_entry_rcu(tb, node, head, tb_hlist) { + struct node *n; + + for (n = fib_trie_get_first(iter, + (struct trie *) tb->tb_data); + n; n = fib_trie_get_next(iter)) + if (pos == idx++) { + iter->tb = tb; + return n; + } + } } + return NULL; } @@ -2295,43 +2307,49 @@ static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos) __acquires(RCU) { struct fib_trie_iter *iter = seq->private; - struct fib_table *tb; - if (!iter->trie_local) { - tb = fib_get_table(iter->p.net, RT_TABLE_LOCAL); - if (tb) - iter->trie_local = (struct trie *) tb->tb_data; - } - if (!iter->trie_main) { - tb = fib_get_table(iter->p.net, RT_TABLE_MAIN); - if (tb) - iter->trie_main = (struct trie *) tb->tb_data; - } rcu_read_lock(); - if (*pos == 0) - return SEQ_START_TOKEN; - return fib_trie_get_idx(iter, *pos - 1); + return fib_trie_get_idx(iter, *pos); } static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct fib_trie_iter *iter = seq->private; - void *l = v; + struct net *net = iter->p.net; + struct fib_table *tb = iter->tb; + struct hlist_node *tb_node; + unsigned int h; + struct node *n; ++*pos; - if (v == SEQ_START_TOKEN) - return fib_trie_get_idx(iter, 0); - - v = fib_trie_get_next(iter); - BUG_ON(v == l); - if (v) - return v; + /* next node in same table */ + n = fib_trie_get_next(iter); + if (n) + return n; - /* continue scan in next trie */ - if (iter->trie == iter->trie_local) - return fib_trie_get_first(iter, iter->trie_main); + /* walk rest of this hash chain */ + h = tb->tb_id & (FIB_TABLE_HASHSZ - 1); + while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) { + tb = hlist_entry(tb_node, struct fib_table, tb_hlist); + n = fib_trie_get_first(iter, (struct trie *) tb->tb_data); + if (n) + goto found; + } + /* new hash chain */ + while (++h < FIB_TABLE_HASHSZ) { + struct hlist_head *head = &net->ipv4.fib_table_hash[h]; + hlist_for_each_entry_rcu(tb, tb_node, head, tb_hlist) { + n = fib_trie_get_first(iter, (struct trie *) tb->tb_data); + if (n) + goto found; + } + } return NULL; + +found: + iter->tb = tb; + return n; } static void fib_trie_seq_stop(struct seq_file *seq, void *v) @@ -2388,15 +2406,8 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v) const struct fib_trie_iter *iter = seq->private; struct node *n = v; - if (v == SEQ_START_TOKEN) - return 0; - - if (!node_parent_rcu(n)) { - if (iter->trie == iter->trie_local) - seq_puts(seq, ":\n"); - else - seq_puts(seq, "
:\n"); - } + if (!node_parent_rcu(n)) + fib_table_print(seq, iter->tb); if (IS_TNODE(n)) { struct tnode *tn = (struct tnode *) n; -- cgit v1.2.3-59-g8ed1b From 2444844cefd2ce0ac73858cf980de07e33a5dd20 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sun, 23 Mar 2008 22:46:34 -0700 Subject: [SCTP]: Replace char msg[] with static const char[]. 133886 2004 220 136110 213ae sctp.new/sctp.o 134018 2004 220 136242 21432 sctp.old/sctp.o Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- net/sctp/sm_make_chunk.c | 2 +- net/sctp/sm_statefuns.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 578630e8e00d..c8982452580e 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1782,7 +1782,7 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc, const struct sctp_chunk *chunk, struct sctp_chunk **errp) { - char error[] = "The following parameter had invalid length:"; + static const char error[] = "The following parameter had invalid length:"; size_t payload_len = WORD_ROUND(sizeof(error)) + sizeof(sctp_paramhdr_t); diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index c0c6bee77cf5..6545b5fcbc73 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -4219,7 +4219,7 @@ static sctp_disposition_t sctp_sf_violation_chunklen( void *arg, sctp_cmd_seq_t *commands) { - char err_str[]="The following chunk had invalid length:"; + static const char err_str[]="The following chunk had invalid length:"; return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str, sizeof(err_str)); @@ -4236,7 +4236,7 @@ static sctp_disposition_t sctp_sf_violation_paramlen( const sctp_subtype_t type, void *arg, sctp_cmd_seq_t *commands) { - char err_str[] = "The following parameter had invalid length:"; + static const char err_str[] = "The following parameter had invalid length:"; return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str, sizeof(err_str)); @@ -4255,7 +4255,7 @@ static sctp_disposition_t sctp_sf_violation_ctsn( void *arg, sctp_cmd_seq_t *commands) { - char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:"; + static const char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:"; return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str, sizeof(err_str)); @@ -4274,7 +4274,7 @@ static sctp_disposition_t sctp_sf_violation_chunk( void *arg, sctp_cmd_seq_t *commands) { - char err_str[]="The following chunk violates protocol:"; + static const char err_str[]="The following chunk violates protocol:"; if (!asoc) return sctp_sf_violation(ep, asoc, type, arg, commands); -- cgit v1.2.3-59-g8ed1b From 80445cfb28a6b093540582b68d9ae928bf34cfe7 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sun, 23 Mar 2008 22:47:08 -0700 Subject: [SCTP]: Remove redundant wrapper functions. sctp_datamsg_free and sctp_datamsg_track are just aliases for sctp_datamsg_put and sctp_chunk_hold, respectively. Saves 32 Bytes on x86. Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- include/net/sctp/structs.h | 2 -- net/sctp/chunk.c | 16 +--------------- net/sctp/socket.c | 4 ++-- 3 files changed, 3 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 8966599ddb9f..0ce0443c5b79 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -637,8 +637,6 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *, struct sctp_sndrcvinfo *, struct msghdr *, int len); void sctp_datamsg_put(struct sctp_datamsg *); -void sctp_datamsg_free(struct sctp_datamsg *); -void sctp_datamsg_track(struct sctp_chunk *); void sctp_chunk_fail(struct sctp_chunk *, int error); int sctp_chunk_abandoned(struct sctp_chunk *); diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index e1f355080026..ed857643e3ff 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -136,20 +136,6 @@ void sctp_datamsg_put(struct sctp_datamsg *msg) sctp_datamsg_destroy(msg); } -/* Free a message. Really just give up a reference, the - * really free happens in sctp_datamsg_destroy(). - */ -void sctp_datamsg_free(struct sctp_datamsg *msg) -{ - sctp_datamsg_put(msg); -} - -/* Hold on to all the fragments until all chunks have been sent. */ -void sctp_datamsg_track(struct sctp_chunk *chunk) -{ - sctp_chunk_hold(chunk); -} - /* Assign a chunk to this datamsg. */ static void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk) { @@ -295,7 +281,7 @@ errout: chunk = list_entry(pos, struct sctp_chunk, frag_list); sctp_chunk_free(chunk); } - sctp_datamsg_free(msg); + sctp_datamsg_put(msg); return NULL; } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index a3138a0fe2c5..76c747056dd7 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1729,7 +1729,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, /* Now send the (possibly) fragmented message. */ list_for_each(pos, &datamsg->chunks) { chunk = list_entry(pos, struct sctp_chunk, frag_list); - sctp_datamsg_track(chunk); + sctp_chunk_hold(chunk); /* Do accounting for the write space. */ sctp_set_owner_w(chunk); @@ -1748,7 +1748,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, SCTP_DEBUG_PRINTK("We sent primitively.\n"); } - sctp_datamsg_free(datamsg); + sctp_datamsg_put(datamsg); if (err) goto out_free; else -- cgit v1.2.3-59-g8ed1b From 15439febb0bd530f85e40ad6fa8e9f75106639ef Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 24 Mar 2008 14:53:49 -0700 Subject: [NETNS][UDP]: Register /proc/net/udp in a namespace. After the commit a91275eff43a527e1a25d6d034cbcd19ee323e64 ([NETNS][IPV6] udp - make proc handle the network namespace) it is now possible to make this file present in newly created namespaces. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/udp.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 8c1f5eaafcd2..9cd48b0bb7d4 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1701,14 +1701,29 @@ static struct udp_seq_afinfo udp4_seq_afinfo = { .seq_fops = &udp4_seq_fops, }; +static int udp4_proc_init_net(struct net *net) +{ + return udp_proc_register(net, &udp4_seq_afinfo); +} + +static void udp4_proc_exit_net(struct net *net) +{ + udp_proc_unregister(net, &udp4_seq_afinfo); +} + +static struct pernet_operations udp4_net_ops = { + .init = udp4_proc_init_net, + .exit = udp4_proc_exit_net, +}; + int __init udp4_proc_init(void) { - return udp_proc_register(&init_net, &udp4_seq_afinfo); + return register_pernet_subsys(&udp4_net_ops); } void udp4_proc_exit(void) { - udp_proc_unregister(&init_net, &udp4_seq_afinfo); + unregister_pernet_subsys(&udp4_net_ops); } #endif /* CONFIG_PROC_FS */ -- cgit v1.2.3-59-g8ed1b From 757764f61d07ab8ff84699b6d608eac7bc94cecc Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 24 Mar 2008 14:56:02 -0700 Subject: [NETNS][TCP]: Register /proc/net/tcp in a namespace. After the commit f40c8174d3c21bf178283f3ef3aa8c7bf238fdec ([NETNS][IPV4] tcp - make proc handle the network namespaces) it is now possible to make this file present in newly created namespaces. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1a47719a55ad..649d00a50cb1 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2425,14 +2425,29 @@ static struct tcp_seq_afinfo tcp4_seq_afinfo = { .seq_fops = &tcp4_seq_fops, }; +static int tcp4_proc_init_net(struct net *net) +{ + return tcp_proc_register(net, &tcp4_seq_afinfo); +} + +static void tcp4_proc_exit_net(struct net *net) +{ + tcp_proc_unregister(net, &tcp4_seq_afinfo); +} + +static struct pernet_operations tcp4_net_ops = { + .init = tcp4_proc_init_net, + .exit = tcp4_proc_exit_net, +}; + int __init tcp4_proc_init(void) { - return tcp_proc_register(&init_net, &tcp4_seq_afinfo); + return register_pernet_subsys(&tcp4_net_ops); } void tcp4_proc_exit(void) { - tcp_proc_unregister(&init_net, &tcp4_seq_afinfo); + unregister_pernet_subsys(&tcp4_net_ops); } #endif /* CONFIG_PROC_FS */ -- cgit v1.2.3-59-g8ed1b From ff2bac6a63e3694e7a97152b7e934fe244e2a858 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 24 Mar 2008 14:56:34 -0700 Subject: [UDP-Lite]: Clean up proc creation a bit. Just introduce a helper to remove ifdefs from inside the udplite4_register function. This will help to make the next patch nicer. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/udplite.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 8d42e344b043..653a6fc19023 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -82,6 +82,16 @@ static struct udp_seq_afinfo udplite4_seq_afinfo = { .seq_show = udp4_seq_show, .seq_fops = &udplite4_seq_fops, }; + +static __init int udplite4_proc_init(void) +{ + return udp_proc_register(&init_net, &udplite4_seq_afinfo); +} +#else +static inline int udplite4_proc_init(void) +{ + return 0; +} #endif void __init udplite4_register(void) @@ -94,10 +104,8 @@ void __init udplite4_register(void) inet_register_protosw(&udplite4_protosw); -#ifdef CONFIG_PROC_FS - if (udp_proc_register(&init_net, &udplite4_seq_afinfo)) + if (udplite4_proc_init()) printk(KERN_ERR "%s: Cannot register /proc!\n", __func__); -#endif return; out_unregister_proto: -- cgit v1.2.3-59-g8ed1b From 84c375af0ff61e0bd15fac0aed0438640494483e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 24 Mar 2008 14:56:57 -0700 Subject: [NETNS][UDP-Lite]: Register /proc/net/udplite(6) in a namespace. UDP-Lite sockets are displayed in another files, rather than UDP ones, so make the present in namespaces as well. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/udplite.c | 17 ++++++++++++++++- net/ipv6/udplite.c | 19 +++++++++++++++++-- 2 files changed, 33 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 653a6fc19023..ddf4cc432796 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -83,9 +83,24 @@ static struct udp_seq_afinfo udplite4_seq_afinfo = { .seq_fops = &udplite4_seq_fops, }; +static int udplite4_proc_init_net(struct net *net) +{ + return udp_proc_register(net, &udplite4_seq_afinfo); +} + +static void udplite4_proc_exit_net(struct net *net) +{ + udp_proc_unregister(net, &udplite4_seq_afinfo); +} + +static struct pernet_operations udplite4_net_ops = { + .init = udplite4_proc_init_net, + .exit = udplite4_proc_exit_net, +}; + static __init int udplite4_proc_init(void) { - return udp_proc_register(&init_net, &udplite4_seq_afinfo); + return register_pernet_subsys(&udplite4_net_ops); } #else static inline int udplite4_proc_init(void) diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 93e52e0d57f2..706c5c375a01 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -109,13 +109,28 @@ static struct udp_seq_afinfo udplite6_seq_afinfo = { .seq_fops = &udplite6_seq_fops, }; +static int udplite6_proc_init_net(struct net *net) +{ + return udp_proc_register(net, &udplite6_seq_afinfo); +} + +static void udplite6_proc_exit_net(struct net *net) +{ + udp_proc_unregister(net, &udplite6_seq_afinfo); +} + +static struct pernet_operations udplite6_net_ops = { + .init = udplite6_proc_init_net, + .exit = udplite6_proc_exit_net, +}; + int __init udplite6_proc_init(void) { - return udp_proc_register(&init_net, &udplite6_seq_afinfo); + return register_pernet_subsys(&udplite6_net_ops); } void udplite6_proc_exit(void) { - udp_proc_unregister(&init_net, &udplite6_seq_afinfo); + unregister_pernet_subsys(&udplite6_net_ops); } #endif -- cgit v1.2.3-59-g8ed1b From 2feb27dbe00cbb4f7d31f90acf6bd0d751dd0a50 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 24 Mar 2008 14:57:45 -0700 Subject: [NETNS]: Minor information leak via /proc/net/ptype file. This file displays the registered packet types, but some of them (packet sockets creates such) can be bound to a net device and showing them in a wrong namespace is not correct. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/core/dev.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index f973e38b81af..aebd08606040 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2615,7 +2615,7 @@ static int ptype_seq_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) seq_puts(seq, "Type Device Function\n"); - else { + else if (pt->dev == NULL || pt->dev->nd_net == seq_file_net(seq)) { if (pt->type == htons(ETH_P_ALL)) seq_puts(seq, "ALL "); else @@ -2639,7 +2639,8 @@ static const struct seq_operations ptype_seq_ops = { static int ptype_seq_open(struct inode *inode, struct file *file) { - return seq_open(file, &ptype_seq_ops); + return seq_open_net(inode, file, &ptype_seq_ops, + sizeof(struct seq_net_private)); } static const struct file_operations ptype_seq_fops = { @@ -2647,7 +2648,7 @@ static const struct file_operations ptype_seq_fops = { .open = ptype_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_net, }; -- cgit v1.2.3-59-g8ed1b From 49e8a279a1b79e14b51aa6d4102b3a3de39e7a5e Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 24 Mar 2008 15:28:12 -0700 Subject: [NETNS]: Process ARP in the context of the correct namespace. Get namespace from a device and pass it to the routing engine. Enable ARP packet processing and device notifiers after that. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/arp.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index efe01df8fc0e..6d90ec524212 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -242,7 +242,7 @@ static int arp_constructor(struct neighbour *neigh) return -EINVAL; } - neigh->type = inet_addr_type(&init_net, addr); + neigh->type = inet_addr_type(dev->nd_net, addr); parms = in_dev->arp_parms; __neigh_parms_put(neigh->parms); @@ -341,14 +341,14 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) switch (IN_DEV_ARP_ANNOUNCE(in_dev)) { default: case 0: /* By default announce any local IP */ - if (skb && inet_addr_type(&init_net, ip_hdr(skb)->saddr) == RTN_LOCAL) + if (skb && inet_addr_type(dev->nd_net, ip_hdr(skb)->saddr) == RTN_LOCAL) saddr = ip_hdr(skb)->saddr; break; case 1: /* Restrict announcements of saddr in same subnet */ if (!skb) break; saddr = ip_hdr(skb)->saddr; - if (inet_addr_type(&init_net, saddr) == RTN_LOCAL) { + if (inet_addr_type(dev->nd_net, saddr) == RTN_LOCAL) { /* saddr should be known to target */ if (inet_addr_onlink(in_dev, target, saddr)) break; @@ -424,7 +424,7 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) int flag = 0; /*unsigned long now; */ - if (ip_route_output_key(&init_net, &rt, &fl) < 0) + if (ip_route_output_key(dev->nd_net, &rt, &fl) < 0) return 1; if (rt->u.dst.dev != dev) { NET_INC_STATS_BH(LINUX_MIB_ARPFILTER); @@ -477,7 +477,7 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb) paddr = skb->rtable->rt_gateway; - if (arp_set_predefined(inet_addr_type(&init_net, paddr), haddr, paddr, dev)) + if (arp_set_predefined(inet_addr_type(dev->nd_net, paddr), haddr, paddr, dev)) return 0; n = __neigh_lookup(&arp_tbl, &paddr, dev, 1); @@ -709,6 +709,7 @@ static int arp_process(struct sk_buff *skb) u16 dev_type = dev->type; int addr_type; struct neighbour *n; + struct net *net = dev->nd_net; /* arp_rcv below verifies the ARP header and verifies the device * is ARP'able. @@ -804,7 +805,7 @@ static int arp_process(struct sk_buff *skb) /* Special case: IPv4 duplicate address detection packet (RFC2131) */ if (sip == 0) { if (arp->ar_op == htons(ARPOP_REQUEST) && - inet_addr_type(&init_net, tip) == RTN_LOCAL && + inet_addr_type(net, tip) == RTN_LOCAL && !arp_ignore(in_dev, sip, tip)) arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, dev->dev_addr, sha); @@ -834,7 +835,7 @@ static int arp_process(struct sk_buff *skb) goto out; } else if (IN_DEV_FORWARD(in_dev)) { if (addr_type == RTN_UNICAST && rt->u.dst.dev != dev && - (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, &init_net, &tip, dev, 0))) { + (arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) { n = neigh_event_ns(&arp_tbl, sha, &sip, dev); if (n) neigh_release(n); @@ -864,7 +865,7 @@ static int arp_process(struct sk_buff *skb) */ if (n == NULL && arp->ar_op == htons(ARPOP_REPLY) && - inet_addr_type(&init_net, sip) == RTN_UNICAST) + inet_addr_type(net, sip) == RTN_UNICAST) n = __neigh_lookup(&arp_tbl, &sip, dev, 1); } @@ -911,9 +912,6 @@ static int arp_rcv(struct sk_buff *skb, struct net_device *dev, { struct arphdr *arp; - if (dev->nd_net != &init_net) - goto freeskb; - /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ if (!pskb_may_pull(skb, arp_hdr_len(dev))) goto freeskb; @@ -1198,9 +1196,6 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, vo { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) - return NOTIFY_DONE; - switch (event) { case NETDEV_CHANGEADDR: neigh_changeaddr(&arp_tbl, dev); -- cgit v1.2.3-59-g8ed1b From ffc31d3d7719555cd784ecaf82e9c237f3a747ab Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 24 Mar 2008 15:28:43 -0700 Subject: [NETNS]: /proc/net/arp namespacing. Seqfile operation showing /proc/net/arp are already namespace aware. All we need is to register this file for each namespace. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/arp.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 6d90ec524212..832473e30b36 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1377,13 +1377,29 @@ static const struct file_operations arp_seq_fops = { .release = seq_release_net, }; -static int __init arp_proc_init(void) + +static int __net_init arp_net_init(struct net *net) { - if (!proc_net_fops_create(&init_net, "arp", S_IRUGO, &arp_seq_fops)) + if (!proc_net_fops_create(net, "arp", S_IRUGO, &arp_seq_fops)) return -ENOMEM; return 0; } +static void __net_exit arp_net_exit(struct net *net) +{ + proc_net_remove(net, "arp"); +} + +static struct pernet_operations arp_net_ops = { + .init = arp_net_init, + .exit = arp_net_exit, +}; + +static int __init arp_proc_init(void) +{ + return register_pernet_subsys(&arp_net_ops); +} + #else /* CONFIG_PROC_FS */ static int __init arp_proc_init(void) -- cgit v1.2.3-59-g8ed1b From 0e6bd4a1c6c3881c9ed82985ecb9824d4450c4ba Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 24 Mar 2008 15:29:23 -0700 Subject: [NETNS]: Add namespace parameter to ip_options_compile. ip_options_compile uses inet_addr_type which requires a namespace. The packet argument is optional, so parameter is the only way to obtain it. Pass the init_net there for now. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/ip.h | 3 ++- net/ipv4/ip_input.c | 2 +- net/ipv4/ip_options.c | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/net/ip.h b/include/net/ip.h index 9f50d4f1f157..bcc3afa3df36 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -347,7 +347,8 @@ extern int ip_forward(struct sk_buff *skb); extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, __be32 daddr, struct rtable *rt, int is_frag); extern int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb); extern void ip_options_fragment(struct sk_buff *skb); -extern int ip_options_compile(struct ip_options *opt, struct sk_buff *skb); +extern int ip_options_compile(struct net *net, + struct ip_options *opt, struct sk_buff *skb); extern int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen); extern int ip_options_get_from_user(struct ip_options **optp, diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index e3a0c78fa7bf..f3a7a08a463f 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -286,7 +286,7 @@ static inline int ip_rcv_options(struct sk_buff *skb) opt = &(IPCB(skb)->opt); opt->optlen = iph->ihl*4 - sizeof(struct iphdr); - if (ip_options_compile(opt, skb)) { + if (ip_options_compile(&init_net, opt, skb)) { IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); goto drop; } diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index aeed4e5858ec..f0949b42e79e 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -248,7 +248,8 @@ void ip_options_fragment(struct sk_buff * skb) * If opt == NULL, then skb->data should point to IP header. */ -int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) +int ip_options_compile(struct net *net, + struct ip_options * opt, struct sk_buff * skb) { int l; unsigned char * iph; @@ -389,7 +390,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) { __be32 addr; memcpy(&addr, &optptr[optptr[2]-1], 4); - if (inet_addr_type(&init_net, addr) == RTN_UNICAST) + if (inet_addr_type(net, addr) == RTN_UNICAST) break; if (skb) timeptr = (__be32*)&optptr[optptr[2]+3]; @@ -512,7 +513,7 @@ static int ip_options_get_finish(struct ip_options **optp, while (optlen & 3) opt->__data[optlen++] = IPOPT_END; opt->optlen = optlen; - if (optlen && ip_options_compile(opt, NULL)) { + if (optlen && ip_options_compile(&init_net, opt, NULL)) { kfree(opt); return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From f2c4802b3fdfb0d9596d932ca2af0ef6f8d60491 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 24 Mar 2008 15:29:55 -0700 Subject: [NETNS]: Add namespace parameter to ip_options_get(...). Pass the init_net there for now. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/ip.h | 4 ++-- net/ipv4/ip_options.c | 14 ++++++++------ net/ipv4/ip_sockglue.c | 4 ++-- 3 files changed, 12 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/net/ip.h b/include/net/ip.h index bcc3afa3df36..531270dc48a6 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -349,9 +349,9 @@ extern int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb); extern void ip_options_fragment(struct sk_buff *skb); extern int ip_options_compile(struct net *net, struct ip_options *opt, struct sk_buff *skb); -extern int ip_options_get(struct ip_options **optp, +extern int ip_options_get(struct net *net, struct ip_options **optp, unsigned char *data, int optlen); -extern int ip_options_get_from_user(struct ip_options **optp, +extern int ip_options_get_from_user(struct net *net, struct ip_options **optp, unsigned char __user *data, int optlen); extern void ip_options_undo(struct ip_options * opt); extern void ip_forward_options(struct sk_buff *skb); diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index f0949b42e79e..59f7ddfb29bf 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -507,13 +507,13 @@ static struct ip_options *ip_options_get_alloc(const int optlen) GFP_KERNEL); } -static int ip_options_get_finish(struct ip_options **optp, +static int ip_options_get_finish(struct net *net, struct ip_options **optp, struct ip_options *opt, int optlen) { while (optlen & 3) opt->__data[optlen++] = IPOPT_END; opt->optlen = optlen; - if (optlen && ip_options_compile(&init_net, opt, NULL)) { + if (optlen && ip_options_compile(net, opt, NULL)) { kfree(opt); return -EINVAL; } @@ -522,7 +522,8 @@ static int ip_options_get_finish(struct ip_options **optp, return 0; } -int ip_options_get_from_user(struct ip_options **optp, unsigned char __user *data, int optlen) +int ip_options_get_from_user(struct net *net, struct ip_options **optp, + unsigned char __user *data, int optlen) { struct ip_options *opt = ip_options_get_alloc(optlen); @@ -532,10 +533,11 @@ int ip_options_get_from_user(struct ip_options **optp, unsigned char __user *dat kfree(opt); return -EFAULT; } - return ip_options_get_finish(optp, opt, optlen); + return ip_options_get_finish(net, optp, opt, optlen); } -int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen) +int ip_options_get(struct net *net, struct ip_options **optp, + unsigned char *data, int optlen) { struct ip_options *opt = ip_options_get_alloc(optlen); @@ -543,7 +545,7 @@ int ip_options_get(struct ip_options **optp, unsigned char *data, int optlen) return -ENOMEM; if (optlen) memcpy(opt->__data, data, optlen); - return ip_options_get_finish(optp, opt, optlen); + return ip_options_get_finish(net, optp, opt, optlen); } void ip_forward_options(struct sk_buff *skb) diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index bb3cbe5ec36d..1b86a50269bc 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -176,7 +176,7 @@ int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc) switch (cmsg->cmsg_type) { case IP_RETOPTS: err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); - err = ip_options_get(&ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40); + err = ip_options_get(&init_net, &ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40); if (err) return err; break; @@ -449,7 +449,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, struct ip_options * opt = NULL; if (optlen > 40 || optlen < 0) goto e_inval; - err = ip_options_get_from_user(&opt, optval, optlen); + err = ip_options_get_from_user(&init_net, &opt, optval, optlen); if (err) break; if (inet->is_icsk) { -- cgit v1.2.3-59-g8ed1b From 7a6adb92fe301c10ca4dbd0d9f2422f5880595e7 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 24 Mar 2008 15:30:27 -0700 Subject: [NETNS]: Add namespace parameter to ip_cmsg_send. Pass the init_net there for now. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/ip.h | 3 ++- net/ipv4/ip_sockglue.c | 4 ++-- net/ipv4/raw.c | 2 +- net/ipv4/udp.c | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/net/ip.h b/include/net/ip.h index 531270dc48a6..6d7bcd5e62d4 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -362,7 +362,8 @@ extern int ip_options_rcv_srr(struct sk_buff *skb); */ extern void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb); -extern int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc); +extern int ip_cmsg_send(struct net *net, + struct msghdr *msg, struct ipcm_cookie *ipc); extern int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen); extern int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); extern int compat_ip_setsockopt(struct sock *sk, int level, diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 1b86a50269bc..0857f2d042cd 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -163,7 +163,7 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) ip_cmsg_recv_security(msg, skb); } -int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc) +int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) { int err; struct cmsghdr *cmsg; @@ -176,7 +176,7 @@ int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc) switch (cmsg->cmsg_type) { case IP_RETOPTS: err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); - err = ip_options_get(&init_net, &ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40); + err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg), err < 40 ? err : 40); if (err) return err; break; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index b433b485a883..7d29a05bf887 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -499,7 +499,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ipc.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { - err = ip_cmsg_send(msg, &ipc); + err = ip_cmsg_send(&init_net, msg, &ipc); if (err) goto out; if (ipc.opt) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 9cd48b0bb7d4..d142b87e9eb8 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -607,7 +607,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ipc.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { - err = ip_cmsg_send(msg, &ipc); + err = ip_cmsg_send(&init_net, msg, &ipc); if (err) return err; if (ipc.opt) -- cgit v1.2.3-59-g8ed1b From cb84663e4d239f23f0d872bc6463c272e74daad8 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 24 Mar 2008 15:31:00 -0700 Subject: [NETNS]: Process IP layer in the context of the correct namespace. Replace all the rest of the init_net with a proper net on the IP layer. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/ip_fragment.c | 5 ++++- net/ipv4/ip_input.c | 6 ++++-- net/ipv4/ip_options.c | 2 +- net/ipv4/ip_output.c | 2 +- net/ipv4/ip_sockglue.c | 7 ++++--- 5 files changed, 14 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 3b2e5adca838..8b448c4b9080 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -204,8 +204,11 @@ static void ip_expire(unsigned long arg) if ((qp->q.last_in&FIRST_IN) && qp->q.fragments != NULL) { struct sk_buff *head = qp->q.fragments; + struct net *net; + + net = container_of(qp->q.net, struct net, ipv4.frags); /* Send an ICMP "Fragment Reassembly Timeout" message. */ - if ((head->dev = dev_get_by_index(&init_net, qp->iif)) != NULL) { + if ((head->dev = dev_get_by_index(net, qp->iif)) != NULL) { icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); dev_put(head->dev); } diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index f3a7a08a463f..eb1fa27dc0c4 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -160,6 +160,7 @@ int ip_call_ra_chain(struct sk_buff *skb) struct ip_ra_chain *ra; u8 protocol = ip_hdr(skb)->protocol; struct sock *last = NULL; + struct net_device *dev = skb->dev; read_lock(&ip_ra_lock); for (ra = ip_ra_chain; ra; ra = ra->next) { @@ -170,7 +171,8 @@ int ip_call_ra_chain(struct sk_buff *skb) */ if (sk && inet_sk(sk)->num == protocol && (!sk->sk_bound_dev_if || - sk->sk_bound_dev_if == skb->dev->ifindex)) { + sk->sk_bound_dev_if == dev->ifindex) && + sk->sk_net == dev->nd_net) { if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) { read_unlock(&ip_ra_lock); @@ -286,7 +288,7 @@ static inline int ip_rcv_options(struct sk_buff *skb) opt = &(IPCB(skb)->opt); opt->optlen = iph->ihl*4 - sizeof(struct iphdr); - if (ip_options_compile(&init_net, opt, skb)) { + if (ip_options_compile(dev->nd_net, opt, skb)) { IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); goto drop; } diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 59f7ddfb29bf..87cc1222c600 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -145,7 +145,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) __be32 addr; memcpy(&addr, sptr+soffset-1, 4); - if (inet_addr_type(&init_net, addr) != RTN_LOCAL) { + if (inet_addr_type(skb->dst->dev->nd_net, addr) != RTN_LOCAL) { dopt->ts_needtime = 1; soffset += 8; } diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index dc494ea594a7..349fae58c1a3 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -351,7 +351,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) * itself out. */ security_sk_classify_flow(sk, &fl); - if (ip_route_output_flow(&init_net, &rt, &fl, sk, 0)) + if (ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 0)) goto no_route; } sk_setup_caps(sk, &rt->u.dst); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 0857f2d042cd..b854431047a4 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -449,7 +449,8 @@ static int do_ip_setsockopt(struct sock *sk, int level, struct ip_options * opt = NULL; if (optlen > 40 || optlen < 0) goto e_inval; - err = ip_options_get_from_user(&init_net, &opt, optval, optlen); + err = ip_options_get_from_user(sk->sk_net, &opt, + optval, optlen); if (err) break; if (inet->is_icsk) { @@ -589,13 +590,13 @@ static int do_ip_setsockopt(struct sock *sk, int level, err = 0; break; } - dev = ip_dev_find(&init_net, mreq.imr_address.s_addr); + dev = ip_dev_find(sk->sk_net, mreq.imr_address.s_addr); if (dev) { mreq.imr_ifindex = dev->ifindex; dev_put(dev); } } else - dev = __dev_get_by_index(&init_net, mreq.imr_ifindex); + dev = __dev_get_by_index(sk->sk_net, mreq.imr_ifindex); err = -EADDRNOTAVAIL; -- cgit v1.2.3-59-g8ed1b From 05cf89d40c85e622dac20e44713168767be5c520 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 24 Mar 2008 15:31:35 -0700 Subject: [NETNS]: Process INET socket layer in the correct namespace. Replace all the reast of the init_net with a proper net on the socket layer. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 4 ++-- net/ipv4/inet_connection_sock.c | 2 +- net/ipv4/raw.c | 4 ++-- net/ipv4/udp.c | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 44f5ce1fbfa4..a9e241cdc5b2 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -446,7 +446,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr_len < sizeof(struct sockaddr_in)) goto out; - chk_addr_ret = inet_addr_type(&init_net, addr->sin_addr.s_addr); + chk_addr_ret = inet_addr_type(sk->sk_net, addr->sin_addr.s_addr); /* Not specified by any standard per-se, however it breaks too * many applications when removed. It is unfortunate since @@ -1114,7 +1114,7 @@ int inet_sk_rebuild_header(struct sock *sk) }; security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(&init_net, &rt, &fl, sk, 0); + err = ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 0); } if (!err) sk_setup_caps(sk, &rt->u.dst); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index f9c5c4def1ba..d13c5f12bb32 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -333,7 +333,7 @@ struct dst_entry* inet_csk_route_req(struct sock *sk, .dport = ireq->rmt_port } } }; security_req_classify_flow(req, &fl); - if (ip_route_output_flow(&init_net, &rt, &fl, sk, 0)) { + if (ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 0)) { IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); return NULL; } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 7d29a05bf887..3f68a937b602 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -499,7 +499,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ipc.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { - err = ip_cmsg_send(&init_net, msg, &ipc); + err = ip_cmsg_send(sk->sk_net, msg, &ipc); if (err) goto out; if (ipc.opt) @@ -553,7 +553,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(&init_net, &rt, &fl, sk, 1); + err = ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 1); } if (err) goto done; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d142b87e9eb8..b37581dfd029 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -607,7 +607,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ipc.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { - err = ip_cmsg_send(&init_net, msg, &ipc); + err = ip_cmsg_send(sk->sk_net, msg, &ipc); if (err) return err; if (ipc.opt) @@ -656,7 +656,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, { .sport = inet->sport, .dport = dport } } }; security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(&init_net, &rt, &fl, sk, 1); + err = ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 1); if (err) { if (err == -ENETUNREACH) IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); -- cgit v1.2.3-59-g8ed1b From 0be43f82c4f4c4a999b53cf794513f7f1a4ed7f3 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 24 Mar 2008 15:32:09 -0700 Subject: [NETNS]: Process netfilter hooks in initial namespace only. There were no packets in the namespace other than initial previously. This will be changed in the neareast future. Netfilters are not namespace aware and should be processed in the initial namespace only for now. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/netfilter/core.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'net') diff --git a/net/netfilter/core.c b/net/netfilter/core.c index c4065b8f9a95..ec05684c56d7 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -165,6 +165,14 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb, unsigned int verdict; int ret = 0; +#ifdef CONFIG_NET_NS + struct net *net; + + net = indev == NULL ? outdev->nd_net : indev->nd_net; + if (net != &init_net) + return 1; +#endif + /* We may already have this, but read-locks nest anyway */ rcu_read_lock(); -- cgit v1.2.3-59-g8ed1b From f145049a06f470d0489f47cb83ff3ccb2a0de622 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 24 Mar 2008 15:33:00 -0700 Subject: [NETNS]: Drop packets in the non-initial namespace on the per/protocol basis. IP layer now can handle multiple namespaces normally. So, process such packets normally and drop them only if the transport layer is not aware about namespaces. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/protocol.h | 3 ++- net/ipv4/ip_input.c | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/net/protocol.h b/include/net/protocol.h index ad8c584233a6..8d024d7cb741 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h @@ -39,7 +39,8 @@ struct net_protocol { int (*gso_send_check)(struct sk_buff *skb); struct sk_buff *(*gso_segment)(struct sk_buff *skb, int features); - int no_policy; + unsigned int no_policy:1, + netns_ok:1; }; #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index eb1fa27dc0c4..2aeea5d15425 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -199,6 +199,8 @@ int ip_call_ra_chain(struct sk_buff *skb) static int ip_local_deliver_finish(struct sk_buff *skb) { + struct net *net = skb->dev->nd_net; + __skb_pull(skb, ip_hdrlen(skb)); /* Point into the IP datagram, just past the header. */ @@ -214,7 +216,8 @@ static int ip_local_deliver_finish(struct sk_buff *skb) raw = raw_local_deliver(skb, protocol); hash = protocol & (MAX_INET_PROTOS - 1); - if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) { + ipprot = rcu_dereference(inet_protos[hash]); + if (ipprot != NULL && (net == &init_net || ipprot->netns_ok)) { int ret; if (!ipprot->no_policy) { @@ -375,9 +378,6 @@ int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct iphdr *iph; u32 len; - if (dev->nd_net != &init_net) - goto drop; - /* When the interface is in promisc. mode, drop all the crap * that it receives, do not try to analyse it. */ -- cgit v1.2.3-59-g8ed1b From 2342fd7e146f05edeb13feb03490c13a1bdab2e0 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 24 Mar 2008 15:33:42 -0700 Subject: [NETNS]: Allow to create sockets in non-initial namespace. Allow to create sockets in the namespace if the protocol ok with this. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index a9e241cdc5b2..39ddb84b1b78 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -243,6 +243,23 @@ void build_ehash_secret(void) } EXPORT_SYMBOL(build_ehash_secret); +static inline int inet_netns_ok(struct net *net, int protocol) +{ + int hash; + struct net_protocol *ipprot; + + if (net == &init_net) + return 1; + + hash = protocol & (MAX_INET_PROTOS - 1); + ipprot = rcu_dereference(inet_protos[hash]); + + if (ipprot == NULL) + /* raw IP is OK */ + return 1; + return ipprot->netns_ok; +} + /* * Create an inet socket. */ @@ -259,9 +276,6 @@ static int inet_create(struct net *net, struct socket *sock, int protocol) int try_loading_module = 0; int err; - if (net != &init_net) - return -EAFNOSUPPORT; - if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM && !inet_ehash_secret) @@ -320,6 +334,10 @@ lookup_protocol: if (answer->capability > 0 && !capable(answer->capability)) goto out_rcu_unlock; + err = -EAFNOSUPPORT; + if (!inet_netns_ok(net, protocol)) + goto out_rcu_unlock; + sock->ops = answer->ops; answer_prot = answer->prot; answer_no_check = answer->no_check; -- cgit v1.2.3-59-g8ed1b From 92f1fecb45ef97acae94463302f79228a4b454d9 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 24 Mar 2008 15:34:06 -0700 Subject: [NETNS]: Enable TCP/UDP/ICMP inside namespace. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 3 +++ net/ipv4/udplite.c | 1 + 2 files changed, 4 insertions(+) (limited to 'net') diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 39ddb84b1b78..06cfb0bed631 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1302,17 +1302,20 @@ static struct net_protocol tcp_protocol = { .gso_send_check = tcp_v4_gso_send_check, .gso_segment = tcp_tso_segment, .no_policy = 1, + .netns_ok = 1, }; static struct net_protocol udp_protocol = { .handler = udp_rcv, .err_handler = udp_err, .no_policy = 1, + .netns_ok = 1, }; static struct net_protocol icmp_protocol = { .handler = icmp_rcv, .no_policy = 1, + .netns_ok = 1, }; static int __init init_ipv4_mibs(void) diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index ddf4cc432796..53f3ed496328 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -31,6 +31,7 @@ static struct net_protocol udplite_protocol = { .handler = udplite_rcv, .err_handler = udplite_err, .no_policy = 1, + .netns_ok = 1, }; DEFINE_PROTO_INUSE(udplite) -- cgit v1.2.3-59-g8ed1b From 3b6cdf94cd6dd0b64cc8646cf067a1ae0203276d Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 19 Feb 2008 10:15:27 +0900 Subject: [XFRM] IPV6: Use distribution counting sort for xfrm_state/xfrm_tmpl chain. Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/xfrm6_state.c | 171 +++++++++++++++++++++---------------------------- 1 file changed, 74 insertions(+), 97 deletions(-) (limited to 'net') diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index dc817e035e23..5a46bb99c3af 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c @@ -49,125 +49,102 @@ __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, x->props.family = AF_INET6; } +/* distribution counting sort function for xfrm_state and xfrm_tmpl */ static int -__xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n) +__xfrm6_sort(void **dst, void **src, int n, int (*cmp)(void *p), int maxclass) { int i; - int j = 0; + int class[XFRM_MAX_DEPTH]; + int count[maxclass]; - /* Rule 1: select IPsec transport except AH */ - for (i = 0; i < n; i++) { - if (src[i]->props.mode == XFRM_MODE_TRANSPORT && - src[i]->id.proto != IPPROTO_AH) { - dst[j++] = src[i]; - src[i] = NULL; - } - } - if (j == n) - goto end; + memset(count, 0, sizeof(count)); - /* Rule 2: select MIPv6 RO or inbound trigger */ -#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) for (i = 0; i < n; i++) { - if (src[i] && - (src[i]->props.mode == XFRM_MODE_ROUTEOPTIMIZATION || - src[i]->props.mode == XFRM_MODE_IN_TRIGGER)) { - dst[j++] = src[i]; - src[i] = NULL; - } + int c; + class[i] = c = cmp(src[i]); + count[c]++; } - if (j == n) - goto end; -#endif - /* Rule 3: select IPsec transport AH */ - for (i = 0; i < n; i++) { - if (src[i] && - src[i]->props.mode == XFRM_MODE_TRANSPORT && - src[i]->id.proto == IPPROTO_AH) { - dst[j++] = src[i]; - src[i] = NULL; - } - } - if (j == n) - goto end; + for (i = 2; i < maxclass; i++) + count[i] += count[i - 1]; - /* Rule 4: select IPsec tunnel */ for (i = 0; i < n; i++) { - if (src[i] && - (src[i]->props.mode == XFRM_MODE_TUNNEL || - src[i]->props.mode == XFRM_MODE_BEET)) { - dst[j++] = src[i]; - src[i] = NULL; - } + dst[count[class[i] - 1]++] = src[i]; + src[i] = 0; } - if (likely(j == n)) - goto end; - /* Final rule */ - for (i = 0; i < n; i++) { - if (src[i]) { - dst[j++] = src[i]; - src[i] = NULL; - } - } - - end: return 0; } -static int -__xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n) +/* + * Rule for xfrm_state: + * + * rule 1: select IPsec transport except AH + * rule 2: select MIPv6 RO or inbound trigger + * rule 3: select IPsec transport AH + * rule 4: select IPsec tunnel + * rule 5: others + */ +static int __xfrm6_state_sort_cmp(void *p) { - int i; - int j = 0; - - /* Rule 1: select IPsec transport */ - for (i = 0; i < n; i++) { - if (src[i]->mode == XFRM_MODE_TRANSPORT) { - dst[j++] = src[i]; - src[i] = NULL; - } - } - if (j == n) - goto end; - - /* Rule 2: select MIPv6 RO or inbound trigger */ + struct xfrm_state *v = p; + + switch (v->props.mode) { + case XFRM_MODE_TRANSPORT: + if (v->id.proto != IPPROTO_AH) + return 1; + else + return 3; #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) - for (i = 0; i < n; i++) { - if (src[i] && - (src[i]->mode == XFRM_MODE_ROUTEOPTIMIZATION || - src[i]->mode == XFRM_MODE_IN_TRIGGER)) { - dst[j++] = src[i]; - src[i] = NULL; - } - } - if (j == n) - goto end; + case XFRM_MODE_ROUTEOPTIMIZATION: + case XFRM_MODE_IN_TRIGGER: + return 2; #endif - - /* Rule 3: select IPsec tunnel */ - for (i = 0; i < n; i++) { - if (src[i] && - (src[i]->mode == XFRM_MODE_TUNNEL || - src[i]->mode == XFRM_MODE_BEET)) { - dst[j++] = src[i]; - src[i] = NULL; - } + case XFRM_MODE_TUNNEL: + case XFRM_MODE_BEET: + return 4; } - if (likely(j == n)) - goto end; + return 5; +} - /* Final rule */ - for (i = 0; i < n; i++) { - if (src[i]) { - dst[j++] = src[i]; - src[i] = NULL; - } +static int +__xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n) +{ + return __xfrm6_sort((void **)dst, (void **)src, n, + __xfrm6_state_sort_cmp, 6); +} + +/* + * Rule for xfrm_tmpl: + * + * rule 1: select IPsec transport + * rule 2: select MIPv6 RO or inbound trigger + * rule 3: select IPsec tunnel + * rule 4: others + */ +static int __xfrm6_tmpl_sort_cmp(void *p) +{ + struct xfrm_tmpl *v = p; + switch (v->mode) { + case XFRM_MODE_TRANSPORT: + return 1; +#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) + case XFRM_MODE_ROUTEOPTIMIZATION: + case XFRM_MODE_IN_TRIGGER: + return 2; +#endif + case XFRM_MODE_TUNNEL: + case XFRM_MODE_BEET: + return 3; } + return 4; +} - end: - return 0; +static int +__xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n) +{ + return __xfrm6_sort((void **)dst, (void **)src, n, + __xfrm6_tmpl_sort_cmp, 5); } int xfrm6_extract_header(struct sk_buff *skb) -- cgit v1.2.3-59-g8ed1b From a002c6fd714b1710aaf64e26db3f3f18bf8e8384 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 19 Feb 2008 17:24:33 +0900 Subject: [XFRM] IPV6: Optimize xfrm6_input_addr(). | % size old/net/ipv6/xfrm6_input.o new/net/ipv6/xfrm6_input.o | text data bss dec hex filename | 1026 0 0 1026 402 old/net/ipv6/xfrm6_input.o | 947 0 0 947 3b3 new/net/ipv6/xfrm6_input.o Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/xfrm6_input.c | 55 +++++++++++++------------------------------------- 1 file changed, 14 insertions(+), 41 deletions(-) (limited to 'net') diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index a4714d76ae6b..a71c7ddcb41e 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -59,9 +59,6 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto) { struct xfrm_state *x = NULL; - int wildcard = 0; - xfrm_address_t *xany; - int nh = 0; int i = 0; /* Allocate new secpath or COW existing one. */ @@ -83,10 +80,9 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, goto drop; } - xany = (xfrm_address_t *)&in6addr_any; - for (i = 0; i < 3; i++) { xfrm_address_t *dst, *src; + switch (i) { case 0: dst = daddr; @@ -94,16 +90,13 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, break; case 1: /* lookup state with wild-card source address */ - wildcard = 1; dst = daddr; - src = xany; + src = (xfrm_address_t *)&in6addr_any; break; - case 2: default: /* lookup state with wild-card addresses */ - wildcard = 1; /* XXX */ - dst = xany; - src = xany; + dst = (xfrm_address_t *)&in6addr_any; + src = (xfrm_address_t *)&in6addr_any; break; } @@ -113,39 +106,19 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, spin_lock(&x->lock); - if (wildcard) { - if ((x->props.flags & XFRM_STATE_WILDRECV) == 0) { - spin_unlock(&x->lock); - xfrm_state_put(x); - x = NULL; - continue; - } - } - - if (unlikely(x->km.state != XFRM_STATE_VALID)) { + if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) && + likely(x->km.state == XFRM_STATE_VALID) && + !xfrm_state_check_expire(x)) { spin_unlock(&x->lock); - xfrm_state_put(x); - x = NULL; - continue; - } - if (xfrm_state_check_expire(x)) { + if (x->type->input(x, skb) > 0) { + /* found a valid state */ + break; + } + } else spin_unlock(&x->lock); - xfrm_state_put(x); - x = NULL; - continue; - } - - spin_unlock(&x->lock); - - nh = x->type->input(x, skb); - if (nh <= 0) { - xfrm_state_put(x); - x = NULL; - continue; - } - /* Found a state */ - break; + xfrm_state_put(x); + x = NULL; } if (!x) { -- cgit v1.2.3-59-g8ed1b From df8ea19b5d2e7512095bb1e0737513b8da196d64 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 19 Feb 2008 22:54:00 +0900 Subject: [XFRM] IPV6: Optimize __xfrm_tunnel_alloc_spi(). | % size old/net/ipv6/xfrm6_tunnel.o new/net/ipv6/xfrm6_tunnel.o | text data bss dec hex filename | 1606 40 2080 3726 e8e old/net/ipv6/xfrm6_tunnel.o | 1574 40 2080 3694 e6e new/net/ipv6/xfrm6_tunnel.o Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/xfrm6_tunnel.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'net') diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 639fe8a6ff1e..c2b278138604 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -140,12 +140,26 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); +static int __xfrm6_tunnel_spi_check(u32 spi) +{ + struct xfrm6_tunnel_spi *x6spi; + int index = xfrm6_tunnel_spi_hash_byspi(spi); + struct hlist_node *pos; + + hlist_for_each_entry(x6spi, pos, + &xfrm6_tunnel_spi_byspi[index], + list_byspi) { + if (x6spi->spi == spi) + return -1; + } + return index; +} + static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) { u32 spi; struct xfrm6_tunnel_spi *x6spi; - struct hlist_node *pos; - unsigned index; + int index; if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN || xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX) @@ -154,32 +168,19 @@ static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) xfrm6_tunnel_spi++; for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { - index = xfrm6_tunnel_spi_hash_byspi(spi); - hlist_for_each_entry(x6spi, pos, - &xfrm6_tunnel_spi_byspi[index], - list_byspi) { - if (x6spi->spi == spi) - goto try_next_1; - } - xfrm6_tunnel_spi = spi; - goto alloc_spi; -try_next_1:; + index = __xfrm6_tunnel_spi_check(spi); + if (index >= 0) + goto alloc_spi; } for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) { - index = xfrm6_tunnel_spi_hash_byspi(spi); - hlist_for_each_entry(x6spi, pos, - &xfrm6_tunnel_spi_byspi[index], - list_byspi) { - if (x6spi->spi == spi) - goto try_next_2; - } - xfrm6_tunnel_spi = spi; - goto alloc_spi; -try_next_2:; + index = __xfrm6_tunnel_spi_check(spi); + if (index >= 0) + goto alloc_spi; } spi = 0; goto out; alloc_spi: + xfrm6_tunnel_spi = spi; x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); if (!x6spi) goto out; -- cgit v1.2.3-59-g8ed1b From 9bb182a7007515239091b237fe7169b1328a61d3 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Fri, 22 Feb 2008 14:48:22 +0900 Subject: [XFRM] MIP6: Fix address keys for routing search. Each MIPv6 XFRM state (DSTOPT/RH2) holds either destination or source address to be mangled in the IPv6 header (that is "CoA"). On Inter-MN communication after both nodes binds each other, they use route optimized traffic two MIPv6 states applied, and both source and destination address in the IPv6 header are replaced by the states respectively. The packet format is correct, however, next-hop routing search are not. This patch fixes it by remembering address pairs for later states. Based on patch from Masahide NAKAMURA . Signed-off-by: Masahide NAKAMURA Signed-off-by: YOSHIFUJI Hideaki --- include/net/xfrm.h | 17 +++++++++++++++++ net/xfrm/xfrm_policy.c | 49 ++++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 57 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/net/xfrm.h b/include/net/xfrm.h index c435620dbb37..bed7d43932f6 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1045,6 +1045,23 @@ xfrm_address_t *xfrm_flowi_saddr(struct flowi *fl, unsigned short family) return NULL; } +static __inline__ +void xfrm_flowi_addr_get(struct flowi *fl, + xfrm_address_t *saddr, xfrm_address_t *daddr, + unsigned short family) +{ + switch(family) { + case AF_INET: + memcpy(&saddr->a4, &fl->fl4_src, sizeof(saddr->a4)); + memcpy(&daddr->a4, &fl->fl4_dst, sizeof(daddr->a4)); + break; + case AF_INET6: + ipv6_addr_copy((struct in6_addr *)&saddr->a6, &fl->fl6_src); + ipv6_addr_copy((struct in6_addr *)&daddr->a6, &fl->fl6_dst); + break; + } +} + static __inline__ int __xfrm4_state_addr_check(struct xfrm_state *x, xfrm_address_t *daddr, xfrm_address_t *saddr) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index bae94a8031a2..8e588f20c60c 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -97,25 +97,52 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl, return 0; } +static inline struct dst_entry *__xfrm_dst_lookup(int tos, + xfrm_address_t *saddr, + xfrm_address_t *daddr, + int family) +{ + struct xfrm_policy_afinfo *afinfo; + struct dst_entry *dst; + + afinfo = xfrm_policy_get_afinfo(family); + if (unlikely(afinfo == NULL)) + return ERR_PTR(-EAFNOSUPPORT); + + dst = afinfo->dst_lookup(tos, saddr, daddr); + + xfrm_policy_put_afinfo(afinfo); + + return dst; +} + static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos, + xfrm_address_t *prev_saddr, + xfrm_address_t *prev_daddr, int family) { xfrm_address_t *saddr = &x->props.saddr; xfrm_address_t *daddr = &x->id.daddr; - struct xfrm_policy_afinfo *afinfo; struct dst_entry *dst; - if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) + if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) { saddr = x->coaddr; - if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) + daddr = prev_daddr; + } + if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) { + saddr = prev_saddr; daddr = x->coaddr; + } - afinfo = xfrm_policy_get_afinfo(family); - if (unlikely(afinfo == NULL)) - return ERR_PTR(-EAFNOSUPPORT); + dst = __xfrm_dst_lookup(tos, saddr, daddr, family); + + if (!IS_ERR(dst)) { + if (prev_saddr != saddr) + memcpy(prev_saddr, saddr, sizeof(*prev_saddr)); + if (prev_daddr != daddr) + memcpy(prev_daddr, daddr, sizeof(*prev_daddr)); + } - dst = afinfo->dst_lookup(tos, saddr, daddr); - xfrm_policy_put_afinfo(afinfo); return dst; } @@ -1354,6 +1381,9 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, int trailer_len = 0; int tos; int family = policy->selector.family; + xfrm_address_t saddr, daddr; + + xfrm_flowi_addr_get(fl, &saddr, &daddr, family); tos = xfrm_get_tos(fl, family); err = tos; @@ -1384,7 +1414,8 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { family = xfrm[i]->props.family; - dst = xfrm_dst_lookup(xfrm[i], tos, family); + dst = xfrm_dst_lookup(xfrm[i], tos, &saddr, &daddr, + family); err = PTR_ERR(dst); if (IS_ERR(dst)) goto put_states; -- cgit v1.2.3-59-g8ed1b From a9b05723ffa2e427b0257b81ea74363fcd7c304f Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sun, 2 Mar 2008 10:48:21 +0900 Subject: [IPV6] ADDRCONF: Clean-up ipv6_dev_get_saddr(). old: | text data bss dec hex filename | 28599 1416 96 30111 759f net/ipv6/addrconf.o new: | text data bss dec hex filename | 28007 1416 96 29519 734f net/ipv6/addrconf.o Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/addrconf.c | 420 ++++++++++++++++++++++++++-------------------------- 1 file changed, 206 insertions(+), 214 deletions(-) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4b86d388bf63..787e90af166c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -877,20 +877,39 @@ out: /* * Choose an appropriate source address (RFC3484) */ +enum { + IPV6_SADDR_RULE_INIT = 0, + IPV6_SADDR_RULE_LOCAL, + IPV6_SADDR_RULE_SCOPE, + IPV6_SADDR_RULE_PREFERRED, +#ifdef CONFIG_IPV6_MIP6 + IPV6_SADDR_RULE_HOA, +#endif + IPV6_SADDR_RULE_OIF, + IPV6_SADDR_RULE_LABEL, +#ifdef CONFIG_IPV6_PRIVACY + IPV6_SADDR_RULE_PRIVACY, +#endif + IPV6_SADDR_RULE_ORCHID, + IPV6_SADDR_RULE_PREFIX, + IPV6_SADDR_RULE_MAX +}; + struct ipv6_saddr_score { - int addr_type; - unsigned int attrs; - int matchlen; - int scope; - unsigned int rule; + int rule; + int addr_type; + struct inet6_ifaddr *ifa; + DECLARE_BITMAP(scorebits, IPV6_SADDR_RULE_MAX); + int scopedist; + int matchlen; }; -#define IPV6_SADDR_SCORE_LOCAL 0x0001 -#define IPV6_SADDR_SCORE_PREFERRED 0x0004 -#define IPV6_SADDR_SCORE_HOA 0x0008 -#define IPV6_SADDR_SCORE_OIF 0x0010 -#define IPV6_SADDR_SCORE_LABEL 0x0020 -#define IPV6_SADDR_SCORE_PRIVACY 0x0040 +struct ipv6_saddr_dst { + struct in6_addr *addr; + int ifindex; + int scope; + int label; +}; static inline int ipv6_saddr_preferred(int type) { @@ -900,28 +919,142 @@ static inline int ipv6_saddr_preferred(int type) return 0; } -int ipv6_dev_get_saddr(struct net_device *daddr_dev, +static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score, + struct ipv6_saddr_dst *dst, + int i) +{ + int ret; + + if (i <= score->rule) { + switch (i) { + case IPV6_SADDR_RULE_SCOPE: + ret = score->scopedist; + break; + case IPV6_SADDR_RULE_PREFIX: + ret = score->matchlen; + break; + default: + ret = !!test_bit(i, score->scorebits); + } + goto out; + } + + switch (i) { + case IPV6_SADDR_RULE_INIT: + /* Rule 0: remember if hiscore is not ready yet */ + ret = !!score->ifa; + break; + case IPV6_SADDR_RULE_LOCAL: + /* Rule 1: Prefer same address */ + ret = ipv6_addr_equal(&score->ifa->addr, dst->addr); + break; + case IPV6_SADDR_RULE_SCOPE: + /* Rule 2: Prefer appropriate scope + * + * ret + * ^ + * -1 | d 15 + * ---+--+-+---> scope + * | + * | d is scope of the destination. + * B-d | \ + * | \ <- smaller scope is better if + * B-15 | \ if scope is enough for destinaion. + * | ret = B - scope (-1 <= scope >= d <= 15). + * d-C-1 | / + * |/ <- greater is better + * -C / if scope is not enough for destination. + * /| ret = scope - C (-1 <= d < scope <= 15). + * + * d - C - 1 < B -15 (for all -1 <= d <= 15). + * C > d + 14 - B >= 15 + 14 - B = 29 - B. + * Assume B = 0 and we get C > 29. + */ + ret = __ipv6_addr_src_scope(score->addr_type); + if (ret >= dst->scope) + ret = -ret; + else + ret -= 128; /* 30 is enough */ + score->scopedist = ret; + break; + case IPV6_SADDR_RULE_PREFERRED: + /* Rule 3: Avoid deprecated and optimistic addresses */ + ret = ipv6_saddr_preferred(score->addr_type) || + !(score->ifa->flags & (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)); + break; +#ifdef CONFIG_IPV6_MIP6 + case IPV6_SADDR_RULE_HOA: + /* Rule 4: Prefer home address */ + ret = !!(score->ifa->flags & IFA_F_HOMEADDRESS); + break; +#endif + case IPV6_SADDR_RULE_OIF: + /* Rule 5: Prefer outgoing interface */ + ret = (!dst->ifindex || + dst->ifindex == score->ifa->idev->dev->ifindex); + break; + case IPV6_SADDR_RULE_LABEL: + /* Rule 6: Prefer matching label */ + ret = ipv6_addr_label(&score->ifa->addr, score->addr_type, + score->ifa->idev->dev->ifindex) == dst->label; + break; +#ifdef CONFIG_IPV6_PRIVACY + case IPV6_SADDR_RULE_PRIVACY: + /* Rule 7: Prefer public address + * Note: prefer temprary address if use_tempaddr >= 2 + */ + ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ (score->ifa->idev->cnf.use_tempaddr >= 2); + break; +#endif + case IPV6_SADDR_RULE_ORCHID: + /* Rule 8-: Prefer ORCHID vs ORCHID or + * non-ORCHID vs non-ORCHID + */ + ret = !(ipv6_addr_orchid(&score->ifa->addr) ^ + ipv6_addr_orchid(dst->addr)); + break; + case IPV6_SADDR_RULE_PREFIX: + /* Rule 8: Use longest matching prefix */ + score->matchlen = ret = ipv6_addr_diff(&score->ifa->addr, + dst->addr); + break; + default: + ret = 0; + } + + if (ret) + __set_bit(i, score->scorebits); + score->rule = i; +out: + return ret; +} + +int ipv6_dev_get_saddr(struct net_device *dst_dev, struct in6_addr *daddr, struct in6_addr *saddr) { - struct ipv6_saddr_score hiscore; - struct inet6_ifaddr *ifa_result = NULL; - struct net *net = daddr_dev->nd_net; - int daddr_type = __ipv6_addr_type(daddr); - int daddr_scope = __ipv6_addr_src_scope(daddr_type); - int daddr_ifindex = daddr_dev ? daddr_dev->ifindex : 0; - u32 daddr_label = ipv6_addr_label(daddr, daddr_type, daddr_ifindex); + struct ipv6_saddr_score scores[2], + *score = &scores[0], *hiscore = &scores[1]; + struct net *net = dst_dev->nd_net; + struct ipv6_saddr_dst dst; struct net_device *dev; + int dst_type; + + dst_type = __ipv6_addr_type(daddr); + dst.addr = daddr; + dst.ifindex = dst_dev ? dst_dev->ifindex : 0; + dst.scope = __ipv6_addr_src_scope(dst_type); + dst.label = ipv6_addr_label(daddr, dst_type, dst.ifindex); - memset(&hiscore, 0, sizeof(hiscore)); + hiscore->rule = -1; + hiscore->ifa = NULL; read_lock(&dev_base_lock); rcu_read_lock(); for_each_netdev(net, dev) { struct inet6_dev *idev; - struct inet6_ifaddr *ifa; - /* Rule 0: Candidate Source Address (section 4) + /* Candidate Source Address (section 4) * - multicast and link-local destination address, * the set of candidate source address MUST only * include addresses assigned to interfaces @@ -933,9 +1066,9 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, * belonging to the same site as the outgoing * interface.) */ - if ((daddr_type & IPV6_ADDR_MULTICAST || - daddr_scope <= IPV6_ADDR_SCOPE_LINKLOCAL) && - daddr_dev && dev != daddr_dev) + if (((dst_type & IPV6_ADDR_MULTICAST) || + dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL) && + dst.ifindex && dev->ifindex != dst.ifindex) continue; idev = __in6_dev_get(dev); @@ -943,12 +1076,10 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, continue; read_lock_bh(&idev->lock); - for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) { - struct ipv6_saddr_score score; + for (score->ifa = idev->addr_list; score->ifa; score->ifa = score->ifa->if_next) { + int i; - score.addr_type = __ipv6_addr_type(&ifa->addr); - - /* Rule 0: + /* * - Tentative Address (RFC2462 section 5.4) * - A tentative address is not considered * "assigned to an interface" in the traditional @@ -958,11 +1089,14 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, * addresses, and the unspecified address MUST * NOT be included in a candidate set. */ - if ((ifa->flags & IFA_F_TENTATIVE) && - (!(ifa->flags & IFA_F_OPTIMISTIC))) + if ((score->ifa->flags & IFA_F_TENTATIVE) && + (!(score->ifa->flags & IFA_F_OPTIMISTIC))) continue; - if (unlikely(score.addr_type == IPV6_ADDR_ANY || - score.addr_type & IPV6_ADDR_MULTICAST)) { + + score->addr_type = __ipv6_addr_type(&score->ifa->addr); + + if (unlikely(score->addr_type == IPV6_ADDR_ANY || + score->addr_type & IPV6_ADDR_MULTICAST)) { LIMIT_NETDEBUG(KERN_DEBUG "ADDRCONF: unspecified / multicast address " "assigned as unicast address on %s", @@ -970,201 +1104,59 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, continue; } - score.attrs = 0; - score.matchlen = 0; - score.scope = 0; - score.rule = 0; - - if (ifa_result == NULL) { - /* record it if the first available entry */ - goto record_it; - } - - /* Rule 1: Prefer same address */ - if (hiscore.rule < 1) { - if (ipv6_addr_equal(&ifa_result->addr, daddr)) - hiscore.attrs |= IPV6_SADDR_SCORE_LOCAL; - hiscore.rule++; - } - if (ipv6_addr_equal(&ifa->addr, daddr)) { - score.attrs |= IPV6_SADDR_SCORE_LOCAL; - if (!(hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)) { - score.rule = 1; - goto record_it; - } - } else { - if (hiscore.attrs & IPV6_SADDR_SCORE_LOCAL) - continue; - } + score->rule = -1; + bitmap_zero(score->scorebits, IPV6_SADDR_RULE_MAX); + + for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) { + int minihiscore, miniscore; + + minihiscore = ipv6_get_saddr_eval(hiscore, &dst, i); + miniscore = ipv6_get_saddr_eval(score, &dst, i); + + if (minihiscore > miniscore) { + if (i == IPV6_SADDR_RULE_SCOPE && + score->scopedist > 0) { + /* + * special case: + * each remaining entry + * has too small (not enough) + * scope, because ifa entries + * are sorted by their scope + * values. + */ + goto try_nextdev; + } + break; + } else if (minihiscore < miniscore) { + struct ipv6_saddr_score *tmp; - /* Rule 2: Prefer appropriate scope */ - if (hiscore.rule < 2) { - hiscore.scope = __ipv6_addr_src_scope(hiscore.addr_type); - hiscore.rule++; - } - score.scope = __ipv6_addr_src_scope(score.addr_type); - if (hiscore.scope < score.scope) { - if (hiscore.scope < daddr_scope) { - score.rule = 2; - goto record_it; - } else - continue; - } else if (score.scope < hiscore.scope) { - if (score.scope < daddr_scope) - break; /* addresses sorted by scope */ - else { - score.rule = 2; - goto record_it; - } - } + if (hiscore->ifa) + in6_ifa_put(hiscore->ifa); - /* Rule 3: Avoid deprecated and optimistic addresses */ - if (hiscore.rule < 3) { - if (ipv6_saddr_preferred(hiscore.addr_type) || - (((ifa_result->flags & - (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) - hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED; - hiscore.rule++; - } - if (ipv6_saddr_preferred(score.addr_type) || - (((ifa->flags & - (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) { - score.attrs |= IPV6_SADDR_SCORE_PREFERRED; - if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) { - score.rule = 3; - goto record_it; - } - } else { - if (hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED) - continue; - } + in6_ifa_hold(score->ifa); - /* Rule 4: Prefer home address */ -#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) - if (hiscore.rule < 4) { - if (ifa_result->flags & IFA_F_HOMEADDRESS) - hiscore.attrs |= IPV6_SADDR_SCORE_HOA; - hiscore.rule++; - } - if (ifa->flags & IFA_F_HOMEADDRESS) { - score.attrs |= IPV6_SADDR_SCORE_HOA; - if (!(ifa_result->flags & IFA_F_HOMEADDRESS)) { - score.rule = 4; - goto record_it; - } - } else { - if (hiscore.attrs & IPV6_SADDR_SCORE_HOA) - continue; - } -#else - if (hiscore.rule < 4) - hiscore.rule++; -#endif + tmp = hiscore; + hiscore = score; + score = tmp; - /* Rule 5: Prefer outgoing interface */ - if (hiscore.rule < 5) { - if (daddr_dev == NULL || - daddr_dev == ifa_result->idev->dev) - hiscore.attrs |= IPV6_SADDR_SCORE_OIF; - hiscore.rule++; - } - if (daddr_dev == NULL || - daddr_dev == ifa->idev->dev) { - score.attrs |= IPV6_SADDR_SCORE_OIF; - if (!(hiscore.attrs & IPV6_SADDR_SCORE_OIF)) { - score.rule = 5; - goto record_it; - } - } else { - if (hiscore.attrs & IPV6_SADDR_SCORE_OIF) - continue; - } - - /* Rule 6: Prefer matching label */ - if (hiscore.rule < 6) { - if (ipv6_addr_label(&ifa_result->addr, - hiscore.addr_type, - ifa_result->idev->dev->ifindex) == daddr_label) - hiscore.attrs |= IPV6_SADDR_SCORE_LABEL; - hiscore.rule++; - } - if (ipv6_addr_label(&ifa->addr, - score.addr_type, - ifa->idev->dev->ifindex) == daddr_label) { - score.attrs |= IPV6_SADDR_SCORE_LABEL; - if (!(hiscore.attrs & IPV6_SADDR_SCORE_LABEL)) { - score.rule = 6; - goto record_it; - } - } else { - if (hiscore.attrs & IPV6_SADDR_SCORE_LABEL) - continue; - } + /* restore our iterator */ + score->ifa = hiscore->ifa; -#ifdef CONFIG_IPV6_PRIVACY - /* Rule 7: Prefer public address - * Note: prefer temprary address if use_tempaddr >= 2 - */ - if (hiscore.rule < 7) { - if ((!(ifa_result->flags & IFA_F_TEMPORARY)) ^ - (ifa_result->idev->cnf.use_tempaddr >= 2)) - hiscore.attrs |= IPV6_SADDR_SCORE_PRIVACY; - hiscore.rule++; - } - if ((!(ifa->flags & IFA_F_TEMPORARY)) ^ - (ifa->idev->cnf.use_tempaddr >= 2)) { - score.attrs |= IPV6_SADDR_SCORE_PRIVACY; - if (!(hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)) { - score.rule = 7; - goto record_it; + break; } - } else { - if (hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY) - continue; - } -#else - if (hiscore.rule < 7) - hiscore.rule++; -#endif - - /* Skip rule 8 for orchid -> non-orchid address pairs. */ - if (ipv6_addr_orchid(&ifa->addr) && !ipv6_addr_orchid(daddr)) - continue; - - /* Rule 8: Use longest matching prefix */ - if (hiscore.rule < 8) { - hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr); - hiscore.rule++; - } - score.matchlen = ipv6_addr_diff(&ifa->addr, daddr); - if (score.matchlen > hiscore.matchlen) { - score.rule = 8; - goto record_it; } -#if 0 - else if (score.matchlen < hiscore.matchlen) - continue; -#endif - - /* Final Rule: choose first available one */ - continue; -record_it: - if (ifa_result) - in6_ifa_put(ifa_result); - in6_ifa_hold(ifa); - ifa_result = ifa; - hiscore = score; } +try_nextdev: read_unlock_bh(&idev->lock); } rcu_read_unlock(); read_unlock(&dev_base_lock); - if (!ifa_result) + if (!hiscore->ifa) return -EADDRNOTAVAIL; - ipv6_addr_copy(saddr, &ifa_result->addr); - in6_ifa_put(ifa_result); + ipv6_addr_copy(saddr, &hiscore->ifa->addr); + in6_ifa_put(hiscore->ifa); return 0; } -- cgit v1.2.3-59-g8ed1b From c8cdaf998df221b01134a051aba38c570105061b Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Mon, 10 Mar 2008 04:30:37 -0400 Subject: [IPV4,IPV6]: Share cork.rt between IPv4 and IPv6. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/ipv6.h | 1 - include/net/inet_sock.h | 2 +- net/ipv4/ip_output.c | 14 ++++++-------- net/ipv6/ip6_output.c | 12 ++++++------ 4 files changed, 13 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 4aaefc349a4b..2102d8b67c01 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -315,7 +315,6 @@ struct ipv6_pinfo { struct sk_buff *pktoptions; struct { struct ipv6_txoptions *opt; - struct rt6_info *rt; int hop_limit; int tclass; } cork; diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index b6db16d2766a..a42cd63d241a 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h @@ -136,7 +136,7 @@ struct inet_sock { unsigned int flags; unsigned int fragsize; struct ip_options *opt; - struct rtable *rt; + struct dst_entry *dst; int length; /* Total length of all frames */ __be32 addr; struct flowi fl; diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 349fae58c1a3..913266cd9902 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -825,7 +825,7 @@ int ip_append_data(struct sock *sk, inet->cork.fragsize = mtu = inet->pmtudisc == IP_PMTUDISC_PROBE ? rt->u.dst.dev->mtu : dst_mtu(rt->u.dst.path); - inet->cork.rt = rt; + inet->cork.dst = &rt->u.dst; inet->cork.length = 0; sk->sk_sndmsg_page = NULL; sk->sk_sndmsg_off = 0; @@ -834,7 +834,7 @@ int ip_append_data(struct sock *sk, transhdrlen += exthdrlen; } } else { - rt = inet->cork.rt; + rt = (struct rtable *)inet->cork.dst; if (inet->cork.flags & IPCORK_OPT) opt = inet->cork.opt; @@ -1083,7 +1083,7 @@ ssize_t ip_append_page(struct sock *sk, struct page *page, if (skb_queue_empty(&sk->sk_write_queue)) return -EINVAL; - rt = inet->cork.rt; + rt = (struct rtable *)inet->cork.dst; if (inet->cork.flags & IPCORK_OPT) opt = inet->cork.opt; @@ -1208,10 +1208,8 @@ static void ip_cork_release(struct inet_sock *inet) inet->cork.flags &= ~IPCORK_OPT; kfree(inet->cork.opt); inet->cork.opt = NULL; - if (inet->cork.rt) { - ip_rt_put(inet->cork.rt); - inet->cork.rt = NULL; - } + dst_release(inet->cork.dst); + inet->cork.dst = NULL; } /* @@ -1224,7 +1222,7 @@ int ip_push_pending_frames(struct sock *sk) struct sk_buff **tail_skb; struct inet_sock *inet = inet_sk(sk); struct ip_options *opt = NULL; - struct rtable *rt = inet->cork.rt; + struct rtable *rt = (struct rtable *)inet->cork.dst; struct iphdr *iph; __be16 df = 0; __u8 ttl; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 98762fde2b65..ed6482667a25 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1115,7 +1115,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, /* need source address above miyazawa*/ } dst_hold(&rt->u.dst); - np->cork.rt = rt; + inet->cork.dst = &rt->u.dst; inet->cork.fl = *fl; np->cork.hop_limit = hlimit; np->cork.tclass = tclass; @@ -1136,7 +1136,7 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, length += exthdrlen; transhdrlen += exthdrlen; } else { - rt = np->cork.rt; + rt = (struct rt6_info *)inet->cork.dst; fl = &inet->cork.fl; if (inet->cork.flags & IPCORK_OPT) opt = np->cork.opt; @@ -1381,9 +1381,9 @@ static void ip6_cork_release(struct inet_sock *inet, struct ipv6_pinfo *np) inet->cork.flags &= ~IPCORK_OPT; kfree(np->cork.opt); np->cork.opt = NULL; - if (np->cork.rt) { - dst_release(&np->cork.rt->u.dst); - np->cork.rt = NULL; + if (inet->cork.dst) { + dst_release(inet->cork.dst); + inet->cork.dst = NULL; inet->cork.flags &= ~IPCORK_ALLFRAG; } memset(&inet->cork.fl, 0, sizeof(inet->cork.fl)); @@ -1398,7 +1398,7 @@ int ip6_push_pending_frames(struct sock *sk) struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6hdr *hdr; struct ipv6_txoptions *opt = np->cork.opt; - struct rt6_info *rt = np->cork.rt; + struct rt6_info *rt = (struct rt6_info *)inet->cork.dst; struct flowi *fl = &inet->cork.fl; unsigned char proto = fl->proto; int err = 0; -- cgit v1.2.3-59-g8ed1b From 6b75d0908185bf853b188afa6f269426f6554c5b Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Mon, 10 Mar 2008 06:00:30 -0400 Subject: [IPV6]: Optimize hop-limit determination. Last part of hop-limit determination is always: hoplimit = dst_metric(dst, RTAX_HOPLIMIT); if (hoplimit < 0) hoplimit = ipv6_get_hoplimit(dst->dev). Let's consolidate it as ip6_dst_hoplimit(dst). Signed-off-by: YOSHIFUJI Hideaki --- include/net/addrconf.h | 2 -- include/net/ip6_route.h | 2 ++ net/ipv6/icmp.c | 8 ++------ net/ipv6/ip6_output.c | 4 +--- net/ipv6/ipv6_sockglue.c | 4 +--- net/ipv6/raw.c | 4 +--- net/ipv6/route.c | 20 +++++++++++--------- net/ipv6/udp.c | 4 +--- 8 files changed, 19 insertions(+), 29 deletions(-) (limited to 'net') diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 232da20e7171..edcb4bbaab7d 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -123,8 +123,6 @@ extern int ipv6_is_mld(struct sk_buff *skb, int nexthdr); extern void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len); -extern int ipv6_get_hoplimit(struct net_device *dev); - /* * anycast prototypes (anycast.c) */ diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 0e2895c8b270..5c3b67c86aef 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -88,6 +88,8 @@ extern struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, const struct in6_addr *addr, int anycast); +extern int ip6_dst_hoplimit(struct dst_entry *dst); + /* * support functions for ND * diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 6b5391ab8346..86332417b402 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -464,9 +464,7 @@ route_done: else hlimit = np->hop_limit; if (hlimit < 0) - hlimit = dst_metric(dst, RTAX_HOPLIMIT); - if (hlimit < 0) - hlimit = ipv6_get_hoplimit(dst->dev); + hlimit = ip6_dst_hoplimit(dst); tclass = np->tclass; if (tclass < 0) @@ -560,9 +558,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) else hlimit = np->hop_limit; if (hlimit < 0) - hlimit = dst_metric(dst, RTAX_HOPLIMIT); - if (hlimit < 0) - hlimit = ipv6_get_hoplimit(dst->dev); + hlimit = ip6_dst_hoplimit(dst); tclass = np->tclass; if (tclass < 0) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index ed6482667a25..2a4f08c8a02d 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -237,9 +237,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, if (np) hlimit = np->hop_limit; if (hlimit < 0) - hlimit = dst_metric(dst, RTAX_HOPLIMIT); - if (hlimit < 0) - hlimit = ipv6_get_hoplimit(dst->dev); + hlimit = ip6_dst_hoplimit(dst); tclass = -1; if (np) diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index c11c76cab371..8e29fb1d1df6 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -904,9 +904,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, dst = sk_dst_get(sk); if (dst) { if (val < 0) - val = dst_metric(dst, RTAX_HOPLIMIT); - if (val < 0) - val = ipv6_get_hoplimit(dst->dev); + val = ip6_dst_hoplimit(dst); dst_release(dst); } if (val < 0) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index a9e4235157a2..548d0763f4d3 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -885,9 +885,7 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, else hlimit = np->hop_limit; if (hlimit < 0) - hlimit = dst_metric(dst, RTAX_HOPLIMIT); - if (hlimit < 0) - hlimit = ipv6_get_hoplimit(dst->dev); + hlimit = ip6_dst_hoplimit(dst); } if (tclass < 0) { diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a4b5aee0f68a..aa3f08718e44 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1034,15 +1034,17 @@ static int ipv6_get_mtu(struct net_device *dev) return mtu; } -int ipv6_get_hoplimit(struct net_device *dev) -{ - int hoplimit = ipv6_devconf.hop_limit; - struct inet6_dev *idev; - - idev = in6_dev_get(dev); - if (idev) { - hoplimit = idev->cnf.hop_limit; - in6_dev_put(idev); +int ip6_dst_hoplimit(struct dst_entry *dst) +{ + int hoplimit = dst_metric(dst, RTAX_HOPLIMIT); + if (hoplimit < 0) { + struct net_device *dev = dst->dev; + struct inet6_dev *idev = in6_dev_get(dev); + if (idev) { + hoplimit = idev->cnf.hop_limit; + in6_dev_put(idev); + } else + hoplimit = ipv6_devconf.hop_limit; } return hoplimit; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 5f5d1218c34e..593d3efadaf9 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -792,9 +792,7 @@ do_udp_sendmsg: else hlimit = np->hop_limit; if (hlimit < 0) - hlimit = dst_metric(dst, RTAX_HOPLIMIT); - if (hlimit < 0) - hlimit = ipv6_get_hoplimit(dst->dev); + hlimit = ip6_dst_hoplimit(dst); } if (tclass < 0) { -- cgit v1.2.3-59-g8ed1b From 7cbca67c073263c179f605bdbbdc565ab29d801d Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 25 Mar 2008 09:37:42 +0900 Subject: [IPV6]: Support Source Address Selection API (RFC5014). Signed-off-by: YOSHIFUJI Hideaki --- include/linux/in6.h | 11 +++++++ include/linux/ipv6.h | 6 +++- include/net/addrconf.h | 1 + include/net/ip6_route.h | 9 ++++-- net/ipv6/addrconf.c | 17 +++++++++-- net/ipv6/fib6_rules.c | 12 +++++++- net/ipv6/ip6_output.c | 4 ++- net/ipv6/ipv6_sockglue.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/ndisc.c | 4 ++- net/ipv6/route.c | 11 ++++++- net/ipv6/xfrm6_policy.c | 2 +- net/sctp/ipv6.c | 4 ++- 12 files changed, 146 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/include/linux/in6.h b/include/linux/in6.h index 2a61c82af115..f674000c6c99 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -249,4 +249,15 @@ struct in6_flowlabel_req * IP6T_SO_GET_REVISION_TARGET 69 */ +/* RFC5014: Source address selection */ +#define IPV6_ADDR_PREFERENCES 72 + +#define IPV6_PREFER_SRC_TMP 0x0001 +#define IPV6_PREFER_SRC_PUBLIC 0x0002 +#define IPV6_PREFER_SRC_PUBTMP_DEFAULT 0x0100 +#define IPV6_PREFER_SRC_COA 0x0004 +#define IPV6_PREFER_SRC_HOME 0x0400 +#define IPV6_PREFER_SRC_CGA 0x0008 +#define IPV6_PREFER_SRC_NONCGA 0x0800 + #endif diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 87ae4e389ce1..c9ba0da16ce9 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -322,7 +322,11 @@ struct ipv6_pinfo { __u8 recverr:1, sndflow:1, pmtudisc:2, - ipv6only:1; + ipv6only:1, + srcprefs:3; /* 001: prefer temporary address + * 010: prefer public address + * 100: prefer care-of address + */ __u8 tclass; __u32 dst_cookie; diff --git a/include/net/addrconf.h b/include/net/addrconf.h index edcb4bbaab7d..c9276c72764d 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -78,6 +78,7 @@ extern struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, extern int ipv6_dev_get_saddr(struct net_device *dev, struct in6_addr *daddr, + unsigned int srcprefs, struct in6_addr *saddr); extern int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 5c3b67c86aef..3ae6799c2b14 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -30,9 +30,12 @@ struct route_info { #include #include -#define RT6_LOOKUP_F_IFACE 0x1 -#define RT6_LOOKUP_F_REACHABLE 0x2 -#define RT6_LOOKUP_F_HAS_SADDR 0x4 +#define RT6_LOOKUP_F_IFACE 0x00000001 +#define RT6_LOOKUP_F_REACHABLE 0x00000002 +#define RT6_LOOKUP_F_HAS_SADDR 0x00000004 +#define RT6_LOOKUP_F_SRCPREF_TMP 0x00000008 +#define RT6_LOOKUP_F_SRCPREF_PUBLIC 0x00000010 +#define RT6_LOOKUP_F_SRCPREF_COA 0x00000020 extern struct rt6_info *ip6_null_entry; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 787e90af166c..89954885dee1 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -909,6 +909,7 @@ struct ipv6_saddr_dst { int ifindex; int scope; int label; + unsigned int prefs; }; static inline int ipv6_saddr_preferred(int type) @@ -984,9 +985,12 @@ static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score, break; #ifdef CONFIG_IPV6_MIP6 case IPV6_SADDR_RULE_HOA: + { /* Rule 4: Prefer home address */ - ret = !!(score->ifa->flags & IFA_F_HOMEADDRESS); + int prefhome = !(dst->prefs & IPV6_PREFER_SRC_COA); + ret = !(score->ifa->flags & IFA_F_HOMEADDRESS) ^ prefhome; break; + } #endif case IPV6_SADDR_RULE_OIF: /* Rule 5: Prefer outgoing interface */ @@ -1000,11 +1004,16 @@ static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score, break; #ifdef CONFIG_IPV6_PRIVACY case IPV6_SADDR_RULE_PRIVACY: + { /* Rule 7: Prefer public address * Note: prefer temprary address if use_tempaddr >= 2 */ - ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ (score->ifa->idev->cnf.use_tempaddr >= 2); + int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ? + !!(dst->prefs & IPV6_PREFER_SRC_TMP) : + score->ifa->idev->cnf.use_tempaddr >= 2; + ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ preftmp; break; + } #endif case IPV6_SADDR_RULE_ORCHID: /* Rule 8-: Prefer ORCHID vs ORCHID or @@ -1030,7 +1039,8 @@ out: } int ipv6_dev_get_saddr(struct net_device *dst_dev, - struct in6_addr *daddr, struct in6_addr *saddr) + struct in6_addr *daddr, unsigned int prefs, + struct in6_addr *saddr) { struct ipv6_saddr_score scores[2], *score = &scores[0], *hiscore = &scores[1]; @@ -1044,6 +1054,7 @@ int ipv6_dev_get_saddr(struct net_device *dst_dev, dst.ifindex = dst_dev ? dst_dev->ifindex : 0; dst.scope = __ipv6_addr_src_scope(dst_type); dst.label = ipv6_addr_label(daddr, dst_type, dst.ifindex); + dst.prefs = prefs; hiscore->rule = -1; hiscore->ifa = NULL; diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 55137408f054..e7a7fe26cebf 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -84,8 +84,18 @@ static int fib6_rule_action(struct fib_rule *rule, struct flowi *flp, if ((rule->flags & FIB_RULE_FIND_SADDR) && r->src.plen && !(flags & RT6_LOOKUP_F_HAS_SADDR)) { struct in6_addr saddr; + unsigned int srcprefs = 0; + + if (flags & RT6_LOOKUP_F_SRCPREF_TMP) + srcprefs |= IPV6_PREFER_SRC_TMP; + if (flags & RT6_LOOKUP_F_SRCPREF_PUBLIC) + srcprefs |= IPV6_PREFER_SRC_PUBLIC; + if (flags & RT6_LOOKUP_F_SRCPREF_COA) + srcprefs |= IPV6_PREFER_SRC_COA; + if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev, - &flp->fl6_dst, &saddr)) + &flp->fl6_dst, srcprefs, + &saddr)) goto again; if (!ipv6_prefix_equal(&saddr, &r->src.addr, r->src.plen)) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 2a4f08c8a02d..d34aa61353bb 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -920,7 +920,9 @@ static int ip6_dst_lookup_tail(struct sock *sk, if (ipv6_addr_any(&fl->fl6_src)) { err = ipv6_dev_get_saddr(ip6_dst_idev(*dst)->dev, - &fl->fl6_dst, &fl->fl6_src); + &fl->fl6_dst, + sk ? inet6_sk(sk)->srcprefs : 0, + &fl->fl6_src); if (err) goto out_err_release; } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 8e29fb1d1df6..dc6695cc5767 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -617,7 +617,67 @@ done: retv = xfrm_user_policy(sk, optname, optval, optlen); break; + case IPV6_ADDR_PREFERENCES: + { + unsigned int pref = 0; + unsigned int prefmask = ~0; + + retv = -EINVAL; + + /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */ + switch (val & (IPV6_PREFER_SRC_PUBLIC| + IPV6_PREFER_SRC_TMP| + IPV6_PREFER_SRC_PUBTMP_DEFAULT)) { + case IPV6_PREFER_SRC_PUBLIC: + pref |= IPV6_PREFER_SRC_PUBLIC; + break; + case IPV6_PREFER_SRC_TMP: + pref |= IPV6_PREFER_SRC_TMP; + break; + case IPV6_PREFER_SRC_PUBTMP_DEFAULT: + break; + case 0: + goto pref_skip_pubtmp; + default: + goto e_inval; + } + + prefmask &= ~(IPV6_PREFER_SRC_PUBLIC| + IPV6_PREFER_SRC_TMP); +pref_skip_pubtmp: + + /* check HOME/COA conflicts */ + switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) { + case IPV6_PREFER_SRC_HOME: + break; + case IPV6_PREFER_SRC_COA: + pref |= IPV6_PREFER_SRC_COA; + case 0: + goto pref_skip_coa; + default: + goto e_inval; + } + + prefmask &= ~IPV6_PREFER_SRC_COA; +pref_skip_coa: + + /* check CGA/NONCGA conflicts */ + switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) { + case IPV6_PREFER_SRC_CGA: + case IPV6_PREFER_SRC_NONCGA: + case 0: + break; + default: + goto e_inval; + } + + np->srcprefs = (np->srcprefs & prefmask) | pref; + retv = 0; + + break; + } } + release_sock(sk); return retv; @@ -932,6 +992,24 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, val = np->sndflow; break; + case IPV6_ADDR_PREFERENCES: + val = 0; + + if (np->srcprefs & IPV6_PREFER_SRC_TMP) + val |= IPV6_PREFER_SRC_TMP; + else if (np->srcprefs & IPV6_PREFER_SRC_PUBLIC) + val |= IPV6_PREFER_SRC_PUBLIC; + else { + /* XXX: should we return system default? */ + val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT; + } + + if (np->srcprefs & IPV6_PREFER_SRC_COA) + val |= IPV6_PREFER_SRC_COA; + else + val |= IPV6_PREFER_SRC_HOME; + break; + default: return -ENOPROTOOPT; } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index e7d8e74704c1..3f68a6eae7b2 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -546,7 +546,9 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, override = 0; in6_ifa_put(ifp); } else { - if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr)) + if (ipv6_dev_get_saddr(dev, daddr, + inet6_sk(dev->nd_net->ipv6.ndisc_sk)->srcprefs, + &tmpaddr)) return; src_addr = &tmpaddr; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index aa3f08718e44..06faa46920e1 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -782,6 +782,15 @@ struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, if (!ipv6_addr_any(&fl->fl6_src)) flags |= RT6_LOOKUP_F_HAS_SADDR; + else if (sk) { + unsigned int prefs = inet6_sk(sk)->srcprefs; + if (prefs & IPV6_PREFER_SRC_TMP) + flags |= RT6_LOOKUP_F_SRCPREF_TMP; + if (prefs & IPV6_PREFER_SRC_PUBLIC) + flags |= RT6_LOOKUP_F_SRCPREF_PUBLIC; + if (prefs & IPV6_PREFER_SRC_COA) + flags |= RT6_LOOKUP_F_SRCPREF_COA; + } return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output); } @@ -2162,7 +2171,7 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, else if (dst) { struct in6_addr saddr_buf; if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev, - dst, &saddr_buf) == 0) + dst, 0, &saddr_buf) == 0) NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index e96dafdc7032..d92d1fceb8cf 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -58,7 +58,7 @@ static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) return -EHOSTUNREACH; ipv6_dev_get_saddr(ip6_dst_idev(dst)->dev, - (struct in6_addr *)&daddr->a6, + (struct in6_addr *)&daddr->a6, 0, (struct in6_addr *)&saddr->a6); dst_release(dst); return 0; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 46c5b3c5cb99..dc71d0d83753 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -316,7 +316,9 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc, if (!asoc) { ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, - &daddr->v6.sin6_addr, &saddr->v6.sin6_addr); + &daddr->v6.sin6_addr, + inet6_sk(asoc->base.sk)->srcprefs, + &saddr->v6.sin6_addr); SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n", NIP6(saddr->v6.sin6_addr)); return; -- cgit v1.2.3-59-g8ed1b From c346dca10840a874240c78efe3f39acf4312a1f2 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 25 Mar 2008 21:47:49 +0900 Subject: [NET] NETNS: Omit net_device->nd_net without CONFIG_NET_NS. Introduce per-net_device inlines: dev_net(), dev_net_set(). Without CONFIG_NET_NS, no namespace other than &init_net exists. Let's explicitly define them to help compiler optimizations. Signed-off-by: YOSHIFUJI Hideaki --- arch/ia64/hp/sim/simeth.c | 2 +- drivers/block/aoe/aoenet.c | 2 +- drivers/net/bonding/bond_3ad.c | 2 +- drivers/net/bonding/bond_alb.c | 2 +- drivers/net/bonding/bond_main.c | 6 ++--- drivers/net/hamradio/bpqether.c | 4 ++-- drivers/net/loopback.c | 2 +- drivers/net/macvlan.c | 2 +- drivers/net/pppoe.c | 6 ++--- drivers/net/veth.c | 2 +- drivers/net/via-velocity.c | 2 +- drivers/net/wan/dlci.c | 2 +- drivers/net/wan/hdlc.c | 4 ++-- drivers/net/wan/lapbether.c | 4 ++-- drivers/net/wan/syncppp.c | 2 +- drivers/s390/net/qeth_l3_main.c | 2 +- include/linux/inetdevice.h | 6 ++--- include/linux/netdevice.h | 25 ++++++++++++++++++++- net/8021q/vlan.c | 2 +- net/8021q/vlan_dev.c | 2 +- net/appletalk/aarp.c | 4 ++-- net/appletalk/ddp.c | 6 ++--- net/atm/clip.c | 2 +- net/atm/mpc.c | 2 +- net/ax25/af_ax25.c | 2 +- net/ax25/ax25_in.c | 2 +- net/bridge/br_notify.c | 2 +- net/bridge/br_stp_bpdu.c | 2 +- net/can/af_can.c | 4 ++-- net/can/bcm.c | 2 +- net/can/raw.c | 2 +- net/core/dev.c | 22 +++++++++---------- net/core/dst.c | 2 +- net/core/fib_rules.c | 2 +- net/core/neighbour.c | 12 +++++----- net/core/pktgen.c | 2 +- net/core/rtnetlink.c | 4 ++-- net/decnet/af_decnet.c | 2 +- net/decnet/dn_route.c | 2 +- net/econet/af_econet.c | 4 ++-- net/ipv4/arp.c | 14 ++++++------ net/ipv4/devinet.c | 10 ++++----- net/ipv4/fib_frontend.c | 12 +++++----- net/ipv4/icmp.c | 8 +++---- net/ipv4/igmp.c | 16 +++++++------- net/ipv4/ip_fragment.c | 2 +- net/ipv4/ip_gre.c | 2 +- net/ipv4/ip_input.c | 6 ++--- net/ipv4/ip_options.c | 2 +- net/ipv4/ipconfig.c | 4 ++-- net/ipv4/ipmr.c | 2 +- net/ipv4/netfilter/ip_queue.c | 2 +- net/ipv4/netfilter/ipt_MASQUERADE.c | 2 +- net/ipv4/raw.c | 4 ++-- net/ipv4/route.c | 28 +++++++++++------------ net/ipv4/tcp_ipv4.c | 6 ++--- net/ipv4/udp.c | 4 ++-- net/ipv4/xfrm4_policy.c | 2 +- net/ipv6/addrconf.c | 44 ++++++++++++++++++------------------- net/ipv6/icmp.c | 4 ++-- net/ipv6/ip6_output.c | 2 +- net/ipv6/mcast.c | 6 ++--- net/ipv6/ndisc.c | 24 ++++++++++---------- net/ipv6/netfilter/ip6_queue.c | 2 +- net/ipv6/proc.c | 2 +- net/ipv6/raw.c | 4 ++-- net/ipv6/reassembly.c | 2 +- net/ipv6/route.c | 40 ++++++++++++++++----------------- net/ipv6/tcp_ipv6.c | 10 ++++----- net/ipv6/udp.c | 4 ++-- net/ipv6/xfrm6_policy.c | 2 +- net/ipx/af_ipx.c | 4 ++-- net/irda/irlap_frame.c | 2 +- net/llc/llc_input.c | 2 +- net/netfilter/core.c | 2 +- net/netfilter/nfnetlink_queue.c | 2 +- net/netlabel/netlabel_unlabeled.c | 2 +- net/netrom/af_netrom.c | 2 +- net/packet/af_packet.c | 8 +++---- net/rose/af_rose.c | 2 +- net/sctp/protocol.c | 2 +- net/tipc/eth_media.c | 4 ++-- net/wireless/wext.c | 2 +- net/x25/af_x25.c | 2 +- net/x25/x25_dev.c | 2 +- net/xfrm/xfrm_policy.c | 4 ++-- security/selinux/netif.c | 2 +- 87 files changed, 251 insertions(+), 228 deletions(-) (limited to 'net') diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c index 969fe9f443c4..3d47839a0c48 100644 --- a/arch/ia64/hp/sim/simeth.c +++ b/arch/ia64/hp/sim/simeth.c @@ -294,7 +294,7 @@ simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr) return NOTIFY_DONE; } - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if ( event != NETDEV_UP && event != NETDEV_DOWN ) return NOTIFY_DONE; diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index 8460ef736d56..18d243c73eee 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -115,7 +115,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt, struct aoe_hdr *h; u32 n; - if (ifp->nd_net != &init_net) + if (dev_net(ifp) != &init_net) goto exit; skb = skb_share_check(skb, GFP_ATOMIC); diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index cb3c6faa7888..457d81f73e39 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2429,7 +2429,7 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac struct slave *slave = NULL; int ret = NET_RX_DROP; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto out; if (!(dev->flags & IFF_MASTER)) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index b57bc9467dbe..b986dacf5d33 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -345,7 +345,7 @@ static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct struct arp_pkt *arp = (struct arp_pkt *)skb->data; int res = NET_RX_DROP; - if (bond_dev->nd_net != &init_net) + if (dev_net(bond_dev) != &init_net) goto out; if (!(bond_dev->flags & IFF_MASTER)) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 5fc9d8d58ece..ac688fcb27d7 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2629,7 +2629,7 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack unsigned char *arp_ptr; __be32 sip, tip; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto out; if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) @@ -3470,7 +3470,7 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v { struct net_device *event_dev = (struct net_device *)ptr; - if (event_dev->nd_net != &init_net) + if (dev_net(event_dev) != &init_net) return NOTIFY_DONE; dprintk("event_dev: %s, event: %lx\n", @@ -3508,7 +3508,7 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, struct bonding *bond, *bond_next; struct vlan_entry *vlan, *vlan_next; - if (ifa->ifa_dev->dev->nd_net != &init_net) + if (dev_net(ifa->ifa_dev->dev) != &init_net) return NOTIFY_DONE; list_for_each_entry_safe(bond, bond_next, &bond_dev_list, bond_list) { diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 5ddf8b0c34f9..5f4b4c6c9f76 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -172,7 +172,7 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty struct ethhdr *eth; struct bpqdev *bpq; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) @@ -553,7 +553,7 @@ static int bpq_device_event(struct notifier_block *this,unsigned long event, voi { struct net_device *dev = (struct net_device *)ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (!dev_is_ethdev(dev)) diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index f2a6e7132241..41b774baac4d 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -258,7 +258,7 @@ static __net_init int loopback_net_init(struct net *net) if (!dev) goto out; - dev->nd_net = net; + dev_net_set(dev, net); err = register_netdev(dev); if (err) goto out_free_netdev; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index f651a816b280..2056cfc624dc 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -402,7 +402,7 @@ static int macvlan_newlink(struct net_device *dev, if (!tb[IFLA_LINK]) return -EINVAL; - lowerdev = __dev_get_by_index(dev->nd_net, nla_get_u32(tb[IFLA_LINK])); + lowerdev = __dev_get_by_index(dev_net(dev), nla_get_u32(tb[IFLA_LINK])); if (lowerdev == NULL) return -ENODEV; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index ac0ac98b19cd..4fad4ddb3504 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -301,7 +301,7 @@ static int pppoe_device_event(struct notifier_block *this, { struct net_device *dev = (struct net_device *) ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* Only look at sockets that are using this specific device. */ @@ -392,7 +392,7 @@ static int pppoe_rcv(struct sk_buff *skb, if (!(skb = skb_share_check(skb, GFP_ATOMIC))) goto out; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) @@ -424,7 +424,7 @@ static int pppoe_disc_rcv(struct sk_buff *skb, struct pppoe_hdr *ph; struct pppox_sock *po; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto abort; if (!pskb_may_pull(skb, sizeof(struct pppoe_hdr))) diff --git a/drivers/net/veth.c b/drivers/net/veth.c index e2ad98bee6e7..31cd817f33f9 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -375,7 +375,7 @@ static int veth_newlink(struct net_device *dev, else snprintf(ifname, IFNAMSIZ, DRV_NAME "%%d"); - peer = rtnl_create_link(dev->nd_net, ifname, &veth_link_ops, tbp); + peer = rtnl_create_link(dev_net(dev), ifname, &veth_link_ops, tbp); if (IS_ERR(peer)) return PTR_ERR(peer); diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 1525e8a89844..ed1afaf683a4 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -3464,7 +3464,7 @@ static int velocity_netdev_event(struct notifier_block *nb, unsigned long notifi struct velocity_info *vptr; unsigned long flags; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; spin_lock_irqsave(&velocity_dev_list_lock, flags); diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 96b232446c0b..b14242768fad 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -517,7 +517,7 @@ static int dlci_dev_event(struct notifier_block *unused, { struct net_device *dev = (struct net_device *) ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event == NETDEV_UNREGISTER) { diff --git a/drivers/net/wan/hdlc.c b/drivers/net/wan/hdlc.c index 39951d0c34d6..9a83c9d5b8cf 100644 --- a/drivers/net/wan/hdlc.c +++ b/drivers/net/wan/hdlc.c @@ -68,7 +68,7 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev, { struct hdlc_device *hdlc = dev_to_hdlc(dev); - if (dev->nd_net != &init_net) { + if (dev_net(dev) != &init_net) { kfree_skb(skb); return 0; } @@ -105,7 +105,7 @@ static int hdlc_device_event(struct notifier_block *this, unsigned long event, unsigned long flags; int on; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (dev->get_stats != hdlc_get_stats) diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index fb37b8095231..629c909e05f9 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -91,7 +91,7 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe int len, err; struct lapbethdev *lapbeth; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) @@ -393,7 +393,7 @@ static int lapbeth_device_event(struct notifier_block *this, struct lapbethdev *lapbeth; struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (!dev_is_ethdev(dev)) diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c index 61e24b7a45a3..29b4b94e4947 100644 --- a/drivers/net/wan/syncppp.c +++ b/drivers/net/wan/syncppp.c @@ -1444,7 +1444,7 @@ static void sppp_print_bytes (u_char *p, u16 len) static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev) { - if (dev->nd_net != &init_net) { + if (dev_net(dev) != &init_net) { kfree_skb(skb); return 0; } diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index a856cb47fc78..21c439046b3c 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3250,7 +3250,7 @@ static int qeth_l3_ip_event(struct notifier_block *this, struct qeth_ipaddr *addr; struct qeth_card *card; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; QETH_DBF_TEXT(trace, 3, "ipevent"); diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index da05ab47ff2f..7009b0cdd06f 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -70,13 +70,13 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev) ipv4_devconf_set((in_dev), NET_IPV4_CONF_ ## attr, (val)) #define IN_DEV_ANDCONF(in_dev, attr) \ - (IPV4_DEVCONF_ALL(in_dev->dev->nd_net, attr) && \ + (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), attr) && \ IN_DEV_CONF_GET((in_dev), attr)) #define IN_DEV_ORCONF(in_dev, attr) \ - (IPV4_DEVCONF_ALL(in_dev->dev->nd_net, attr) || \ + (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), attr) || \ IN_DEV_CONF_GET((in_dev), attr)) #define IN_DEV_MAXCONF(in_dev, attr) \ - (max(IPV4_DEVCONF_ALL(in_dev->dev->nd_net, attr), \ + (max(IPV4_DEVCONF_ALL(dev_net(in_dev->dev), attr), \ IN_DEV_CONF_GET((in_dev), attr))) #define IN_DEV_FORWARD(in_dev) IN_DEV_CONF_GET((in_dev), FORWARDING) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index ced61f87660e..d146be40f46c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -708,8 +708,10 @@ struct net_device void (*poll_controller)(struct net_device *dev); #endif +#ifdef CONFIG_NET_NS /* Network namespace this network device is inside */ struct net *nd_net; +#endif /* bridge stuff */ struct net_bridge_port *br_port; @@ -737,6 +739,27 @@ struct net_device #define NETDEV_ALIGN 32 #define NETDEV_ALIGN_CONST (NETDEV_ALIGN - 1) +/* + * Net namespace inlines + */ +static inline +struct net *dev_net(const struct net_device *dev) +{ +#ifdef CONFIG_NET_NS + return dev->nd_net; +#else + return &init_net; +#endif +} + +static inline +void dev_net_set(struct net_device *dev, const struct net *net) +{ +#ifdef CONFIG_NET_NS + dev->nd_dev = net; +#endif +} + /** * netdev_priv - access network device private data * @dev: network device @@ -813,7 +836,7 @@ static inline struct net_device *next_net_device(struct net_device *dev) struct list_head *lh; struct net *net; - net = dev->nd_net; + net = dev_net(dev); lh = dev->dev_list.next; return lh == &net->dev_base_head ? NULL : net_device_entry(lh); } diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index dbc81b965096..c35dc230365c 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -382,7 +382,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, int i, flgs; struct net_device *vlandev; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (!grp) diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 1e5c9904571d..e536162b1ebc 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -153,7 +153,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, struct net_device_stats *stats; unsigned short vlan_TCI; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto err_free; skb = skb_share_check(skb, GFP_ATOMIC); diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 61166f66479f..25aa37ce9430 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -333,7 +333,7 @@ static int aarp_device_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; int ct; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event == NETDEV_DOWN) { @@ -716,7 +716,7 @@ static int aarp_rcv(struct sk_buff *skb, struct net_device *dev, struct atalk_addr sa, *ma, da; struct atalk_iface *ifa; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto out0; /* We only do Ethernet SNAP AARP. */ diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 3be55c8ca4ef..44cd42f7786b 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -648,7 +648,7 @@ static int ddp_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event == NETDEV_DOWN) @@ -1405,7 +1405,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev, int origlen; __u16 len_hops; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto freeit; /* Don't mangle buffer if shared */ @@ -1493,7 +1493,7 @@ freeit: static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto freeit; /* Expand any short form frames */ diff --git a/net/atm/clip.c b/net/atm/clip.c index e82da6746723..6f8223ebf551 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -612,7 +612,7 @@ static int clip_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = arg; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event == NETDEV_UNREGISTER) { diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 9c7f712fc7e9..9db332e7a6c0 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -964,7 +964,7 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo dev = (struct net_device *)dev_ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (dev->name == NULL || strncmp(dev->name, "lec", 3)) diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 48bfcc741f25..ee9dd83e7561 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -116,7 +116,7 @@ static int ax25_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* Reject non AX.25 devices */ diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index d1be080dcb25..33790a8efbc8 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -451,7 +451,7 @@ int ax25_kiss_rcv(struct sk_buff *skb, struct net_device *dev, skb->sk = NULL; /* Initially we don't know who it's for */ skb->destructor = NULL; /* Who initializes this, dammit?! */ - if (dev->nd_net != &init_net) { + if (dev_net(dev) != &init_net) { kfree_skb(skb); return 0; } diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 07ac3ae68d8f..00644a544e3c 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -37,7 +37,7 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v struct net_bridge_port *p = dev->br_port; struct net_bridge *br; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* not a port of a bridge */ diff --git a/net/bridge/br_stp_bpdu.c b/net/bridge/br_stp_bpdu.c index 0edbd2a1c3f3..8deab645ef75 100644 --- a/net/bridge/br_stp_bpdu.c +++ b/net/bridge/br_stp_bpdu.c @@ -142,7 +142,7 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev, struct net_bridge *br; const unsigned char *buf; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto err; if (!p) diff --git a/net/can/af_can.c b/net/can/af_can.c index 36b9f22ed83a..2759b76f731c 100644 --- a/net/can/af_can.c +++ b/net/can/af_can.c @@ -599,7 +599,7 @@ static int can_rcv(struct sk_buff *skb, struct net_device *dev, struct dev_rcv_lists *d; int matches; - if (dev->type != ARPHRD_CAN || dev->nd_net != &init_net) { + if (dev->type != ARPHRD_CAN || dev_net(dev) != &init_net) { kfree_skb(skb); return 0; } @@ -710,7 +710,7 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg, struct net_device *dev = (struct net_device *)data; struct dev_rcv_lists *d; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (dev->type != ARPHRD_CAN) diff --git a/net/can/bcm.c b/net/can/bcm.c index bd4282dae754..e9f99b2c6bc9 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1285,7 +1285,7 @@ static int bcm_notifier(struct notifier_block *nb, unsigned long msg, struct bcm_op *op; int notify_enodev = 0; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (dev->type != ARPHRD_CAN) diff --git a/net/can/raw.c b/net/can/raw.c index 94cd7f27c444..ead50c7c0d40 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -210,7 +210,7 @@ static int raw_notifier(struct notifier_block *nb, struct raw_sock *ro = container_of(nb, struct raw_sock, notifier); struct sock *sk = &ro->sk; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (dev->type != ARPHRD_CAN) diff --git a/net/core/dev.c b/net/core/dev.c index aebd08606040..812534828914 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -216,7 +216,7 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) /* Device list insertion */ static int list_netdevice(struct net_device *dev) { - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); ASSERT_RTNL(); @@ -852,8 +852,8 @@ int dev_alloc_name(struct net_device *dev, const char *name) struct net *net; int ret; - BUG_ON(!dev->nd_net); - net = dev->nd_net; + BUG_ON(!dev_net(dev)); + net = dev_net(dev); ret = __dev_alloc_name(net, name, buf); if (ret >= 0) strlcpy(dev->name, buf, IFNAMSIZ); @@ -877,9 +877,9 @@ int dev_change_name(struct net_device *dev, char *newname) struct net *net; ASSERT_RTNL(); - BUG_ON(!dev->nd_net); + BUG_ON(!dev_net(dev)); - net = dev->nd_net; + net = dev_net(dev); if (dev->flags & IFF_UP) return -EBUSY; @@ -2615,7 +2615,7 @@ static int ptype_seq_show(struct seq_file *seq, void *v) if (v == SEQ_START_TOKEN) seq_puts(seq, "Type Device Function\n"); - else if (pt->dev == NULL || pt->dev->nd_net == seq_file_net(seq)) { + else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) { if (pt->type == htons(ETH_P_ALL)) seq_puts(seq, "ALL "); else @@ -3689,8 +3689,8 @@ int register_netdevice(struct net_device *dev) /* When net_device's are persistent, this will be fatal. */ BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); - BUG_ON(!dev->nd_net); - net = dev->nd_net; + BUG_ON(!dev_net(dev)); + net = dev_net(dev); spin_lock_init(&dev->queue_lock); spin_lock_init(&dev->_xmit_lock); @@ -4011,7 +4011,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, dev = (struct net_device *) (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); dev->padded = (char *)dev - (char *)p; - dev->nd_net = &init_net; + dev_net_set(dev, &init_net); if (sizeof_priv) { dev->priv = ((char *)dev + @@ -4136,7 +4136,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* Get out if there is nothing todo */ err = 0; - if (dev->nd_net == net) + if (dev_net(dev) == net) goto out; /* Pick the destination device name, and ensure @@ -4187,7 +4187,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char dev_addr_discard(dev); /* Actually switch the network namespace */ - dev->nd_net = net; + dev_net_set(dev, net); /* Assign the new device name */ if (destname != dev->name) diff --git a/net/core/dst.c b/net/core/dst.c index 3a01a819ba47..694cd2a3f6d2 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -279,7 +279,7 @@ static inline void dst_ifdown(struct dst_entry *dst, struct net_device *dev, if (!unregister) { dst->input = dst->output = dst_discard; } else { - dst->dev = dst->dev->nd_net->loopback_dev; + dst->dev = dev_net(dst->dev)->loopback_dev; dev_hold(dst->dev); dev_put(dev); if (dst->neighbour && dst->neighbour->dev == dev) { diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 42ccaf5b8509..942be93a2eb0 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -618,7 +618,7 @@ static int fib_rules_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct fib_rules_ops *ops; ASSERT_RTNL(); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 23c0a10c0c37..c978bd1cd659 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -388,7 +388,7 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net, hash_val = tbl->hash(pkey, NULL); for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) { if (!memcmp(n->primary_key, pkey, key_len) && - (net == n->dev->nd_net)) { + dev_net(n->dev) == net) { neigh_hold(n); NEIGH_CACHE_STAT_INC(tbl, hits); break; @@ -1298,7 +1298,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, struct neigh_parms *p, *ref; struct net *net; - net = dev->nd_net; + net = dev_net(dev); ref = lookup_neigh_params(tbl, net, 0); if (!ref) return NULL; @@ -2050,7 +2050,7 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, s_idx = 0; for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next) { int lidx; - if (n->dev->nd_net != net) + if (dev_net(n->dev) != net) continue; lidx = idx++; if (lidx < s_idx) @@ -2155,7 +2155,7 @@ static struct neighbour *neigh_get_first(struct seq_file *seq) n = tbl->hash_buckets[bucket]; while (n) { - if (n->dev->nd_net != net) + if (dev_net(n->dev) != net) goto next; if (state->neigh_sub_iter) { loff_t fakep = 0; @@ -2198,7 +2198,7 @@ static struct neighbour *neigh_get_next(struct seq_file *seq, while (1) { while (n) { - if (n->dev->nd_net != net) + if (dev_net(n->dev) != net) goto next; if (state->neigh_sub_iter) { void *v = state->neigh_sub_iter(state, n, pos); @@ -2482,7 +2482,7 @@ static inline size_t neigh_nlmsg_size(void) static void __neigh_notify(struct neighbour *n, int type, int flags) { - struct net *net = n->dev->nd_net; + struct net *net = dev_net(n->dev); struct sk_buff *skb; int err = -ENOBUFS; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 20e63b302ba6..a803b442234c 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -1874,7 +1874,7 @@ static int pktgen_device_event(struct notifier_block *unused, { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* It is OK that we do not hold the group lock right now, diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 2bd9c5f7627d..09250a0800f6 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -972,7 +972,7 @@ struct net_device *rtnl_create_link(struct net *net, char *ifname, goto err_free; } - dev->nd_net = net; + dev_net_set(dev, net); dev->rtnl_link_ops = ops; if (tb[IFLA_MTU]) @@ -1198,7 +1198,7 @@ static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change) { - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct sk_buff *skb; int err = -ENOBUFS; diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 23fd95a7ad15..3554fb3d251c 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -2089,7 +2089,7 @@ static int dn_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; switch(event) { diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 9dc0abb50eaf..0a46b6c10e51 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -580,7 +580,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr; unsigned char padlen = 0; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto dump_it; if (dn == NULL) diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c index bc0f6252613f..68d154480043 100644 --- a/net/econet/af_econet.c +++ b/net/econet/af_econet.c @@ -1064,7 +1064,7 @@ static int econet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet struct sock *sk; struct ec_device *edev = dev->ec_ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; if (skb->pkt_type == PACKET_OTHERHOST) @@ -1121,7 +1121,7 @@ static int econet_notifier(struct notifier_block *this, unsigned long msg, void struct net_device *dev = (struct net_device *)data; struct ec_device *edev; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; switch (msg) { diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 832473e30b36..3ce2e137e7bc 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -242,7 +242,7 @@ static int arp_constructor(struct neighbour *neigh) return -EINVAL; } - neigh->type = inet_addr_type(dev->nd_net, addr); + neigh->type = inet_addr_type(dev_net(dev), addr); parms = in_dev->arp_parms; __neigh_parms_put(neigh->parms); @@ -341,14 +341,14 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) switch (IN_DEV_ARP_ANNOUNCE(in_dev)) { default: case 0: /* By default announce any local IP */ - if (skb && inet_addr_type(dev->nd_net, ip_hdr(skb)->saddr) == RTN_LOCAL) + if (skb && inet_addr_type(dev_net(dev), ip_hdr(skb)->saddr) == RTN_LOCAL) saddr = ip_hdr(skb)->saddr; break; case 1: /* Restrict announcements of saddr in same subnet */ if (!skb) break; saddr = ip_hdr(skb)->saddr; - if (inet_addr_type(dev->nd_net, saddr) == RTN_LOCAL) { + if (inet_addr_type(dev_net(dev), saddr) == RTN_LOCAL) { /* saddr should be known to target */ if (inet_addr_onlink(in_dev, target, saddr)) break; @@ -424,7 +424,7 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) int flag = 0; /*unsigned long now; */ - if (ip_route_output_key(dev->nd_net, &rt, &fl) < 0) + if (ip_route_output_key(dev_net(dev), &rt, &fl) < 0) return 1; if (rt->u.dst.dev != dev) { NET_INC_STATS_BH(LINUX_MIB_ARPFILTER); @@ -477,7 +477,7 @@ int arp_find(unsigned char *haddr, struct sk_buff *skb) paddr = skb->rtable->rt_gateway; - if (arp_set_predefined(inet_addr_type(dev->nd_net, paddr), haddr, paddr, dev)) + if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr, paddr, dev)) return 0; n = __neigh_lookup(&arp_tbl, &paddr, dev, 1); @@ -709,7 +709,7 @@ static int arp_process(struct sk_buff *skb) u16 dev_type = dev->type; int addr_type; struct neighbour *n; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); /* arp_rcv below verifies the ARP header and verifies the device * is ARP'able. @@ -858,7 +858,7 @@ static int arp_process(struct sk_buff *skb) n = __neigh_lookup(&arp_tbl, &sip, dev, 0); - if (IPV4_DEVCONF_ALL(dev->nd_net, ARP_ACCEPT)) { + if (IPV4_DEVCONF_ALL(dev_net(dev), ARP_ACCEPT)) { /* Unsolicited ARP is not accepted by default. It is possible, that this option should be enabled for some devices (strip is candidate) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 4a10dbbbe0a1..823c724a8593 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -165,7 +165,7 @@ static struct in_device *inetdev_init(struct net_device *dev) if (!in_dev) goto out; INIT_RCU_HEAD(&in_dev->rcu_head); - memcpy(&in_dev->cnf, dev->nd_net->ipv4.devconf_dflt, + memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt, sizeof(in_dev->cnf)); in_dev->cnf.sysctl = NULL; in_dev->dev = dev; @@ -872,7 +872,7 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) { __be32 addr = 0; struct in_device *in_dev; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); @@ -974,7 +974,7 @@ __be32 inet_confirm_addr(struct in_device *in_dev, if (scope != RT_SCOPE_LINK) return confirm_addr_indev(in_dev, dst, local, scope); - net = in_dev->dev->nd_net; + net = dev_net(in_dev->dev); read_lock(&dev_base_lock); rcu_read_lock(); for_each_netdev(net, dev) { @@ -1203,7 +1203,7 @@ static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh, int err = -ENOBUFS; struct net *net; - net = ifa->ifa_dev->dev->nd_net; + net = dev_net(ifa->ifa_dev->dev); skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL); if (skb == NULL) goto errout; @@ -1517,7 +1517,7 @@ static void devinet_sysctl_register(struct in_device *idev) { neigh_sysctl_register(idev->dev, idev->arp_parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4", NULL, NULL); - __devinet_sysctl_register(idev->dev->nd_net, idev->dev->name, + __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, idev->dev->ifindex, &idev->cnf); } diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 86ff2711fc95..0e4b34b07cb5 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -257,7 +257,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif, if (in_dev == NULL) goto e_inval; - net = dev->nd_net; + net = dev_net(dev); if (fib_lookup(net, &fl, &res)) goto last_resort; if (res.type != RTN_UNICAST) @@ -674,7 +674,7 @@ out: static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa) { - struct net *net = ifa->ifa_dev->dev->nd_net; + struct net *net = dev_net(ifa->ifa_dev->dev); struct fib_table *tb; struct fib_config cfg = { .fc_protocol = RTPROT_KERNEL, @@ -801,15 +801,15 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa) fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); /* Check, that this local address finally disappeared. */ - if (inet_addr_type(dev->nd_net, ifa->ifa_local) != RTN_LOCAL) { + if (inet_addr_type(dev_net(dev), ifa->ifa_local) != RTN_LOCAL) { /* And the last, but not the least thing. We must flush stray FIB entries. First of all, we scan fib_info list searching for stray nexthop entries, then ignite fib_flush. */ - if (fib_sync_down_addr(dev->nd_net, ifa->ifa_local)) - fib_flush(dev->nd_net); + if (fib_sync_down_addr(dev_net(dev), ifa->ifa_local)) + fib_flush(dev_net(dev)); } } #undef LOCAL_OK @@ -899,7 +899,7 @@ static void nl_fib_lookup_exit(struct net *net) static void fib_disable_ip(struct net_device *dev, int force) { if (fib_sync_down_dev(dev, force)) - fib_flush(dev->nd_net); + fib_flush(dev_net(dev)); rt_cache_flush(0); arp_ifdown(dev); } diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index ff9a8e643fcc..f38f093ef751 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -351,7 +351,7 @@ static void icmp_push_reply(struct icmp_bxm *icmp_param, struct sock *sk; struct sk_buff *skb; - sk = icmp_sk(rt->u.dst.dev->nd_net); + sk = icmp_sk(dev_net(rt->u.dst.dev)); if (ip_append_data(sk, icmp_glue_bits, icmp_param, icmp_param->data_len+icmp_param->head_len, icmp_param->head_len, @@ -382,7 +382,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) { struct ipcm_cookie ipc; struct rtable *rt = skb->rtable; - struct net *net = rt->u.dst.dev->nd_net; + struct net *net = dev_net(rt->u.dst.dev); struct sock *sk = icmp_sk(net); struct inet_sock *inet = inet_sk(sk); __be32 daddr; @@ -447,7 +447,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) if (!rt) goto out; - net = rt->u.dst.dev->nd_net; + net = dev_net(rt->u.dst.dev); sk = icmp_sk(net); /* @@ -677,7 +677,7 @@ static void icmp_unreach(struct sk_buff *skb) u32 info = 0; struct net *net; - net = skb->dst->dev->nd_net; + net = dev_net(skb->dst->dev); /* * Incomplete header ? diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 6a4ee8da6994..682f632bfb77 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -130,12 +130,12 @@ */ #define IGMP_V1_SEEN(in_dev) \ - (IPV4_DEVCONF_ALL(in_dev->dev->nd_net, FORCE_IGMP_VERSION) == 1 || \ + (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), FORCE_IGMP_VERSION) == 1 || \ IN_DEV_CONF_GET((in_dev), FORCE_IGMP_VERSION) == 1 || \ ((in_dev)->mr_v1_seen && \ time_before(jiffies, (in_dev)->mr_v1_seen))) #define IGMP_V2_SEEN(in_dev) \ - (IPV4_DEVCONF_ALL(in_dev->dev->nd_net, FORCE_IGMP_VERSION) == 2 || \ + (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), FORCE_IGMP_VERSION) == 2 || \ IN_DEV_CONF_GET((in_dev), FORCE_IGMP_VERSION) == 2 || \ ((in_dev)->mr_v2_seen && \ time_before(jiffies, (in_dev)->mr_v2_seen))) @@ -1198,7 +1198,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) ASSERT_RTNL(); - if (in_dev->dev->nd_net != &init_net) + if (dev_net(in_dev->dev) != &init_net) return; for (im=in_dev->mc_list; im; im=im->next) { @@ -1280,7 +1280,7 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) ASSERT_RTNL(); - if (in_dev->dev->nd_net != &init_net) + if (dev_net(in_dev->dev) != &init_net) return; for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) { @@ -1310,7 +1310,7 @@ void ip_mc_down(struct in_device *in_dev) ASSERT_RTNL(); - if (in_dev->dev->nd_net != &init_net) + if (dev_net(in_dev->dev) != &init_net) return; for (i=in_dev->mc_list; i; i=i->next) @@ -1333,7 +1333,7 @@ void ip_mc_init_dev(struct in_device *in_dev) { ASSERT_RTNL(); - if (in_dev->dev->nd_net != &init_net) + if (dev_net(in_dev->dev) != &init_net) return; in_dev->mc_tomb = NULL; @@ -1359,7 +1359,7 @@ void ip_mc_up(struct in_device *in_dev) ASSERT_RTNL(); - if (in_dev->dev->nd_net != &init_net) + if (dev_net(in_dev->dev) != &init_net) return; ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS); @@ -1378,7 +1378,7 @@ void ip_mc_destroy_dev(struct in_device *in_dev) ASSERT_RTNL(); - if (in_dev->dev->nd_net != &init_net) + if (dev_net(in_dev->dev) != &init_net) return; /* Deactivate timers */ diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 8b448c4b9080..fcb60e76b234 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -571,7 +571,7 @@ int ip_defrag(struct sk_buff *skb, u32 user) IP_INC_STATS_BH(IPSTATS_MIB_REASMREQDS); - net = skb->dev ? skb->dev->nd_net : skb->dst->dev->nd_net; + net = skb->dev ? dev_net(skb->dev) : dev_net(skb->dst->dev); /* Start by cleaning up the memory. */ if (atomic_read(&net->ipv4.frags.mem) > net->ipv4.frags.high_thresh) ip_evictor(net); diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index f9ee84420cb3..50972b397a9a 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1190,7 +1190,7 @@ static int ipgre_close(struct net_device *dev) struct ip_tunnel *t = netdev_priv(dev); if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) { struct in_device *in_dev; - in_dev = inetdev_by_index(dev->nd_net, t->mlink); + in_dev = inetdev_by_index(dev_net(dev), t->mlink); if (in_dev) { ip_mc_dec_group(in_dev, t->parms.iph.daddr); in_dev_put(in_dev); diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 2aeea5d15425..26685c83a146 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -172,7 +172,7 @@ int ip_call_ra_chain(struct sk_buff *skb) if (sk && inet_sk(sk)->num == protocol && (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dev->ifindex) && - sk->sk_net == dev->nd_net) { + sk->sk_net == dev_net(dev)) { if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) { read_unlock(&ip_ra_lock); @@ -199,7 +199,7 @@ int ip_call_ra_chain(struct sk_buff *skb) static int ip_local_deliver_finish(struct sk_buff *skb) { - struct net *net = skb->dev->nd_net; + struct net *net = dev_net(skb->dev); __skb_pull(skb, ip_hdrlen(skb)); @@ -291,7 +291,7 @@ static inline int ip_rcv_options(struct sk_buff *skb) opt = &(IPCB(skb)->opt); opt->optlen = iph->ihl*4 - sizeof(struct iphdr); - if (ip_options_compile(dev->nd_net, opt, skb)) { + if (ip_options_compile(dev_net(dev), opt, skb)) { IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS); goto drop; } diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 87cc1222c600..d107543d3f81 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -145,7 +145,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb) __be32 addr; memcpy(&addr, sptr+soffset-1, 4); - if (inet_addr_type(skb->dst->dev->nd_net, addr) != RTN_LOCAL) { + if (inet_addr_type(dev_net(skb->dst->dev), addr) != RTN_LOCAL) { dopt->ts_needtime = 1; soffset += 8; } diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 96138b128de8..08e8fb60d315 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -434,7 +434,7 @@ ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt unsigned char *sha, *tha; /* s for "source", t for "target" */ struct ic_device *d; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) @@ -854,7 +854,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str struct ic_device *d; int len, ext_len; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; /* Perform verifications before taking the lock. */ diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 7d63d74ef62a..e54bc1364473 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -1089,7 +1089,7 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v struct vif_device *v; int ct; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event != NETDEV_UNREGISTER) diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index fe05da41d6ba..500998a2dec1 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -481,7 +481,7 @@ ipq_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* Drop any packets associated with the downed device */ diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index c6817b18366a..84c26dd27d81 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -120,7 +120,7 @@ static int masq_device_event(struct notifier_block *this, { const struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event == NETDEV_DOWN) { diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 3f68a937b602..8756d502a47f 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -168,7 +168,7 @@ static int raw_v4_input(struct sk_buff *skb, struct iphdr *iph, int hash) if (hlist_empty(head)) goto out; - net = skb->dev->nd_net; + net = dev_net(skb->dev); sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol, iph->saddr, iph->daddr, skb->dev->ifindex); @@ -276,7 +276,7 @@ void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); if (raw_sk != NULL) { iph = (struct iphdr *)skb->data; - net = skb->dev->nd_net; + net = dev_net(skb->dev); while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol, iph->daddr, iph->saddr, diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 2941ef21f203..7768d718e199 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -284,7 +284,7 @@ static struct rtable *rt_cache_get_first(struct rt_cache_iter_state *st) rcu_read_lock_bh(); r = rcu_dereference(rt_hash_table[st->bucket].chain); while (r) { - if (r->u.dst.dev->nd_net == st->p.net && + if (dev_net(r->u.dst.dev) == st->p.net && r->rt_genid == st->genid) return r; r = rcu_dereference(r->u.dst.rt_next); @@ -312,7 +312,7 @@ static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, struct rtable *r) { while ((r = __rt_cache_get_next(st, r)) != NULL) { - if (r->u.dst.dev->nd_net != st->p.net) + if (dev_net(r->u.dst.dev) != st->p.net) continue; if (r->rt_genid == st->genid) break; @@ -680,7 +680,7 @@ static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) static inline int compare_netns(struct rtable *rt1, struct rtable *rt2) { - return rt1->u.dst.dev->nd_net == rt2->u.dst.dev->nd_net; + return dev_net(rt1->u.dst.dev) == dev_net(rt2->u.dst.dev); } /* @@ -1164,7 +1164,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, if (!in_dev) return; - net = dev->nd_net; + net = dev_net(dev); if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev) || ipv4_is_multicast(new_gw) || ipv4_is_lbcast(new_gw) || ipv4_is_zeronet(new_gw)) @@ -1195,7 +1195,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, rth->fl.oif != ikeys[k] || rth->fl.iif != 0 || rth->rt_genid != atomic_read(&rt_genid) || - rth->u.dst.dev->nd_net != net) { + dev_net(rth->u.dst.dev) != net) { rthp = &rth->u.dst.rt_next; continue; } @@ -1454,7 +1454,7 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, rth->rt_src == iph->saddr && rth->fl.iif == 0 && !(dst_metric_locked(&rth->u.dst, RTAX_MTU)) && - rth->u.dst.dev->nd_net == net && + dev_net(rth->u.dst.dev) == net && rth->rt_genid == atomic_read(&rt_genid)) { unsigned short mtu = new_mtu; @@ -1530,9 +1530,9 @@ static void ipv4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, { struct rtable *rt = (struct rtable *) dst; struct in_device *idev = rt->idev; - if (dev != dev->nd_net->loopback_dev && idev && idev->dev == dev) { + if (dev != dev_net(dev)->loopback_dev && idev && idev->dev == dev) { struct in_device *loopback_idev = - in_dev_get(dev->nd_net->loopback_dev); + in_dev_get(dev_net(dev)->loopback_dev); if (loopback_idev) { rt->idev = loopback_idev; in_dev_put(idev); @@ -1576,7 +1576,7 @@ void ip_rt_get_source(u8 *addr, struct rtable *rt) if (rt->fl.iif == 0) src = rt->rt_src; - else if (fib_lookup(rt->u.dst.dev->nd_net, &rt->fl, &res) == 0) { + else if (fib_lookup(dev_net(rt->u.dst.dev), &rt->fl, &res) == 0) { src = FIB_RES_PREFSRC(res); fib_res_put(&res); } else @@ -1900,7 +1900,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, __be32 spec_dst; int err = -EINVAL; int free_res = 0; - struct net * net = dev->nd_net; + struct net * net = dev_net(dev); /* IP on this device is disabled. */ @@ -2071,7 +2071,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, int iif = dev->ifindex; struct net *net; - net = dev->nd_net; + net = dev_net(dev); tos &= IPTOS_RT_MASK; hash = rt_hash(daddr, saddr, iif); @@ -2084,7 +2084,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->fl.oif == 0 && rth->fl.mark == skb->mark && rth->fl.fl4_tos == tos && - rth->u.dst.dev->nd_net == net && + dev_net(rth->u.dst.dev) == net && rth->rt_genid == atomic_read(&rt_genid)) { dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(in_hit); @@ -2486,7 +2486,7 @@ int __ip_route_output_key(struct net *net, struct rtable **rp, rth->fl.mark == flp->mark && !((rth->fl.fl4_tos ^ flp->fl4_tos) & (IPTOS_RT_MASK | RTO_ONLINK)) && - rth->u.dst.dev->nd_net == net && + dev_net(rth->u.dst.dev) == net && rth->rt_genid == atomic_read(&rt_genid)) { dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(out_hit); @@ -2795,7 +2795,7 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) rcu_read_lock_bh(); for (rt = rcu_dereference(rt_hash_table[h].chain), idx = 0; rt; rt = rcu_dereference(rt->u.dst.rt_next), idx++) { - if (rt->u.dst.dev->nd_net != net || idx < s_idx) + if (dev_net(rt->u.dst.dev) != net || idx < s_idx) continue; if (rt->rt_genid != atomic_read(&rt_genid)) continue; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 649d00a50cb1..28bece6f281b 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -353,7 +353,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info) return; } - sk = inet_lookup(skb->dev->nd_net, &tcp_hashinfo, iph->daddr, th->dest, + sk = inet_lookup(dev_net(skb->dev), &tcp_hashinfo, iph->daddr, th->dest, iph->saddr, th->source, inet_iif(skb)); if (!sk) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); @@ -1644,7 +1644,7 @@ int tcp_v4_rcv(struct sk_buff *skb) TCP_SKB_CB(skb)->flags = iph->tos; TCP_SKB_CB(skb)->sacked = 0; - sk = __inet_lookup(skb->dev->nd_net, &tcp_hashinfo, iph->saddr, + sk = __inet_lookup(dev_net(skb->dev), &tcp_hashinfo, iph->saddr, th->source, iph->daddr, th->dest, inet_iif(skb)); if (!sk) goto no_tcp_socket; @@ -1718,7 +1718,7 @@ do_time_wait: } switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) { case TCP_TW_SYN: { - struct sock *sk2 = inet_lookup_listener(skb->dev->nd_net, + struct sock *sk2 = inet_lookup_listener(dev_net(skb->dev), &tcp_hashinfo, iph->daddr, th->dest, inet_iif(skb)); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index b37581dfd029..e2cd93481359 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -357,7 +357,7 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) int harderr; int err; - sk = __udp4_lib_lookup(skb->dev->nd_net, iph->daddr, uh->dest, + sk = __udp4_lib_lookup(dev_net(skb->dev), iph->daddr, uh->dest, iph->saddr, uh->source, skb->dev->ifindex, udptable); if (sk == NULL) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); @@ -1181,7 +1181,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); - sk = __udp4_lib_lookup(skb->dev->nd_net, saddr, uh->source, daddr, + sk = __udp4_lib_lookup(dev_net(skb->dev), saddr, uh->source, daddr, uh->dest, inet_iif(skb), udptable); if (sk != NULL) { diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 10ed70491434..c63de0a72aba 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -221,7 +221,7 @@ static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, xdst = (struct xfrm_dst *)dst; if (xdst->u.rt.idev->dev == dev) { struct in_device *loopback_idev = - in_dev_get(dev->nd_net->loopback_dev); + in_dev_get(dev_net(dev)->loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 89954885dee1..d1de9ec74261 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -335,7 +335,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) rwlock_init(&ndev->lock); ndev->dev = dev; - memcpy(&ndev->cnf, dev->nd_net->ipv6.devconf_dflt, sizeof(ndev->cnf)); + memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf)); ndev->cnf.mtu6 = dev->mtu; ndev->cnf.sysctl = NULL; ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); @@ -561,7 +561,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, write_lock(&addrconf_hash_lock); /* Ignore adding duplicate addresses on an interface */ - if (ipv6_chk_same_addr(idev->dev->nd_net, addr, idev->dev)) { + if (ipv6_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) { ADBG(("ipv6_add_addr: already assigned\n")); err = -EEXIST; goto out; @@ -751,7 +751,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) if ((ifp->flags & IFA_F_PERMANENT) && onlink < 1) { struct in6_addr prefix; struct rt6_info *rt; - struct net *net = ifp->idev->dev->nd_net; + struct net *net = dev_net(ifp->idev->dev); ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); rt = rt6_lookup(net, &prefix, NULL, ifp->idev->dev->ifindex, 1); @@ -1044,7 +1044,7 @@ int ipv6_dev_get_saddr(struct net_device *dst_dev, { struct ipv6_saddr_score scores[2], *score = &scores[0], *hiscore = &scores[1]; - struct net *net = dst_dev->nd_net; + struct net *net = dev_net(dst_dev); struct ipv6_saddr_dst dst; struct net_device *dev; int dst_type; @@ -1217,7 +1217,7 @@ int ipv6_chk_addr(struct net *net, struct in6_addr *addr, read_lock_bh(&addrconf_hash_lock); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { - if (ifp->idev->dev->nd_net != net) + if (dev_net(ifp->idev->dev) != net) continue; if (ipv6_addr_equal(&ifp->addr, addr) && !(ifp->flags&IFA_F_TENTATIVE)) { @@ -1239,7 +1239,7 @@ int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, u8 hash = ipv6_addr_hash(addr); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { - if (ifp->idev->dev->nd_net != net) + if (dev_net(ifp->idev->dev) != net) continue; if (ipv6_addr_equal(&ifp->addr, addr)) { if (dev == NULL || ifp->idev->dev == dev) @@ -1257,7 +1257,7 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, struct in6_addr *addr, read_lock_bh(&addrconf_hash_lock); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { - if (ifp->idev->dev->nd_net != net) + if (dev_net(ifp->idev->dev) != net) continue; if (ipv6_addr_equal(&ifp->addr, addr)) { if (dev == NULL || ifp->idev->dev == dev || @@ -1559,7 +1559,7 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, .fc_expires = expires, .fc_dst_len = plen, .fc_flags = RTF_UP | flags, - .fc_nlinfo.nl_net = dev->nd_net, + .fc_nlinfo.nl_net = dev_net(dev), }; ipv6_addr_copy(&cfg.fc_dst, pfx); @@ -1586,7 +1586,7 @@ static void addrconf_add_mroute(struct net_device *dev) .fc_ifindex = dev->ifindex, .fc_dst_len = 8, .fc_flags = RTF_UP, - .fc_nlinfo.nl_net = dev->nd_net, + .fc_nlinfo.nl_net = dev_net(dev), }; ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0); @@ -1603,7 +1603,7 @@ static void sit_route_add(struct net_device *dev) .fc_ifindex = dev->ifindex, .fc_dst_len = 96, .fc_flags = RTF_UP | RTF_NONEXTHOP, - .fc_nlinfo.nl_net = dev->nd_net, + .fc_nlinfo.nl_net = dev_net(dev), }; /* prefix length - 96 bits "::d.d.d.d" */ @@ -1704,7 +1704,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) if (pinfo->onlink) { struct rt6_info *rt; - rt = rt6_lookup(dev->nd_net, &pinfo->prefix, NULL, + rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL, dev->ifindex, 1); if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { @@ -1748,7 +1748,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) ok: - ifp = ipv6_get_ifaddr(dev->nd_net, &addr, dev, 1); + ifp = ipv6_get_ifaddr(dev_net(dev), &addr, dev, 1); if (ifp == NULL && valid_lft) { int max_addresses = in6_dev->cnf.max_addresses; @@ -2071,7 +2071,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev) struct inet6_ifaddr * ifp; struct in6_addr addr; struct net_device *dev; - struct net *net = idev->dev->nd_net; + struct net *net = dev_net(idev->dev); int scope; ASSERT_RTNL(); @@ -2261,7 +2261,7 @@ ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev) static void ip6_tnl_add_linklocal(struct inet6_dev *idev) { struct net_device *link_dev; - struct net *net = idev->dev->nd_net; + struct net *net = dev_net(idev->dev); /* first try to inherit the link-local address from the link device */ if (idev->dev->iflink && @@ -2442,7 +2442,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) { struct inet6_dev *idev; struct inet6_ifaddr *ifa, **bifa; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); int i; ASSERT_RTNL(); @@ -2771,7 +2771,7 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq) for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { ifa = inet6_addr_lst[state->bucket]; - while (ifa && ifa->idev->dev->nd_net != net) + while (ifa && dev_net(ifa->idev->dev) != net) ifa = ifa->lst_next; if (ifa) break; @@ -2787,7 +2787,7 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifad ifa = ifa->lst_next; try_again: if (ifa) { - if (ifa->idev->dev->nd_net != net) { + if (dev_net(ifa->idev->dev) != net) { ifa = ifa->lst_next; goto try_again; } @@ -2905,7 +2905,7 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) u8 hash = ipv6_addr_hash(addr); read_lock_bh(&addrconf_hash_lock); for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) { - if (ifp->idev->dev->nd_net != net) + if (dev_net(ifp->idev->dev) != net) continue; if (ipv6_addr_cmp(&ifp->addr, addr) == 0 && (ifp->flags & IFA_F_HOMEADDRESS)) { @@ -3469,7 +3469,7 @@ errout: static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) { struct sk_buff *skb; - struct net *net = ifa->idev->dev->nd_net; + struct net *net = dev_net(ifa->idev->dev); int err = -ENOBUFS; skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC); @@ -3675,7 +3675,7 @@ cont: void inet6_ifinfo_notify(int event, struct inet6_dev *idev) { struct sk_buff *skb; - struct net *net = idev->dev->nd_net; + struct net *net = dev_net(idev->dev); int err = -ENOBUFS; skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC); @@ -3745,7 +3745,7 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, struct prefix_info *pinfo) { struct sk_buff *skb; - struct net *net = idev->dev->nd_net; + struct net *net = dev_net(idev->dev); int err = -ENOBUFS; skb = nlmsg_new(inet6_prefix_nlmsg_size(), GFP_ATOMIC); @@ -4157,7 +4157,7 @@ static void addrconf_sysctl_register(struct inet6_dev *idev) NET_IPV6_NEIGH, "ipv6", &ndisc_ifinfo_sysctl_change, NULL); - __addrconf_sysctl_register(idev->dev->nd_net, idev->dev->name, + __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, idev->dev->ifindex, idev, &idev->cnf); } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 86332417b402..50857662e6b7 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -306,7 +306,7 @@ static inline void mip6_addr_swap(struct sk_buff *skb) {} void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, struct net_device *dev) { - struct net *net = skb->dev->nd_net; + struct net *net = dev_net(skb->dev); struct inet6_dev *idev = NULL; struct ipv6hdr *hdr = ipv6_hdr(skb); struct sock *sk; @@ -507,7 +507,7 @@ EXPORT_SYMBOL(icmpv6_send); static void icmpv6_echo_reply(struct sk_buff *skb) { - struct net *net = skb->dev->nd_net; + struct net *net = dev_net(skb->dev); struct sock *sk; struct inet6_dev *idev; struct ipv6_pinfo *np; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index d34aa61353bb..556300f0eba5 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -402,7 +402,7 @@ int ip6_forward(struct sk_buff *skb) struct dst_entry *dst = skb->dst; struct ipv6hdr *hdr = ipv6_hdr(skb); struct inet6_skb_parm *opt = IP6CB(skb); - struct net *net = dst->dev->nd_net; + struct net *net = dev_net(dst->dev); if (ipv6_devconf.forwarding == 0) goto error; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 957ac7e9e929..0357de8e78c8 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1400,7 +1400,7 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted) static struct sk_buff *mld_newpack(struct net_device *dev, int size) { - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct sock *sk = net->ipv6.igmp_sk; struct sk_buff *skb; struct mld2_report *pmr; @@ -1448,7 +1448,7 @@ static void mld_sendpack(struct sk_buff *skb) (struct mld2_report *)skb_transport_header(skb); int payload_len, mldlen; struct inet6_dev *idev = in6_dev_get(skb->dev); - struct net *net = skb->dev->nd_net; + struct net *net = dev_net(skb->dev); int err; struct flowi fl; @@ -1762,7 +1762,7 @@ static void mld_send_cr(struct inet6_dev *idev) static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) { - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct sock *sk = net->ipv6.igmp_sk; struct inet6_dev *idev; struct sk_buff *skb; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 3f68a6eae7b2..79af57f586e8 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -447,7 +447,7 @@ static void __ndisc_send(struct net_device *dev, { struct flowi fl; struct dst_entry *dst; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct sock *sk = net->ipv6.ndisc_sk; struct sk_buff *skb; struct icmp6hdr *hdr; @@ -539,7 +539,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, }; /* for anycast or proxy, solicited_addr != src_addr */ - ifp = ipv6_get_ifaddr(dev->nd_net, solicited_addr, dev, 1); + ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1); if (ifp) { src_addr = solicited_addr; if (ifp->flags & IFA_F_OPTIMISTIC) @@ -547,7 +547,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, in6_ifa_put(ifp); } else { if (ipv6_dev_get_saddr(dev, daddr, - inet6_sk(dev->nd_net->ipv6.ndisc_sk)->srcprefs, + inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs, &tmpaddr)) return; src_addr = &tmpaddr; @@ -601,7 +601,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, * suppress the inclusion of the sllao. */ if (send_sllao) { - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev->nd_net, saddr, + struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr, dev, 1); if (ifp) { if (ifp->flags & IFA_F_OPTIMISTIC) { @@ -639,7 +639,7 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; int probes = atomic_read(&neigh->probes); - if (skb && ipv6_chk_addr(dev->nd_net, &ipv6_hdr(skb)->saddr, dev, 1)) + if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1)) saddr = &ipv6_hdr(skb)->saddr; if ((probes -= neigh->parms->ucast_probes) < 0) { @@ -727,7 +727,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) inc = ipv6_addr_is_multicast(daddr); - ifp = ipv6_get_ifaddr(dev->nd_net, &msg->target, dev, 1); + ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); if (ifp) { if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { @@ -776,7 +776,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) if (ipv6_chk_acast_addr(dev, &msg->target) || (idev->cnf.forwarding && (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && - (pneigh = pneigh_lookup(&nd_tbl, dev->nd_net, + (pneigh = pneigh_lookup(&nd_tbl, dev_net(dev), &msg->target, dev, 0)) != NULL)) { if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && skb->pkt_type != PACKET_HOST && @@ -886,7 +886,7 @@ static void ndisc_recv_na(struct sk_buff *skb) return; } } - ifp = ipv6_get_ifaddr(dev->nd_net, &msg->target, dev, 1); + ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); if (ifp) { if (ifp->flags & IFA_F_TENTATIVE) { addrconf_dad_failure(ifp); @@ -918,7 +918,7 @@ static void ndisc_recv_na(struct sk_buff *skb) */ if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp && - pneigh_lookup(&nd_tbl, dev->nd_net, &msg->target, dev, 0)) { + pneigh_lookup(&nd_tbl, dev_net(dev), &msg->target, dev, 0)) { /* XXX: idev->cnf.prixy_ndp */ goto out; } @@ -1008,7 +1008,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) struct sk_buff *skb; struct nlmsghdr *nlh; struct nduseroptmsg *ndmsg; - struct net *net = ra->dev->nd_net; + struct net *net = dev_net(ra->dev); int err; int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg) + (opt->nd_opt_len << 3)); @@ -1395,7 +1395,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, struct in6_addr *target) { struct net_device *dev = skb->dev; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct sock *sk = net->ipv6.ndisc_sk; int len = sizeof(struct icmp6hdr) + 2 * sizeof(struct in6_addr); struct sk_buff *buff; @@ -1597,7 +1597,7 @@ int ndisc_rcv(struct sk_buff *skb) static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); switch (event) { case NETDEV_CHANGEADDR: diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index cc2f9afcf808..a6d30626b47c 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -484,7 +484,7 @@ ipq_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* Drop any packets associated with the downed device */ diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 8a5be290c710..364dc332532c 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -214,7 +214,7 @@ int snmp6_register_dev(struct inet6_dev *idev) if (!idev || !idev->dev) return -EINVAL; - if (idev->dev->nd_net != &init_net) + if (dev_net(idev->dev) != &init_net) return 0; if (!proc_net_devsnmp6) diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 548d0763f4d3..efb0047f6880 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -176,7 +176,7 @@ static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) if (sk == NULL) goto out; - net = skb->dev->nd_net; + net = dev_net(skb->dev); sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); while (sk) { @@ -363,7 +363,7 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, if (sk != NULL) { saddr = &ipv6_hdr(skb)->saddr; daddr = &ipv6_hdr(skb)->daddr; - net = skb->dev->nd_net; + net = dev_net(skb->dev); while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr, IP6CB(skb)->iif))) { diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index f936d045a39d..4e1447634f36 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -600,7 +600,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb) return 1; } - net = skb->dev->nd_net; + net = dev_net(skb->dev); if (atomic_read(&net->ipv6.frags.mem) > net->ipv6.frags.high_thresh) ip6_evictor(net, ip6_dst_idev(skb->dst)); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 06faa46920e1..65053fba8c1a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -208,7 +208,7 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, struct rt6_info *rt = (struct rt6_info *)dst; struct inet6_dev *idev = rt->rt6i_idev; struct net_device *loopback_dev = - dev->nd_net->loopback_dev; + dev_net(dev)->loopback_dev; if (dev != loopback_dev && idev != NULL && idev->dev == dev) { struct inet6_dev *loopback_idev = @@ -433,7 +433,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) RT6_TRACE("%s() => %p\n", __func__, match); - net = rt0->rt6i_dev->nd_net; + net = dev_net(rt0->rt6i_dev); return (match ? match : net->ipv6.ip6_null_entry); } @@ -441,7 +441,7 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, struct in6_addr *gwaddr) { - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct route_info *rinfo = (struct route_info *) opt; struct in6_addr prefix_buf, *prefix; unsigned int pref; @@ -607,7 +607,7 @@ static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info) int ip6_ins_rt(struct rt6_info *rt) { struct nl_info info = { - .nl_net = rt->rt6i_dev->nd_net, + .nl_net = dev_net(rt->rt6i_dev), }; return __ip6_ins_rt(rt, &info); } @@ -745,7 +745,7 @@ static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table * void ip6_route_input(struct sk_buff *skb) { struct ipv6hdr *iph = ipv6_hdr(skb); - struct net *net = skb->dev->nd_net; + struct net *net = dev_net(skb->dev); int flags = RT6_LOOKUP_F_HAS_SADDR; struct flowi fl = { .iif = skb->dev->ifindex, @@ -928,7 +928,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, { struct rt6_info *rt; struct inet6_dev *idev = in6_dev_get(dev); - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); if (unlikely(idev == NULL)) return NULL; @@ -1252,7 +1252,7 @@ install_route: rt->rt6i_idev = idev; rt->rt6i_table = table; - cfg->fc_nlinfo.nl_net = dev->nd_net; + cfg->fc_nlinfo.nl_net = dev_net(dev); return __ip6_ins_rt(rt, &cfg->fc_nlinfo); @@ -1270,7 +1270,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) { int err; struct fib6_table *table; - struct net *net = rt->rt6i_dev->nd_net; + struct net *net = dev_net(rt->rt6i_dev); if (rt == net->ipv6.ip6_null_entry) return -ENOENT; @@ -1289,7 +1289,7 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) int ip6_del_rt(struct rt6_info *rt) { struct nl_info info = { - .nl_net = rt->rt6i_dev->nd_net, + .nl_net = dev_net(rt->rt6i_dev), }; return __ip6_del_rt(rt, &info); } @@ -1401,7 +1401,7 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, struct net_device *dev) { int flags = RT6_LOOKUP_F_HAS_SADDR; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); struct ip6rd_flowi rdfl = { .fl = { .oif = dev->ifindex, @@ -1428,7 +1428,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, { struct rt6_info *rt, *nrt = NULL; struct netevent_redirect netevent; - struct net *net = neigh->dev->nd_net; + struct net *net = dev_net(neigh->dev); rt = ip6_route_redirect(dest, src, saddr, neigh->dev); @@ -1477,7 +1477,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, nrt->rt6i_nexthop = neigh_clone(neigh); /* Reset pmtu, it may be better */ nrt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev); - nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(neigh->dev->nd_net, + nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dev_net(neigh->dev), dst_mtu(&nrt->u.dst)); if (ip6_ins_rt(nrt)) @@ -1506,7 +1506,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, struct net_device *dev, u32 pmtu) { struct rt6_info *rt, *nrt; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); int allfrag = 0; rt = rt6_lookup(net, daddr, saddr, dev->ifindex, 0); @@ -1583,7 +1583,7 @@ out: static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) { - struct net *net = ort->rt6i_dev->nd_net; + struct net *net = dev_net(ort->rt6i_dev); struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); if (rt) { @@ -1682,7 +1682,7 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d struct rt6_info *rt; struct fib6_table *table; - table = fib6_get_table(dev->nd_net, RT6_TABLE_DFLT); + table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT); if (table == NULL) return NULL; @@ -1713,7 +1713,7 @@ struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, RTF_UP | RTF_EXPIRES | RTF_PREF(pref), .fc_nlinfo.pid = 0, .fc_nlinfo.nlh = NULL, - .fc_nlinfo.nl_net = dev->nd_net, + .fc_nlinfo.nl_net = dev_net(dev), }; ipv6_addr_copy(&cfg.fc_gateway, gwaddr); @@ -1862,7 +1862,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, const struct in6_addr *addr, int anycast) { - struct net *net = idev->dev->nd_net; + struct net *net = dev_net(idev->dev); struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); if (rt == NULL) @@ -1939,7 +1939,7 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) { struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg; struct inet6_dev *idev; - struct net *net = arg->dev->nd_net; + struct net *net = dev_net(arg->dev); /* In IPv6 pmtu discovery is not optional, so that RTAX_MTU lock cannot disable it. @@ -1983,7 +1983,7 @@ void rt6_mtu_change(struct net_device *dev, unsigned mtu) .mtu = mtu, }; - fib6_clean_all(dev->nd_net, rt6_mtu_change_route, 0, &arg); + fib6_clean_all(dev_net(dev), rt6_mtu_change_route, 0, &arg); } static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { @@ -2321,7 +2321,7 @@ static int ip6_route_dev_notify(struct notifier_block *this, unsigned long event, void *data) { struct net_device *dev = (struct net_device *)data; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { net->ipv6.ip6_null_entry->u.dst.dev = dev; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8dd72966ff78..086deffff9c9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -321,7 +321,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct tcp_sock *tp; __u32 seq; - sk = inet6_lookup(skb->dev->nd_net, &tcp_hashinfo, &hdr->daddr, + sk = inet6_lookup(dev_net(skb->dev), &tcp_hashinfo, &hdr->daddr, th->dest, &hdr->saddr, th->source, skb->dev->ifindex); if (sk == NULL) { @@ -988,7 +988,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) struct tcphdr *th = tcp_hdr(skb), *t1; struct sk_buff *buff; struct flowi fl; - struct net *net = skb->dst->dev->nd_net; + struct net *net = dev_net(skb->dst->dev); struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(*th); #ifdef CONFIG_TCP_MD5SIG @@ -1093,7 +1093,7 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, struct tcphdr *th = tcp_hdr(skb), *t1; struct sk_buff *buff; struct flowi fl; - struct net *net = skb->dev->nd_net; + struct net *net = dev_net(skb->dev); struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(struct tcphdr); __be32 *topt; @@ -1739,7 +1739,7 @@ static int tcp_v6_rcv(struct sk_buff *skb) TCP_SKB_CB(skb)->flags = ipv6_get_dsfield(ipv6_hdr(skb)); TCP_SKB_CB(skb)->sacked = 0; - sk = __inet6_lookup(skb->dev->nd_net, &tcp_hashinfo, + sk = __inet6_lookup(dev_net(skb->dev), &tcp_hashinfo, &ipv6_hdr(skb)->saddr, th->source, &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb)); @@ -1822,7 +1822,7 @@ do_time_wait: { struct sock *sk2; - sk2 = inet6_lookup_listener(skb->dev->nd_net, &tcp_hashinfo, + sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo, &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb)); if (sk2 != NULL) { diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 593d3efadaf9..6683c04b427e 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -235,7 +235,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, struct sock *sk; int err; - sk = __udp6_lib_lookup(skb->dev->nd_net, daddr, uh->dest, + sk = __udp6_lib_lookup(dev_net(skb->dev), daddr, uh->dest, saddr, uh->source, inet6_iif(skb), udptable); if (sk == NULL) return; @@ -483,7 +483,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], * check socket cache ... must talk to Alan about his plans * for sock caches... i'll skip this for now. */ - sk = __udp6_lib_lookup(skb->dev->nd_net, saddr, uh->source, + sk = __udp6_lib_lookup(dev_net(skb->dev), saddr, uh->source, daddr, uh->dest, inet6_iif(skb), udptable); if (sk == NULL) { diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index d92d1fceb8cf..8f1e0543b3c4 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -247,7 +247,7 @@ static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, xdst = (struct xfrm_dst *)dst; if (xdst->u.rt6.rt6i_idev->dev == dev) { struct inet6_dev *loopback_idev = - in6_dev_get(dev->nd_net->loopback_dev); + in6_dev_get(dev_net(dev)->loopback_dev); BUG_ON(!loopback_idev); do { diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c index c76a9523091b..81ae8735f5e3 100644 --- a/net/ipx/af_ipx.c +++ b/net/ipx/af_ipx.c @@ -335,7 +335,7 @@ static int ipxitf_device_event(struct notifier_block *notifier, struct net_device *dev = ptr; struct ipx_interface *i, *tmp; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event != NETDEV_DOWN && event != NETDEV_UP) @@ -1636,7 +1636,7 @@ static int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty u16 ipx_pktsize; int rc = 0; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; /* Not ours */ diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c index a38b231c8689..90894534f3cc 100644 --- a/net/irda/irlap_frame.c +++ b/net/irda/irlap_frame.c @@ -1326,7 +1326,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, int command; __u8 control; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto out; /* FIXME: should we get our own field? */ diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c index b9143d2a04e1..a69c5c427fe3 100644 --- a/net/llc/llc_input.c +++ b/net/llc/llc_input.c @@ -146,7 +146,7 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, int (*rcv)(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *); - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; /* diff --git a/net/netfilter/core.c b/net/netfilter/core.c index ec05684c56d7..292fa28146fb 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -168,7 +168,7 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb, #ifdef CONFIG_NET_NS struct net *net; - net = indev == NULL ? outdev->nd_net : indev->nd_net; + net = indev == NULL ? dev_net(outdev) : dev_net(indev); if (net != &init_net) return 1; #endif diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 012cb6910820..81fb048add88 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -557,7 +557,7 @@ nfqnl_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* Drop any packets associated with the downed device */ diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 4478f2f6079d..a547c6320eb3 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -954,7 +954,7 @@ static int netlbl_unlhsh_netdev_handler(struct notifier_block *this, struct net_device *dev = ptr; struct netlbl_unlhsh_iface *iface = NULL; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; /* XXX - should this be a check for NETDEV_DOWN or _UNREGISTER? */ diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 972250c974f1..a270ebf9f765 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -106,7 +106,7 @@ static int nr_device_event(struct notifier_block *this, unsigned long event, voi { struct net_device *dev = (struct net_device *)ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event != NETDEV_DOWN) diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index a56ed2120e07..baa290d3444a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -263,7 +263,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct if (skb->pkt_type == PACKET_LOOPBACK) goto out; - if (dev->nd_net != sk->sk_net) + if (dev_net(dev) != sk->sk_net) goto out; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) @@ -451,7 +451,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet sk = pt->af_packet_priv; po = pkt_sk(sk); - if (dev->nd_net != sk->sk_net) + if (dev_net(dev) != sk->sk_net) goto drop; skb->dev = dev; @@ -568,7 +568,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe sk = pt->af_packet_priv; po = pkt_sk(sk); - if (dev->nd_net != sk->sk_net) + if (dev_net(dev) != sk->sk_net) goto drop; if (dev->header_ops) { @@ -1450,7 +1450,7 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void struct sock *sk; struct hlist_node *node; struct net_device *dev = data; - struct net *net = dev->nd_net; + struct net *net = dev_net(dev); read_lock(&net->packet.sklist_lock); sk_for_each(sk, node, &net->packet.sklist) { diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 4a31a81059ab..1a7f143cf741 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -197,7 +197,7 @@ static int rose_device_event(struct notifier_block *this, unsigned long event, { struct net_device *dev = (struct net_device *)ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event != NETDEV_DOWN) diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index beea2fb18b15..2faa0d8839eb 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -630,7 +630,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, struct sctp_sockaddr_entry *temp; int found = 0; - if (ifa->ifa_dev->dev->nd_net != &init_net) + if (dev_net(ifa->ifa_dev->dev) != &init_net) return NOTIFY_DONE; switch (ev) { diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 3bbef2ab22ae..9cd35eec3e7f 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -101,7 +101,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, struct eth_bearer *eb_ptr = (struct eth_bearer *)pt->af_packet_priv; u32 size; - if (dev->nd_net != &init_net) { + if (dev_net(dev) != &init_net) { kfree_skb(buf); return 0; } @@ -198,7 +198,7 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, struct eth_bearer *eb_ptr = ð_bearers[0]; struct eth_bearer *stop = ð_bearers[MAX_ETH_BEARERS]; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; while ((eb_ptr->dev != dev)) { diff --git a/net/wireless/wext.c b/net/wireless/wext.c index 2c569b63e7d8..947188a5b937 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -1157,7 +1157,7 @@ static void rtmsg_iwinfo(struct net_device *dev, char *event, int event_len) struct sk_buff *skb; int err; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return; skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 339ca4a8e89e..7a46ea73fe2d 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -191,7 +191,7 @@ static int x25_device_event(struct notifier_block *this, unsigned long event, struct net_device *dev = ptr; struct x25_neigh *nb; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (dev->type == ARPHRD_X25 diff --git a/net/x25/x25_dev.c b/net/x25/x25_dev.c index f0679d283110..3ff206c0ae94 100644 --- a/net/x25/x25_dev.c +++ b/net/x25/x25_dev.c @@ -95,7 +95,7 @@ int x25_lapb_receive_frame(struct sk_buff *skb, struct net_device *dev, struct sk_buff *nskb; struct x25_neigh *nb; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) goto drop; nskb = skb_copy(skb, GFP_ATOMIC); diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 8e588f20c60c..15d73e47cc2c 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -2079,7 +2079,7 @@ static int stale_bundle(struct dst_entry *dst) void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) { while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { - dst->dev = dev->nd_net->loopback_dev; + dst->dev = dev_net(dev)->loopback_dev; dev_hold(dst->dev); dev_put(dev); } @@ -2350,7 +2350,7 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; switch (event) { diff --git a/security/selinux/netif.c b/security/selinux/netif.c index 013d3117a86b..9c8a82aa8baf 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c @@ -281,7 +281,7 @@ static int sel_netif_netdev_notifier_handler(struct notifier_block *this, { struct net_device *dev = ptr; - if (dev->nd_net != &init_net) + if (dev_net(dev) != &init_net) return NOTIFY_DONE; if (event == NETDEV_DOWN) -- cgit v1.2.3-59-g8ed1b From 3b1e0a655f8eba44ab1ee2a1068d169ccfb853b9 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 26 Mar 2008 02:26:21 +0900 Subject: [NET] NETNS: Omit sock->sk_net without CONFIG_NET_NS. Introduce per-sock inlines: sock_net(), sock_net_set() and per-inet_timewait_sock inlines: twsk_net(), twsk_net_set(). Without CONFIG_NET_NS, no namespace other than &init_net exists. Let's explicitly define them to help compiler optimizations. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/ipv6.h | 4 ++-- include/net/inet_hashtables.h | 8 ++++---- include/net/inet_timewait_sock.h | 18 ++++++++++++++++++ include/net/route.h | 4 ++-- include/net/sock.h | 24 ++++++++++++++++++++++-- net/atm/svc.c | 2 +- net/ax25/af_ax25.c | 2 +- net/bluetooth/l2cap.c | 2 +- net/bluetooth/rfcomm/sock.c | 2 +- net/bluetooth/sco.c | 2 +- net/bridge/br_netlink.c | 4 ++-- net/core/fib_rules.c | 6 +++--- net/core/neighbour.c | 10 +++++----- net/core/rtnetlink.c | 12 ++++++------ net/core/sock.c | 10 +++++----- net/decnet/af_decnet.c | 2 +- net/decnet/dn_dev.c | 6 +++--- net/decnet/dn_fib.c | 4 ++-- net/decnet/dn_route.c | 4 ++-- net/decnet/dn_table.c | 2 +- net/ipv4/af_inet.c | 6 +++--- net/ipv4/devinet.c | 6 +++--- net/ipv4/fib_frontend.c | 8 ++++---- net/ipv4/fib_rules.c | 2 +- net/ipv4/igmp.c | 14 +++++++------- net/ipv4/inet_connection_sock.c | 4 ++-- net/ipv4/inet_hashtables.c | 8 ++++---- net/ipv4/inet_timewait_sock.c | 2 +- net/ipv4/ip_input.c | 2 +- net/ipv4/ip_output.c | 4 ++-- net/ipv4/ip_sockglue.c | 6 +++--- net/ipv4/ipmr.c | 4 ++-- net/ipv4/netfilter/arp_tables.c | 16 ++++++++-------- net/ipv4/netfilter/ip_tables.c | 16 ++++++++-------- net/ipv4/raw.c | 12 ++++++------ net/ipv4/route.c | 4 ++-- net/ipv4/tcp_ipv4.c | 14 +++++++------- net/ipv4/udp.c | 16 ++++++++-------- net/ipv6/addrconf.c | 10 +++++----- net/ipv6/addrlabel.c | 6 +++--- net/ipv6/af_inet6.c | 4 ++-- net/ipv6/fib6_rules.c | 2 +- net/ipv6/icmp.c | 2 +- net/ipv6/inet6_hashtables.c | 4 ++-- net/ipv6/ip6_fib.c | 2 +- net/ipv6/ip6_output.c | 2 +- net/ipv6/ipv6_sockglue.c | 2 +- net/ipv6/mcast.c | 12 ++++++------ net/ipv6/netfilter/ip6_tables.c | 16 ++++++++-------- net/ipv6/raw.c | 6 +++--- net/ipv6/route.c | 4 ++-- net/ipv6/tcp_ipv6.c | 2 +- net/ipv6/udp.c | 4 ++-- net/irda/af_irda.c | 2 +- net/llc/llc_conn.c | 2 +- net/netfilter/nf_sockopt.c | 2 +- net/netlink/af_netlink.c | 30 +++++++++++++++--------------- net/netrom/af_netrom.c | 2 +- net/packet/af_packet.c | 28 ++++++++++++++-------------- net/rose/af_rose.c | 2 +- net/sched/act_api.c | 4 ++-- net/sched/cls_api.c | 4 ++-- net/sched/sch_api.c | 10 +++++----- net/sctp/ipv6.c | 2 +- net/sctp/protocol.c | 2 +- net/socket.c | 4 ++-- net/tipc/socket.c | 2 +- net/unix/af_unix.c | 20 ++++++++++---------- net/x25/af_x25.c | 2 +- 69 files changed, 253 insertions(+), 215 deletions(-) (limited to 'net') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index c9ba0da16ce9..b90d3d461d4e 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -481,7 +481,7 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk) #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ #define INET6_MATCH(__sk, __net, __hash, __saddr, __daddr, __ports, __dif)\ - (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net)) && \ + (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ ((__sk)->sk_family == AF_INET6) && \ ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr)) && \ @@ -489,7 +489,7 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk) (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #define INET6_TW_MATCH(__sk, __net, __hash, __saddr, __daddr, __ports, __dif) \ - (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net)) && \ + (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ (*((__portpair *)&(inet_twsk(__sk)->tw_dport)) == (__ports)) && \ ((__sk)->sk_family == PF_INET6) && \ (ipv6_addr_equal(&inet6_twsk(__sk)->tw_v6_daddr, (__saddr))) && \ diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index d99c1ba2ece0..5525227c5e92 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -314,25 +314,25 @@ typedef __u64 __bitwise __addrpair; ((__force __u64)(__be32)(__saddr))); #endif /* __BIG_ENDIAN */ #define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ - (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net)) && \ + (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ ((*((__addrpair *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #define INET_TW_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ - (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net)) && \ + (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ ((*((__addrpair *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \ ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #else /* 32-bit arch */ #define INET_ADDR_COOKIE(__name, __saddr, __daddr) #define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif) \ - (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net)) && \ + (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ (inet_sk(__sk)->daddr == (__saddr)) && \ (inet_sk(__sk)->rcv_saddr == (__daddr)) && \ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #define INET_TW_MATCH(__sk, __net, __hash,__cookie, __saddr, __daddr, __ports, __dif) \ - (((__sk)->sk_hash == (__hash)) && ((__sk)->sk_net == (__net)) && \ + (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ (inet_twsk(__sk)->tw_daddr == (__saddr)) && \ (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \ ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 296547bfb0b7..07fe0d1a4f03 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -207,4 +207,22 @@ extern void inet_twsk_schedule(struct inet_timewait_sock *tw, const int timeo, const int timewait_len); extern void inet_twsk_deschedule(struct inet_timewait_sock *tw, struct inet_timewait_death_row *twdr); + +static inline +struct net *twsk_net(const struct inet_timewait_sock *twsk) +{ +#ifdef CONFIG_NET_NS + return twsk->tw_net; +#else + return &init_net; +#endif +} + +static inline +void twsk_net_set(struct inet_timewait_sock *twsk, const struct net *net) +{ +#ifdef CONFIG_NET_NS + twsk->tw_net = net; +#endif +} #endif /* _INET_TIMEWAIT_SOCK_ */ diff --git a/include/net/route.h b/include/net/route.h index 28dba925663c..c6338802e8f1 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -160,7 +160,7 @@ static inline int ip_route_connect(struct rtable **rp, __be32 dst, .dport = dport } } }; int err; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); if (!dst || !src) { err = __ip_route_output_key(net, rp, &fl); if (err) @@ -188,7 +188,7 @@ static inline int ip_route_newports(struct rtable **rp, u8 protocol, ip_rt_put(*rp); *rp = NULL; security_sk_classify_flow(sk, &fl); - return ip_route_output_flow(sk->sk_net, rp, &fl, sk, 0); + return ip_route_output_flow(sock_net(sk), rp, &fl, sk, 0); } return 0; } diff --git a/include/net/sock.h b/include/net/sock.h index b433b1ed203d..7e0d4a0c4d12 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -126,7 +126,9 @@ struct sock_common { atomic_t skc_refcnt; unsigned int skc_hash; struct proto *skc_prot; +#ifdef CONFIG_NET_NS struct net *skc_net; +#endif }; /** @@ -1345,6 +1347,24 @@ static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, int copied_e } #endif +static inline +struct net *sock_net(const struct sock *sk) +{ +#ifdef CONFIG_NET_NS + return sk->sk_net; +#else + return &init_net; +#endif +} + +static inline +void sock_net_set(struct sock *sk, const struct net *net) +{ +#ifdef CONFIG_NET_NS + sk->sk_net = net; +#endif +} + /* * Kernel sockets, f.e. rtnl or icmp_socket, are a part of a namespace. * They should not hold a referrence to a namespace in order to allow @@ -1353,8 +1373,8 @@ static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb, int copied_e */ static inline void sk_change_net(struct sock *sk, struct net *net) { - put_net(sk->sk_net); - sk->sk_net = net; + put_net(sock_net(sk)); + sock_net_set(sk, net); } extern void sock_enable_timestamp(struct sock *sk); diff --git a/net/atm/svc.c b/net/atm/svc.c index daf9a48a7db0..de1e4f2f3a43 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -326,7 +326,7 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) lock_sock(sk); - error = svc_create(sk->sk_net, newsock,0); + error = svc_create(sock_net(sk), newsock,0); if (error) goto out; diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index ee9dd83e7561..2712544cf0ca 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -869,7 +869,7 @@ struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev) struct sock *sk; ax25_cb *ax25, *oax25; - sk = sk_alloc(osk->sk_net, PF_AX25, GFP_ATOMIC, osk->sk_prot); + sk = sk_alloc(sock_net(osk), PF_AX25, GFP_ATOMIC, osk->sk_prot); if (sk == NULL) return NULL; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 34f8bf98bc05..6b995ac832f5 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -1499,7 +1499,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd goto response; } - sk = l2cap_sock_alloc(parent->sk_net, NULL, BTPROTO_L2CAP, GFP_ATOMIC); + sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC); if (!sk) goto response; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index c46d51035e77..c103fa02893b 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -868,7 +868,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * goto done; } - sk = rfcomm_sock_alloc(parent->sk_net, NULL, BTPROTO_RFCOMM, GFP_ATOMIC); + sk = rfcomm_sock_alloc(sock_net(parent), NULL, BTPROTO_RFCOMM, GFP_ATOMIC); if (!sk) goto done; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index b91d3c81a73c..2a5953b4405d 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -803,7 +803,7 @@ static void sco_conn_ready(struct sco_conn *conn) bh_lock_sock(parent); - sk = sco_sock_alloc(parent->sk_net, NULL, BTPROTO_SCO, GFP_ATOMIC); + sk = sco_sock_alloc(sock_net(parent), NULL, BTPROTO_SCO, GFP_ATOMIC); if (!sk) { bh_unlock_sock(parent); goto done; diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index f5d69336d97b..f155e6ce8a21 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -108,7 +108,7 @@ errout: */ static int br_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct net_device *dev; int idx; @@ -140,7 +140,7 @@ skip: */ static int br_rtm_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ifinfomsg *ifm; struct nlattr *protinfo; struct net_device *dev; diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 942be93a2eb0..540c07283e31 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -214,7 +214,7 @@ errout: static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct fib_rule_hdr *frh = nlmsg_data(nlh); struct fib_rules_ops *ops = NULL; struct fib_rule *rule, *r, *last = NULL; @@ -352,7 +352,7 @@ errout: static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct fib_rule_hdr *frh = nlmsg_data(nlh); struct fib_rules_ops *ops = NULL; struct fib_rule *rule, *tmp; @@ -534,7 +534,7 @@ skip: static int fib_nl_dumprule(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct fib_rules_ops *ops; int idx = 0, family; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index c978bd1cd659..065fbac7ecd3 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1478,7 +1478,7 @@ int neigh_table_clear(struct neigh_table *tbl) static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ndmsg *ndm; struct nlattr *dst_attr; struct neigh_table *tbl; @@ -1544,7 +1544,7 @@ out: static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ndmsg *ndm; struct nlattr *tb[NDA_MAX+1]; struct neigh_table *tbl; @@ -1812,7 +1812,7 @@ static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = { static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct neigh_table *tbl; struct ndtmsg *ndtmsg; struct nlattr *tb[NDTA_MAX+1]; @@ -1937,7 +1937,7 @@ errout: static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int family, tidx, nidx = 0; int tbl_skip = cb->args[0]; int neigh_skip = cb->args[1]; @@ -2037,7 +2037,7 @@ static void neigh_update_notify(struct neighbour *neigh) static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, struct netlink_callback *cb) { - struct net * net = skb->sk->sk_net; + struct net * net = sock_net(skb->sk); struct neighbour *n; int rc, h, s_h = cb->args[1]; int idx, s_idx = idx = cb->args[2]; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 09250a0800f6..da99ac0871bf 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -662,7 +662,7 @@ nla_put_failure: static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int idx; int s_idx = cb->args[0]; struct net_device *dev; @@ -879,7 +879,7 @@ errout: static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ifinfomsg *ifm; struct net_device *dev; int err; @@ -921,7 +921,7 @@ errout: static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); const struct rtnl_link_ops *ops; struct net_device *dev; struct ifinfomsg *ifm; @@ -1000,7 +1000,7 @@ err: static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); const struct rtnl_link_ops *ops; struct net_device *dev; struct ifinfomsg *ifm; @@ -1132,7 +1132,7 @@ replay: static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ifinfomsg *ifm; struct nlattr *tb[IFLA_MAX+1]; struct net_device *dev = NULL; @@ -1227,7 +1227,7 @@ static int rtattr_max; static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); rtnl_doit_func doit; int sz_idx, kind; int min_len; diff --git a/net/core/sock.c b/net/core/sock.c index b1a6ed4d33c1..3ee95060dbd0 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -372,7 +372,7 @@ static int sock_bindtodevice(struct sock *sk, char __user *optval, int optlen) { int ret = -ENOPROTOOPT; #ifdef CONFIG_NETDEVICES - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); char devname[IFNAMSIZ]; int index; @@ -958,7 +958,7 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority, */ sk->sk_prot = sk->sk_prot_creator = prot; sock_lock_init(sk); - sk->sk_net = get_net(net); + sock_net_set(sk, get_net(net)); } return sk; @@ -983,7 +983,7 @@ void sk_free(struct sock *sk) printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n", __func__, atomic_read(&sk->sk_omem_alloc)); - put_net(sk->sk_net); + put_net(sock_net(sk)); sk_prot_free(sk->sk_prot_creator, sk); } @@ -1001,7 +1001,7 @@ void sk_release_kernel(struct sock *sk) sock_hold(sk); sock_release(sk->sk_socket); - sk->sk_net = get_net(&init_net); + sock_net_set(sk, get_net(&init_net)); sock_put(sk); } EXPORT_SYMBOL(sk_release_kernel); @@ -1017,7 +1017,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) sock_copy(newsk, sk); /* SANITY */ - get_net(newsk->sk_net); + get_net(sock_net(newsk)); sk_node_init(&newsk->sk_node); sock_lock_init(newsk); bh_lock_sock(newsk); diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 3554fb3d251c..fc2efe899e91 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -1094,7 +1094,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) cb = DN_SKB_CB(skb); sk->sk_ack_backlog--; - newsk = dn_alloc_sock(sk->sk_net, newsock, sk->sk_allocation); + newsk = dn_alloc_sock(sock_net(sk), newsock, sk->sk_allocation); if (newsk == NULL) { release_sock(sk); kfree_skb(skb); diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 1bbfce5f7a2d..2f0ac3c3eb71 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -625,7 +625,7 @@ static const struct nla_policy dn_ifa_policy[IFA_MAX+1] = { static int dn_nl_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct nlattr *tb[IFA_MAX+1]; struct dn_dev *dn_db; struct ifaddrmsg *ifm; @@ -663,7 +663,7 @@ errout: static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct nlattr *tb[IFA_MAX+1]; struct net_device *dev; struct dn_dev *dn_db; @@ -779,7 +779,7 @@ errout: static int dn_nl_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int idx, dn_idx = 0, skip_ndevs, skip_naddr; struct net_device *dev; struct dn_dev *dn_db; diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c index 4aa9a423e606..27ea2e9b080a 100644 --- a/net/decnet/dn_fib.c +++ b/net/decnet/dn_fib.c @@ -504,7 +504,7 @@ static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta) static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct dn_fib_table *tb; struct rtattr **rta = arg; struct rtmsg *r = NLMSG_DATA(nlh); @@ -524,7 +524,7 @@ static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void * static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct dn_fib_table *tb; struct rtattr **rta = arg; struct rtmsg *r = NLMSG_DATA(nlh); diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 0a46b6c10e51..2f665a516476 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1512,7 +1512,7 @@ rtattr_failure: */ static int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = in_skb->sk->sk_net; + struct net *net = sock_net(in_skb->sk); struct rtattr **rta = arg; struct rtmsg *rtm = NLMSG_DATA(nlh); struct dn_route *rt = NULL; @@ -1601,7 +1601,7 @@ out_free: */ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct dn_route *rt; int h, s_h; int idx, s_idx; diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index e09d915dbd77..3a2830ac89c2 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c @@ -463,7 +463,7 @@ static int dn_fib_table_dump(struct dn_fib_table *tb, struct sk_buff *skb, int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); unsigned int h, s_h; unsigned int e = 0, s_e; struct dn_fib_table *tb; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 06cfb0bed631..5882a1316441 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -464,7 +464,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (addr_len < sizeof(struct sockaddr_in)) goto out; - chk_addr_ret = inet_addr_type(sk->sk_net, addr->sin_addr.s_addr); + chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); /* Not specified by any standard per-se, however it breaks too * many applications when removed. It is unfortunate since @@ -802,7 +802,7 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; int err = 0; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); switch (cmd) { case SIOCGSTAMP: @@ -1132,7 +1132,7 @@ int inet_sk_rebuild_header(struct sock *sk) }; security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 0); + err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0); } if (!err) sk_setup_caps(sk, &rt->u.dst); diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 823c724a8593..6848e4760f34 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -437,7 +437,7 @@ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct nlattr *tb[IFA_MAX+1]; struct in_device *in_dev; struct ifaddrmsg *ifm; @@ -552,7 +552,7 @@ errout: static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct in_ifaddr *ifa; ASSERT_RTNL(); @@ -1158,7 +1158,7 @@ nla_put_failure: static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int idx, ip_idx; struct net_device *dev; struct in_device *in_dev; diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 0e4b34b07cb5..0f1557a4ac7a 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -583,7 +583,7 @@ errout: static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct fib_config cfg; struct fib_table *tb; int err; @@ -605,7 +605,7 @@ errout: static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct fib_config cfg; struct fib_table *tb; int err; @@ -627,7 +627,7 @@ errout: static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); unsigned int h, s_h; unsigned int e = 0, s_e; struct fib_table *tb; @@ -857,7 +857,7 @@ static void nl_fib_input(struct sk_buff *skb) struct fib_table *tb; u32 pid; - net = skb->sk->sk_net; + net = sock_net(skb->sk); nlh = nlmsg_hdr(skb); if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len || nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn))) diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 19274d01afa4..1fb56876be54 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -137,7 +137,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, struct nlmsghdr *nlh, struct fib_rule_hdr *frh, struct nlattr **tb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int err = -EINVAL; struct fib4_rule *rule4 = (struct fib4_rule *) rule; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 682f632bfb77..6250f4239b61 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1762,7 +1762,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) if (!ipv4_is_multicast(addr)) return -EINVAL; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -EPROTONOSUPPORT; rtnl_lock(); @@ -1833,7 +1833,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) u32 ifindex; int ret = -EADDRNOTAVAIL; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -EPROTONOSUPPORT; rtnl_lock(); @@ -1881,7 +1881,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct if (!ipv4_is_multicast(addr)) return -EINVAL; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -EPROTONOSUPPORT; rtnl_lock(); @@ -2017,7 +2017,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) msf->imsf_fmode != MCAST_EXCLUDE) return -EINVAL; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -EPROTONOSUPPORT; rtnl_lock(); @@ -2100,7 +2100,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, if (!ipv4_is_multicast(addr)) return -EINVAL; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -EPROTONOSUPPORT; rtnl_lock(); @@ -2165,7 +2165,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, if (!ipv4_is_multicast(addr)) return -EINVAL; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -EPROTONOSUPPORT; rtnl_lock(); @@ -2252,7 +2252,7 @@ void ip_mc_drop_socket(struct sock *sk) if (inet->mc_list == NULL) return; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return; rtnl_lock(); diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index d13c5f12bb32..a7fcaf205644 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -85,7 +85,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum) struct hlist_node *node; struct inet_bind_bucket *tb; int ret; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); local_bh_disable(); if (!snum) { @@ -333,7 +333,7 @@ struct dst_entry* inet_csk_route_req(struct sock *sk, .dport = ireq->rmt_port } } }; security_req_classify_flow(req, &fl); - if (ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 0)) { + if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0)) { IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); return NULL; } diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 8cd1ad9b9111..1064111e5b96 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -139,7 +139,7 @@ static struct sock *inet_lookup_listener_slow(struct net *net, sk_for_each(sk, node, head) { const struct inet_sock *inet = inet_sk(sk); - if (sk->sk_net == net && inet->num == hnum && + if (sock_net(sk) == net && inet->num == hnum && !ipv6_only_sock(sk)) { const __be32 rcv_saddr = inet->rcv_saddr; int score = sk->sk_family == PF_INET ? 1 : 0; @@ -182,7 +182,7 @@ struct sock *__inet_lookup_listener(struct net *net, if (inet->num == hnum && !sk->sk_node.next && (!inet->rcv_saddr || inet->rcv_saddr == daddr) && (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) && - !sk->sk_bound_dev_if && sk->sk_net == net) + !sk->sk_bound_dev_if && sock_net(sk) == net) goto sherry_cache; sk = inet_lookup_listener_slow(net, head, daddr, hnum, dif); } @@ -254,7 +254,7 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, struct sock *sk2; const struct hlist_node *node; struct inet_timewait_sock *tw; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); prefetch(head->chain.first); write_lock(lock); @@ -406,7 +406,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, struct inet_bind_hashbucket *head; struct inet_bind_bucket *tb; int ret; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); if (!snum) { int i, remaining, low, high, port; diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 717c411a5c6b..f12bc24de46f 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -124,7 +124,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat tw->tw_hash = sk->sk_hash; tw->tw_ipv6only = 0; tw->tw_prot = sk->sk_prot_creator; - tw->tw_net = sk->sk_net; + twsk_net_set(tw, sock_net(sk)); atomic_set(&tw->tw_refcnt, 1); inet_twsk_dead_node_init(tw); __module_get(tw->tw_prot->owner); diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 26685c83a146..4be00959b748 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -172,7 +172,7 @@ int ip_call_ra_chain(struct sk_buff *skb) if (sk && inet_sk(sk)->num == protocol && (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dev->ifindex) && - sk->sk_net == dev_net(dev)) { + sock_net(sk) == dev_net(dev)) { if (ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)) { if (ip_defrag(skb, IP_DEFRAG_CALL_RA_CHAIN)) { read_unlock(&ip_ra_lock); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 913266cd9902..08349267ceb4 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -351,7 +351,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok) * itself out. */ security_sk_classify_flow(sk, &fl); - if (ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 0)) + if (ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 0)) goto no_route; } sk_setup_caps(sk, &rt->u.dst); @@ -1382,7 +1382,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar .dport = tcp_hdr(skb)->source } }, .proto = sk->sk_protocol }; security_skb_classify_flow(skb, &fl); - if (ip_route_output_key(sk->sk_net, &rt, &fl)) + if (ip_route_output_key(sock_net(sk), &rt, &fl)) return; } diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index b854431047a4..d6e76f5229cc 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -449,7 +449,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, struct ip_options * opt = NULL; if (optlen > 40 || optlen < 0) goto e_inval; - err = ip_options_get_from_user(sk->sk_net, &opt, + err = ip_options_get_from_user(sock_net(sk), &opt, optval, optlen); if (err) break; @@ -590,13 +590,13 @@ static int do_ip_setsockopt(struct sock *sk, int level, err = 0; break; } - dev = ip_dev_find(sk->sk_net, mreq.imr_address.s_addr); + dev = ip_dev_find(sock_net(sk), mreq.imr_address.s_addr); if (dev) { mreq.imr_ifindex = dev->ifindex; dev_put(dev); } } else - dev = __dev_get_by_index(sk->sk_net, mreq.imr_ifindex); + dev = __dev_get_by_index(sock_net(sk), mreq.imr_ifindex); err = -EADDRNOTAVAIL; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index e54bc1364473..11700a4dcd95 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -849,7 +849,7 @@ static void mrtsock_destruct(struct sock *sk) { rtnl_lock(); if (sk == mroute_socket) { - IPV4_DEVCONF_ALL(sk->sk_net, MC_FORWARDING)--; + IPV4_DEVCONF_ALL(sock_net(sk), MC_FORWARDING)--; write_lock_bh(&mrt_lock); mroute_socket=NULL; @@ -898,7 +898,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int opt mroute_socket=sk; write_unlock_bh(&mrt_lock); - IPV4_DEVCONF_ALL(sk->sk_net, MC_FORWARDING)++; + IPV4_DEVCONF_ALL(sock_net(sk), MC_FORWARDING)++; } rtnl_unlock(); return ret; diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 756bc0e1a7c6..1563f29b5117 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -1496,11 +1496,11 @@ static int compat_do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, switch (cmd) { case ARPT_SO_SET_REPLACE: - ret = compat_do_replace(sk->sk_net, user, len); + ret = compat_do_replace(sock_net(sk), user, len); break; case ARPT_SO_SET_ADD_COUNTERS: - ret = do_add_counters(sk->sk_net, user, len, 1); + ret = do_add_counters(sock_net(sk), user, len, 1); break; default: @@ -1644,10 +1644,10 @@ static int compat_do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, switch (cmd) { case ARPT_SO_GET_INFO: - ret = get_info(sk->sk_net, user, len, 1); + ret = get_info(sock_net(sk), user, len, 1); break; case ARPT_SO_GET_ENTRIES: - ret = compat_get_entries(sk->sk_net, user, len); + ret = compat_get_entries(sock_net(sk), user, len); break; default: ret = do_arpt_get_ctl(sk, cmd, user, len); @@ -1665,11 +1665,11 @@ static int do_arpt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned switch (cmd) { case ARPT_SO_SET_REPLACE: - ret = do_replace(sk->sk_net, user, len); + ret = do_replace(sock_net(sk), user, len); break; case ARPT_SO_SET_ADD_COUNTERS: - ret = do_add_counters(sk->sk_net, user, len, 0); + ret = do_add_counters(sock_net(sk), user, len, 0); break; default: @@ -1689,11 +1689,11 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len switch (cmd) { case ARPT_SO_GET_INFO: - ret = get_info(sk->sk_net, user, len, 0); + ret = get_info(sock_net(sk), user, len, 0); break; case ARPT_SO_GET_ENTRIES: - ret = get_entries(sk->sk_net, user, len); + ret = get_entries(sock_net(sk), user, len); break; case ARPT_SO_GET_REVISION_TARGET: { diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 85a75e186b4b..a819d191e1aa 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1852,11 +1852,11 @@ compat_do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, switch (cmd) { case IPT_SO_SET_REPLACE: - ret = compat_do_replace(sk->sk_net, user, len); + ret = compat_do_replace(sock_net(sk), user, len); break; case IPT_SO_SET_ADD_COUNTERS: - ret = do_add_counters(sk->sk_net, user, len, 1); + ret = do_add_counters(sock_net(sk), user, len, 1); break; default: @@ -1963,10 +1963,10 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) switch (cmd) { case IPT_SO_GET_INFO: - ret = get_info(sk->sk_net, user, len, 1); + ret = get_info(sock_net(sk), user, len, 1); break; case IPT_SO_GET_ENTRIES: - ret = compat_get_entries(sk->sk_net, user, len); + ret = compat_get_entries(sock_net(sk), user, len); break; default: ret = do_ipt_get_ctl(sk, cmd, user, len); @@ -1985,11 +1985,11 @@ do_ipt_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) switch (cmd) { case IPT_SO_SET_REPLACE: - ret = do_replace(sk->sk_net, user, len); + ret = do_replace(sock_net(sk), user, len); break; case IPT_SO_SET_ADD_COUNTERS: - ret = do_add_counters(sk->sk_net, user, len, 0); + ret = do_add_counters(sock_net(sk), user, len, 0); break; default: @@ -2010,11 +2010,11 @@ do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) switch (cmd) { case IPT_SO_GET_INFO: - ret = get_info(sk->sk_net, user, len, 0); + ret = get_info(sock_net(sk), user, len, 0); break; case IPT_SO_GET_ENTRIES: - ret = get_entries(sk->sk_net, user, len); + ret = get_entries(sock_net(sk), user, len); break; case IPT_SO_GET_REVISION_MATCH: diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 8756d502a47f..be19a4048d7c 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -117,7 +117,7 @@ static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, sk_for_each_from(sk, node) { struct inet_sock *inet = inet_sk(sk); - if (sk->sk_net == net && inet->num == num && + if (sock_net(sk) == net && inet->num == num && !(inet->daddr && inet->daddr != raddr) && !(inet->rcv_saddr && inet->rcv_saddr != laddr) && !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) @@ -499,7 +499,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ipc.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { - err = ip_cmsg_send(sk->sk_net, msg, &ipc); + err = ip_cmsg_send(sock_net(sk), msg, &ipc); if (err) goto out; if (ipc.opt) @@ -553,7 +553,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, } security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 1); + err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 1); } if (err) goto done; @@ -620,7 +620,7 @@ static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in)) goto out; - chk_addr_ret = inet_addr_type(sk->sk_net, addr->sin_addr.s_addr); + chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); ret = -EADDRNOTAVAIL; if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) @@ -856,7 +856,7 @@ static struct sock *raw_get_first(struct seq_file *seq) struct hlist_node *node; sk_for_each(sk, node, &state->h->ht[state->bucket]) - if (sk->sk_net == state->p.net) + if (sock_net(sk) == state->p.net) goto found; } sk = NULL; @@ -872,7 +872,7 @@ static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk) sk = sk_next(sk); try_again: ; - } while (sk && sk->sk_net != state->p.net); + } while (sk && sock_net(sk) != state->p.net); if (!sk && ++state->bucket < RAW_HTABLE_SIZE) { sk = sk_head(&state->h->ht[state->bucket]); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 7768d718e199..194f5cca3121 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2689,7 +2689,7 @@ nla_put_failure: static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = in_skb->sk->sk_net; + struct net *net = sock_net(in_skb->sk); struct rtmsg *rtm; struct nlattr *tb[RTA_MAX+1]; struct rtable *rt = NULL; @@ -2785,7 +2785,7 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) int idx, s_idx; struct net *net; - net = skb->sk->sk_net; + net = sock_net(skb->sk); s_h = cb->args[0]; if (s_h < 0) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 28bece6f281b..46847e600a46 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1486,7 +1486,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) if (req) return tcp_check_req(sk, skb, req, prev); - nsk = inet_lookup_established(sk->sk_net, &tcp_hashinfo, iph->saddr, + nsk = inet_lookup_established(sock_net(sk), &tcp_hashinfo, iph->saddr, th->source, iph->daddr, th->dest, inet_iif(skb)); if (nsk) { @@ -1974,7 +1974,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) while (1) { while (req) { if (req->rsk_ops->family == st->family && - req->sk->sk_net == net) { + sock_net(req->sk) == net) { cur = req; goto out; } @@ -1998,7 +1998,7 @@ get_req: } get_sk: sk_for_each_from(sk, node) { - if (sk->sk_family == st->family && sk->sk_net == net) { + if (sk->sk_family == st->family && sock_net(sk) == net) { cur = sk; goto out; } @@ -2049,7 +2049,7 @@ static void *established_get_first(struct seq_file *seq) read_lock_bh(lock); sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) { if (sk->sk_family != st->family || - sk->sk_net != net) { + sock_net(sk) != net) { continue; } rc = sk; @@ -2059,7 +2059,7 @@ static void *established_get_first(struct seq_file *seq) inet_twsk_for_each(tw, node, &tcp_hashinfo.ehash[st->bucket].twchain) { if (tw->tw_family != st->family || - tw->tw_net != net) { + twsk_net(tw) != net) { continue; } rc = tw; @@ -2086,7 +2086,7 @@ static void *established_get_next(struct seq_file *seq, void *cur) tw = cur; tw = tw_next(tw); get_tw: - while (tw && (tw->tw_family != st->family || tw->tw_net != net)) { + while (tw && (tw->tw_family != st->family || twsk_net(tw) != net)) { tw = tw_next(tw); } if (tw) { @@ -2107,7 +2107,7 @@ get_tw: sk = sk_next(sk); sk_for_each_from(sk, node) { - if (sk->sk_family == st->family && sk->sk_net == net) + if (sk->sk_family == st->family && sock_net(sk) == net) goto found; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index e2cd93481359..76d52d37d6ac 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -137,7 +137,7 @@ static inline int __udp_lib_lport_inuse(struct net *net, __u16 num, struct hlist_node *node; sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)]) - if (sk->sk_net == net && sk->sk_hash == num) + if (sock_net(sk) == net && sk->sk_hash == num) return 1; return 0; } @@ -158,7 +158,7 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, struct hlist_head *head; struct sock *sk2; int error = 1; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); write_lock_bh(&udp_hash_lock); @@ -218,7 +218,7 @@ gotit: sk_for_each(sk2, node, head) if (sk2->sk_hash == snum && sk2 != sk && - sk2->sk_net == net && + sock_net(sk2) == net && (!sk2->sk_reuse || !sk->sk_reuse) && (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && @@ -269,7 +269,7 @@ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { struct inet_sock *inet = inet_sk(sk); - if (sk->sk_net == net && sk->sk_hash == hnum && + if (sock_net(sk) == net && sk->sk_hash == hnum && !ipv6_only_sock(sk)) { int score = (sk->sk_family == PF_INET ? 1 : 0); if (inet->rcv_saddr) { @@ -607,7 +607,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, ipc.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { - err = ip_cmsg_send(sk->sk_net, msg, &ipc); + err = ip_cmsg_send(sock_net(sk), msg, &ipc); if (err) return err; if (ipc.opt) @@ -656,7 +656,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, { .sport = inet->sport, .dport = dport } } }; security_sk_classify_flow(sk, &fl); - err = ip_route_output_flow(sk->sk_net, &rt, &fl, sk, 1); + err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 1); if (err) { if (err == -ENETUNREACH) IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); @@ -1511,7 +1511,7 @@ static struct sock *udp_get_first(struct seq_file *seq) for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { struct hlist_node *node; sk_for_each(sk, node, state->hashtable + state->bucket) { - if (sk->sk_net != net) + if (sock_net(sk) != net) continue; if (sk->sk_family == state->family) goto found; @@ -1531,7 +1531,7 @@ static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) sk = sk_next(sk); try_again: ; - } while (sk && (sk->sk_net != net || sk->sk_family != state->family)); + } while (sk && (sock_net(sk) != net || sk->sk_family != state->family)); if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { sk = sk_head(state->hashtable + state->bucket); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d1de9ec74261..f2c90f145cbb 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3054,7 +3054,7 @@ static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = { static int inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ifaddrmsg *ifm; struct nlattr *tb[IFA_MAX+1]; struct in6_addr *pfx; @@ -3112,7 +3112,7 @@ static int inet6_addr_modify(struct inet6_ifaddr *ifp, u8 ifa_flags, static int inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ifaddrmsg *ifm; struct nlattr *tb[IFA_MAX+1]; struct in6_addr *pfx; @@ -3322,7 +3322,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, struct inet6_ifaddr *ifa; struct ifmcaddr6 *ifmca; struct ifacaddr6 *ifaca; - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); s_idx = cb->args[0]; s_ip_idx = ip_idx = cb->args[1]; @@ -3418,7 +3418,7 @@ static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb) static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = in_skb->sk->sk_net; + struct net *net = sock_net(in_skb->sk); struct ifaddrmsg *ifm; struct nlattr *tb[IFA_MAX+1]; struct in6_addr *addr = NULL; @@ -3645,7 +3645,7 @@ nla_put_failure: static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int idx, err; int s_idx = cb->args[0]; struct net_device *dev; diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index de371b5997fe..9bfa8846f262 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c @@ -364,7 +364,7 @@ static const struct nla_policy ifal_policy[IFAL_MAX+1] = { static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ifaddrlblmsg *ifal; struct nlattr *tb[IFAL_MAX+1]; struct in6_addr *pfx; @@ -452,7 +452,7 @@ static int ip6addrlbl_fill(struct sk_buff *skb, static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct ip6addrlbl_entry *p; struct hlist_node *pos; int idx = 0, s_idx = cb->args[0]; @@ -490,7 +490,7 @@ static inline int ip6addrlbl_msgsize(void) static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = in_skb->sk->sk_net; + struct net *net = sock_net(in_skb->sk); struct ifaddrlblmsg *ifal; struct nlattr *tb[IFAL_MAX+1]; struct in6_addr *addr; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index f52bdaed8a1b..12f04e9d3e88 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -245,7 +245,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct sock *sk = sock->sk; struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); __be32 v4addr = 0; unsigned short snum; int addr_type = 0; @@ -438,7 +438,7 @@ EXPORT_SYMBOL(inet6_getname); int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); switch(cmd) { diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index e7a7fe26cebf..cac580749ebe 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -154,7 +154,7 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, struct nlattr **tb) { int err = -EINVAL; - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct fib6_rule *rule6 = (struct fib6_rule *) rule; if (rule->action == FR_ACT_TO_TBL) { diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 50857662e6b7..63309d10df3a 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -163,7 +163,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type, struct flowi *fl) { struct dst_entry *dst; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); int res = 0; /* Informational messages are not limited. */ diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index c0c8d2d17682..21c467675412 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -105,7 +105,7 @@ struct sock *inet6_lookup_listener(struct net *net, read_lock(&hashinfo->lhash_lock); sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) { - if (sk->sk_net == net && inet_sk(sk)->num == hnum && + if (sock_net(sk) == net && inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) { const struct ipv6_pinfo *np = inet6_sk(sk); @@ -172,7 +172,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, struct sock *sk2; const struct hlist_node *node; struct inet_timewait_sock *tw; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); prefetch(head->chain.first); write_lock(lock); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index b0814b0082e7..b3f6e03c454c 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -346,7 +346,7 @@ end: static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); unsigned int h, s_h; unsigned int e = 0, s_e; struct rt6_rtnl_dump_arg arg; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 556300f0eba5..a8b4da25b0a7 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -910,7 +910,7 @@ static int ip6_dst_lookup_tail(struct sock *sk, struct dst_entry **dst, struct flowi *fl) { int err; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); if (*dst == NULL) *dst = ip6_route_output(net, sk, fl); diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index dc6695cc5767..d3d93d752e10 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -107,7 +107,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); int val, valbool; int retv = -ENOPROTOOPT; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 0357de8e78c8..20a3d8e2f6c6 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -181,7 +181,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) struct net_device *dev = NULL; struct ipv6_mc_socklist *mc_lst; struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); int err; if (!ipv6_addr_is_multicast(addr)) @@ -255,7 +255,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_mc_socklist *mc_lst, **lnk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); write_lock_bh(&ipv6_sk_mc_lock); for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) { @@ -327,7 +327,7 @@ void ipv6_sock_mc_close(struct sock *sk) { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_mc_socklist *mc_lst; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); write_lock_bh(&ipv6_sk_mc_lock); while ((mc_lst = np->ipv6_mc_list) != NULL) { @@ -365,7 +365,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, struct inet6_dev *idev; struct ipv6_pinfo *inet6 = inet6_sk(sk); struct ip6_sf_socklist *psl; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); int i, j, rv; int leavegroup = 0; int pmclocked = 0; @@ -505,7 +505,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) struct inet6_dev *idev; struct ipv6_pinfo *inet6 = inet6_sk(sk); struct ip6_sf_socklist *newpsl, *psl; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); int leavegroup = 0; int i, err; @@ -598,7 +598,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, struct net_device *dev; struct ipv6_pinfo *inet6 = inet6_sk(sk); struct ip6_sf_socklist *psl; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index af1ec7ba757c..70ef0d276cc0 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1879,11 +1879,11 @@ compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, switch (cmd) { case IP6T_SO_SET_REPLACE: - ret = compat_do_replace(sk->sk_net, user, len); + ret = compat_do_replace(sock_net(sk), user, len); break; case IP6T_SO_SET_ADD_COUNTERS: - ret = do_add_counters(sk->sk_net, user, len, 1); + ret = do_add_counters(sock_net(sk), user, len, 1); break; default: @@ -1990,10 +1990,10 @@ compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) switch (cmd) { case IP6T_SO_GET_INFO: - ret = get_info(sk->sk_net, user, len, 1); + ret = get_info(sock_net(sk), user, len, 1); break; case IP6T_SO_GET_ENTRIES: - ret = compat_get_entries(sk->sk_net, user, len); + ret = compat_get_entries(sock_net(sk), user, len); break; default: ret = do_ip6t_get_ctl(sk, cmd, user, len); @@ -2012,11 +2012,11 @@ do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) switch (cmd) { case IP6T_SO_SET_REPLACE: - ret = do_replace(sk->sk_net, user, len); + ret = do_replace(sock_net(sk), user, len); break; case IP6T_SO_SET_ADD_COUNTERS: - ret = do_add_counters(sk->sk_net, user, len, 0); + ret = do_add_counters(sock_net(sk), user, len, 0); break; default: @@ -2037,11 +2037,11 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) switch (cmd) { case IP6T_SO_GET_INFO: - ret = get_info(sk->sk_net, user, len, 0); + ret = get_info(sock_net(sk), user, len, 0); break; case IP6T_SO_GET_ENTRIES: - ret = get_entries(sk->sk_net, user, len); + ret = get_entries(sock_net(sk), user, len); break; case IP6T_SO_GET_REVISION_MATCH: diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index efb0047f6880..12c7a1560977 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -76,7 +76,7 @@ static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, if (inet_sk(sk)->num == num) { struct ipv6_pinfo *np = inet6_sk(sk); - if (sk->sk_net != net) + if (sock_net(sk) != net) continue; if (!ipv6_addr_any(&np->daddr) && @@ -280,7 +280,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (!sk->sk_bound_dev_if) goto out; - dev = dev_get_by_index(sk->sk_net, sk->sk_bound_dev_if); + dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if); if (!dev) { err = -ENODEV; goto out; @@ -293,7 +293,7 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) v4addr = LOOPBACK4_IPV6; if (!(addr_type & IPV6_ADDR_MULTICAST)) { err = -EADDRNOTAVAIL; - if (!ipv6_chk_addr(sk->sk_net, &addr->sin6_addr, + if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr, dev, 0)) { if (dev) dev_put(dev); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 65053fba8c1a..ac4428371432 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2020,7 +2020,7 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; cfg->fc_nlinfo.nlh = nlh; - cfg->fc_nlinfo.nl_net = skb->sk->sk_net; + cfg->fc_nlinfo.nl_net = sock_net(skb->sk); if (tb[RTA_GATEWAY]) { nla_memcpy(&cfg->fc_gateway, tb[RTA_GATEWAY], 16); @@ -2216,7 +2216,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) { - struct net *net = in_skb->sk->sk_net; + struct net *net = sock_net(in_skb->sk); struct nlattr *tb[RTA_MAX+1]; struct rt6_info *rt; struct sk_buff *skb; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 086deffff9c9..323c7e06ef43 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1218,7 +1218,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) if (req) return tcp_check_req(sk, skb, req, prev); - nsk = __inet6_lookup_established(sk->sk_net, &tcp_hashinfo, + nsk = __inet6_lookup_established(sock_net(sk), &tcp_hashinfo, &ipv6_hdr(skb)->saddr, th->source, &ipv6_hdr(skb)->daddr, ntohs(th->dest), inet6_iif(skb)); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 6683c04b427e..db266ff297e5 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -70,7 +70,7 @@ static struct sock *__udp6_lib_lookup(struct net *net, sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { struct inet_sock *inet = inet_sk(sk); - if (sk->sk_net == net && sk->sk_hash == hnum && + if (sock_net(sk) == net && sk->sk_hash == hnum && sk->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); int score = 0; @@ -323,7 +323,7 @@ static struct sock *udp_v6_mcast_next(struct sock *sk, sk_for_each_from(s, node) { struct inet_sock *inet = inet_sk(s); - if (s->sk_net != sk->sk_net) + if (sock_net(s) != sock_net(sk)) continue; if (s->sk_hash == num && s->sk_family == PF_INET6) { diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 6f21a53cb3e7..ae54b20d0470 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -837,7 +837,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) IRDA_DEBUG(2, "%s()\n", __func__); - err = irda_create(sk->sk_net, newsock, sk->sk_protocol); + err = irda_create(sock_net(sk), newsock, sk->sk_protocol); if (err) return err; diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 5ebfd93ff5e7..5c6d89c6d51d 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -700,7 +700,7 @@ static struct sock *llc_create_incoming_sock(struct sock *sk, struct llc_addr *saddr, struct llc_addr *daddr) { - struct sock *newsk = llc_sk_alloc(sk->sk_net, sk->sk_family, GFP_ATOMIC, + struct sock *newsk = llc_sk_alloc(sock_net(sk), sk->sk_family, GFP_ATOMIC, sk->sk_prot); struct llc_sock *newllc, *llc = llc_sk(sk); diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c index 3dd4b3c76d81..69d699f95f4c 100644 --- a/net/netfilter/nf_sockopt.c +++ b/net/netfilter/nf_sockopt.c @@ -65,7 +65,7 @@ static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, int pf, { struct nf_sockopt_ops *ops; - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return ERR_PTR(-ENOPROTOOPT); if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 86bd8660a8f2..712a7bff8560 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -228,7 +228,7 @@ static inline struct sock *netlink_lookup(struct net *net, int protocol, read_lock(&nl_table_lock); head = nl_pid_hashfn(hash, pid); sk_for_each(sk, node, head) { - if ((sk->sk_net == net) && (nlk_sk(sk)->pid == pid)) { + if (sock_net(sk) == net && (nlk_sk(sk)->pid == pid)) { sock_hold(sk); goto found; } @@ -348,7 +348,7 @@ static int netlink_insert(struct sock *sk, struct net *net, u32 pid) head = nl_pid_hashfn(hash, pid); len = 0; sk_for_each(osk, node, head) { - if ((osk->sk_net == net) && (nlk_sk(osk)->pid == pid)) + if (sock_net(osk) == net && (nlk_sk(osk)->pid == pid)) break; len++; } @@ -486,7 +486,7 @@ static int netlink_release(struct socket *sock) if (nlk->pid && !nlk->subscriptions) { struct netlink_notify n = { - .net = sk->sk_net, + .net = sock_net(sk), .protocol = sk->sk_protocol, .pid = nlk->pid, }; @@ -518,7 +518,7 @@ static int netlink_release(struct socket *sock) static int netlink_autobind(struct socket *sock) { struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct nl_pid_hash *hash = &nl_table[sk->sk_protocol].hash; struct hlist_head *head; struct sock *osk; @@ -532,7 +532,7 @@ retry: netlink_table_grab(); head = nl_pid_hashfn(hash, pid); sk_for_each(osk, node, head) { - if ((osk->sk_net != net)) + if (sock_net(osk) != net) continue; if (nlk_sk(osk)->pid == pid) { /* Bind collision, search negative pid values. */ @@ -611,7 +611,7 @@ static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) { struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct netlink_sock *nlk = nlk_sk(sk); struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; int err; @@ -720,7 +720,7 @@ static struct sock *netlink_getsockbypid(struct sock *ssk, u32 pid) struct sock *sock; struct netlink_sock *nlk; - sock = netlink_lookup(ssk->sk_net, ssk->sk_protocol, pid); + sock = netlink_lookup(sock_net(ssk), ssk->sk_protocol, pid); if (!sock) return ERR_PTR(-ECONNREFUSED); @@ -962,7 +962,7 @@ static inline int do_one_broadcast(struct sock *sk, !test_bit(p->group - 1, nlk->groups)) goto out; - if ((sk->sk_net != p->net)) + if (sock_net(sk) != p->net) goto out; if (p->failure) { @@ -1006,7 +1006,7 @@ out: int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid, u32 group, gfp_t allocation) { - struct net *net = ssk->sk_net; + struct net *net = sock_net(ssk); struct netlink_broadcast_data info; struct hlist_node *node; struct sock *sk; @@ -1064,7 +1064,7 @@ static inline int do_one_set_err(struct sock *sk, if (sk == p->exclude_sk) goto out; - if (sk->sk_net != p->exclude_sk->sk_net) + if (sock_net(sk) != sock_net(p->exclude_sk)) goto out; if (nlk->pid == p->pid || p->group - 1 >= nlk->ngroups || @@ -1601,7 +1601,7 @@ int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, atomic_inc(&skb->users); cb->skb = skb; - sk = netlink_lookup(ssk->sk_net, ssk->sk_protocol, NETLINK_CB(skb).pid); + sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).pid); if (sk == NULL) { netlink_destroy_callback(cb); return -ECONNREFUSED; @@ -1643,7 +1643,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) if (!skb) { struct sock *sk; - sk = netlink_lookup(in_skb->sk->sk_net, + sk = netlink_lookup(sock_net(in_skb->sk), in_skb->sk->sk_protocol, NETLINK_CB(in_skb).pid); if (sk) { @@ -1758,7 +1758,7 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) for (j = 0; j <= hash->mask; j++) { sk_for_each(s, node, &hash->table[j]) { - if (iter->p.net != s->sk_net) + if (sock_net(s) != iter->p.net) continue; if (off == pos) { iter->link = i; @@ -1794,7 +1794,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) s = v; do { s = sk_next(s); - } while (s && (iter->p.net != s->sk_net)); + } while (s && (sock_net(s) != iter->p.net)); if (s) return s; @@ -1806,7 +1806,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) for (; j <= hash->mask; j++) { s = sk_head(&hash->table[j]); - while (s && (iter->p.net != s->sk_net)) + while (s && sock_net(s) != iter->p.net) s = sk_next(s); if (s) { iter->link = i; diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index a270ebf9f765..4bae8b998cab 100644 --- a/net/netrom/af_netrom.c +++ b/net/netrom/af_netrom.c @@ -466,7 +466,7 @@ static struct sock *nr_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) return NULL; - sk = sk_alloc(osk->sk_net, PF_NETROM, GFP_ATOMIC, osk->sk_prot); + sk = sk_alloc(sock_net(osk), PF_NETROM, GFP_ATOMIC, osk->sk_prot); if (sk == NULL) return NULL; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index baa290d3444a..25070240d4ae 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -263,7 +263,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct if (skb->pkt_type == PACKET_LOOPBACK) goto out; - if (dev_net(dev) != sk->sk_net) + if (dev_net(dev) != sock_net(sk)) goto out; if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) @@ -337,7 +337,7 @@ static int packet_sendmsg_spkt(struct kiocb *iocb, struct socket *sock, */ saddr->spkt_device[13] = 0; - dev = dev_get_by_name(sk->sk_net, saddr->spkt_device); + dev = dev_get_by_name(sock_net(sk), saddr->spkt_device); err = -ENODEV; if (dev == NULL) goto out_unlock; @@ -451,7 +451,7 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packet sk = pt->af_packet_priv; po = pkt_sk(sk); - if (dev_net(dev) != sk->sk_net) + if (dev_net(dev) != sock_net(sk)) goto drop; skb->dev = dev; @@ -568,7 +568,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, struct packe sk = pt->af_packet_priv; po = pkt_sk(sk); - if (dev_net(dev) != sk->sk_net) + if (dev_net(dev) != sock_net(sk)) goto drop; if (dev->header_ops) { @@ -728,7 +728,7 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, } - dev = dev_get_by_index(sk->sk_net, ifindex); + dev = dev_get_by_index(sock_net(sk), ifindex); err = -ENXIO; if (dev == NULL) goto out_unlock; @@ -800,7 +800,7 @@ static int packet_release(struct socket *sock) if (!sk) return 0; - net = sk->sk_net; + net = sock_net(sk); po = pkt_sk(sk); write_lock_bh(&net->packet.sklist_lock); @@ -914,7 +914,7 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr, int add return -EINVAL; strlcpy(name,uaddr->sa_data,sizeof(name)); - dev = dev_get_by_name(sk->sk_net, name); + dev = dev_get_by_name(sock_net(sk), name); if (dev) { err = packet_do_bind(sk, dev, pkt_sk(sk)->num); dev_put(dev); @@ -941,7 +941,7 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len if (sll->sll_ifindex) { err = -ENODEV; - dev = dev_get_by_index(sk->sk_net, sll->sll_ifindex); + dev = dev_get_by_index(sock_net(sk), sll->sll_ifindex); if (dev == NULL) goto out; } @@ -1135,7 +1135,7 @@ static int packet_getname_spkt(struct socket *sock, struct sockaddr *uaddr, return -EOPNOTSUPP; uaddr->sa_family = AF_PACKET; - dev = dev_get_by_index(sk->sk_net, pkt_sk(sk)->ifindex); + dev = dev_get_by_index(sock_net(sk), pkt_sk(sk)->ifindex); if (dev) { strlcpy(uaddr->sa_data, dev->name, 15); dev_put(dev); @@ -1160,7 +1160,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, sll->sll_family = AF_PACKET; sll->sll_ifindex = po->ifindex; sll->sll_protocol = po->num; - dev = dev_get_by_index(sk->sk_net, po->ifindex); + dev = dev_get_by_index(sock_net(sk), po->ifindex); if (dev) { sll->sll_hatype = dev->type; sll->sll_halen = dev->addr_len; @@ -1212,7 +1212,7 @@ static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq) rtnl_lock(); err = -ENODEV; - dev = __dev_get_by_index(sk->sk_net, mreq->mr_ifindex); + dev = __dev_get_by_index(sock_net(sk), mreq->mr_ifindex); if (!dev) goto done; @@ -1266,7 +1266,7 @@ static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq) if (--ml->count == 0) { struct net_device *dev; *mlp = ml->next; - dev = dev_get_by_index(sk->sk_net, ml->ifindex); + dev = dev_get_by_index(sock_net(sk), ml->ifindex); if (dev) { packet_dev_mc(dev, ml, -1); dev_put(dev); @@ -1294,7 +1294,7 @@ static void packet_flush_mclist(struct sock *sk) struct net_device *dev; po->mclist = ml->next; - if ((dev = dev_get_by_index(sk->sk_net, ml->ifindex)) != NULL) { + if ((dev = dev_get_by_index(sock_net(sk), ml->ifindex)) != NULL) { packet_dev_mc(dev, ml, -1); dev_put(dev); } @@ -1540,7 +1540,7 @@ static int packet_ioctl(struct socket *sock, unsigned int cmd, case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCSIFFLAGS: - if (sk->sk_net != &init_net) + if (sock_net(sk) != &init_net) return -ENOIOCTLCMD; return inet_dgram_ops.ioctl(sock, cmd, arg); #endif diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 1a7f143cf741..92d85c38e4d2 100644 --- a/net/rose/af_rose.c +++ b/net/rose/af_rose.c @@ -551,7 +551,7 @@ static struct sock *rose_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) return NULL; - sk = sk_alloc(osk->sk_net, PF_ROSE, GFP_ATOMIC, &rose_proto); + sk = sk_alloc(sock_net(osk), PF_ROSE, GFP_ATOMIC, &rose_proto); if (sk == NULL) return NULL; diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 0b8eb235bc13..74e662cbb2c5 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -951,7 +951,7 @@ done: static int tc_ctl_action(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct nlattr *tca[TCA_ACT_MAX + 1]; u32 pid = skb ? NETLINK_CB(skb).pid : 0; int ret = 0, ovr = 0; @@ -1029,7 +1029,7 @@ find_dump_kind(struct nlmsghdr *n) static int tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct nlmsghdr *nlh; unsigned char *b = skb_tail_pointer(skb); struct nlattr *nest; diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 0fbedcabf111..1086df7478bc 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -118,7 +118,7 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp) static int tc_ctl_tfilter(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct nlattr *tca[TCA_MAX + 1]; struct tcmsg *t; u32 protocol; @@ -389,7 +389,7 @@ static int tcf_node_dump(struct tcf_proto *tp, unsigned long n, static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int t; int s_t; struct net_device *dev; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 7e3c048ba9b1..15b91a9ee8e8 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -605,7 +605,7 @@ check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w) static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct tcmsg *tcm = NLMSG_DATA(n); struct nlattr *tca[TCA_MAX + 1]; struct net_device *dev; @@ -674,7 +674,7 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct tcmsg *tcm; struct nlattr *tca[TCA_MAX + 1]; struct net_device *dev; @@ -893,7 +893,7 @@ err_out: static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int idx, q_idx; int s_idx, s_q_idx; struct net_device *dev; @@ -945,7 +945,7 @@ done: static int tc_ctl_tclass(struct sk_buff *skb, struct nlmsghdr *n, void *arg) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); struct tcmsg *tcm = NLMSG_DATA(n); struct nlattr *tca[TCA_MAX + 1]; struct net_device *dev; @@ -1139,7 +1139,7 @@ static int qdisc_class_dump(struct Qdisc *q, unsigned long cl, struct qdisc_walk static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = skb->sk->sk_net; + struct net *net = sock_net(skb->sk); int t; int s_t; struct net_device *dev; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index dc71d0d83753..036bfcc8d15b 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -636,7 +636,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk, struct ipv6_pinfo *newnp, *np = inet6_sk(sk); struct sctp6_sock *newsctp6sk; - newsk = sk_alloc(sk->sk_net, PF_INET6, GFP_KERNEL, sk->sk_prot); + newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot); if (!newsk) goto out; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 2faa0d8839eb..5aea91137fbb 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -554,7 +554,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk, { struct inet_sock *inet = inet_sk(sk); struct inet_sock *newinet; - struct sock *newsk = sk_alloc(sk->sk_net, PF_INET, GFP_KERNEL, + struct sock *newsk = sk_alloc(sock_net(sk), PF_INET, GFP_KERNEL, sk->sk_prot); if (!newsk) diff --git a/net/socket.c b/net/socket.c index 9d3fbfbc8535..79e5382fd110 100644 --- a/net/socket.c +++ b/net/socket.c @@ -857,7 +857,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) sock = file->private_data; sk = sock->sk; - net = sk->sk_net; + net = sock_net(sk); if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { err = dev_ioctl(net, cmd, argp); } else @@ -1375,7 +1375,7 @@ asmlinkage long sys_listen(int fd, int backlog) sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock) { - somaxconn = sock->sk->sk_net->sysctl_somaxconn; + somaxconn = sock_net(sock->sk)->sysctl_somaxconn; if ((unsigned)backlog > somaxconn) backlog = somaxconn; diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 3220d5cb5b5d..ae45df060e3a 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1375,7 +1375,7 @@ static int accept(struct socket *sock, struct socket *newsock, int flags) } buf = skb_peek(&sock->sk->sk_receive_queue); - res = tipc_create(sock->sk->sk_net, newsock, 0); + res = tipc_create(sock_net(sock->sk), newsock, 0); if (!res) { struct tipc_sock *new_tsock = tipc_sk(newsock->sk); struct tipc_portid id; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index ae584356852c..cb9d0cb5f270 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -252,7 +252,7 @@ static struct sock *__unix_find_socket_byname(struct net *net, sk_for_each(s, node, &unix_socket_table[hash ^ type]) { struct unix_sock *u = unix_sk(s); - if (s->sk_net != net) + if (sock_net(s) != net) continue; if (u->addr->len == len && @@ -289,7 +289,7 @@ static struct sock *unix_find_socket_byinode(struct net *net, struct inode *i) &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) { struct dentry *dentry = unix_sk(s)->dentry; - if (s->sk_net != net) + if (sock_net(s) != net) continue; if(dentry && dentry->d_inode == i) @@ -654,7 +654,7 @@ static int unix_release(struct socket *sock) static int unix_autobind(struct socket *sock) { struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); static u32 ordernum = 1; struct unix_address * addr; @@ -758,7 +758,7 @@ fail: static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; struct dentry * dentry = NULL; @@ -899,7 +899,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct sockaddr_un *sunaddr=(struct sockaddr_un*)addr; struct sock *other; unsigned hash; @@ -996,7 +996,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, { struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk), *newu, *otheru; struct sock *newsk = NULL; struct sock *other = NULL; @@ -1025,7 +1025,7 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, err = -ENOMEM; /* create new sock for complete connection */ - newsk = unix_create1(sk->sk_net, NULL); + newsk = unix_create1(sock_net(sk), NULL); if (newsk == NULL) goto out; @@ -1312,7 +1312,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, { struct sock_iocb *siocb = kiocb_to_siocb(kiocb); struct sock *sk = sock->sk; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); struct sockaddr_un *sunaddr=msg->msg_name; struct sock *other = NULL; @@ -2022,7 +2022,7 @@ static struct sock *unix_seq_idx(struct unix_iter_state *iter, loff_t pos) struct sock *s; for (s = first_unix_socket(&iter->i); s; s = next_unix_socket(&iter->i, s)) { - if (s->sk_net != iter->p.net) + if (sock_net(s) != iter->p.net) continue; if (off == pos) return s; @@ -2050,7 +2050,7 @@ static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) sk = first_unix_socket(&iter->i); else sk = next_unix_socket(&iter->i, sk); - while (sk && (sk->sk_net != iter->p.net)) + while (sk && (sock_net(sk) != iter->p.net)) sk = next_unix_socket(&iter->i, sk); return sk; } diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 7a46ea73fe2d..6ba67c523c16 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -549,7 +549,7 @@ static struct sock *x25_make_new(struct sock *osk) if (osk->sk_type != SOCK_SEQPACKET) goto out; - if ((sk = x25_alloc_socket(osk->sk_net)) == NULL) + if ((sk = x25_alloc_socket(sock_net(osk))) == NULL) goto out; x25 = x25_sk(sk); -- cgit v1.2.3-59-g8ed1b From 1218854afa6f659be90b748cf1bc7badee954a35 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 26 Mar 2008 02:36:06 +0900 Subject: [NET] NETNS: Omit seq_net_private->net without CONFIG_NET_NS. Without CONFIG_NET_NS, no namespace other than &init_net exists, no need to store net in seq_net_private. Signed-off-by: YOSHIFUJI Hideaki --- fs/proc/proc_net.c | 6 +++--- include/linux/seq_file.h | 7 +++++++ net/core/neighbour.c | 8 ++++---- net/ipv4/fib_hash.c | 5 ++--- net/ipv4/fib_trie.c | 13 ++++++------- net/ipv4/raw.c | 4 ++-- net/ipv4/route.c | 29 +++++++++++++++-------------- net/ipv6/addrconf.c | 4 ++-- net/ipv6/mcast.c | 4 ++-- net/netfilter/x_tables.c | 4 ++-- net/netlink/af_netlink.c | 6 +++--- net/unix/af_unix.c | 10 +++++----- 12 files changed, 53 insertions(+), 47 deletions(-) (limited to 'net') diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c index 4caa5f774fb7..13cd7835d0df 100644 --- a/fs/proc/proc_net.c +++ b/fs/proc/proc_net.c @@ -44,7 +44,9 @@ int seq_open_net(struct inode *ino, struct file *f, put_net(net); return -ENOMEM; } +#ifdef CONFIG_NET_NS p->net = net; +#endif return 0; } EXPORT_SYMBOL_GPL(seq_open_net); @@ -52,12 +54,10 @@ EXPORT_SYMBOL_GPL(seq_open_net); int seq_release_net(struct inode *ino, struct file *f) { struct seq_file *seq; - struct seq_net_private *p; seq = f->private_data; - p = seq->private; - put_net(p->net); + put_net(seq_file_net(seq)); seq_release_private(ino, f); return 0; } diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 67c2563961f3..d870a8253769 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -5,6 +5,7 @@ #include #include #include +#include struct seq_operations; struct file; @@ -64,7 +65,9 @@ extern struct list_head *seq_list_next(void *v, struct list_head *head, struct net; struct seq_net_private { +#ifdef CONFIG_NET_NS struct net *net; +#endif }; int seq_open_net(struct inode *, struct file *, @@ -72,7 +75,11 @@ int seq_open_net(struct inode *, struct file *, int seq_release_net(struct inode *, struct file *); static inline struct net *seq_file_net(struct seq_file *seq) { +#ifdef CONFIG_NET_NS return ((struct seq_net_private *)seq->private)->net; +#else + return &init_net; +#endif } #endif diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 065fbac7ecd3..b8d491fb4b42 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -2145,7 +2145,7 @@ EXPORT_SYMBOL(__neigh_for_each_release); static struct neighbour *neigh_get_first(struct seq_file *seq) { struct neigh_seq_state *state = seq->private; - struct net *net = state->p.net; + struct net *net = seq_file_net(seq); struct neigh_table *tbl = state->tbl; struct neighbour *n = NULL; int bucket = state->bucket; @@ -2186,7 +2186,7 @@ static struct neighbour *neigh_get_next(struct seq_file *seq, loff_t *pos) { struct neigh_seq_state *state = seq->private; - struct net *net = state->p.net; + struct net *net = seq_file_net(seq); struct neigh_table *tbl = state->tbl; if (state->neigh_sub_iter) { @@ -2246,7 +2246,7 @@ static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos) static struct pneigh_entry *pneigh_get_first(struct seq_file *seq) { struct neigh_seq_state *state = seq->private; - struct net * net = state->p.net; + struct net *net = seq_file_net(seq); struct neigh_table *tbl = state->tbl; struct pneigh_entry *pn = NULL; int bucket = state->bucket; @@ -2269,7 +2269,7 @@ static struct pneigh_entry *pneigh_get_next(struct seq_file *seq, loff_t *pos) { struct neigh_seq_state *state = seq->private; - struct net * net = state->p.net; + struct net *net = seq_file_net(seq); struct neigh_table *tbl = state->tbl; pn = pn->next; diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index 8d58d85dfac6..02088deb0461 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -821,7 +821,7 @@ static struct fib_alias *fib_get_first(struct seq_file *seq) struct fib_table *main_table; struct fn_hash *table; - main_table = fib_get_table(iter->p.net, RT_TABLE_MAIN); + main_table = fib_get_table(seq_file_net(seq), RT_TABLE_MAIN); table = (struct fn_hash *)main_table->tb_data; iter->bucket = 0; @@ -959,11 +959,10 @@ static struct fib_alias *fib_get_idx(struct seq_file *seq, loff_t pos) static void *fib_seq_start(struct seq_file *seq, loff_t *pos) __acquires(fib_hash_lock) { - struct fib_iter_state *iter = seq->private; void *v = NULL; read_lock(&fib_hash_lock); - if (fib_get_table(iter->p.net, RT_TABLE_MAIN)) + if (fib_get_table(seq_file_net(seq), RT_TABLE_MAIN)) v = *pos ? fib_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; return v; } diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index ce6cb34e28e1..9e491e70e855 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2279,9 +2279,10 @@ static const struct file_operations fib_triestat_fops = { .release = fib_triestat_seq_release, }; -static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, loff_t pos) +static struct node *fib_trie_get_idx(struct seq_file *seq, loff_t pos) { - struct net *net = iter->p.net; + struct fib_trie_iter *iter = seq->private; + struct net *net = seq_file_net(seq); loff_t idx = 0; unsigned int h; @@ -2309,16 +2310,14 @@ static struct node *fib_trie_get_idx(struct fib_trie_iter *iter, loff_t pos) static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos) __acquires(RCU) { - struct fib_trie_iter *iter = seq->private; - rcu_read_lock(); - return fib_trie_get_idx(iter, *pos); + return fib_trie_get_idx(seq, *pos); } static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct fib_trie_iter *iter = seq->private; - struct net *net = iter->p.net; + struct net *net = seq_file_net(seq); struct fib_table *tb = iter->tb; struct hlist_node *tb_node; unsigned int h; @@ -2513,7 +2512,7 @@ static void *fib_route_seq_start(struct seq_file *seq, loff_t *pos) struct fib_table *tb; rcu_read_lock(); - tb = fib_get_table(iter->p.net, RT_TABLE_MAIN); + tb = fib_get_table(seq_file_net(seq), RT_TABLE_MAIN); if (!tb) return NULL; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index be19a4048d7c..25dc8b38cac3 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -856,7 +856,7 @@ static struct sock *raw_get_first(struct seq_file *seq) struct hlist_node *node; sk_for_each(sk, node, &state->h->ht[state->bucket]) - if (sock_net(sk) == state->p.net) + if (sock_net(sk) == seq_file_net(seq)) goto found; } sk = NULL; @@ -872,7 +872,7 @@ static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk) sk = sk_next(sk); try_again: ; - } while (sk && sock_net(sk) != state->p.net); + } while (sk && sock_net(sk) != seq_file_net(seq)); if (!sk && ++state->bucket < RAW_HTABLE_SIZE) { sk = sk_head(&state->h->ht[state->bucket]); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 194f5cca3121..eab8d75e5222 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -276,15 +276,16 @@ struct rt_cache_iter_state { int genid; }; -static struct rtable *rt_cache_get_first(struct rt_cache_iter_state *st) +static struct rtable *rt_cache_get_first(struct seq_file *seq) { + struct rt_cache_iter_state *st = seq->private; struct rtable *r = NULL; for (st->bucket = rt_hash_mask; st->bucket >= 0; --st->bucket) { rcu_read_lock_bh(); r = rcu_dereference(rt_hash_table[st->bucket].chain); while (r) { - if (dev_net(r->u.dst.dev) == st->p.net && + if (dev_net(r->u.dst.dev) == seq_file_net(seq) && r->rt_genid == st->genid) return r; r = rcu_dereference(r->u.dst.rt_next); @@ -294,9 +295,10 @@ static struct rtable *rt_cache_get_first(struct rt_cache_iter_state *st) return r; } -static struct rtable *__rt_cache_get_next(struct rt_cache_iter_state *st, +static struct rtable *__rt_cache_get_next(struct seq_file *seq, struct rtable *r) { + struct rt_cache_iter_state *st = seq->private; r = r->u.dst.rt_next; while (!r) { rcu_read_unlock_bh(); @@ -308,11 +310,12 @@ static struct rtable *__rt_cache_get_next(struct rt_cache_iter_state *st, return rcu_dereference(r); } -static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, +static struct rtable *rt_cache_get_next(struct seq_file *seq, struct rtable *r) { - while ((r = __rt_cache_get_next(st, r)) != NULL) { - if (dev_net(r->u.dst.dev) != st->p.net) + struct rt_cache_iter_state *st = seq->private; + while ((r = __rt_cache_get_next(seq, r)) != NULL) { + if (dev_net(r->u.dst.dev) != seq_file_net(seq)) continue; if (r->rt_genid == st->genid) break; @@ -320,12 +323,12 @@ static struct rtable *rt_cache_get_next(struct rt_cache_iter_state *st, return r; } -static struct rtable *rt_cache_get_idx(struct rt_cache_iter_state *st, loff_t pos) +static struct rtable *rt_cache_get_idx(struct seq_file *seq, loff_t pos) { - struct rtable *r = rt_cache_get_first(st); + struct rtable *r = rt_cache_get_first(seq); if (r) - while (pos && (r = rt_cache_get_next(st, r))) + while (pos && (r = rt_cache_get_next(seq, r))) --pos; return pos ? NULL : r; } @@ -333,9 +336,8 @@ static struct rtable *rt_cache_get_idx(struct rt_cache_iter_state *st, loff_t po static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos) { struct rt_cache_iter_state *st = seq->private; - if (*pos) - return rt_cache_get_idx(st, *pos - 1); + return rt_cache_get_idx(seq, *pos - 1); st->genid = atomic_read(&rt_genid); return SEQ_START_TOKEN; } @@ -343,12 +345,11 @@ static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos) static void *rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct rtable *r; - struct rt_cache_iter_state *st = seq->private; if (v == SEQ_START_TOKEN) - r = rt_cache_get_first(st); + r = rt_cache_get_first(seq); else - r = rt_cache_get_next(st, v); + r = rt_cache_get_next(seq, v); ++*pos; return r; } diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index f2c90f145cbb..ac5d4f4b6312 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2766,7 +2766,7 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq) { struct inet6_ifaddr *ifa = NULL; struct if6_iter_state *state = seq->private; - struct net *net = state->p.net; + struct net *net = seq_file_net(seq); for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { ifa = inet6_addr_lst[state->bucket]; @@ -2782,7 +2782,7 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq) static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifaddr *ifa) { struct if6_iter_state *state = seq->private; - struct net *net = state->p.net; + struct net *net = seq_file_net(seq); ifa = ifa->lst_next; try_again: diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 20a3d8e2f6c6..d810cff818cf 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -2355,7 +2355,7 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) { struct ifmcaddr6 *im = NULL; struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); - struct net *net = state->p.net; + struct net *net = seq_file_net(seq); state->idev = NULL; for_each_netdev(net, state->dev) { @@ -2486,7 +2486,7 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) struct ip6_sf_list *psf = NULL; struct ifmcaddr6 *im = NULL; struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); - struct net *net = state->p.net; + struct net *net = seq_file_net(seq); state->idev = NULL; state->im = NULL; diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index a6792089fcf9..0bd95680a494 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -727,7 +727,7 @@ struct xt_names_priv { static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos) { struct xt_names_priv *priv = seq->private; - struct net *net = priv->p.net; + struct net *net = seq_file_net(seq); int af = priv->af; mutex_lock(&xt[af].mutex); @@ -737,7 +737,7 @@ static void *xt_table_seq_start(struct seq_file *seq, loff_t *pos) static void *xt_table_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct xt_names_priv *priv = seq->private; - struct net *net = priv->p.net; + struct net *net = seq_file_net(seq); int af = priv->af; return seq_list_next(v, &net->xt.tables[af], pos); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 712a7bff8560..1d16d95dfaaf 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1758,7 +1758,7 @@ static struct sock *netlink_seq_socket_idx(struct seq_file *seq, loff_t pos) for (j = 0; j <= hash->mask; j++) { sk_for_each(s, node, &hash->table[j]) { - if (sock_net(s) != iter->p.net) + if (sock_net(s) != seq_file_net(seq)) continue; if (off == pos) { iter->link = i; @@ -1794,7 +1794,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) s = v; do { s = sk_next(s); - } while (s && (sock_net(s) != iter->p.net)); + } while (s && sock_net(s) != seq_file_net(seq)); if (s) return s; @@ -1806,7 +1806,7 @@ static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) for (; j <= hash->mask; j++) { s = sk_head(&hash->table[j]); - while (s && sock_net(s) != iter->p.net) + while (s && sock_net(s) != seq_file_net(seq)) s = sk_next(s); if (s) { iter->link = i; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index cb9d0cb5f270..4a4793051bcb 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2016,13 +2016,14 @@ struct unix_iter_state { struct seq_net_private p; int i; }; -static struct sock *unix_seq_idx(struct unix_iter_state *iter, loff_t pos) +static struct sock *unix_seq_idx(struct seq_file *seq, loff_t pos) { + struct unix_iter_state *iter = seq->private; loff_t off = 0; struct sock *s; for (s = first_unix_socket(&iter->i); s; s = next_unix_socket(&iter->i, s)) { - if (sock_net(s) != iter->p.net) + if (sock_net(s) != seq_file_net(seq)) continue; if (off == pos) return s; @@ -2035,9 +2036,8 @@ static struct sock *unix_seq_idx(struct unix_iter_state *iter, loff_t pos) static void *unix_seq_start(struct seq_file *seq, loff_t *pos) __acquires(unix_table_lock) { - struct unix_iter_state *iter = seq->private; spin_lock(&unix_table_lock); - return *pos ? unix_seq_idx(iter, *pos - 1) : ((void *) 1); + return *pos ? unix_seq_idx(seq, *pos - 1) : ((void *) 1); } static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) @@ -2050,7 +2050,7 @@ static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) sk = first_unix_socket(&iter->i); else sk = next_unix_socket(&iter->i, sk); - while (sk && (sock_net(sk) != iter->p.net)) + while (sk && (sock_net(sk) != seq_file_net(seq))) sk = next_unix_socket(&iter->i, sk); return sk; } -- cgit v1.2.3-59-g8ed1b From 57da52c1e62c6c13875e97de6c69d3156f8416da Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 26 Mar 2008 03:49:59 +0900 Subject: [NET] NETNS: Omit neigh_parms->net and pneigh_entry->net without CONFIG_NET_NS. Introduce neigh_parms/pneigh_entry inlines: neigh_parms_net(), pneigh_net(). Without CONFIG_NET_NS, no namespace other than &init_net exists. Let's explicitly define them to help compiler optimizations. Signed-off-by: YOSHIFUJI Hideaki --- include/net/neighbour.h | 25 +++++++++++++++++++++++++ net/core/neighbour.c | 26 ++++++++++++++++---------- 2 files changed, 41 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 062281872064..8bec0d69b270 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -38,7 +38,9 @@ struct neighbour; struct neigh_parms { +#ifdef CONFIG_NET_NS struct net *net; +#endif struct net_device *dev; struct neigh_parms *next; int (*neigh_setup)(struct neighbour *); @@ -131,7 +133,9 @@ struct neigh_ops struct pneigh_entry { struct pneigh_entry *next; +#ifdef CONFIG_NET_NS struct net *net; +#endif struct net_device *dev; u8 flags; u8 key[0]; @@ -213,6 +217,17 @@ extern struct neighbour *neigh_event_ns(struct neigh_table *tbl, extern struct neigh_parms *neigh_parms_alloc(struct net_device *dev, struct neigh_table *tbl); extern void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms); + +static inline +struct net *neigh_parms_net(const struct neigh_parms *parms) +{ +#ifdef CONFIG_NET_NS + return parms->net; +#else + return &init_net; +#endif +} + extern unsigned long neigh_rand_reach_time(unsigned long base); extern void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, @@ -220,6 +235,16 @@ extern void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, extern struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, struct net *net, const void *key, struct net_device *dev, int creat); extern int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *key, struct net_device *dev); +static inline +struct net *pneigh_net(const struct pneigh_entry *pneigh) +{ +#ifdef CONFIG_NET_NS + return pneigh->net; +#else + return &init_net; +#endif +} + extern void neigh_app_ns(struct neighbour *n); extern void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie); extern void __neigh_for_each_release(struct neigh_table *tbl, int (*cb)(struct neighbour *)); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index b8d491fb4b42..de654ea8a944 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -483,7 +483,7 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, for (n = tbl->phash_buckets[hash_val]; n; n = n->next) { if (!memcmp(n->key, pkey, key_len) && - (n->net == net) && + (pneigh_net(n) == net) && (n->dev == dev || !n->dev)) { read_unlock_bh(&tbl->lock); goto out; @@ -500,7 +500,9 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, if (!n) goto out; +#ifdef CONFIG_NET_NS n->net = hold_net(net); +#endif memcpy(n->key, pkey, key_len); n->dev = dev; if (dev) @@ -540,14 +542,14 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey, for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL; np = &n->next) { if (!memcmp(n->key, pkey, key_len) && n->dev == dev && - (n->net == net)) { + (pneigh_net(n) == net)) { *np = n->next; write_unlock_bh(&tbl->lock); if (tbl->pdestructor) tbl->pdestructor(n); if (n->dev) dev_put(n->dev); - release_net(n->net); + release_net(pneigh_net(n)); kfree(n); return 0; } @@ -570,7 +572,7 @@ static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev) tbl->pdestructor(n); if (n->dev) dev_put(n->dev); - release_net(n->net); + release_net(pneigh_net(n)); kfree(n); continue; } @@ -1284,7 +1286,7 @@ static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, struct neigh_parms *p; for (p = &tbl->parms; p; p = p->next) { - if ((p->dev && p->dev->ifindex == ifindex && p->net == net) || + if ((p->dev && p->dev->ifindex == ifindex && neigh_parms_net(p) == net) || (!p->dev && !ifindex)) return p; } @@ -1318,7 +1320,9 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, dev_hold(dev); p->dev = dev; +#ifdef CONFIG_NET_NS p->net = hold_net(net); +#endif p->sysctl_table = NULL; write_lock_bh(&tbl->lock); p->next = tbl->parms.next; @@ -1360,7 +1364,7 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) static void neigh_parms_destroy(struct neigh_parms *parms) { - release_net(parms->net); + release_net(neigh_parms_net(parms)); kfree(parms); } @@ -1371,7 +1375,9 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl) unsigned long now = jiffies; unsigned long phsize; +#ifdef CONFIG_NET_NS tbl->parms.net = &init_net; +#endif atomic_set(&tbl->parms.refcnt, 1); INIT_RCU_HEAD(&tbl->parms.rcu_head); tbl->parms.reachable_time = @@ -1958,7 +1964,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) break; for (nidx = 0, p = tbl->parms.next; p; p = p->next) { - if (net != p->net) + if (net != neigh_parms_net(p)) continue; if (nidx++ < neigh_skip) @@ -2254,7 +2260,7 @@ static struct pneigh_entry *pneigh_get_first(struct seq_file *seq) state->flags |= NEIGH_SEQ_IS_PNEIGH; for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) { pn = tbl->phash_buckets[bucket]; - while (pn && (pn->net != net)) + while (pn && (pneigh_net(pn) != net)) pn = pn->next; if (pn) break; @@ -2277,7 +2283,7 @@ static struct pneigh_entry *pneigh_get_next(struct seq_file *seq, if (++state->bucket > PNEIGH_HASHMASK) break; pn = tbl->phash_buckets[state->bucket]; - while (pn && (pn->net != net)) + while (pn && (pneigh_net(pn) != net)) pn = pn->next; if (pn) break; @@ -2740,7 +2746,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, neigh_path[NEIGH_CTL_PATH_PROTO].ctl_name = p_id; t->sysctl_header = - register_net_sysctl_table(p->net, neigh_path, t->neigh_vars); + register_net_sysctl_table(neigh_parms_net(p), neigh_path, t->neigh_vars); if (!t->sysctl_header) goto free_procname; -- cgit v1.2.3-59-g8ed1b From 878628fbf2589eb24357e42027d5f54b1dafd3c8 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Wed, 26 Mar 2008 03:57:35 +0900 Subject: [NET] NETNS: Omit namespace comparision without CONFIG_NET_NS. Introduce an inline net_eq() to compare two namespaces. Without CONFIG_NET_NS, since no namespace other than &init_net exists, it is always 1. We do not need to convert 1) inline vs inline and 2) inline vs &init_net comparisons. Signed-off-by: YOSHIFUJI Hideaki --- include/net/net_namespace.h | 12 ++++++++++++ net/core/dev.c | 2 +- net/core/neighbour.c | 18 +++++++++--------- net/ipv4/inet_hashtables.c | 4 ++-- net/ipv4/raw.c | 2 +- net/ipv4/route.c | 10 +++++----- net/ipv4/tcp_ipv4.c | 12 ++++++------ net/ipv4/udp.c | 10 +++++----- net/ipv6/addrconf.c | 12 ++++++------ net/ipv6/inet6_hashtables.c | 2 +- net/ipv6/raw.c | 2 +- net/ipv6/udp.c | 2 +- net/netlink/af_netlink.c | 8 ++++---- net/unix/af_unix.c | 4 ++-- 14 files changed, 56 insertions(+), 44 deletions(-) (limited to 'net') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 923f2b8b9096..f8f3d1a5fc35 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -118,6 +118,12 @@ static inline void release_net(struct net *net) { atomic_dec(&net->use_count); } + +static inline +int net_eq(const struct net *net1, const struct net *net2) +{ + return net1 == net2; +} #else static inline struct net *get_net(struct net *net) { @@ -141,6 +147,12 @@ static inline struct net *maybe_get_net(struct net *net) { return net; } + +static inline +int net_eq(const struct net *net1, const struct net *net2) +{ + return 1; +} #endif #define for_each_net(VAR) \ diff --git a/net/core/dev.c b/net/core/dev.c index 812534828914..75c3f7f4edd5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4136,7 +4136,7 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* Get out if there is nothing todo */ err = 0; - if (dev_net(dev) == net) + if (net_eq(dev_net(dev), net)) goto out; /* Pick the destination device name, and ensure diff --git a/net/core/neighbour.c b/net/core/neighbour.c index de654ea8a944..857915a12c15 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -388,7 +388,7 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net, hash_val = tbl->hash(pkey, NULL); for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) { if (!memcmp(n->primary_key, pkey, key_len) && - dev_net(n->dev) == net) { + net_eq(dev_net(n->dev), net)) { neigh_hold(n); NEIGH_CACHE_STAT_INC(tbl, hits); break; @@ -483,7 +483,7 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, for (n = tbl->phash_buckets[hash_val]; n; n = n->next) { if (!memcmp(n->key, pkey, key_len) && - (pneigh_net(n) == net) && + net_eq(pneigh_net(n), net) && (n->dev == dev || !n->dev)) { read_unlock_bh(&tbl->lock); goto out; @@ -542,7 +542,7 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey, for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL; np = &n->next) { if (!memcmp(n->key, pkey, key_len) && n->dev == dev && - (pneigh_net(n) == net)) { + net_eq(pneigh_net(n), net)) { *np = n->next; write_unlock_bh(&tbl->lock); if (tbl->pdestructor) @@ -1286,7 +1286,7 @@ static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, struct neigh_parms *p; for (p = &tbl->parms; p; p = p->next) { - if ((p->dev && p->dev->ifindex == ifindex && neigh_parms_net(p) == net) || + if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) || (!p->dev && !ifindex)) return p; } @@ -1964,7 +1964,7 @@ static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) break; for (nidx = 0, p = tbl->parms.next; p; p = p->next) { - if (net != neigh_parms_net(p)) + if (!net_eq(neigh_parms_net(p), net)) continue; if (nidx++ < neigh_skip) @@ -2161,7 +2161,7 @@ static struct neighbour *neigh_get_first(struct seq_file *seq) n = tbl->hash_buckets[bucket]; while (n) { - if (dev_net(n->dev) != net) + if (!net_eq(dev_net(n->dev), net)) goto next; if (state->neigh_sub_iter) { loff_t fakep = 0; @@ -2204,7 +2204,7 @@ static struct neighbour *neigh_get_next(struct seq_file *seq, while (1) { while (n) { - if (dev_net(n->dev) != net) + if (!net_eq(dev_net(n->dev), net)) goto next; if (state->neigh_sub_iter) { void *v = state->neigh_sub_iter(state, n, pos); @@ -2260,7 +2260,7 @@ static struct pneigh_entry *pneigh_get_first(struct seq_file *seq) state->flags |= NEIGH_SEQ_IS_PNEIGH; for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) { pn = tbl->phash_buckets[bucket]; - while (pn && (pneigh_net(pn) != net)) + while (pn && !net_eq(pneigh_net(pn), net)) pn = pn->next; if (pn) break; @@ -2283,7 +2283,7 @@ static struct pneigh_entry *pneigh_get_next(struct seq_file *seq, if (++state->bucket > PNEIGH_HASHMASK) break; pn = tbl->phash_buckets[state->bucket]; - while (pn && (pneigh_net(pn) != net)) + while (pn && !net_eq(pneigh_net(pn), net)) pn = pn->next; if (pn) break; diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 1064111e5b96..1b6ff513c75d 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -139,7 +139,7 @@ static struct sock *inet_lookup_listener_slow(struct net *net, sk_for_each(sk, node, head) { const struct inet_sock *inet = inet_sk(sk); - if (sock_net(sk) == net && inet->num == hnum && + if (net_eq(sock_net(sk), net) && inet->num == hnum && !ipv6_only_sock(sk)) { const __be32 rcv_saddr = inet->rcv_saddr; int score = sk->sk_family == PF_INET ? 1 : 0; @@ -182,7 +182,7 @@ struct sock *__inet_lookup_listener(struct net *net, if (inet->num == hnum && !sk->sk_node.next && (!inet->rcv_saddr || inet->rcv_saddr == daddr) && (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) && - !sk->sk_bound_dev_if && sock_net(sk) == net) + !sk->sk_bound_dev_if && net_eq(sock_net(sk), net)) goto sherry_cache; sk = inet_lookup_listener_slow(net, head, daddr, hnum, dif); } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 25dc8b38cac3..d965f0a39c84 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -117,7 +117,7 @@ static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, sk_for_each_from(sk, node) { struct inet_sock *inet = inet_sk(sk); - if (sock_net(sk) == net && inet->num == num && + if (net_eq(sock_net(sk), net) && inet->num == num && !(inet->daddr && inet->daddr != raddr) && !(inet->rcv_saddr && inet->rcv_saddr != laddr) && !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index eab8d75e5222..230716c2dfe0 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1196,7 +1196,7 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, rth->fl.oif != ikeys[k] || rth->fl.iif != 0 || rth->rt_genid != atomic_read(&rt_genid) || - dev_net(rth->u.dst.dev) != net) { + !net_eq(dev_net(rth->u.dst.dev), net)) { rthp = &rth->u.dst.rt_next; continue; } @@ -1455,7 +1455,7 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, rth->rt_src == iph->saddr && rth->fl.iif == 0 && !(dst_metric_locked(&rth->u.dst, RTAX_MTU)) && - dev_net(rth->u.dst.dev) == net && + net_eq(dev_net(rth->u.dst.dev), net) && rth->rt_genid == atomic_read(&rt_genid)) { unsigned short mtu = new_mtu; @@ -2085,7 +2085,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->fl.oif == 0 && rth->fl.mark == skb->mark && rth->fl.fl4_tos == tos && - dev_net(rth->u.dst.dev) == net && + net_eq(dev_net(rth->u.dst.dev), net) && rth->rt_genid == atomic_read(&rt_genid)) { dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(in_hit); @@ -2487,7 +2487,7 @@ int __ip_route_output_key(struct net *net, struct rtable **rp, rth->fl.mark == flp->mark && !((rth->fl.fl4_tos ^ flp->fl4_tos) & (IPTOS_RT_MASK | RTO_ONLINK)) && - dev_net(rth->u.dst.dev) == net && + net_eq(dev_net(rth->u.dst.dev), net) && rth->rt_genid == atomic_read(&rt_genid)) { dst_use(&rth->u.dst, jiffies); RT_CACHE_STAT_INC(out_hit); @@ -2796,7 +2796,7 @@ int ip_rt_dump(struct sk_buff *skb, struct netlink_callback *cb) rcu_read_lock_bh(); for (rt = rcu_dereference(rt_hash_table[h].chain), idx = 0; rt; rt = rcu_dereference(rt->u.dst.rt_next), idx++) { - if (dev_net(rt->u.dst.dev) != net || idx < s_idx) + if (!net_eq(dev_net(rt->u.dst.dev), net) || idx < s_idx) continue; if (rt->rt_genid != atomic_read(&rt_genid)) continue; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 46847e600a46..2a5881c81778 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1974,7 +1974,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) while (1) { while (req) { if (req->rsk_ops->family == st->family && - sock_net(req->sk) == net) { + net_eq(sock_net(req->sk), net)) { cur = req; goto out; } @@ -1998,7 +1998,7 @@ get_req: } get_sk: sk_for_each_from(sk, node) { - if (sk->sk_family == st->family && sock_net(sk) == net) { + if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) { cur = sk; goto out; } @@ -2049,7 +2049,7 @@ static void *established_get_first(struct seq_file *seq) read_lock_bh(lock); sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) { if (sk->sk_family != st->family || - sock_net(sk) != net) { + !net_eq(sock_net(sk), net)) { continue; } rc = sk; @@ -2059,7 +2059,7 @@ static void *established_get_first(struct seq_file *seq) inet_twsk_for_each(tw, node, &tcp_hashinfo.ehash[st->bucket].twchain) { if (tw->tw_family != st->family || - twsk_net(tw) != net) { + !net_eq(twsk_net(tw), net)) { continue; } rc = tw; @@ -2086,7 +2086,7 @@ static void *established_get_next(struct seq_file *seq, void *cur) tw = cur; tw = tw_next(tw); get_tw: - while (tw && (tw->tw_family != st->family || twsk_net(tw) != net)) { + while (tw && (tw->tw_family != st->family || !net_eq(twsk_net(tw), net))) { tw = tw_next(tw); } if (tw) { @@ -2107,7 +2107,7 @@ get_tw: sk = sk_next(sk); sk_for_each_from(sk, node) { - if (sk->sk_family == st->family && sock_net(sk) == net) + if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) goto found; } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 76d52d37d6ac..80007c79f12f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -137,7 +137,7 @@ static inline int __udp_lib_lport_inuse(struct net *net, __u16 num, struct hlist_node *node; sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)]) - if (sock_net(sk) == net && sk->sk_hash == num) + if (net_eq(sock_net(sk), net) && sk->sk_hash == num) return 1; return 0; } @@ -218,7 +218,7 @@ gotit: sk_for_each(sk2, node, head) if (sk2->sk_hash == snum && sk2 != sk && - sock_net(sk2) == net && + net_eq(sock_net(sk2), net) && (!sk2->sk_reuse || !sk->sk_reuse) && (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && @@ -269,7 +269,7 @@ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { struct inet_sock *inet = inet_sk(sk); - if (sock_net(sk) == net && sk->sk_hash == hnum && + if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && !ipv6_only_sock(sk)) { int score = (sk->sk_family == PF_INET ? 1 : 0); if (inet->rcv_saddr) { @@ -1511,7 +1511,7 @@ static struct sock *udp_get_first(struct seq_file *seq) for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { struct hlist_node *node; sk_for_each(sk, node, state->hashtable + state->bucket) { - if (sock_net(sk) != net) + if (!net_eq(sock_net(sk), net)) continue; if (sk->sk_family == state->family) goto found; @@ -1531,7 +1531,7 @@ static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) sk = sk_next(sk); try_again: ; - } while (sk && (sock_net(sk) != net || sk->sk_family != state->family)); + } while (sk && (!net_eq(sock_net(sk), net) || sk->sk_family != state->family)); if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { sk = sk_head(state->hashtable + state->bucket); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ac5d4f4b6312..5ab9973571ef 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1217,7 +1217,7 @@ int ipv6_chk_addr(struct net *net, struct in6_addr *addr, read_lock_bh(&addrconf_hash_lock); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { - if (dev_net(ifp->idev->dev) != net) + if (!net_eq(dev_net(ifp->idev->dev), net)) continue; if (ipv6_addr_equal(&ifp->addr, addr) && !(ifp->flags&IFA_F_TENTATIVE)) { @@ -1239,7 +1239,7 @@ int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, u8 hash = ipv6_addr_hash(addr); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { - if (dev_net(ifp->idev->dev) != net) + if (!net_eq(dev_net(ifp->idev->dev), net)) continue; if (ipv6_addr_equal(&ifp->addr, addr)) { if (dev == NULL || ifp->idev->dev == dev) @@ -1257,7 +1257,7 @@ struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, struct in6_addr *addr, read_lock_bh(&addrconf_hash_lock); for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { - if (dev_net(ifp->idev->dev) != net) + if (!net_eq(dev_net(ifp->idev->dev), net)) continue; if (ipv6_addr_equal(&ifp->addr, addr)) { if (dev == NULL || ifp->idev->dev == dev || @@ -2771,7 +2771,7 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq) for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { ifa = inet6_addr_lst[state->bucket]; - while (ifa && dev_net(ifa->idev->dev) != net) + while (ifa && !net_eq(dev_net(ifa->idev->dev), net)) ifa = ifa->lst_next; if (ifa) break; @@ -2787,7 +2787,7 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifad ifa = ifa->lst_next; try_again: if (ifa) { - if (dev_net(ifa->idev->dev) != net) { + if (!net_eq(dev_net(ifa->idev->dev), net)) { ifa = ifa->lst_next; goto try_again; } @@ -2905,7 +2905,7 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) u8 hash = ipv6_addr_hash(addr); read_lock_bh(&addrconf_hash_lock); for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) { - if (dev_net(ifp->idev->dev) != net) + if (!net_eq(dev_net(ifp->idev->dev), net)) continue; if (ipv6_addr_cmp(&ifp->addr, addr) == 0 && (ifp->flags & IFA_F_HOMEADDRESS)) { diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 21c467675412..340c7d42b83a 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -105,7 +105,7 @@ struct sock *inet6_lookup_listener(struct net *net, read_lock(&hashinfo->lhash_lock); sk_for_each(sk, node, &hashinfo->listening_hash[inet_lhashfn(hnum)]) { - if (sock_net(sk) == net && inet_sk(sk)->num == hnum && + if (net_eq(sock_net(sk), net) && inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) { const struct ipv6_pinfo *np = inet6_sk(sk); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 12c7a1560977..830da4603697 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -76,7 +76,7 @@ static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, if (inet_sk(sk)->num == num) { struct ipv6_pinfo *np = inet6_sk(sk); - if (sock_net(sk) != net) + if (!net_eq(sock_net(sk), net)) continue; if (!ipv6_addr_any(&np->daddr) && diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index db266ff297e5..aacbc82ecf0f 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -70,7 +70,7 @@ static struct sock *__udp6_lib_lookup(struct net *net, sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { struct inet_sock *inet = inet_sk(sk); - if (sock_net(sk) == net && sk->sk_hash == hnum && + if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && sk->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); int score = 0; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 1d16d95dfaaf..36f75d873898 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -228,7 +228,7 @@ static inline struct sock *netlink_lookup(struct net *net, int protocol, read_lock(&nl_table_lock); head = nl_pid_hashfn(hash, pid); sk_for_each(sk, node, head) { - if (sock_net(sk) == net && (nlk_sk(sk)->pid == pid)) { + if (net_eq(sock_net(sk), net) && (nlk_sk(sk)->pid == pid)) { sock_hold(sk); goto found; } @@ -348,7 +348,7 @@ static int netlink_insert(struct sock *sk, struct net *net, u32 pid) head = nl_pid_hashfn(hash, pid); len = 0; sk_for_each(osk, node, head) { - if (sock_net(osk) == net && (nlk_sk(osk)->pid == pid)) + if (net_eq(sock_net(osk), net) && (nlk_sk(osk)->pid == pid)) break; len++; } @@ -532,7 +532,7 @@ retry: netlink_table_grab(); head = nl_pid_hashfn(hash, pid); sk_for_each(osk, node, head) { - if (sock_net(osk) != net) + if (!net_eq(sock_net(osk), net)) continue; if (nlk_sk(osk)->pid == pid) { /* Bind collision, search negative pid values. */ @@ -962,7 +962,7 @@ static inline int do_one_broadcast(struct sock *sk, !test_bit(p->group - 1, nlk->groups)) goto out; - if (sock_net(sk) != p->net) + if (!net_eq(sock_net(sk), p->net)) goto out; if (p->failure) { diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 4a4793051bcb..50bbf6bb1a22 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -252,7 +252,7 @@ static struct sock *__unix_find_socket_byname(struct net *net, sk_for_each(s, node, &unix_socket_table[hash ^ type]) { struct unix_sock *u = unix_sk(s); - if (sock_net(s) != net) + if (!net_eq(sock_net(s), net)) continue; if (u->addr->len == len && @@ -289,7 +289,7 @@ static struct sock *unix_find_socket_byinode(struct net *net, struct inode *i) &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) { struct dentry *dentry = unix_sk(s)->dentry; - if (sock_net(s) != net) + if (!net_eq(sock_net(s), net)) continue; if(dentry && dentry->d_inode == i) -- cgit v1.2.3-59-g8ed1b From 5d2cdcd4e85c5187db30a6b29f79fbbe59f39f78 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 20 Mar 2008 15:06:41 +0200 Subject: mac80211: get a TKIP phase key from skb This patch makes mac80211 able to compute a TKIP key from an skb. The requested key can be a phase 1 or a phase 2 key. This is useful for drivers who need to provide tkip key to their HW to enable HW encryption. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- include/net/mac80211.h | 30 ++++++++++++++++++++++++++++ net/mac80211/tkip.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5ab6a350ee6d..2a134582fc16 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -643,6 +643,21 @@ enum sta_notify_cmd { STA_NOTIFY_ADD, STA_NOTIFY_REMOVE }; +/** + * enum ieee80211_tkip_key_type - get tkip key + * + * Used by drivers which need to get a tkip key for skb. Some drivers need a + * phase 1 key, others need a phase 2 key. A single function allows the driver + * to get the key, this enum indicates what type of key is required. + * + * @IEEE80211_TKIP_P1_KEY: the driver needs a phase 1 key + * @IEEE80211_TKIP_P2_KEY: the driver needs a phase 2 key + */ +enum ieee80211_tkip_key_type { + IEEE80211_TKIP_P1_KEY, + IEEE80211_TKIP_P2_KEY, +}; + /** * enum ieee80211_hw_flags - hardware flags * @@ -1471,6 +1486,21 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb); */ int ieee80211_get_hdrlen(u16 fc); +/** + * ieee80211_get_tkip_key - get a TKIP rc4 for skb + * + * This function computes a TKIP rc4 key for an skb. It computes + * a phase 1 key if needed (iv16 wraps around). This function is to + * be used by drivers which can do HW encryption but need to compute + * to phase 1/2 key in SW. + * + * @keyconf: the parameter passed with the set key + * @skb: the skb for which the key is needed + * @rc4key: a buffer to which the key will be written + */ +void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, + struct sk_buff *skb, + enum ieee80211_tkip_key_type type, u8 *key); /** * ieee80211_wake_queue - wake specific queue * @hw: pointer as obtained from ieee80211_alloc_hw(). diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 3abe194e4d55..5c36b2df3faf 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -214,6 +214,59 @@ void ieee80211_tkip_gen_rc4key(struct ieee80211_key *key, u8 *ta, key->u.tkip.iv16, rc4key); } +void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, + struct sk_buff *skb, enum ieee80211_tkip_key_type type, + u8 *outkey) +{ + struct ieee80211_key *key = (struct ieee80211_key *) + container_of(keyconf, struct ieee80211_key, conf); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u8 *data = (u8 *) hdr; + u16 fc = le16_to_cpu(hdr->frame_control); + int hdr_len = ieee80211_get_hdrlen(fc); + u8 *ta = hdr->addr2; + u16 iv16; + u32 iv32; + + iv16 = data[hdr_len] << 8; + iv16 += data[hdr_len + 2]; + iv32 = data[hdr_len + 4] + + (data[hdr_len + 5] >> 8) + + (data[hdr_len + 6] >> 16) + + (data[hdr_len + 7] >> 24); + +#ifdef CONFIG_TKIP_DEBUG + printk(KERN_DEBUG "TKIP encrypt: iv16 = 0x%04x, iv32 = 0x%08x\n", + iv16, iv32); + + if (iv32 != key->u.tkip.iv32) { + printk(KERN_DEBUG "skb: iv32 = 0x%08x key: iv32 = 0x%08x\n", + iv32, key->u.tkip.iv32); + printk(KERN_DEBUG "Wrap around of iv16 in the middle of a " + "fragmented packet\n"); + } +#endif /* CONFIG_TKIP_DEBUG */ + + /* Update the p1k only when the iv16 in the packet wraps around, this + * might occur after the wrap around of iv16 in the key in case of + * fragmented packets. */ + if (iv16 == 0 || !key->u.tkip.tx_initialized) { + /* IV16 wrapped around - perform TKIP phase 1 */ + tkip_mixing_phase1(ta, &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], + iv32, key->u.tkip.p1k); + key->u.tkip.tx_initialized = 1; + } + + if (type == IEEE80211_TKIP_P1_KEY) { + memcpy(outkey, key->u.tkip.p1k, sizeof(u16) * 5); + return; + } + + tkip_mixing_phase2(key->u.tkip.p1k, + &key->conf.key[ALG_TKIP_TEMP_ENCR_KEY], iv16, outkey); +} +EXPORT_SYMBOL(ieee80211_get_tkip_key); + /* Encrypt packet payload with TKIP using @key. @pos is a pointer to the * beginning of the buffer containing payload. This payload must include * headroom of eight octets for IV and Ext. IV and taildroom of four octets -- cgit v1.2.3-59-g8ed1b From 9ae4fda332df616ef47d5bb710c39681641d4303 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 20 Mar 2008 15:06:42 +0200 Subject: mac80211: allows driver to request a Phase 1 RX key This patch makes mac80211 able to send a phase1 key for TKIP decryption. This is needed for drivers that don't do the rekeying by themselves (i.e. iwlwifi). Upon IV16 wrap around, the packet is decrypted in SW, if decryption is ok, mac80211 calls to update_tkip_key with a new phase 1 RX key. Signed-off-by: Emmanuel Grumbach Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- include/net/mac80211.h | 17 +++++++++++++++++ net/mac80211/tkip.c | 15 ++++++++++++++- net/mac80211/tkip.h | 2 +- net/mac80211/wpa.c | 2 +- 4 files changed, 33 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 2a134582fc16..48428a6b9109 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -827,6 +827,16 @@ static inline void SET_IEEE80211_PERM_ADDR(struct ieee80211_hw *hw, u8 *addr) * parameter is guaranteed to be valid until another call to set_key() * removes it, but it can only be used as a cookie to differentiate * keys. + * + * In TKIP some HW need to be provided a phase 1 key, for RX decryption + * acceleration (i.e. iwlwifi). Those drivers should provide update_tkip_key + * handler. + * The update_tkip_key() call updates the driver with the new phase 1 key. + * This happens everytime the iv16 wraps around (every 65536 packets). The + * set_key() call will happen only once for each key (unless the AP did + * rekeying), it will not include a valid phase 1 key. The valid phase 1 key is + * provided by udpate_tkip_key only. The trigger that makes mac80211 call this + * handler is software decryption with wrap around of iv16. */ /** @@ -1003,6 +1013,10 @@ enum ieee80211_ampdu_mlme_action { * and remove_interface calls, i.e. while the interface with the * given local_address is enabled. * + * @update_tkip_key: See the section "Hardware crypto acceleration" + * This callback will be called in the context of Rx. Called for drivers + * which set IEEE80211_KEY_FLAG_TKIP_REQ_RX_P1_KEY. + * * @hw_scan: Ask the hardware to service the scan request, no need to start * the scan state machine in stack. The scan must honour the channel * configuration done by the regulatory agent in the wiphy's registered @@ -1094,6 +1108,9 @@ struct ieee80211_ops { int (*set_key)(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_address, const u8 *address, struct ieee80211_key_conf *key); + void (*update_tkip_key)(struct ieee80211_hw *hw, + struct ieee80211_key_conf *conf, const u8 *address, + u32 iv32, u16 *phase1key); int (*hw_scan)(struct ieee80211_hw *hw, u8 *ssid, size_t len); int (*get_stats)(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats); diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 5c36b2df3faf..45d59f19c29f 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -291,7 +291,7 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, struct ieee80211_key *key, u8 *payload, size_t payload_len, u8 *ta, - int only_iv, int queue, + u8 *ra, int only_iv, int queue, u32 *out_iv32, u16 *out_iv16) { u32 iv32; @@ -368,6 +368,19 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, printk("\n"); } #endif /* CONFIG_TKIP_DEBUG */ + if (key->local->ops->update_tkip_key && + key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { + u8 bcast[ETH_ALEN] = + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + u8 *sta_addr = key->sta->addr; + + if (is_multicast_ether_addr(ra)) + sta_addr = bcast; + + key->local->ops->update_tkip_key( + local_to_hw(key->local), &key->conf, + sta_addr, iv32, key->u.tkip.p1k_rx[queue]); + } } tkip_mixing_phase2(key->u.tkip.p1k_rx[queue], diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h index 73d8ef2a93b0..ffaee3253e19 100644 --- a/net/mac80211/tkip.h +++ b/net/mac80211/tkip.h @@ -31,7 +31,7 @@ enum { int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, struct ieee80211_key *key, u8 *payload, size_t payload_len, u8 *ta, - int only_iv, int queue, + u8 *ra, int only_iv, int queue, u32 *out_iv32, u16 *out_iv16); #endif /* TKIP_H */ diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index df0b7341efc8..45709ada8fee 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -312,7 +312,7 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) res = ieee80211_tkip_decrypt_data(rx->local->wep_rx_tfm, key, skb->data + hdrlen, skb->len - hdrlen, rx->sta->addr, - hwaccel, rx->queue, + hdr->addr1, hwaccel, rx->queue, &rx->tkip_iv32, &rx->tkip_iv16); if (res != TKIP_DECRYPT_OK || wpa_test) { -- cgit v1.2.3-59-g8ed1b From 906c730a2db950b7bce4ef17d65399acd791c360 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 16 Mar 2008 18:34:33 +0100 Subject: wireless: add wiphy channel freq to channel struct lookup helper Add ieee80211_get_channel() which gets you a channel struct for a specific wiphy if that channel is present in that wiphy. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/wireless.h | 6 ++++++ net/wireless/util.c | 23 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) (limited to 'net') diff --git a/include/net/wireless.h b/include/net/wireless.h index c7f805ee5545..f4b77ab66bae 100644 --- a/include/net/wireless.h +++ b/include/net/wireless.h @@ -304,4 +304,10 @@ extern int ieee80211_channel_to_frequency(int chan); */ extern int ieee80211_frequency_to_channel(int freq); +/** + * ieee80211_get_channel - get channel struct from wiphy for specified frequency + */ +extern struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, + int freq); + #endif /* __NET_WIRELESS_H */ diff --git a/net/wireless/util.c b/net/wireless/util.c index 77336c22fcf2..f3e623df3515 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -33,6 +33,29 @@ int ieee80211_frequency_to_channel(int freq) } EXPORT_SYMBOL(ieee80211_frequency_to_channel); +struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, + int freq) +{ + enum ieee80211_band band; + struct ieee80211_supported_band *sband; + int i; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + + if (!sband) + continue; + + for (i = 0; i < sband->n_channels; i++) { + if (sband->channels[i].center_freq == freq) + return &sband->channels[i]; + } + } + + return NULL; +} +EXPORT_SYMBOL(ieee80211_get_channel); + static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, enum ieee80211_band band) { -- cgit v1.2.3-59-g8ed1b From e048c6e4fdac9be0dbcb7e0c5d518737c867ef09 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 16 Mar 2008 18:35:56 +0100 Subject: mac80211: use ieee80211_get_channel Use the new ieee80211_get_channel() function instead of open-coding it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_ioctl.c | 29 ++++------------------------- 1 file changed, 4 insertions(+), 25 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 1d91575a0fe9..8e8e5a19d893 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -279,35 +279,14 @@ static int ieee80211_ioctl_giwmode(struct net_device *dev, int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz) { - int set = 0; int ret = -EINVAL; - enum ieee80211_band band; - struct ieee80211_supported_band *sband; - int i; - - for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { - sband = local->hw.wiphy->bands[band]; + struct ieee80211_channel *chan; - if (!sband) - continue; + chan = ieee80211_get_channel(local->hw.wiphy, freqMHz); - for (i = 0; i < sband->n_channels; i++) { - struct ieee80211_channel *chan = &sband->channels[i]; - - if (chan->flags & IEEE80211_CHAN_DISABLED) - continue; - - if (chan->center_freq == freqMHz) { - set = 1; - local->oper_channel = chan; - break; - } - } - if (set) - break; - } + if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { + local->oper_channel = chan; - if (set) { if (local->sta_sw_scanning) ret = 0; else -- cgit v1.2.3-59-g8ed1b From fab7d4a2b1d8ce47b69a133f6f9a203b0f12636e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 16 Mar 2008 18:42:44 +0100 Subject: mac80211: filter scan results on unusable channels When you have an AP on channel 13, it will currently often enough be listed in scan results even when the regulatory domain restricts to channels 1-11. This is due to channel overlap. To avoid getting very strange failures, don't show such APs in the scan results. The failure mode will now go from "I can see the AP but not associate" to "I can't see the AP although I know it's there" which is easier to debug. This problem was first really noticed by Jes Sorensen. Signed-off-by: Johannes Berg Cc: Jes Sorensen Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 8b991ebcbb4e..86da69f44384 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2356,6 +2356,7 @@ static void ieee80211_rx_bss_info(struct net_device *dev, struct sta_info *sta; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); u64 beacon_timestamp, rx_timestamp; + struct ieee80211_channel *channel; DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac2); @@ -2420,6 +2421,11 @@ static void ieee80211_rx_bss_info(struct net_device *dev, else freq = rx_status->freq; + channel = ieee80211_get_channel(local->hw.wiphy, freq); + + if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) + return; + #ifdef CONFIG_MAC80211_MESH if (elems.mesh_config) bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id, -- cgit v1.2.3-59-g8ed1b From 2e354ed7bec8a6fc9ecc71e908555af708583c30 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Tue, 18 Mar 2008 15:00:30 -0700 Subject: mac80211: fixing delba debug print This patch fixes a wrong debug print when receiving delba Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 86da69f44384..28703d1e8362 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1427,7 +1427,7 @@ static void ieee80211_sta_process_delba(struct net_device *dev, if (net_ratelimit()) printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n", print_mac(mac, mgmt->sa), - initiator ? "recipient" : "initiator", tid, + initiator ? "initiator" : "recipient", tid, mgmt->u.action.u.delba.reason_code); #endif /* CONFIG_MAC80211_HT_DEBUG */ -- cgit v1.2.3-59-g8ed1b From 7b9d44cd6b393cb1032ce201307ae87e5677bfa7 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Tue, 18 Mar 2008 15:00:31 -0700 Subject: mac80211: fixing debug prints for AddBA request This patch also fixes the Rx timer's comments Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 28703d1e8362..9beedb655896 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1145,7 +1145,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, status = WLAN_STATUS_INVALID_QOS_PARAM; #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) - printk(KERN_DEBUG "Block Ack Req with bad params from " + printk(KERN_DEBUG "AddBA Req with bad params from " "%s on tid %u. policy %d, buffer size %d\n", print_mac(mac, mgmt->sa), tid, ba_policy, buf_size); @@ -1169,7 +1169,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, if (tid_agg_rx->state != HT_AGG_STATE_IDLE) { #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) - printk(KERN_DEBUG "unexpected Block Ack Req from " + printk(KERN_DEBUG "unexpected AddBA Req from " "%s on tid %u\n", print_mac(mac, mgmt->sa), tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ @@ -1497,8 +1497,8 @@ timer_expired_exit: } /* - * After receiving Block Ack Request (BAR) we activated a - * timer after each frame arrives from the originator. + * After accepting the AddBA Request we activated a timer, + * resetting it after each frame that arrives from the originator. * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. */ void sta_rx_agg_session_timer_expired(unsigned long data) -- cgit v1.2.3-59-g8ed1b From 85249e5fab13edb89258fa6d551cd4a3a4f0d569 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Tue, 18 Mar 2008 15:00:32 -0700 Subject: mac80211: tear down of block ack sessions This patch adds a clean tear down for all block ack sessions if interface goes down or if a deauthentication is done. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 7 +------ net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/ieee80211_sta.c | 15 ++++++++++++++- 3 files changed, 17 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 55b63712e48c..616ce10d2a38 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -386,7 +386,6 @@ static int ieee80211_stop(struct net_device *dev) struct ieee80211_local *local = sdata->local; struct ieee80211_if_init_conf conf; struct sta_info *sta; - int i; /* * Stop TX on this interface first. @@ -400,11 +399,7 @@ static int ieee80211_stop(struct net_device *dev) list_for_each_entry_rcu(sta, &local->sta_list, list) { if (sta->sdata == sdata) - for (i = 0; i < STA_TID_NUM; i++) - ieee80211_sta_stop_rx_ba_session(sdata->dev, - sta->addr, i, - WLAN_BACK_RECIPIENT, - WLAN_REASON_QSTA_LEAVE_QBSS); + ieee80211_sta_tear_down_BA_sessions(dev, sta->addr); } rcu_read_unlock(); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7f10ff5d4a0b..a6485f01b3c8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -928,10 +928,12 @@ void ieee80211_send_addba_request(struct net_device *dev, const u8 *da, u16 agg_size, u16 timeout); void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, u16 initiator, u16 reason_code); + void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *da, u16 tid, u16 initiator, u16 reason); void sta_rx_agg_session_timer_expired(unsigned long data); void sta_addba_resp_timer_expired(unsigned long data); +void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr); u64 ieee80211_sta_get_rates(struct ieee80211_local *local, struct ieee802_11_elems *elems, enum ieee80211_band band); diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 9beedb655896..fc73ca4abc08 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -467,8 +467,8 @@ static void ieee80211_set_associated(struct net_device *dev, memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN); ieee80211_sta_send_associnfo(dev, ifsta); } else { + ieee80211_sta_tear_down_BA_sessions(dev, ifsta->bssid); ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; - netif_carrier_off(dev); ieee80211_reset_erp_info(dev); memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); @@ -1518,6 +1518,19 @@ void sta_rx_agg_session_timer_expired(unsigned long data) WLAN_REASON_QSTA_TIMEOUT); } +void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + int i; + + for (i = 0; i < STA_TID_NUM; i++) { + ieee80211_stop_tx_ba_session(&local->hw, addr, i, + WLAN_BACK_INITIATOR); + ieee80211_sta_stop_rx_ba_session(dev, addr, i, + WLAN_BACK_RECIPIENT, + WLAN_REASON_QSTA_LEAVE_QBSS); + } +} static void ieee80211_rx_mgmt_auth(struct net_device *dev, struct ieee80211_if_sta *ifsta, -- cgit v1.2.3-59-g8ed1b From 675ef586f04e3a4566c9f437790a340711be5bd2 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Thu, 20 Mar 2008 08:14:29 -0700 Subject: mac80211: prevent tuning during scanning Postpone calling ieee80211_hw_config if hardware scanning is active. This is similar to solution for software scanning where channel setting is delayed until scan complete. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_ioctl.c | 2 +- net/mac80211/ieee80211_sta.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 8e8e5a19d893..5af23d318726 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -287,7 +287,7 @@ int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz) if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { local->oper_channel = chan; - if (local->sta_sw_scanning) + if (local->sta_sw_scanning || local->sta_hw_scanning) ret = 0; else ret = ieee80211_hw_config(local); diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index fc73ca4abc08..bf130b6255ab 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -3615,6 +3615,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) if (local->sta_hw_scanning) { local->sta_hw_scanning = 0; + if (ieee80211_hw_config(local)) + printk(KERN_DEBUG "%s: failed to restore operational " + "channel after scan\n", dev->name); /* Restart STA timer for HW scan case */ rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) -- cgit v1.2.3-59-g8ed1b From e2839d8f509451acf6b1f22787f25ce98383d94c Mon Sep 17 00:00:00 2001 From: Vladimir Koutny Date: Tue, 18 Mar 2008 21:14:07 +0100 Subject: mac80211: configure default wmm params correctly Default WMM params have to be set according to beacon/probe response information prior to authentication (or IBSS start/join); beacon queue is configured only in IBSS. This does not affect the use of 'real' WMM params as reported by AP. Signed-off-by: Vladimir Koutny Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 91 ++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 33 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index bf130b6255ab..cf51ca6804dd 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -220,6 +220,61 @@ static int ecw2cw(int ecw) return (1 << ecw) - 1; } + +static void ieee80211_sta_def_wmm_params(struct net_device *dev, + struct ieee80211_sta_bss *bss, + int ibss) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + int i, have_higher_than_11mbit = 0; + + + /* cf. IEEE 802.11 9.2.12 */ + for (i = 0; i < bss->supp_rates_len; i++) + if ((bss->supp_rates[i] & 0x7f) * 5 > 110) + have_higher_than_11mbit = 1; + + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + have_higher_than_11mbit) + sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; + else + sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; + + + if (local->ops->conf_tx) { + struct ieee80211_tx_queue_params qparam; + int i; + + memset(&qparam, 0, sizeof(qparam)); + + qparam.aifs = 2; + + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) + qparam.cw_min = 31; + else + qparam.cw_min = 15; + + qparam.cw_max = 1023; + qparam.txop = 0; + + for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) + local->ops->conf_tx(local_to_hw(local), + i + IEEE80211_TX_QUEUE_DATA0, + &qparam); + + if (ibss) { + /* IBSS uses different parameters for Beacon sending */ + qparam.cw_min++; + qparam.cw_min *= 2; + qparam.cw_min--; + local->ops->conf_tx(local_to_hw(local), + IEEE80211_TX_QUEUE_BEACON, &qparam); + } + } +} + static void ieee80211_sta_wmm_params(struct net_device *dev, struct ieee80211_if_sta *ifsta, u8 *wmm_param, size_t wmm_param_len) @@ -2302,6 +2357,8 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, rates |= BIT(j); } ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; + + ieee80211_sta_def_wmm_params(dev, bss, 1); } while (0); if (skb) { @@ -3293,6 +3350,7 @@ static int ieee80211_sta_config_auth(struct net_device *dev, ieee80211_sta_set_ssid(dev, selected->ssid, selected->ssid_len); ieee80211_sta_set_bssid(dev, selected->bssid); + ieee80211_sta_def_wmm_params(dev, selected, 0); ieee80211_rx_bss_put(dev, selected); ifsta->state = IEEE80211_AUTHENTICATE; ieee80211_sta_reset_auth(dev, ifsta); @@ -3467,43 +3525,10 @@ int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_if_sta *ifsta; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); if (len > IEEE80211_MAX_SSID_LEN) return -EINVAL; - /* TODO: This should always be done for IBSS, even if IEEE80211_QOS is - * not defined. */ - if (local->ops->conf_tx) { - struct ieee80211_tx_queue_params qparam; - int i; - - memset(&qparam, 0, sizeof(qparam)); - - qparam.aifs = 2; - - if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && - !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) - qparam.cw_min = 31; - else - qparam.cw_min = 15; - - qparam.cw_max = 1023; - qparam.txop = 0; - - for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) - local->ops->conf_tx(local_to_hw(local), - i + IEEE80211_TX_QUEUE_DATA0, - &qparam); - - /* IBSS uses different parameters for Beacon sending */ - qparam.cw_min++; - qparam.cw_min *= 2; - qparam.cw_min--; - local->ops->conf_tx(local_to_hw(local), - IEEE80211_TX_QUEUE_BEACON, &qparam); - } - ifsta = &sdata->u.sta; if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) -- cgit v1.2.3-59-g8ed1b From 30c69fed7d94c5c330a47fcc4833627644c19a5b Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:06:59 -0700 Subject: [NETFILTER]: ipt_CLUSTERIP: fix non-existant macro-name With nf_conntrack DUMP_TUPLE got renamed to NF_CT_DUMP_TUPLE, fix CLUSTERIP to use the proper macro name. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_CLUSTERIP.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index c6cf84c77611..1b10f3628390 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -332,7 +332,7 @@ clusterip_tg(struct sk_buff *skb, const struct net_device *in, } #ifdef DEBUG - DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); #endif pr_debug("hash=%u ct_hash=%u ", hash, ct->mark); if (!clusterip_responsible(cipinfo->config, hash)) { -- cgit v1.2.3-59-g8ed1b From 1d9d752259ab2e16b99f84b7e7bd4a30c884c289 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:07:58 -0700 Subject: [NETFILTER]: nf_conntrack_expect: constify nf_ct_expect_init arguments Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/netfilter/nf_conntrack_expect.h | 6 +++--- net/netfilter/nf_conntrack_expect.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index cb608a1b44e5..f1bdcb4f3f2a 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -75,9 +75,9 @@ void nf_ct_unexpect_related(struct nf_conntrack_expect *exp); nf_ct_expect_related. You will have to call put afterwards. */ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me); void nf_ct_expect_init(struct nf_conntrack_expect *, int, - union nf_inet_addr *, - union nf_inet_addr *, - u_int8_t, __be16 *, __be16 *); + const union nf_inet_addr *, + const union nf_inet_addr *, + u_int8_t, const __be16 *, const __be16 *); void nf_ct_expect_put(struct nf_conntrack_expect *exp); int nf_ct_expect_related(struct nf_conntrack_expect *expect); diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 684ec9c1ad38..740d94d30091 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -229,9 +229,9 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me) EXPORT_SYMBOL_GPL(nf_ct_expect_alloc); void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family, - union nf_inet_addr *saddr, - union nf_inet_addr *daddr, - u_int8_t proto, __be16 *src, __be16 *dst) + const union nf_inet_addr *saddr, + const union nf_inet_addr *daddr, + u_int8_t proto, const __be16 *src, const __be16 *dst) { int len; -- cgit v1.2.3-59-g8ed1b From 4bb119eab7b724109d8eeb0f8d86ed1e4953d338 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:08:17 -0700 Subject: [NETFILTER]: nf_conntrack_expect: show NF_CT_EXPECT_PERMANENT flag in /proc Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_expect.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 740d94d30091..4c05a588116f 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -475,6 +475,10 @@ static int exp_seq_show(struct seq_file *s, void *v) __nf_ct_l3proto_find(expect->tuple.src.l3num), __nf_ct_l4proto_find(expect->tuple.src.l3num, expect->tuple.dst.protonum)); + + if (expect->flags & NF_CT_EXPECT_PERMANENT) + seq_printf(s, "PERMANENT "); + return seq_putc(s, '\n'); } -- cgit v1.2.3-59-g8ed1b From 359b9ab614aba71c2c3bc047efbd6d12dd4a2b9e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:08:37 -0700 Subject: [NETFILTER]: nf_conntrack_expect: support inactive expectations This is useful for the SIP helper and signalling expectations. We don't want to create a full-blown expectation with a wildcard as source based on a single UDP packet, but need to know the final port anyways. With inactive expectations we can register the expectation and reserve the tuple, but wait for confirmation from the registrar before activating it. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/netfilter/nf_conntrack_expect.h | 3 ++- net/netfilter/nf_conntrack_expect.c | 25 +++++++++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index f1bdcb4f3f2a..47c28dd07896 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -53,7 +53,8 @@ struct nf_conntrack_expect struct rcu_head rcu; }; -#define NF_CT_EXPECT_PERMANENT 0x1 +#define NF_CT_EXPECT_PERMANENT 0x1 +#define NF_CT_EXPECT_INACTIVE 0x2 int nf_conntrack_expect_init(void); void nf_conntrack_expect_fini(void); diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 4c05a588116f..882602f1c0ef 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -126,9 +126,21 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_find_get); struct nf_conntrack_expect * nf_ct_find_expectation(const struct nf_conntrack_tuple *tuple) { - struct nf_conntrack_expect *exp; + struct nf_conntrack_expect *i, *exp = NULL; + struct hlist_node *n; + unsigned int h; + + if (!nf_ct_expect_count) + return NULL; - exp = __nf_ct_expect_find(tuple); + h = nf_ct_expect_dst_hash(tuple); + hlist_for_each_entry(i, n, &nf_ct_expect_hash[h], hnode) { + if (!(i->flags & NF_CT_EXPECT_INACTIVE) && + nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) { + exp = i; + break; + } + } if (!exp) return NULL; @@ -460,6 +472,7 @@ static int exp_seq_show(struct seq_file *s, void *v) { struct nf_conntrack_expect *expect; struct hlist_node *n = v; + char *delim = ""; expect = hlist_entry(n, struct nf_conntrack_expect, hnode); @@ -476,8 +489,12 @@ static int exp_seq_show(struct seq_file *s, void *v) __nf_ct_l4proto_find(expect->tuple.src.l3num, expect->tuple.dst.protonum)); - if (expect->flags & NF_CT_EXPECT_PERMANENT) - seq_printf(s, "PERMANENT "); + if (expect->flags & NF_CT_EXPECT_PERMANENT) { + seq_printf(s, "PERMANENT"); + delim = ","; + } + if (expect->flags & NF_CT_EXPECT_INACTIVE) + seq_printf(s, "%sINACTIVE", delim); return seq_putc(s, '\n'); } -- cgit v1.2.3-59-g8ed1b From 6002f266b3e7f0acc2d5158cddbed41730b02e82 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:09:15 -0700 Subject: [NETFILTER]: nf_conntrack: introduce expectation classes and policies Introduce expectation classes and policies. An expectation class is used to distinguish different types of expectations by the same helper (for example audio/video/t.120). The expectation policy is used to hold the maximum number of expectations and the initial timeout for each class. The individual classes are isolated from each other, which means that for example an audio expectation will only evict other audio expectations. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/netfilter/nf_conntrack.h | 5 ++- include/net/netfilter/nf_conntrack_expect.h | 13 +++++- include/net/netfilter/nf_conntrack_helper.h | 5 +-- net/ipv4/netfilter/nf_nat_snmp_basic.c | 12 ++++-- net/netfilter/nf_conntrack_amanda.c | 14 +++--- net/netfilter/nf_conntrack_expect.c | 50 ++++++++++++++-------- net/netfilter/nf_conntrack_ftp.c | 10 +++-- net/netfilter/nf_conntrack_h323_main.c | 66 ++++++++++++++++++----------- net/netfilter/nf_conntrack_helper.c | 3 +- net/netfilter/nf_conntrack_irc.c | 10 +++-- net/netfilter/nf_conntrack_netbios_ns.c | 9 +++- net/netfilter/nf_conntrack_pptp.c | 14 ++++-- net/netfilter/nf_conntrack_sane.c | 11 +++-- net/netfilter/nf_conntrack_sip.c | 10 +++-- net/netfilter/nf_conntrack_tftp.c | 11 +++-- 15 files changed, 166 insertions(+), 77 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 90b3e7f5df5f..922877133598 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -75,6 +75,9 @@ do { \ struct nf_conntrack_helper; +/* Must be kept in sync with the classes defined by helpers */ +#define NF_CT_MAX_EXPECT_CLASSES 1 + /* nf_conn feature for connections that have a helper */ struct nf_conn_help { /* Helper. if any */ @@ -85,7 +88,7 @@ struct nf_conn_help { struct hlist_head expectations; /* Current number of expected connections */ - unsigned int expecting; + u8 expecting[NF_CT_MAX_EXPECT_CLASSES]; }; diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 47c28dd07896..dfdf4b459475 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -41,6 +41,9 @@ struct nf_conntrack_expect /* Flags */ unsigned int flags; + /* Expectation class */ + unsigned int class; + #ifdef CONFIG_NF_NAT_NEEDED __be32 saved_ip; /* This is the original per-proto part, used to map the @@ -53,6 +56,14 @@ struct nf_conntrack_expect struct rcu_head rcu; }; +struct nf_conntrack_expect_policy +{ + unsigned int max_expected; + unsigned int timeout; +}; + +#define NF_CT_EXPECT_CLASS_DEFAULT 0 + #define NF_CT_EXPECT_PERMANENT 0x1 #define NF_CT_EXPECT_INACTIVE 0x2 @@ -75,7 +86,7 @@ void nf_ct_unexpect_related(struct nf_conntrack_expect *exp); /* Allocate space for an expectation: this is mandatory before calling nf_ct_expect_related. You will have to call put afterwards. */ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me); -void nf_ct_expect_init(struct nf_conntrack_expect *, int, +void nf_ct_expect_init(struct nf_conntrack_expect *, unsigned int, int, const union nf_inet_addr *, const union nf_inet_addr *, u_int8_t, const __be16 *, const __be16 *); diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index 4ca125e9b3ce..f8060ab5a083 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -20,9 +20,7 @@ struct nf_conntrack_helper const char *name; /* name of the module */ struct module *me; /* pointer to self */ - unsigned int max_expected; /* Maximum number of concurrent - * expected connections */ - unsigned int timeout; /* timeout for expecteds */ + const struct nf_conntrack_expect_policy *expect_policy; /* Tuple of things we will help (compared against server response) */ struct nf_conntrack_tuple tuple; @@ -37,6 +35,7 @@ struct nf_conntrack_helper void (*destroy)(struct nf_conn *ct); int (*to_nlattr)(struct sk_buff *skb, const struct nf_conn *ct); + unsigned int expect_class_max; }; extern struct nf_conntrack_helper * diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c index 540ce6ae887c..000e080bac5c 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c @@ -50,6 +50,7 @@ #include #include +#include #include #include @@ -1267,11 +1268,15 @@ static int help(struct sk_buff *skb, unsigned int protoff, return ret; } +static const struct nf_conntrack_expect_policy snmp_exp_policy = { + .max_expected = 0, + .timeout = 180, +}; + static struct nf_conntrack_helper snmp_helper __read_mostly = { - .max_expected = 0, - .timeout = 180, .me = THIS_MODULE, .help = help, + .expect_policy = &snmp_exp_policy, .name = "snmp", .tuple.src.l3num = AF_INET, .tuple.src.u.udp.port = __constant_htons(SNMP_PORT), @@ -1279,10 +1284,9 @@ static struct nf_conntrack_helper snmp_helper __read_mostly = { }; static struct nf_conntrack_helper snmp_trap_helper __read_mostly = { - .max_expected = 0, - .timeout = 180, .me = THIS_MODULE, .help = help, + .expect_policy = &snmp_exp_policy, .name = "snmp_trap", .tuple.src.l3num = AF_INET, .tuple.src.u.udp.port = __constant_htons(SNMP_TRAP_PORT), diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c index 7b8239c0cd5e..d14585a19b7d 100644 --- a/net/netfilter/nf_conntrack_amanda.c +++ b/net/netfilter/nf_conntrack_amanda.c @@ -148,7 +148,8 @@ static int amanda_help(struct sk_buff *skb, goto out; } tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; - nf_ct_expect_init(exp, family, &tuple->src.u3, &tuple->dst.u3, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family, + &tuple->src.u3, &tuple->dst.u3, IPPROTO_TCP, NULL, &port); nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook); @@ -164,26 +165,29 @@ out: return ret; } +static const struct nf_conntrack_expect_policy amanda_exp_policy = { + .max_expected = 3, + .timeout = 180, +}; + static struct nf_conntrack_helper amanda_helper[2] __read_mostly = { { .name = "amanda", - .max_expected = 3, - .timeout = 180, .me = THIS_MODULE, .help = amanda_help, .tuple.src.l3num = AF_INET, .tuple.src.u.udp.port = __constant_htons(10080), .tuple.dst.protonum = IPPROTO_UDP, + .expect_policy = &amanda_exp_policy, }, { .name = "amanda", - .max_expected = 3, - .timeout = 180, .me = THIS_MODULE, .help = amanda_help, .tuple.src.l3num = AF_INET6, .tuple.src.u.udp.port = __constant_htons(10080), .tuple.dst.protonum = IPPROTO_UDP, + .expect_policy = &amanda_exp_policy, }, }; diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 882602f1c0ef..e31beeb33b2b 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -54,7 +54,7 @@ void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) nf_ct_expect_count--; hlist_del(&exp->lnode); - master_help->expecting--; + master_help->expecting[exp->class]--; nf_ct_expect_put(exp); NF_CT_STAT_INC(expect_delete); @@ -171,7 +171,7 @@ void nf_ct_remove_expectations(struct nf_conn *ct) struct hlist_node *n, *next; /* Optimization: most connection never expect any others. */ - if (!help || help->expecting == 0) + if (!help) return; hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { @@ -205,7 +205,7 @@ static inline int expect_clash(const struct nf_conntrack_expect *a, static inline int expect_matches(const struct nf_conntrack_expect *a, const struct nf_conntrack_expect *b) { - return a->master == b->master + return a->master == b->master && a->class == b->class && nf_ct_tuple_equal(&a->tuple, &b->tuple) && nf_ct_tuple_mask_equal(&a->mask, &b->mask); } @@ -240,7 +240,8 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me) } EXPORT_SYMBOL_GPL(nf_ct_expect_alloc); -void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family, +void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class, + int family, const union nf_inet_addr *saddr, const union nf_inet_addr *daddr, u_int8_t proto, const __be16 *src, const __be16 *dst) @@ -253,6 +254,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, int family, len = 16; exp->flags = 0; + exp->class = class; exp->expectfn = NULL; exp->helper = NULL; exp->tuple.src.l3num = family; @@ -309,19 +311,21 @@ EXPORT_SYMBOL_GPL(nf_ct_expect_put); static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) { struct nf_conn_help *master_help = nfct_help(exp->master); + const struct nf_conntrack_expect_policy *p; unsigned int h = nf_ct_expect_dst_hash(&exp->tuple); atomic_inc(&exp->use); hlist_add_head(&exp->lnode, &master_help->expectations); - master_help->expecting++; + master_help->expecting[exp->class]++; hlist_add_head_rcu(&exp->hnode, &nf_ct_expect_hash[h]); nf_ct_expect_count++; setup_timer(&exp->timeout, nf_ct_expectation_timed_out, (unsigned long)exp); - exp->timeout.expires = jiffies + master_help->helper->timeout * HZ; + p = &master_help->helper->expect_policy[exp->class]; + exp->timeout.expires = jiffies + p->timeout * HZ; add_timer(&exp->timeout); atomic_inc(&exp->use); @@ -329,35 +333,41 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp) } /* Race with expectations being used means we could have none to find; OK. */ -static void evict_oldest_expect(struct nf_conn *master) +static void evict_oldest_expect(struct nf_conn *master, + struct nf_conntrack_expect *new) { struct nf_conn_help *master_help = nfct_help(master); - struct nf_conntrack_expect *exp = NULL; + struct nf_conntrack_expect *exp, *last = NULL; struct hlist_node *n; - hlist_for_each_entry(exp, n, &master_help->expectations, lnode) - ; /* nothing */ + hlist_for_each_entry(exp, n, &master_help->expectations, lnode) { + if (exp->class == new->class) + last = exp; + } - if (exp && del_timer(&exp->timeout)) { - nf_ct_unlink_expect(exp); - nf_ct_expect_put(exp); + if (last && del_timer(&last->timeout)) { + nf_ct_unlink_expect(last); + nf_ct_expect_put(last); } } static inline int refresh_timer(struct nf_conntrack_expect *i) { struct nf_conn_help *master_help = nfct_help(i->master); + const struct nf_conntrack_expect_policy *p; if (!del_timer(&i->timeout)) return 0; - i->timeout.expires = jiffies + master_help->helper->timeout*HZ; + p = &master_help->helper->expect_policy[i->class]; + i->timeout.expires = jiffies + p->timeout * HZ; add_timer(&i->timeout); return 1; } int nf_ct_expect_related(struct nf_conntrack_expect *expect) { + const struct nf_conntrack_expect_policy *p; struct nf_conntrack_expect *i; struct nf_conn *master = expect->master; struct nf_conn_help *master_help = nfct_help(master); @@ -386,9 +396,15 @@ int nf_ct_expect_related(struct nf_conntrack_expect *expect) } } /* Will be over limit? */ - if (master_help->helper->max_expected && - master_help->expecting >= master_help->helper->max_expected) - evict_oldest_expect(master); + p = &master_help->helper->expect_policy[expect->class]; + if (p->max_expected && + master_help->expecting[expect->class] >= p->max_expected) { + evict_oldest_expect(master, expect); + if (master_help->expecting[expect->class] >= p->max_expected) { + ret = -EMFILE; + goto out; + } + } if (nf_ct_expect_count >= nf_ct_expect_max) { if (net_ratelimit()) diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 6770baf2e845..7eff876bb8bc 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -483,7 +483,7 @@ static int help(struct sk_buff *skb, daddr = &cmd.u3; } - nf_ct_expect_init(exp, cmd.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, cmd.l3num, &ct->tuplehash[!dir].tuple.src.u3, daddr, IPPROTO_TCP, NULL, &cmd.u.tcp.port); @@ -517,6 +517,11 @@ out_update_nl: static struct nf_conntrack_helper ftp[MAX_PORTS][2] __read_mostly; static char ftp_names[MAX_PORTS][2][sizeof("ftp-65535")] __read_mostly; +static const struct nf_conntrack_expect_policy ftp_exp_policy = { + .max_expected = 1, + .timeout = 5 * 60, +}; + /* don't make this __exit, since it's called from __init ! */ static void nf_conntrack_ftp_fini(void) { @@ -556,8 +561,7 @@ static int __init nf_conntrack_ftp_init(void) for (j = 0; j < 2; j++) { ftp[i][j].tuple.src.u.tcp.port = htons(ports[i]); ftp[i][j].tuple.dst.protonum = IPPROTO_TCP; - ftp[i][j].max_expected = 1; - ftp[i][j].timeout = 5 * 60; /* 5 Minutes */ + ftp[i][j].expect_policy = &ftp_exp_policy; ftp[i][j].me = THIS_MODULE; ftp[i][j].help = help; tmpname = &ftp_names[i][j][0]; diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c index 898f1922b5b8..505052d495cf 100644 --- a/net/netfilter/nf_conntrack_h323_main.c +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -277,7 +277,8 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct, /* Create expect for RTP */ if ((rtp_exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(rtp_exp, ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(rtp_exp, NF_CT_EXPECT_CLASS_DEFAULT, + ct->tuplehash[!dir].tuple.src.l3num, &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, IPPROTO_UDP, NULL, &rtp_port); @@ -287,7 +288,8 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct, nf_ct_expect_put(rtp_exp); return -1; } - nf_ct_expect_init(rtcp_exp, ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(rtcp_exp, NF_CT_EXPECT_CLASS_DEFAULT, + ct->tuplehash[!dir].tuple.src.l3num, &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, IPPROTO_UDP, NULL, &rtcp_port); @@ -344,7 +346,8 @@ static int expect_t120(struct sk_buff *skb, /* Create expect for T.120 connections */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, + ct->tuplehash[!dir].tuple.src.l3num, &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, IPPROTO_TCP, NULL, &port); @@ -612,13 +615,17 @@ static int h245_help(struct sk_buff *skb, unsigned int protoff, } /****************************************************************************/ +static const struct nf_conntrack_expect_policy h245_exp_policy = { + .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */, + .timeout = 240, +}; + static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly = { .name = "H.245", .me = THIS_MODULE, - .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */, - .timeout = 240, .tuple.dst.protonum = IPPROTO_UDP, - .help = h245_help + .help = h245_help, + .expect_policy = &h245_exp_policy, }; /****************************************************************************/ @@ -676,7 +683,8 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct, /* Create expect for h245 connection */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, + ct->tuplehash[!dir].tuple.src.l3num, &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, IPPROTO_TCP, NULL, &port); @@ -792,7 +800,8 @@ static int expect_callforwarding(struct sk_buff *skb, /* Create expect for the second call leg */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, + ct->tuplehash[!dir].tuple.src.l3num, &ct->tuplehash[!dir].tuple.src.u3, &addr, IPPROTO_TCP, NULL, &port); exp->helper = nf_conntrack_helper_q931; @@ -1156,28 +1165,30 @@ static int q931_help(struct sk_buff *skb, unsigned int protoff, } /****************************************************************************/ +static const struct nf_conntrack_expect_policy q931_exp_policy = { + /* T.120 and H.245 */ + .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4, + .timeout = 240, +}; + static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = { { .name = "Q.931", .me = THIS_MODULE, - /* T.120 and H.245 */ - .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4, - .timeout = 240, .tuple.src.l3num = AF_INET, .tuple.src.u.tcp.port = __constant_htons(Q931_PORT), .tuple.dst.protonum = IPPROTO_TCP, - .help = q931_help + .help = q931_help, + .expect_policy = &q931_exp_policy, }, { .name = "Q.931", .me = THIS_MODULE, - /* T.120 and H.245 */ - .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4, - .timeout = 240, .tuple.src.l3num = AF_INET6, .tuple.src.u.tcp.port = __constant_htons(Q931_PORT), .tuple.dst.protonum = IPPROTO_TCP, - .help = q931_help + .help = q931_help, + .expect_policy = &q931_exp_policy, }, }; @@ -1261,7 +1272,8 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct, /* Create expect for Q.931 */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, + ct->tuplehash[!dir].tuple.src.l3num, gkrouted_only ? /* only accept calls from GK? */ &ct->tuplehash[!dir].tuple.src.u3 : NULL, &ct->tuplehash[!dir].tuple.dst.u3, @@ -1332,7 +1344,8 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct, /* Need new expect */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, + ct->tuplehash[!dir].tuple.src.l3num, &ct->tuplehash[!dir].tuple.src.u3, &addr, IPPROTO_UDP, NULL, &port); exp->helper = nf_conntrack_helper_ras; @@ -1536,7 +1549,8 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct, /* Need new expect */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, + ct->tuplehash[!dir].tuple.src.l3num, &ct->tuplehash[!dir].tuple.src.u3, &addr, IPPROTO_TCP, NULL, &port); exp->flags = NF_CT_EXPECT_PERMANENT; @@ -1589,7 +1603,8 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct, /* Need new expect for call signal */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, + ct->tuplehash[!dir].tuple.src.l3num, &ct->tuplehash[!dir].tuple.src.u3, &addr, IPPROTO_TCP, NULL, &port); exp->flags = NF_CT_EXPECT_PERMANENT; @@ -1728,26 +1743,29 @@ static int ras_help(struct sk_buff *skb, unsigned int protoff, } /****************************************************************************/ +static const struct nf_conntrack_expect_policy ras_exp_policy = { + .max_expected = 32, + .timeout = 240, +}; + static struct nf_conntrack_helper nf_conntrack_helper_ras[] __read_mostly = { { .name = "RAS", .me = THIS_MODULE, - .max_expected = 32, - .timeout = 240, .tuple.src.l3num = AF_INET, .tuple.src.u.udp.port = __constant_htons(RAS_PORT), .tuple.dst.protonum = IPPROTO_UDP, .help = ras_help, + .expect_policy = &ras_exp_policy, }, { .name = "RAS", .me = THIS_MODULE, - .max_expected = 32, - .timeout = 240, .tuple.src.l3num = AF_INET6, .tuple.src.u.udp.port = __constant_htons(RAS_PORT), .tuple.dst.protonum = IPPROTO_UDP, .help = ras_help, + .expect_policy = &ras_exp_policy, }, }; diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index b1fd21cc1dbc..e350f56d43c9 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -110,7 +110,8 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me) { unsigned int h = helper_hash(&me->tuple); - BUG_ON(me->timeout == 0); + BUG_ON(me->expect_policy == NULL); + BUG_ON(me->expect_class_max >= NF_CT_MAX_EXPECT_CLASSES); mutex_lock(&nf_ct_helper_mutex); hlist_add_head_rcu(&me->hnode, &nf_ct_helper_hash[h]); diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c index c336b07a0d4c..02f21cbe5ae7 100644 --- a/net/netfilter/nf_conntrack_irc.c +++ b/net/netfilter/nf_conntrack_irc.c @@ -187,7 +187,8 @@ static int help(struct sk_buff *skb, unsigned int protoff, } tuple = &ct->tuplehash[!dir].tuple; port = htons(dcc_port); - nf_ct_expect_init(exp, tuple->src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, + tuple->src.l3num, NULL, &tuple->dst.u3, IPPROTO_TCP, NULL, &port); @@ -210,6 +211,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, static struct nf_conntrack_helper irc[MAX_PORTS] __read_mostly; static char irc_names[MAX_PORTS][sizeof("irc-65535")] __read_mostly; +static struct nf_conntrack_expect_policy irc_exp_policy; static void nf_conntrack_irc_fini(void); @@ -223,6 +225,9 @@ static int __init nf_conntrack_irc_init(void) return -EINVAL; } + irc_exp_policy.max_expected = max_dcc_channels; + irc_exp_policy.timeout = dcc_timeout; + irc_buffer = kmalloc(65536, GFP_KERNEL); if (!irc_buffer) return -ENOMEM; @@ -235,8 +240,7 @@ static int __init nf_conntrack_irc_init(void) irc[i].tuple.src.l3num = AF_INET; irc[i].tuple.src.u.tcp.port = htons(ports[i]); irc[i].tuple.dst.protonum = IPPROTO_TCP; - irc[i].max_expected = max_dcc_channels; - irc[i].timeout = dcc_timeout; + irc[i].expect_policy = &irc_exp_policy; irc[i].me = THIS_MODULE; irc[i].help = help; diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c index 60dedaded84e..08404e6755fb 100644 --- a/net/netfilter/nf_conntrack_netbios_ns.c +++ b/net/netfilter/nf_conntrack_netbios_ns.c @@ -86,6 +86,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, exp->expectfn = NULL; exp->flags = NF_CT_EXPECT_PERMANENT; + exp->class = NF_CT_EXPECT_CLASS_DEFAULT; exp->helper = NULL; nf_ct_expect_related(exp); @@ -96,19 +97,23 @@ out: return NF_ACCEPT; } +static struct nf_conntrack_expect_policy exp_policy = { + .max_expected = 1, +}; + static struct nf_conntrack_helper helper __read_mostly = { .name = "netbios-ns", .tuple.src.l3num = AF_INET, .tuple.src.u.udp.port = __constant_htons(NMBD_PORT), .tuple.dst.protonum = IPPROTO_UDP, - .max_expected = 1, .me = THIS_MODULE, .help = help, + .expect_policy = &exp_policy, }; static int __init nf_conntrack_netbios_ns_init(void) { - helper.timeout = timeout; + exp_policy.timeout = timeout; return nf_conntrack_helper_register(&helper); } diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c index b5cb8e831230..8fd83470d1b3 100644 --- a/net/netfilter/nf_conntrack_pptp.c +++ b/net/netfilter/nf_conntrack_pptp.c @@ -208,7 +208,8 @@ static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid) /* original direction, PNS->PAC */ dir = IP_CT_DIR_ORIGINAL; - nf_ct_expect_init(exp_orig, ct->tuplehash[dir].tuple.src.l3num, + nf_ct_expect_init(exp_orig, NF_CT_EXPECT_CLASS_DEFAULT, + ct->tuplehash[dir].tuple.src.l3num, &ct->tuplehash[dir].tuple.src.u3, &ct->tuplehash[dir].tuple.dst.u3, IPPROTO_GRE, &peer_callid, &callid); @@ -216,7 +217,8 @@ static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid) /* reply direction, PAC->PNS */ dir = IP_CT_DIR_REPLY; - nf_ct_expect_init(exp_reply, ct->tuplehash[dir].tuple.src.l3num, + nf_ct_expect_init(exp_reply, NF_CT_EXPECT_CLASS_DEFAULT, + ct->tuplehash[dir].tuple.src.l3num, &ct->tuplehash[dir].tuple.src.u3, &ct->tuplehash[dir].tuple.dst.u3, IPPROTO_GRE, &callid, &peer_callid); @@ -575,17 +577,21 @@ conntrack_pptp_help(struct sk_buff *skb, unsigned int protoff, return ret; } +static const struct nf_conntrack_expect_policy pptp_exp_policy = { + .max_expected = 2, + .timeout = 5 * 60, +}; + /* control protocol helper */ static struct nf_conntrack_helper pptp __read_mostly = { .name = "pptp", .me = THIS_MODULE, - .max_expected = 2, - .timeout = 5 * 60, .tuple.src.l3num = AF_INET, .tuple.src.u.tcp.port = __constant_htons(PPTP_CONTROL_PORT), .tuple.dst.protonum = IPPROTO_TCP, .help = conntrack_pptp_help, .destroy = pptp_destroy_siblings, + .expect_policy = &pptp_exp_policy, }; static int __init nf_conntrack_pptp_init(void) diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c index a70051d741a7..7542e25eede3 100644 --- a/net/netfilter/nf_conntrack_sane.c +++ b/net/netfilter/nf_conntrack_sane.c @@ -143,7 +143,8 @@ static int help(struct sk_buff *skb, } tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; - nf_ct_expect_init(exp, family, &tuple->src.u3, &tuple->dst.u3, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family, + &tuple->src.u3, &tuple->dst.u3, IPPROTO_TCP, NULL, &reply->port); pr_debug("nf_ct_sane: expect: "); @@ -163,6 +164,11 @@ out: static struct nf_conntrack_helper sane[MAX_PORTS][2] __read_mostly; static char sane_names[MAX_PORTS][2][sizeof("sane-65535")] __read_mostly; +static const struct nf_conntrack_expect_policy sane_exp_policy = { + .max_expected = 1, + .timeout = 5 * 60, +}; + /* don't make this __exit, since it's called from __init ! */ static void nf_conntrack_sane_fini(void) { @@ -200,8 +206,7 @@ static int __init nf_conntrack_sane_init(void) for (j = 0; j < 2; j++) { sane[i][j].tuple.src.u.tcp.port = htons(ports[i]); sane[i][j].tuple.dst.protonum = IPPROTO_TCP; - sane[i][j].max_expected = 1; - sane[i][j].timeout = 5 * 60; /* 5 Minutes */ + sane[i][j].expect_policy = &sane_exp_policy; sane[i][j].me = THIS_MODULE; sane[i][j].help = help; tmpname = &sane_names[i][j][0]; diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index c521c891d351..0021d5b60cec 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -380,7 +380,7 @@ static int set_expected_rtp(struct sk_buff *skb, exp = nf_ct_expect_alloc(ct); if (exp == NULL) return NF_DROP; - nf_ct_expect_init(exp, family, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family, &ct->tuplehash[!dir].tuple.src.u3, addr, IPPROTO_UDP, NULL, &port); @@ -476,6 +476,11 @@ out: static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly; +static const struct nf_conntrack_expect_policy sip_exp_policy = { + .max_expected = 2, + .timeout = 3 * 60, +}; + static void nf_conntrack_sip_fini(void) { int i, j; @@ -505,8 +510,7 @@ static int __init nf_conntrack_sip_init(void) for (j = 0; j < 2; j++) { sip[i][j].tuple.dst.protonum = IPPROTO_UDP; sip[i][j].tuple.src.u.udp.port = htons(ports[i]); - sip[i][j].max_expected = 2; - sip[i][j].timeout = 3 * 60; /* 3 minutes */ + sip[i][j].expect_policy = &sip_exp_policy; sip[i][j].me = THIS_MODULE; sip[i][j].help = sip_help; diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c index bd2e800f23cc..a28341b30f21 100644 --- a/net/netfilter/nf_conntrack_tftp.c +++ b/net/netfilter/nf_conntrack_tftp.c @@ -63,7 +63,8 @@ static int tftp_help(struct sk_buff *skb, if (exp == NULL) return NF_DROP; tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; - nf_ct_expect_init(exp, family, &tuple->src.u3, &tuple->dst.u3, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family, + &tuple->src.u3, &tuple->dst.u3, IPPROTO_UDP, NULL, &tuple->dst.u.udp.port); pr_debug("expect: "); @@ -92,6 +93,11 @@ static int tftp_help(struct sk_buff *skb, static struct nf_conntrack_helper tftp[MAX_PORTS][2] __read_mostly; static char tftp_names[MAX_PORTS][2][sizeof("tftp-65535")] __read_mostly; +static const struct nf_conntrack_expect_policy tftp_exp_policy = { + .max_expected = 1, + .timeout = 5 * 60, +}; + static void nf_conntrack_tftp_fini(void) { int i, j; @@ -118,8 +124,7 @@ static int __init nf_conntrack_tftp_init(void) for (j = 0; j < 2; j++) { tftp[i][j].tuple.dst.protonum = IPPROTO_UDP; tftp[i][j].tuple.src.u.udp.port = htons(ports[i]); - tftp[i][j].max_expected = 1; - tftp[i][j].timeout = 5 * 60; /* 5 minutes */ + tftp[i][j].expect_policy = &tftp_exp_policy; tftp[i][j].me = THIS_MODULE; tftp[i][j].help = tftp_help; -- cgit v1.2.3-59-g8ed1b From 3d244121d88cd9b0baa12c25ff25561e7b4f71cd Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:09:51 -0700 Subject: [NETFILTER]: nf_nat_sip: fix NAT setup order We need to set up the destination NAT mapping before the source NAT mapping, so the NAT core gets to see the final tuple and can decide whether the source port needs to be remapped. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/nf_nat_sip.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index b4c8d4968bb2..84d8b4982cdf 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -224,17 +224,17 @@ static void ip_nat_sdp_expect(struct nf_conn *ct, /* This must be a fresh one. */ BUG_ON(ct->status & IPS_NAT_DONE_MASK); - /* Change src to where master sends to */ - range.flags = IP_NAT_RANGE_MAP_IPS; - range.min_ip = range.max_ip - = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; - nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC); - /* For DST manip, map port here to where it's expected. */ range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); range.min = range.max = exp->saved_proto; range.min_ip = range.max_ip = exp->saved_ip; nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST); + + /* Change src to where master sends to */ + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; + nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC); } /* So, this packet has hit the connection tracking matching code. -- cgit v1.2.3-59-g8ed1b From b1ec488b1fb3c7a8819857e3506787516ca1ed4d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:10:11 -0700 Subject: [NETFILTER]: nf_conntrack_sip: fix some off-by-ones "limit" marks the first character outside the bounds. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_sip.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 0021d5b60cec..016e1c1aafe4 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -192,10 +192,10 @@ int ct_sip_lnlen(const char *line, const char *limit) { const char *k = line; - while ((line <= limit) && (*line == '\r' || *line == '\n')) + while ((line < limit) && (*line == '\r' || *line == '\n')) line++; - while (line <= limit) { + while (line < limit) { if (*line == '\r' || *line == '\n') break; line++; @@ -211,7 +211,7 @@ const char *ct_sip_search(const char *needle, const char *haystack, { const char *limit = haystack + (haystack_len - needle_len); - while (haystack <= limit) { + while (haystack < limit) { if (case_sensitive) { if (strncmp(haystack, needle, needle_len) == 0) return haystack; @@ -229,7 +229,7 @@ static int digits_len(const struct nf_conn *ct, const char *dptr, const char *limit, int *shift) { int len = 0; - while (dptr <= limit && isdigit(*dptr)) { + while (dptr < limit && isdigit(*dptr)) { dptr++; len++; } @@ -240,7 +240,7 @@ static int digits_len(const struct nf_conn *ct, const char *dptr, static int skp_digits_len(const struct nf_conn *ct, const char *dptr, const char *limit, int *shift) { - for (; dptr <= limit && *dptr == ' '; dptr++) + for (; dptr < limit && *dptr == ' '; dptr++) (*shift)++; return digits_len(ct, dptr, limit, shift); @@ -302,13 +302,13 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, /* Search for @, but stop at the end of the line. * We are inside a sip: URI, so we don't need to worry about * continuation lines. */ - while (dptr <= limit && + while (dptr < limit && *dptr != '@' && *dptr != '\r' && *dptr != '\n') { (*shift)++; dptr++; } - if (dptr <= limit && *dptr == '@') { + if (dptr < limit && *dptr == '@') { dptr++; (*shift)++; } else { @@ -332,7 +332,7 @@ int ct_sip_get_info(const struct nf_conn *ct, limit = dptr + (dlen - hnfo->lnlen); - while (dptr <= limit) { + while (dptr < limit) { if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && (hnfo->sname == NULL || strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { -- cgit v1.2.3-59-g8ed1b From 2a6cfb22ae002330d445f734668d9158db9e90de Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:16:54 -0700 Subject: [NETFILTER]: nf_conntrack_sip: adjust dptr and datalen after packet mangling After mangling the packet, the pointer to the data and the length of the data portion may change and need to be adjusted. Use double data pointers and a pointer to the length everywhere and add a helper function to the NAT helper for performing the adjustments. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 6 +- net/ipv4/netfilter/nf_nat_sip.c | 91 ++++++++++++++++-------------- net/netfilter/nf_conntrack_sip.c | 14 +++-- 3 files changed, 60 insertions(+), 51 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 8e5ce1ca7bfc..9d0dbfb26300 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -24,11 +24,13 @@ enum sip_header_pos { extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, - const char **dptr); + const char **dptr, + unsigned int *datalen); extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conntrack_expect *exp, - const char *dptr); + const char **dptr, + unsigned int *datalen); extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, size_t dlen, unsigned int *matchoff, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 84d8b4982cdf..e77122e65283 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -60,15 +60,35 @@ static void addr_map_init(const struct nf_conn *ct, struct addr_map *map) } } +static unsigned int mangle_packet(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int matchoff, unsigned int matchlen, + const char *buffer, unsigned int buflen) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + + if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, matchoff, matchlen, + buffer, buflen)) + return 0; + + /* Reload data pointer and adjust datalen value */ + *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr); + *datalen += buflen - matchlen; + return 1; +} + static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo, - struct nf_conn *ct, const char **dptr, size_t dlen, + struct nf_conn *ct, + const char **dptr, unsigned int *datalen, enum sip_header_pos pos, struct addr_map *map) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); unsigned int matchlen, matchoff, addrlen; char *addr; - if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) + if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, + pos) <= 0) return 1; if ((matchlen == map->addr[dir].srciplen || @@ -84,26 +104,19 @@ static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo, } else return 1; - if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, - matchoff, matchlen, addr, addrlen)) - return 0; - *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr); - return 1; - + return mangle_packet(skb, dptr, datalen, matchoff, matchlen, + addr, addrlen); } static unsigned int ip_nat_sip(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, - const char **dptr) + const char **dptr, unsigned int *datalen) { enum sip_header_pos pos; struct addr_map map; - int dataoff, datalen; - dataoff = ip_hdrlen(skb) + sizeof(struct udphdr); - datalen = skb->len - dataoff; - if (datalen < sizeof("SIP/2.0") - 1) + if (*datalen < sizeof("SIP/2.0") - 1) return NF_ACCEPT; addr_map_init(ct, &map); @@ -115,7 +128,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, * The "userinfo" and "@" components of the SIP URI MUST NOT * be present. */ - if (datalen >= sizeof("REGISTER") - 1 && + if (*datalen >= sizeof("REGISTER") - 1 && strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0) pos = POS_REG_REQ_URI; else @@ -136,51 +149,45 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, static unsigned int mangle_sip_packet(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, - const char **dptr, size_t dlen, + const char **dptr, unsigned int *datalen, char *buffer, int bufflen, enum sip_header_pos pos) { unsigned int matchlen, matchoff; - if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) - return 0; - - if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, - matchoff, matchlen, buffer, bufflen)) + if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, + pos) <= 0) return 0; - /* We need to reload this. Thanks Patrick. */ - *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr); - return 1; + return mangle_packet(skb, dptr, datalen, matchoff, matchlen, + buffer, bufflen); } static int mangle_content_len(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, - const char *dptr) + const char **dptr, unsigned int *datalen) { - unsigned int dataoff, matchoff, matchlen; + unsigned int matchoff, matchlen; char buffer[sizeof("65536")]; int bufflen; - dataoff = ip_hdrlen(skb) + sizeof(struct udphdr); - /* Get actual SDP length */ - if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff, + if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, POS_SDP_HEADER) > 0) { /* since ct_sip_get_info() give us a pointer passing 'v=' we need to add 2 bytes in this count. */ - int c_len = skb->len - dataoff - matchoff + 2; + int c_len = *datalen - matchoff + 2; /* Now, update SDP length */ - if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff, + if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, POS_CONTENT) > 0) { bufflen = sprintf(buffer, "%u", c_len); - return nf_nat_mangle_udp_packet(skb, ct, ctinfo, - matchoff, matchlen, - buffer, bufflen); + return mangle_packet(skb, dptr, datalen, + matchoff, matchlen, + buffer, bufflen); } } return 0; @@ -190,30 +197,28 @@ static unsigned int mangle_sdp(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, __be32 newip, u_int16_t port, - const char *dptr) + const char **dptr, unsigned int *datalen) { char buffer[sizeof("nnn.nnn.nnn.nnn")]; - unsigned int dataoff, bufflen; - - dataoff = ip_hdrlen(skb) + sizeof(struct udphdr); + unsigned int bufflen; /* Mangle owner and contact info. */ bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); - if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff, + if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen, buffer, bufflen, POS_OWNER_IP4)) return 0; - if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff, + if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen, buffer, bufflen, POS_CONNECTION_IP4)) return 0; /* Mangle media port. */ bufflen = sprintf(buffer, "%u", port); - if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff, + if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen, buffer, bufflen, POS_MEDIA)) return 0; - return mangle_content_len(skb, ctinfo, ct, dptr); + return mangle_content_len(skb, ctinfo, ct, dptr, datalen); } static void ip_nat_sdp_expect(struct nf_conn *ct, @@ -242,7 +247,7 @@ static void ip_nat_sdp_expect(struct nf_conn *ct, static unsigned int ip_nat_sdp(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conntrack_expect *exp, - const char *dptr) + const char **dptr, unsigned int *datalen) { struct nf_conn *ct = exp->master; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); @@ -275,7 +280,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, if (port == 0) return NF_DROP; - if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr)) { + if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) { nf_ct_unexpect_related(exp); return NF_DROP; } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 016e1c1aafe4..fa0d5599ff24 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -39,13 +39,15 @@ MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conn *ct, - const char **dptr) __read_mostly; + const char **dptr, + unsigned int *datalen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sip_hook); unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, enum ip_conntrack_info ctinfo, struct nf_conntrack_expect *exp, - const char *dptr) __read_mostly; + const char **dptr, + unsigned int *datalen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); static int digits_len(const struct nf_conn *, const char *, const char *, int *); @@ -369,7 +371,7 @@ static int set_expected_rtp(struct sk_buff *skb, enum ip_conntrack_info ctinfo, union nf_inet_addr *addr, __be16 port, - const char *dptr) + const char **dptr, unsigned int *datalen) { struct nf_conntrack_expect *exp; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); @@ -386,7 +388,7 @@ static int set_expected_rtp(struct sk_buff *skb, nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); if (nf_nat_sdp && ct->status & IPS_NAT_MASK) - ret = nf_nat_sdp(skb, ctinfo, exp, dptr); + ret = nf_nat_sdp(skb, ctinfo, exp, dptr, datalen); else { if (nf_ct_expect_related(exp) != 0) ret = NF_DROP; @@ -429,7 +431,7 @@ static int sip_help(struct sk_buff *skb, nf_nat_sip = rcu_dereference(nf_nat_sip_hook); if (nf_nat_sip && ct->status & IPS_NAT_MASK) { - if (!nf_nat_sip(skb, ctinfo, ct, &dptr)) { + if (!nf_nat_sip(skb, ctinfo, ct, &dptr, &datalen)) { ret = NF_DROP; goto out; } @@ -466,7 +468,7 @@ static int sip_help(struct sk_buff *skb, goto out; } ret = set_expected_rtp(skb, ct, ctinfo, &addr, - htons(port), dptr); + htons(port), &dptr, &datalen); } } out: -- cgit v1.2.3-59-g8ed1b From 212440a7d04a12ee13787afecc6c86c7fc4e6184 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:17:13 -0700 Subject: [NETFILTER]: nf_conntrack_sip: remove redundant function arguments The conntrack reference and ctinfo can be derived from the packet. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 7 ++--- net/ipv4/netfilter/nf_nat_sip.c | 49 +++++++++++++++--------------- net/netfilter/nf_conntrack_sip.c | 24 ++++++--------- 3 files changed, 37 insertions(+), 43 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 9d0dbfb26300..b94de3d60303 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -22,15 +22,12 @@ enum sip_header_pos { }; extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, const char **dptr, unsigned int *datalen); extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conntrack_expect *exp, const char **dptr, - unsigned int *datalen); + unsigned int *datalen, + struct nf_conntrack_expect *exp); extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, size_t dlen, unsigned int *matchoff, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index e77122e65283..acaa7d4569fa 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -78,11 +78,12 @@ static unsigned int mangle_packet(struct sk_buff *skb, return 1; } -static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo, - struct nf_conn *ct, +static int map_sip_addr(struct sk_buff *skb, const char **dptr, unsigned int *datalen, enum sip_header_pos pos, struct addr_map *map) { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); unsigned int matchlen, matchoff, addrlen; char *addr; @@ -109,10 +110,10 @@ static int map_sip_addr(struct sk_buff *skb, enum ip_conntrack_info ctinfo, } static unsigned int ip_nat_sip(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, const char **dptr, unsigned int *datalen) { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum sip_header_pos pos; struct addr_map map; @@ -134,25 +135,25 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, else pos = POS_REQ_URI; - if (!map_sip_addr(skb, ctinfo, ct, dptr, datalen, pos, &map)) + if (!map_sip_addr(skb, dptr, datalen, pos, &map)) return NF_DROP; } - if (!map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_FROM, &map) || - !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_TO, &map) || - !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_VIA, &map) || - !map_sip_addr(skb, ctinfo, ct, dptr, datalen, POS_CONTACT, &map)) + if (!map_sip_addr(skb, dptr, datalen, POS_FROM, &map) || + !map_sip_addr(skb, dptr, datalen, POS_TO, &map) || + !map_sip_addr(skb, dptr, datalen, POS_VIA, &map) || + !map_sip_addr(skb, dptr, datalen, POS_CONTACT, &map)) return NF_DROP; return NF_ACCEPT; } static unsigned int mangle_sip_packet(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, const char **dptr, unsigned int *datalen, char *buffer, int bufflen, enum sip_header_pos pos) { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchlen, matchoff; if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, @@ -164,10 +165,10 @@ static unsigned int mangle_sip_packet(struct sk_buff *skb, } static int mangle_content_len(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, const char **dptr, unsigned int *datalen) { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchoff, matchlen; char buffer[sizeof("65536")]; int bufflen; @@ -204,21 +205,21 @@ static unsigned int mangle_sdp(struct sk_buff *skb, /* Mangle owner and contact info. */ bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); - if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen, - buffer, bufflen, POS_OWNER_IP4)) + if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen, + POS_OWNER_IP4)) return 0; - if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen, - buffer, bufflen, POS_CONNECTION_IP4)) + if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen, + POS_CONNECTION_IP4)) return 0; /* Mangle media port. */ bufflen = sprintf(buffer, "%u", port); - if (!mangle_sip_packet(skb, ctinfo, ct, dptr, datalen, - buffer, bufflen, POS_MEDIA)) + if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen, + POS_MEDIA)) return 0; - return mangle_content_len(skb, ctinfo, ct, dptr, datalen); + return mangle_content_len(skb, dptr, datalen); } static void ip_nat_sdp_expect(struct nf_conn *ct, @@ -245,11 +246,11 @@ static void ip_nat_sdp_expect(struct nf_conn *ct, /* So, this packet has hit the connection tracking matching code. Mangle it, and change the expectation to match the new version. */ static unsigned int ip_nat_sdp(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conntrack_expect *exp, - const char **dptr, unsigned int *datalen) + const char **dptr, unsigned int *datalen, + struct nf_conntrack_expect *exp) { - struct nf_conn *ct = exp->master; + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); __be32 newip; u_int16_t port; diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index fa0d5599ff24..38e1e7a05334 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -37,17 +37,14 @@ module_param(sip_timeout, uint, 0600); MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, const char **dptr, unsigned int *datalen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sip_hook); unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conntrack_expect *exp, const char **dptr, - unsigned int *datalen) __read_mostly; + unsigned int *datalen, + struct nf_conntrack_expect *exp) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); static int digits_len(const struct nf_conn *, const char *, const char *, int *); @@ -367,13 +364,12 @@ int ct_sip_get_info(const struct nf_conn *ct, EXPORT_SYMBOL_GPL(ct_sip_get_info); static int set_expected_rtp(struct sk_buff *skb, - struct nf_conn *ct, - enum ip_conntrack_info ctinfo, - union nf_inet_addr *addr, - __be16 port, - const char **dptr, unsigned int *datalen) + const char **dptr, unsigned int *datalen, + union nf_inet_addr *addr, __be16 port) { struct nf_conntrack_expect *exp; + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); int family = ct->tuplehash[!dir].tuple.src.l3num; int ret; @@ -388,7 +384,7 @@ static int set_expected_rtp(struct sk_buff *skb, nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); if (nf_nat_sdp && ct->status & IPS_NAT_MASK) - ret = nf_nat_sdp(skb, ctinfo, exp, dptr, datalen); + ret = nf_nat_sdp(skb, dptr, datalen, exp); else { if (nf_ct_expect_related(exp) != 0) ret = NF_DROP; @@ -431,7 +427,7 @@ static int sip_help(struct sk_buff *skb, nf_nat_sip = rcu_dereference(nf_nat_sip_hook); if (nf_nat_sip && ct->status & IPS_NAT_MASK) { - if (!nf_nat_sip(skb, ctinfo, ct, &dptr, &datalen)) { + if (!nf_nat_sip(skb, &dptr, &datalen)) { ret = NF_DROP; goto out; } @@ -467,8 +463,8 @@ static int sip_help(struct sk_buff *skb, ret = NF_DROP; goto out; } - ret = set_expected_rtp(skb, ct, ctinfo, &addr, - htons(port), &dptr, &datalen); + ret = set_expected_rtp(skb, &dptr, &datalen, + &addr, htons(port)); } } out: -- cgit v1.2.3-59-g8ed1b From 779382eb324ad0c39f8c4d10a47a813b490ab82c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:17:36 -0700 Subject: [NETFILTER]: nf_conntrack_sip: use strlen/strcmp Replace sizeof/memcmp by strlen/strcmp. Use case-insensitive comparison for SIP methods and the SIP/2.0 string, as specified in RFC 3261. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/nf_nat_sip.c | 12 ++++++------ net/netfilter/nf_conntrack_sip.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index acaa7d4569fa..dd1b2d86deee 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -94,12 +94,12 @@ static int map_sip_addr(struct sk_buff *skb, if ((matchlen == map->addr[dir].srciplen || matchlen == map->addr[dir].srclen) && - memcmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { + strncmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { addr = map->addr[!dir].dst; addrlen = map->addr[!dir].dstlen; } else if ((matchlen == map->addr[dir].dstiplen || matchlen == map->addr[dir].dstlen) && - memcmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { + strncmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { addr = map->addr[!dir].src; addrlen = map->addr[!dir].srclen; } else @@ -117,20 +117,20 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, enum sip_header_pos pos; struct addr_map map; - if (*datalen < sizeof("SIP/2.0") - 1) + if (*datalen < strlen("SIP/2.0")) return NF_ACCEPT; addr_map_init(ct, &map); /* Basic rules: requests and responses. */ - if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 0) { + if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { /* 10.2: Constructing the REGISTER Request: * * The "userinfo" and "@" components of the SIP URI MUST NOT * be present. */ - if (*datalen >= sizeof("REGISTER") - 1 && - strncmp(*dptr, "REGISTER", sizeof("REGISTER") - 1) == 0) + if (*datalen >= strlen("REGISTER") && + strnicmp(*dptr, "REGISTER", strlen("REGISTER")) == 0) pos = POS_REG_REQ_URI; else pos = POS_REQ_URI; diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 38e1e7a05334..cf19a7082a75 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -434,15 +434,15 @@ static int sip_help(struct sk_buff *skb, } datalen = skb->len - dataoff; - if (datalen < sizeof("SIP/2.0 200") - 1) + if (datalen < strlen("SIP/2.0 200")) goto out; /* RTP info only in some SDP pkts */ - if (memcmp(dptr, "INVITE", sizeof("INVITE") - 1) != 0 && - memcmp(dptr, "UPDATE", sizeof("UPDATE") - 1) != 0 && - memcmp(dptr, "SIP/2.0 180", sizeof("SIP/2.0 180") - 1) != 0 && - memcmp(dptr, "SIP/2.0 183", sizeof("SIP/2.0 183") - 1) != 0 && - memcmp(dptr, "SIP/2.0 200", sizeof("SIP/2.0 200") - 1) != 0) { + if (strnicmp(dptr, "INVITE", strlen("INVITE")) != 0 && + strnicmp(dptr, "UPDATE", strlen("UPDATE")) != 0 && + strnicmp(dptr, "SIP/2.0 180", strlen("SIP/2.0 180")) != 0 && + strnicmp(dptr, "SIP/2.0 183", strlen("SIP/2.0 183")) != 0 && + strnicmp(dptr, "SIP/2.0 200", strlen("SIP/2.0 200")) != 0) { goto out; } /* Get address and port from SDP packet. */ -- cgit v1.2.3-59-g8ed1b From 3e9b4600b4e71beaa9d943251bfe9c25f6a97b8c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:17:55 -0700 Subject: [NETFILTER]: nf_conntrack_sip: add seperate SDP header parsing function SDP and SIP headers are quite different, SIP can have continuation lines, leading and trailing whitespace after the colon and is mostly case-insensitive while SDP headers always begin on a new line and are followed by an equal sign and the value, without any whitespace. Introduce new SDP header parsing function and convert all users that used the SIP header parsing function. This will allow to properly deal with the special SIP cases in the SIP header parsing function later. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 49 +++++++-- net/ipv4/netfilter/nf_nat_sip.c | 69 ++++++------- net/netfilter/nf_conntrack_sip.c | 159 +++++++++++++++++------------ 3 files changed, 169 insertions(+), 108 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index b94de3d60303..9131cbc9b9de 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -13,12 +13,42 @@ enum sip_header_pos { POS_VIA, POS_CONTACT, POS_CONTENT, - POS_MEDIA, - POS_OWNER_IP4, - POS_CONNECTION_IP4, - POS_OWNER_IP6, - POS_CONNECTION_IP6, - POS_SDP_HEADER, +}; + +struct sip_header { + const char *name; + const char *cname; + const char *search; + unsigned int len; + unsigned int clen; + unsigned int slen; + int (*match_len)(const struct nf_conn *ct, + const char *dptr, const char *limit, + int *shift); +}; + +#define __SIP_HDR(__name, __cname, __search, __match) \ +{ \ + .name = (__name), \ + .len = sizeof(__name) - 1, \ + .cname = (__cname), \ + .clen = (__cname) ? sizeof(__cname) - 1 : 0, \ + .search = (__search), \ + .slen = (__search) ? sizeof(__search) - 1 : 0, \ + .match_len = (__match), \ +} + +#define SDP_HDR(__name, __search, __match) \ + __SIP_HDR(__name, NULL, __search, __match) + +enum sdp_header_types { + SDP_HDR_UNSPEC, + SDP_HDR_VERSION, + SDP_HDR_OWNER_IP4, + SDP_HDR_CONNECTION_IP4, + SDP_HDR_OWNER_IP6, + SDP_HDR_CONNECTION_IP6, + SDP_HDR_MEDIA, }; extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, @@ -36,5 +66,12 @@ extern int ct_sip_lnlen(const char *line, const char *limit); extern const char *ct_sip_search(const char *needle, const char *haystack, size_t needle_len, size_t haystack_len, int case_sensitive); + +extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sdp_header_types type, + enum sdp_header_types term, + unsigned int *matchoff, unsigned int *matchlen); + #endif /* __KERNEL__ */ #endif /* __NF_CONNTRACK_SIP_H__ */ diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index dd1b2d86deee..aa8a4f492baf 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -147,51 +147,46 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, return NF_ACCEPT; } -static unsigned int mangle_sip_packet(struct sk_buff *skb, - const char **dptr, unsigned int *datalen, - char *buffer, int bufflen, - enum sip_header_pos pos) +static int mangle_content_len(struct sk_buff *skb, + const char **dptr, unsigned int *datalen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - unsigned int matchlen, matchoff; + unsigned int matchoff, matchlen; + char buffer[sizeof("65536")]; + int buflen, c_len; + /* Get actual SDP length */ + if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, + SDP_HDR_VERSION, SDP_HDR_UNSPEC, + &matchoff, &matchlen) <= 0) + return 0; + c_len = *datalen - matchoff + strlen("v="); + + /* Now, update SDP length */ if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, - pos) <= 0) + POS_CONTENT) <= 0) return 0; + buflen = sprintf(buffer, "%u", c_len); return mangle_packet(skb, dptr, datalen, matchoff, matchlen, - buffer, bufflen); + buffer, buflen); } -static int mangle_content_len(struct sk_buff *skb, - const char **dptr, unsigned int *datalen) +static unsigned mangle_sdp_packet(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + enum sdp_header_types type, + char *buffer, int buflen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - unsigned int matchoff, matchlen; - char buffer[sizeof("65536")]; - int bufflen; + unsigned int matchlen, matchoff; - /* Get actual SDP length */ - if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, - &matchlen, POS_SDP_HEADER) > 0) { - - /* since ct_sip_get_info() give us a pointer passing 'v=' - we need to add 2 bytes in this count. */ - int c_len = *datalen - matchoff + 2; - - /* Now, update SDP length */ - if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, - &matchlen, POS_CONTENT) > 0) { - - bufflen = sprintf(buffer, "%u", c_len); - return mangle_packet(skb, dptr, datalen, - matchoff, matchlen, - buffer, bufflen); - } - } - return 0; + if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, type, SDP_HDR_UNSPEC, + &matchoff, &matchlen) <= 0) + return 0; + return mangle_packet(skb, dptr, datalen, matchoff, matchlen, + buffer, buflen); } static unsigned int mangle_sdp(struct sk_buff *skb, @@ -205,18 +200,18 @@ static unsigned int mangle_sdp(struct sk_buff *skb, /* Mangle owner and contact info. */ bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); - if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen, - POS_OWNER_IP4)) + if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_OWNER_IP4, + buffer, bufflen)) return 0; - if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen, - POS_CONNECTION_IP4)) + if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_CONNECTION_IP4, + buffer, bufflen)) return 0; /* Mangle media port. */ bufflen = sprintf(buffer, "%u", port); - if (!mangle_sip_packet(skb, dptr, datalen, buffer, bufflen, - POS_MEDIA)) + if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_MEDIA, + buffer, bufflen)) return 0; return mangle_content_len(skb, dptr, datalen); diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index cf19a7082a75..801fcb3c749f 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -124,66 +124,6 @@ static const struct sip_header_nfo ct_sip_hdrs[] = { .ln_strlen = sizeof(":") - 1, .match_len = skp_digits_len }, - [POS_MEDIA] = { /* SDP media info */ - .case_sensitive = 1, - .lname = "\nm=", - .lnlen = sizeof("\nm=") - 1, - .sname = "\rm=", - .snlen = sizeof("\rm=") - 1, - .ln_str = "audio ", - .ln_strlen = sizeof("audio ") - 1, - .match_len = digits_len - }, - [POS_OWNER_IP4] = { /* SDP owner address*/ - .case_sensitive = 1, - .lname = "\no=", - .lnlen = sizeof("\no=") - 1, - .sname = "\ro=", - .snlen = sizeof("\ro=") - 1, - .ln_str = "IN IP4 ", - .ln_strlen = sizeof("IN IP4 ") - 1, - .match_len = epaddr_len - }, - [POS_CONNECTION_IP4] = {/* SDP connection info */ - .case_sensitive = 1, - .lname = "\nc=", - .lnlen = sizeof("\nc=") - 1, - .sname = "\rc=", - .snlen = sizeof("\rc=") - 1, - .ln_str = "IN IP4 ", - .ln_strlen = sizeof("IN IP4 ") - 1, - .match_len = epaddr_len - }, - [POS_OWNER_IP6] = { /* SDP owner address*/ - .case_sensitive = 1, - .lname = "\no=", - .lnlen = sizeof("\no=") - 1, - .sname = "\ro=", - .snlen = sizeof("\ro=") - 1, - .ln_str = "IN IP6 ", - .ln_strlen = sizeof("IN IP6 ") - 1, - .match_len = epaddr_len - }, - [POS_CONNECTION_IP6] = {/* SDP connection info */ - .case_sensitive = 1, - .lname = "\nc=", - .lnlen = sizeof("\nc=") - 1, - .sname = "\rc=", - .snlen = sizeof("\rc=") - 1, - .ln_str = "IN IP6 ", - .ln_strlen = sizeof("IN IP6 ") - 1, - .match_len = epaddr_len - }, - [POS_SDP_HEADER] = { /* SDP version header */ - .case_sensitive = 1, - .lname = "\nv=", - .lnlen = sizeof("\nv=") - 1, - .sname = "\rv=", - .snlen = sizeof("\rv=") - 1, - .ln_str = "=", - .ln_strlen = sizeof("=") - 1, - .match_len = digits_len - } }; /* get line length until first CR or LF seen. */ @@ -363,6 +303,92 @@ int ct_sip_get_info(const struct nf_conn *ct, } EXPORT_SYMBOL_GPL(ct_sip_get_info); +/* SDP header parsing: a SDP session description contains an ordered set of + * headers, starting with a section containing general session parameters, + * optionally followed by multiple media descriptions. + * + * SDP headers always start at the beginning of a line. According to RFC 2327: + * "The sequence CRLF (0x0d0a) is used to end a record, although parsers should + * be tolerant and also accept records terminated with a single newline + * character". We handle both cases. + */ +static const struct sip_header ct_sdp_hdrs[] = { + [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len), + [SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", epaddr_len), + [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len), + [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len), + [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len), + [SDP_HDR_MEDIA] = SDP_HDR("m=", "audio ", digits_len), +}; + +/* Linear string search within SDP header values */ +static const char *ct_sdp_header_search(const char *dptr, const char *limit, + const char *needle, unsigned int len) +{ + for (limit -= len; dptr < limit; dptr++) { + if (*dptr == '\r' || *dptr == '\n') + break; + if (strncmp(dptr, needle, len) == 0) + return dptr; + } + return NULL; +} + +/* Locate a SDP header (optionally a substring within the header value), + * optionally stopping at the first occurence of the term header, parse + * it and return the offset and length of the data we're interested in. + */ +int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sdp_header_types type, + enum sdp_header_types term, + unsigned int *matchoff, unsigned int *matchlen) +{ + const struct sip_header *hdr = &ct_sdp_hdrs[type]; + const struct sip_header *thdr = &ct_sdp_hdrs[term]; + const char *start = dptr, *limit = dptr + datalen; + int shift = 0; + + for (dptr += dataoff; dptr < limit; dptr++) { + /* Find beginning of line */ + if (*dptr != '\r' && *dptr != '\n') + continue; + if (++dptr >= limit) + break; + if (*(dptr - 1) == '\r' && *dptr == '\n') { + if (++dptr >= limit) + break; + } + + if (term != SDP_HDR_UNSPEC && + limit - dptr >= thdr->len && + strnicmp(dptr, thdr->name, thdr->len) == 0) + break; + else if (limit - dptr >= hdr->len && + strnicmp(dptr, hdr->name, hdr->len) == 0) + dptr += hdr->len; + else + continue; + + *matchoff = dptr - start; + if (hdr->search) { + dptr = ct_sdp_header_search(dptr, limit, hdr->search, + hdr->slen); + if (!dptr) + return -1; + dptr += hdr->slen; + } + + *matchlen = hdr->match_len(ct, dptr, limit, &shift); + if (!*matchlen) + return -1; + *matchoff = dptr - start + shift; + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header); + static int set_expected_rtp(struct sk_buff *skb, const char **dptr, unsigned int *datalen, union nf_inet_addr *addr, __be16 port) @@ -408,7 +434,7 @@ static int sip_help(struct sk_buff *skb, int ret = NF_ACCEPT; unsigned int matchoff, matchlen; u_int16_t port; - enum sip_header_pos pos; + enum sdp_header_types type; typeof(nf_nat_sip_hook) nf_nat_sip; /* No Data ? */ @@ -446,8 +472,10 @@ static int sip_help(struct sk_buff *skb, goto out; } /* Get address and port from SDP packet. */ - pos = family == AF_INET ? POS_CONNECTION_IP4 : POS_CONNECTION_IP6; - if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen, pos) > 0) { + type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : + SDP_HDR_CONNECTION_IP6; + if (ct_sip_get_sdp_header(ct, dptr, 0, datalen, type, SDP_HDR_UNSPEC, + &matchoff, &matchlen) > 0) { /* We'll drop only if there are parse problems. */ if (!parse_addr(ct, dptr + matchoff, NULL, &addr, @@ -455,8 +483,9 @@ static int sip_help(struct sk_buff *skb, ret = NF_DROP; goto out; } - if (ct_sip_get_info(ct, dptr, datalen, &matchoff, &matchlen, - POS_MEDIA) > 0) { + if (ct_sip_get_sdp_header(ct, dptr, 0, datalen, + SDP_HDR_MEDIA, SDP_HDR_UNSPEC, + &matchoff, &matchlen) > 0) { port = simple_strtoul(dptr + matchoff, NULL, 10); if (port < 1024) { -- cgit v1.2.3-59-g8ed1b From ac3677406d4e36e86b1eb5a453997a3b3e0c089a Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:18:40 -0700 Subject: [NETFILTER]: nf_conntrack_sip: kill request URI "header" definitions The request URI is not a header and needs to be treated differently than real SIP headers. Add a seperate function for parsing it and get rid of the POS_REQ_URI/POS_REG_REQ_URI definitions. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 5 ++- net/ipv4/netfilter/nf_nat_sip.c | 46 +++++++++++---------- net/netfilter/nf_conntrack_sip.c | 64 +++++++++++++++++++++++------- 3 files changed, 77 insertions(+), 38 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 9131cbc9b9de..480b26f40ce4 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -6,8 +6,6 @@ #define SIP_TIMEOUT 3600 enum sip_header_pos { - POS_REG_REQ_URI, - POS_REQ_URI, POS_FROM, POS_TO, POS_VIA, @@ -59,6 +57,9 @@ extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, unsigned int *datalen, struct nf_conntrack_expect *exp); +extern int ct_sip_parse_request(const struct nf_conn *ct, + const char *dptr, unsigned int datalen, + unsigned int *matchoff, unsigned int *matchlen); extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, size_t dlen, unsigned int *matchoff, unsigned int *matchlen, enum sip_header_pos pos); diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index aa8a4f492baf..60151b5901a5 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -78,20 +78,17 @@ static unsigned int mangle_packet(struct sk_buff *skb, return 1; } -static int map_sip_addr(struct sk_buff *skb, - const char **dptr, unsigned int *datalen, - enum sip_header_pos pos, struct addr_map *map) +static int map_addr(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int matchoff, unsigned int matchlen, + struct addr_map *map) { enum ip_conntrack_info ctinfo; - struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + struct nf_conn *ct __maybe_unused = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - unsigned int matchlen, matchoff, addrlen; + unsigned int addrlen; char *addr; - if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, - pos) <= 0) - return 1; - if ((matchlen == map->addr[dir].srciplen || matchlen == map->addr[dir].srclen) && strncmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { @@ -109,13 +106,27 @@ static int map_sip_addr(struct sk_buff *skb, addr, addrlen); } +static int map_sip_addr(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + enum sip_header_pos pos, struct addr_map *map) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchlen, matchoff; + + if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, + pos) <= 0) + return 1; + return map_addr(skb, dptr, datalen, matchoff, matchlen, map); +} + static unsigned int ip_nat_sip(struct sk_buff *skb, const char **dptr, unsigned int *datalen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - enum sip_header_pos pos; struct addr_map map; + unsigned int matchoff, matchlen; if (*datalen < strlen("SIP/2.0")) return NF_ACCEPT; @@ -124,18 +135,9 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, /* Basic rules: requests and responses. */ if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { - /* 10.2: Constructing the REGISTER Request: - * - * The "userinfo" and "@" components of the SIP URI MUST NOT - * be present. - */ - if (*datalen >= strlen("REGISTER") && - strnicmp(*dptr, "REGISTER", strlen("REGISTER")) == 0) - pos = POS_REG_REQ_URI; - else - pos = POS_REQ_URI; - - if (!map_sip_addr(skb, dptr, datalen, pos, &map)) + if (ct_sip_parse_request(ct, *dptr, *datalen, + &matchoff, &matchlen) > 0 && + !map_addr(skb, dptr, datalen, matchoff, matchlen, &map)) return NF_DROP; } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 801fcb3c749f..bb4396155681 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -65,20 +65,6 @@ struct sip_header_nfo { }; static const struct sip_header_nfo ct_sip_hdrs[] = { - [POS_REG_REQ_URI] = { /* SIP REGISTER request URI */ - .lname = "sip:", - .lnlen = sizeof("sip:") - 1, - .ln_str = ":", - .ln_strlen = sizeof(":") - 1, - .match_len = epaddr_len, - }, - [POS_REQ_URI] = { /* SIP request URI */ - .lname = "sip:", - .lnlen = sizeof("sip:") - 1, - .ln_str = "@", - .ln_strlen = sizeof("@") - 1, - .match_len = epaddr_len, - }, [POS_FROM] = { /* SIP From header */ .lname = "From:", .lnlen = sizeof("From:") - 1, @@ -164,6 +150,18 @@ const char *ct_sip_search(const char *needle, const char *haystack, } EXPORT_SYMBOL_GPL(ct_sip_search); +static int string_len(const struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +{ + int len = 0; + + while (dptr < limit && isalpha(*dptr)) { + dptr++; + len++; + } + return len; +} + static int digits_len(const struct nf_conn *ct, const char *dptr, const char *limit, int *shift) { @@ -258,6 +256,44 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, return epaddr_len(ct, dptr, limit, shift); } +/* Parse a SIP request line of the form: + * + * Request-Line = Method SP Request-URI SP SIP-Version CRLF + * + * and return the offset and length of the address contained in the Request-URI. + */ +int ct_sip_parse_request(const struct nf_conn *ct, + const char *dptr, unsigned int datalen, + unsigned int *matchoff, unsigned int *matchlen) +{ + const char *start = dptr, *limit = dptr + datalen; + unsigned int mlen; + int shift = 0; + + /* Skip method and following whitespace */ + mlen = string_len(ct, dptr, limit, NULL); + if (!mlen) + return 0; + dptr += mlen; + if (++dptr >= limit) + return 0; + + /* Find SIP URI */ + limit -= strlen("sip:"); + for (; dptr < limit; dptr++) { + if (*dptr == '\r' || *dptr == '\n') + return -1; + if (strnicmp(dptr, "sip:", strlen("sip:")) == 0) + break; + } + *matchlen = skp_epaddr_len(ct, dptr, limit, &shift); + if (!*matchlen) + return 0; + *matchoff = dptr - start + shift; + return 1; +} +EXPORT_SYMBOL_GPL(ct_sip_parse_request); + /* Returns 0 if not found, -1 error parsing. */ int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, size_t dlen, -- cgit v1.2.3-59-g8ed1b From ea45f12a2766dae54e5426a23e8f4bafdbe2782e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:18:57 -0700 Subject: [NETFILTER]: nf_conntrack_sip: parse SIP headers properly Introduce new function for SIP header parsing that properly deals with continuation lines and whitespace in headers and use it. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 30 ++-- net/ipv4/netfilter/nf_nat_sip.c | 18 +- net/netfilter/nf_conntrack_sip.c | 271 ++++++++++++++--------------- 3 files changed, 151 insertions(+), 168 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 480b26f40ce4..ccc701422963 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -5,14 +5,6 @@ #define SIP_PORT 5060 #define SIP_TIMEOUT 3600 -enum sip_header_pos { - POS_FROM, - POS_TO, - POS_VIA, - POS_CONTACT, - POS_CONTENT, -}; - struct sip_header { const char *name; const char *cname; @@ -36,9 +28,20 @@ struct sip_header { .match_len = (__match), \ } +#define SIP_HDR(__name, __cname, __search, __match) \ + __SIP_HDR(__name, __cname, __search, __match) + #define SDP_HDR(__name, __search, __match) \ __SIP_HDR(__name, NULL, __search, __match) +enum sip_header_types { + SIP_HDR_FROM, + SIP_HDR_TO, + SIP_HDR_CONTACT, + SIP_HDR_VIA, + SIP_HDR_CONTENT_LENGTH, +}; + enum sdp_header_types { SDP_HDR_UNSPEC, SDP_HDR_VERSION, @@ -60,13 +63,10 @@ extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, extern int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr, unsigned int datalen, unsigned int *matchoff, unsigned int *matchlen); -extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, - size_t dlen, unsigned int *matchoff, - unsigned int *matchlen, enum sip_header_pos pos); -extern int ct_sip_lnlen(const char *line, const char *limit); -extern const char *ct_sip_search(const char *needle, const char *haystack, - size_t needle_len, size_t haystack_len, - int case_sensitive); +extern int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sip_header_types type, + unsigned int *matchoff, unsigned int *matchlen); extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, unsigned int dataoff, unsigned int datalen, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 60151b5901a5..c13e43862361 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -108,14 +108,14 @@ static int map_addr(struct sk_buff *skb, static int map_sip_addr(struct sk_buff *skb, const char **dptr, unsigned int *datalen, - enum sip_header_pos pos, struct addr_map *map) + enum sip_header_types type, struct addr_map *map) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchlen, matchoff; - if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, - pos) <= 0) + if (ct_sip_get_header(ct, *dptr, 0, *datalen, type, + &matchoff, &matchlen) <= 0) return 1; return map_addr(skb, dptr, datalen, matchoff, matchlen, map); } @@ -141,10 +141,10 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, return NF_DROP; } - if (!map_sip_addr(skb, dptr, datalen, POS_FROM, &map) || - !map_sip_addr(skb, dptr, datalen, POS_TO, &map) || - !map_sip_addr(skb, dptr, datalen, POS_VIA, &map) || - !map_sip_addr(skb, dptr, datalen, POS_CONTACT, &map)) + if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM, &map) || + !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO, &map) || + !map_sip_addr(skb, dptr, datalen, SIP_HDR_VIA, &map) || + !map_sip_addr(skb, dptr, datalen, SIP_HDR_CONTACT, &map)) return NF_DROP; return NF_ACCEPT; } @@ -166,8 +166,8 @@ static int mangle_content_len(struct sk_buff *skb, c_len = *datalen - matchoff + strlen("v="); /* Now, update SDP length */ - if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, - POS_CONTENT) <= 0) + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH, + &matchoff, &matchlen) <= 0) return 0; buflen = sprintf(buffer, "%u", c_len); diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index bb4396155681..cbc91598acee 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -47,109 +47,6 @@ unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, struct nf_conntrack_expect *exp) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); -static int digits_len(const struct nf_conn *, const char *, const char *, int *); -static int epaddr_len(const struct nf_conn *, const char *, const char *, int *); -static int skp_digits_len(const struct nf_conn *, const char *, const char *, int *); -static int skp_epaddr_len(const struct nf_conn *, const char *, const char *, int *); - -struct sip_header_nfo { - const char *lname; - const char *sname; - const char *ln_str; - size_t lnlen; - size_t snlen; - size_t ln_strlen; - int case_sensitive; - int (*match_len)(const struct nf_conn *, const char *, - const char *, int *); -}; - -static const struct sip_header_nfo ct_sip_hdrs[] = { - [POS_FROM] = { /* SIP From header */ - .lname = "From:", - .lnlen = sizeof("From:") - 1, - .sname = "\r\nf:", - .snlen = sizeof("\r\nf:") - 1, - .ln_str = "sip:", - .ln_strlen = sizeof("sip:") - 1, - .match_len = skp_epaddr_len, - }, - [POS_TO] = { /* SIP To header */ - .lname = "To:", - .lnlen = sizeof("To:") - 1, - .sname = "\r\nt:", - .snlen = sizeof("\r\nt:") - 1, - .ln_str = "sip:", - .ln_strlen = sizeof("sip:") - 1, - .match_len = skp_epaddr_len - }, - [POS_VIA] = { /* SIP Via header */ - .lname = "Via:", - .lnlen = sizeof("Via:") - 1, - .sname = "\r\nv:", - .snlen = sizeof("\r\nv:") - 1, /* rfc3261 "\r\n" */ - .ln_str = "UDP ", - .ln_strlen = sizeof("UDP ") - 1, - .match_len = epaddr_len, - }, - [POS_CONTACT] = { /* SIP Contact header */ - .lname = "Contact:", - .lnlen = sizeof("Contact:") - 1, - .sname = "\r\nm:", - .snlen = sizeof("\r\nm:") - 1, - .ln_str = "sip:", - .ln_strlen = sizeof("sip:") - 1, - .match_len = skp_epaddr_len - }, - [POS_CONTENT] = { /* SIP Content length header */ - .lname = "Content-Length:", - .lnlen = sizeof("Content-Length:") - 1, - .sname = "\r\nl:", - .snlen = sizeof("\r\nl:") - 1, - .ln_str = ":", - .ln_strlen = sizeof(":") - 1, - .match_len = skp_digits_len - }, -}; - -/* get line length until first CR or LF seen. */ -int ct_sip_lnlen(const char *line, const char *limit) -{ - const char *k = line; - - while ((line < limit) && (*line == '\r' || *line == '\n')) - line++; - - while (line < limit) { - if (*line == '\r' || *line == '\n') - break; - line++; - } - return line - k; -} -EXPORT_SYMBOL_GPL(ct_sip_lnlen); - -/* Linear string search, case sensitive. */ -const char *ct_sip_search(const char *needle, const char *haystack, - size_t needle_len, size_t haystack_len, - int case_sensitive) -{ - const char *limit = haystack + (haystack_len - needle_len); - - while (haystack < limit) { - if (case_sensitive) { - if (strncmp(haystack, needle, needle_len) == 0) - return haystack; - } else { - if (strnicmp(haystack, needle, needle_len) == 0) - return haystack; - } - haystack++; - } - return NULL; -} -EXPORT_SYMBOL_GPL(ct_sip_search); - static int string_len(const struct nf_conn *ct, const char *dptr, const char *limit, int *shift) { @@ -173,16 +70,6 @@ static int digits_len(const struct nf_conn *ct, const char *dptr, return len; } -/* get digits length, skipping blank spaces. */ -static int skp_digits_len(const struct nf_conn *ct, const char *dptr, - const char *limit, int *shift) -{ - for (; dptr < limit && *dptr == ' '; dptr++) - (*shift)++; - - return digits_len(ct, dptr, limit, shift); -} - static int parse_addr(const struct nf_conn *ct, const char *cp, const char **endp, union nf_inet_addr *addr, const char *limit) @@ -294,50 +181,146 @@ int ct_sip_parse_request(const struct nf_conn *ct, } EXPORT_SYMBOL_GPL(ct_sip_parse_request); -/* Returns 0 if not found, -1 error parsing. */ -int ct_sip_get_info(const struct nf_conn *ct, - const char *dptr, size_t dlen, - unsigned int *matchoff, - unsigned int *matchlen, - enum sip_header_pos pos) +/* SIP header parsing: SIP headers are located at the beginning of a line, but + * may span several lines, in which case the continuation lines begin with a + * whitespace character. RFC 2543 allows lines to be terminated with CR, LF or + * CRLF, RFC 3261 allows only CRLF, we support both. + * + * Headers are followed by (optionally) whitespace, a colon, again (optionally) + * whitespace and the values. Whitespace in this context means any amount of + * tabs, spaces and continuation lines, which are treated as a single whitespace + * character. + */ +static const struct sip_header ct_sip_hdrs[] = { + [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len), + [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), + [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), + [SIP_HDR_VIA] = SIP_HDR("Via", "v", "UDP ", epaddr_len), + [SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len), +}; + +static const char *sip_follow_continuation(const char *dptr, const char *limit) { - const struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos]; - const char *limit, *aux, *k = dptr; - int shift = 0; + /* Walk past newline */ + if (++dptr >= limit) + return NULL; + + /* Skip '\n' in CR LF */ + if (*(dptr - 1) == '\r' && *dptr == '\n') { + if (++dptr >= limit) + return NULL; + } + + /* Continuation line? */ + if (*dptr != ' ' && *dptr != '\t') + return NULL; + + /* skip leading whitespace */ + for (; dptr < limit; dptr++) { + if (*dptr != ' ' && *dptr != '\t') + break; + } + return dptr; +} + +static const char *sip_skip_whitespace(const char *dptr, const char *limit) +{ + for (; dptr < limit; dptr++) { + if (*dptr == ' ') + continue; + if (*dptr != '\r' && *dptr != '\n') + break; + dptr = sip_follow_continuation(dptr, limit); + if (dptr == NULL) + return NULL; + } + return dptr; +} - limit = dptr + (dlen - hnfo->lnlen); +/* Search within a SIP header value, dealing with continuation lines */ +static const char *ct_sip_header_search(const char *dptr, const char *limit, + const char *needle, unsigned int len) +{ + for (limit -= len; dptr < limit; dptr++) { + if (*dptr == '\r' || *dptr == '\n') { + dptr = sip_follow_continuation(dptr, limit); + if (dptr == NULL) + break; + continue; + } - while (dptr < limit) { - if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && - (hnfo->sname == NULL || - strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { - dptr++; + if (strnicmp(dptr, needle, len) == 0) + return dptr; + } + return NULL; +} + +int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sip_header_types type, + unsigned int *matchoff, unsigned int *matchlen) +{ + const struct sip_header *hdr = &ct_sip_hdrs[type]; + const char *start = dptr, *limit = dptr + datalen; + int shift = 0; + + for (dptr += dataoff; dptr < limit; dptr++) { + /* Find beginning of line */ + if (*dptr != '\r' && *dptr != '\n') continue; + if (++dptr >= limit) + break; + if (*(dptr - 1) == '\r' && *dptr == '\n') { + if (++dptr >= limit) + break; } - aux = ct_sip_search(hnfo->ln_str, dptr, hnfo->ln_strlen, - ct_sip_lnlen(dptr, limit), - hnfo->case_sensitive); - if (!aux) { - pr_debug("'%s' not found in '%s'.\n", hnfo->ln_str, - hnfo->lname); - return -1; + + /* Skip continuation lines */ + if (*dptr == ' ' || *dptr == '\t') + continue; + + /* Find header. Compact headers must be followed by a + * non-alphabetic character to avoid mismatches. */ + if (limit - dptr >= hdr->len && + strnicmp(dptr, hdr->name, hdr->len) == 0) + dptr += hdr->len; + else if (hdr->cname && limit - dptr >= hdr->clen + 1 && + strnicmp(dptr, hdr->cname, hdr->clen) == 0 && + !isalpha(*(dptr + hdr->clen + 1))) + dptr += hdr->clen; + else + continue; + + /* Find and skip colon */ + dptr = sip_skip_whitespace(dptr, limit); + if (dptr == NULL) + break; + if (*dptr != ':' || ++dptr >= limit) + break; + + /* Skip whitespace after colon */ + dptr = sip_skip_whitespace(dptr, limit); + if (dptr == NULL) + break; + + *matchoff = dptr - start; + if (hdr->search) { + dptr = ct_sip_header_search(dptr, limit, hdr->search, + hdr->slen); + if (!dptr) + return -1; + dptr += hdr->slen; } - aux += hnfo->ln_strlen; - *matchlen = hnfo->match_len(ct, aux, limit, &shift); + *matchlen = hdr->match_len(ct, dptr, limit, &shift); if (!*matchlen) return -1; - - *matchoff = (aux - k) + shift; - - pr_debug("%s match succeeded! - len: %u\n", hnfo->lname, - *matchlen); + *matchoff = dptr - start + shift; return 1; } - pr_debug("%s header not found.\n", hnfo->lname); return 0; } -EXPORT_SYMBOL_GPL(ct_sip_get_info); +EXPORT_SYMBOL_GPL(ct_sip_get_header); /* SDP header parsing: a SDP session description contains an ordered set of * headers, starting with a section containing general session parameters, -- cgit v1.2.3-59-g8ed1b From 05e3ced297fe755093140e7487e292fb7603316e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:19:13 -0700 Subject: [NETFILTER]: nf_conntrack_sip: introduce SIP-URI parsing helper Introduce a helper function to parse a SIP-URI in a header value, optionally iterating through all headers of this kind. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 5 ++ net/netfilter/nf_conntrack_sip.c | 107 +++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index ccc701422963..87bc6f79efc4 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -67,6 +67,11 @@ extern int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, unsigned int dataoff, unsigned int datalen, enum sip_header_types type, unsigned int *matchoff, unsigned int *matchlen); +extern int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + unsigned int *dataoff, unsigned int datalen, + enum sip_header_types type, int *in_header, + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr, __be16 *port); extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, unsigned int dataoff, unsigned int datalen, diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index cbc91598acee..a74d76a97312 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -190,6 +190,9 @@ EXPORT_SYMBOL_GPL(ct_sip_parse_request); * whitespace and the values. Whitespace in this context means any amount of * tabs, spaces and continuation lines, which are treated as a single whitespace * character. + * + * Some headers may appear multiple times. A comma seperated list of values is + * equivalent to multiple headers. */ static const struct sip_header ct_sip_hdrs[] = { [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len), @@ -322,6 +325,110 @@ int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, } EXPORT_SYMBOL_GPL(ct_sip_get_header); +/* Get next header field in a list of comma seperated values */ +static int ct_sip_next_header(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sip_header_types type, + unsigned int *matchoff, unsigned int *matchlen) +{ + const struct sip_header *hdr = &ct_sip_hdrs[type]; + const char *start = dptr, *limit = dptr + datalen; + int shift = 0; + + dptr += dataoff; + + dptr = ct_sip_header_search(dptr, limit, ",", strlen(",")); + if (!dptr) + return 0; + + dptr = ct_sip_header_search(dptr, limit, hdr->search, hdr->slen); + if (!dptr) + return 0; + dptr += hdr->slen; + + *matchoff = dptr - start; + *matchlen = hdr->match_len(ct, dptr, limit, &shift); + if (!*matchlen) + return -1; + *matchoff += shift; + return 1; +} + +/* Walk through headers until a parsable one is found or no header of the + * given type is left. */ +static int ct_sip_walk_headers(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sip_header_types type, int *in_header, + unsigned int *matchoff, unsigned int *matchlen) +{ + int ret; + + if (in_header && *in_header) { + while (1) { + ret = ct_sip_next_header(ct, dptr, dataoff, datalen, + type, matchoff, matchlen); + if (ret > 0) + return ret; + if (ret == 0) + break; + dataoff += *matchoff; + } + *in_header = 0; + } + + while (1) { + ret = ct_sip_get_header(ct, dptr, dataoff, datalen, + type, matchoff, matchlen); + if (ret > 0) + break; + if (ret == 0) + return ret; + dataoff += *matchoff; + } + + if (in_header) + *in_header = 1; + return 1; +} + +/* Locate a SIP header, parse the URI and return the offset and length of + * the address as well as the address and port themselves. A stream of + * headers can be parsed by handing in a non-NULL datalen and in_header + * pointer. + */ +int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, + unsigned int *dataoff, unsigned int datalen, + enum sip_header_types type, int *in_header, + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr, __be16 *port) +{ + const char *c, *limit = dptr + datalen; + unsigned int p; + int ret; + + ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, + type, in_header, matchoff, matchlen); + WARN_ON(ret < 0); + if (ret == 0) + return ret; + + if (!parse_addr(ct, dptr + *matchoff, &c, addr, limit)) + return -1; + if (*c == ':') { + c++; + p = simple_strtoul(c, (char **)&c, 10); + if (p < 1024 || p > 65535) + return -1; + *port = htons(p); + } else + *port = htons(SIP_PORT); + + if (dataoff) + *dataoff = c - dptr; + return 1; +} +EXPORT_SYMBOL_GPL(ct_sip_parse_header_uri); + /* SDP header parsing: a SDP session description contains an ordered set of * headers, starting with a section containing general session parameters, * optionally followed by multiple media descriptions. -- cgit v1.2.3-59-g8ed1b From 624f8b7bba98c27a1464f5f858c4a861d5d3e8d7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:19:30 -0700 Subject: [NETFILTER]: nf_nat_sip: get rid of text based header translation Use the URI parsing helper to get the numerical addresses and get rid of the text based header translation. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 3 +- net/ipv4/netfilter/nf_nat_sip.c | 100 +++++++++++------------------ net/netfilter/nf_conntrack_sip.c | 27 ++++++-- 3 files changed, 62 insertions(+), 68 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 87bc6f79efc4..68a0d6a41733 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -62,7 +62,8 @@ extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, extern int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr, unsigned int datalen, - unsigned int *matchoff, unsigned int *matchlen); + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr, __be16 *port); extern int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, unsigned int dataoff, unsigned int datalen, enum sip_header_types type, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index c13e43862361..5b4a5cd23f39 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -26,39 +26,6 @@ MODULE_AUTHOR("Christian Hentschel "); MODULE_DESCRIPTION("SIP NAT helper"); MODULE_ALIAS("ip_nat_sip"); -struct addr_map { - struct { - char src[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; - char dst[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; - unsigned int srclen, srciplen; - unsigned int dstlen, dstiplen; - } addr[IP_CT_DIR_MAX]; -}; - -static void addr_map_init(const struct nf_conn *ct, struct addr_map *map) -{ - const struct nf_conntrack_tuple *t; - enum ip_conntrack_dir dir; - unsigned int n; - - for (dir = 0; dir < IP_CT_DIR_MAX; dir++) { - t = &ct->tuplehash[dir].tuple; - - n = sprintf(map->addr[dir].src, "%u.%u.%u.%u", - NIPQUAD(t->src.u3.ip)); - map->addr[dir].srciplen = n; - n += sprintf(map->addr[dir].src + n, ":%u", - ntohs(t->src.u.udp.port)); - map->addr[dir].srclen = n; - - n = sprintf(map->addr[dir].dst, "%u.%u.%u.%u", - NIPQUAD(t->dst.u3.ip)); - map->addr[dir].dstiplen = n; - n += sprintf(map->addr[dir].dst + n, ":%u", - ntohs(t->dst.u.udp.port)); - map->addr[dir].dstlen = n; - } -} static unsigned int mangle_packet(struct sk_buff *skb, const char **dptr, unsigned int *datalen, @@ -81,43 +48,51 @@ static unsigned int mangle_packet(struct sk_buff *skb, static int map_addr(struct sk_buff *skb, const char **dptr, unsigned int *datalen, unsigned int matchoff, unsigned int matchlen, - struct addr_map *map) + union nf_inet_addr *addr, __be16 port) { enum ip_conntrack_info ctinfo; - struct nf_conn *ct __maybe_unused = nf_ct_get(skb, &ctinfo); + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - unsigned int addrlen; - char *addr; - - if ((matchlen == map->addr[dir].srciplen || - matchlen == map->addr[dir].srclen) && - strncmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { - addr = map->addr[!dir].dst; - addrlen = map->addr[!dir].dstlen; - } else if ((matchlen == map->addr[dir].dstiplen || - matchlen == map->addr[dir].dstlen) && - strncmp(*dptr + matchoff, map->addr[dir].dst, matchlen) == 0) { - addr = map->addr[!dir].src; - addrlen = map->addr[!dir].srclen; + char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + unsigned int buflen; + __be32 newaddr; + __be16 newport; + + if (ct->tuplehash[dir].tuple.src.u3.ip == addr->ip && + ct->tuplehash[dir].tuple.src.u.udp.port == port) { + newaddr = ct->tuplehash[!dir].tuple.dst.u3.ip; + newport = ct->tuplehash[!dir].tuple.dst.u.udp.port; + } else if (ct->tuplehash[dir].tuple.dst.u3.ip == addr->ip && + ct->tuplehash[dir].tuple.dst.u.udp.port == port) { + newaddr = ct->tuplehash[!dir].tuple.src.u3.ip; + newport = ct->tuplehash[!dir].tuple.src.u.udp.port; } else return 1; + if (newaddr == addr->ip && newport == port) + return 1; + + buflen = sprintf(buffer, "%u.%u.%u.%u:%u", + NIPQUAD(newaddr), ntohs(newport)); + return mangle_packet(skb, dptr, datalen, matchoff, matchlen, - addr, addrlen); + buffer, buflen); } static int map_sip_addr(struct sk_buff *skb, const char **dptr, unsigned int *datalen, - enum sip_header_types type, struct addr_map *map) + enum sip_header_types type) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchlen, matchoff; + union nf_inet_addr addr; + __be16 port; - if (ct_sip_get_header(ct, *dptr, 0, *datalen, type, - &matchoff, &matchlen) <= 0) + if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL, + &matchoff, &matchlen, &addr, &port) <= 0) return 1; - return map_addr(skb, dptr, datalen, matchoff, matchlen, map); + return map_addr(skb, dptr, datalen, matchoff, matchlen, &addr, port); } static unsigned int ip_nat_sip(struct sk_buff *skb, @@ -125,26 +100,27 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - struct addr_map map; unsigned int matchoff, matchlen; + union nf_inet_addr addr; + __be16 port; if (*datalen < strlen("SIP/2.0")) return NF_ACCEPT; - addr_map_init(ct, &map); - /* Basic rules: requests and responses. */ if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { if (ct_sip_parse_request(ct, *dptr, *datalen, - &matchoff, &matchlen) > 0 && - !map_addr(skb, dptr, datalen, matchoff, matchlen, &map)) + &matchoff, &matchlen, + &addr, &port) > 0 && + !map_addr(skb, dptr, datalen, matchoff, matchlen, + &addr, port)) return NF_DROP; } - if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM, &map) || - !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO, &map) || - !map_sip_addr(skb, dptr, datalen, SIP_HDR_VIA, &map) || - !map_sip_addr(skb, dptr, datalen, SIP_HDR_CONTACT, &map)) + if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM) || + !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO) || + !map_sip_addr(skb, dptr, datalen, SIP_HDR_VIA) || + !map_sip_addr(skb, dptr, datalen, SIP_HDR_CONTACT)) return NF_DROP; return NF_ACCEPT; } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index a74d76a97312..f20fa2d94c0a 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -151,10 +151,12 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, */ int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr, unsigned int datalen, - unsigned int *matchoff, unsigned int *matchlen) + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr, __be16 *port) { - const char *start = dptr, *limit = dptr + datalen; + const char *start = dptr, *limit = dptr + datalen, *end; unsigned int mlen; + unsigned int p; int shift = 0; /* Skip method and following whitespace */ @@ -173,10 +175,25 @@ int ct_sip_parse_request(const struct nf_conn *ct, if (strnicmp(dptr, "sip:", strlen("sip:")) == 0) break; } - *matchlen = skp_epaddr_len(ct, dptr, limit, &shift); - if (!*matchlen) + if (!skp_epaddr_len(ct, dptr, limit, &shift)) return 0; - *matchoff = dptr - start + shift; + dptr += shift; + + if (!parse_addr(ct, dptr, &end, addr, limit)) + return -1; + if (end < limit && *end == ':') { + end++; + p = simple_strtoul(end, (char **)&end, 10); + if (p < 1024 || p > 65535) + return -1; + *port = htons(p); + } else + *port = htons(SIP_PORT); + + if (end == dptr) + return 0; + *matchoff = dptr - start; + *matchlen = end - dptr; return 1; } EXPORT_SYMBOL_GPL(ct_sip_parse_request); -- cgit v1.2.3-59-g8ed1b From 7d3dd043b69b10f5abe9c785ab82cc6627898fcd Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:19:46 -0700 Subject: [NETFILTER]: nf_conntrack_sip: move SDP parsing to seperate function Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_sip.c | 84 ++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 41 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index f20fa2d94c0a..96bedb52bd4b 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -565,19 +565,49 @@ static int set_expected_rtp(struct sk_buff *skb, return ret; } +static int process_sdp(struct sk_buff *skb, + const char **dptr, unsigned int *datalen) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + unsigned int matchoff, matchlen; + union nf_inet_addr addr; + unsigned int port; + enum sdp_header_types type; + + /* Get address and port from SDP packet. */ + type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : + SDP_HDR_CONNECTION_IP6; + + if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, + type, SDP_HDR_UNSPEC, + &matchoff, &matchlen) <= 0) + return NF_ACCEPT; + + /* We'll drop only if there are parse problems. */ + if (!parse_addr(ct, *dptr + matchoff, NULL, &addr, *dptr + *datalen)) + return NF_DROP; + + if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, + SDP_HDR_MEDIA, SDP_HDR_UNSPEC, + &matchoff, &matchlen) <= 0) + return NF_ACCEPT; + + port = simple_strtoul(*dptr + matchoff, NULL, 10); + if (port < 1024 || port > 65535) + return NF_DROP; + + return set_expected_rtp(skb, dptr, datalen, &addr, htons(port)); +} + static int sip_help(struct sk_buff *skb, unsigned int protoff, struct nf_conn *ct, enum ip_conntrack_info ctinfo) { - int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; - union nf_inet_addr addr; unsigned int dataoff, datalen; const char *dptr; - int ret = NF_ACCEPT; - unsigned int matchoff, matchlen; - u_int16_t port; - enum sdp_header_types type; typeof(nf_nat_sip_hook) nf_nat_sip; /* No Data ? */ @@ -591,56 +621,28 @@ static int sip_help(struct sk_buff *skb, dptr = skb->data + dataoff; else { pr_debug("Copy of skbuff not supported yet.\n"); - goto out; + return NF_ACCEPT; } nf_nat_sip = rcu_dereference(nf_nat_sip_hook); if (nf_nat_sip && ct->status & IPS_NAT_MASK) { - if (!nf_nat_sip(skb, &dptr, &datalen)) { - ret = NF_DROP; - goto out; - } + if (!nf_nat_sip(skb, &dptr, &datalen)) + return NF_DROP; } datalen = skb->len - dataoff; if (datalen < strlen("SIP/2.0 200")) - goto out; + return NF_ACCEPT; /* RTP info only in some SDP pkts */ if (strnicmp(dptr, "INVITE", strlen("INVITE")) != 0 && strnicmp(dptr, "UPDATE", strlen("UPDATE")) != 0 && strnicmp(dptr, "SIP/2.0 180", strlen("SIP/2.0 180")) != 0 && strnicmp(dptr, "SIP/2.0 183", strlen("SIP/2.0 183")) != 0 && - strnicmp(dptr, "SIP/2.0 200", strlen("SIP/2.0 200")) != 0) { - goto out; - } - /* Get address and port from SDP packet. */ - type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : - SDP_HDR_CONNECTION_IP6; - if (ct_sip_get_sdp_header(ct, dptr, 0, datalen, type, SDP_HDR_UNSPEC, - &matchoff, &matchlen) > 0) { + strnicmp(dptr, "SIP/2.0 200", strlen("SIP/2.0 200")) != 0) + return NF_ACCEPT; - /* We'll drop only if there are parse problems. */ - if (!parse_addr(ct, dptr + matchoff, NULL, &addr, - dptr + datalen)) { - ret = NF_DROP; - goto out; - } - if (ct_sip_get_sdp_header(ct, dptr, 0, datalen, - SDP_HDR_MEDIA, SDP_HDR_UNSPEC, - &matchoff, &matchlen) > 0) { - - port = simple_strtoul(dptr + matchoff, NULL, 10); - if (port < 1024) { - ret = NF_DROP; - goto out; - } - ret = set_expected_rtp(skb, &dptr, &datalen, - &addr, htons(port)); - } - } -out: - return ret; + return process_sdp(skb, &dptr, &datalen); } static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; -- cgit v1.2.3-59-g8ed1b From 30f33e6dee80c6ded917f978e4f377d1069d519d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:22:20 -0700 Subject: [NETFILTER]: nf_conntrack_sip: support method specific request/response handling Add support for per-method request/response handlers and perform SDP parsing for INVITE/UPDATE requests and for all informational and successful responses. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 20 ++++++ net/netfilter/nf_conntrack_sip.c | 107 ++++++++++++++++++++++++++--- 2 files changed, 117 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 68a0d6a41733..da93e80804c2 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -5,6 +5,25 @@ #define SIP_PORT 5060 #define SIP_TIMEOUT 3600 +struct sip_handler { + const char *method; + unsigned int len; + int (*request)(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq); + int (*response)(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq, unsigned int code); +}; + +#define SIP_HANDLER(__method, __request, __response) \ +{ \ + .method = (__method), \ + .len = sizeof(__method) - 1, \ + .request = (__request), \ + .response = (__response), \ +} + struct sip_header { const char *name; const char *cname; @@ -35,6 +54,7 @@ struct sip_header { __SIP_HDR(__name, NULL, __search, __match) enum sip_header_types { + SIP_HDR_CSEQ, SIP_HDR_FROM, SIP_HDR_TO, SIP_HDR_CONTACT, diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 96bedb52bd4b..1be949febab7 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -212,6 +212,7 @@ EXPORT_SYMBOL_GPL(ct_sip_parse_request); * equivalent to multiple headers. */ static const struct sip_header ct_sip_hdrs[] = { + [SIP_HDR_CSEQ] = SIP_HDR("CSeq", NULL, NULL, digits_len), [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len), [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), @@ -566,7 +567,8 @@ static int set_expected_rtp(struct sk_buff *skb, } static int process_sdp(struct sk_buff *skb, - const char **dptr, unsigned int *datalen) + const char **dptr, unsigned int *datalen, + unsigned int cseq) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); @@ -600,6 +602,96 @@ static int process_sdp(struct sk_buff *skb, return set_expected_rtp(skb, dptr, datalen, &addr, htons(port)); } +static int process_invite_response(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq, unsigned int code) +{ + if ((code >= 100 && code <= 199) || + (code >= 200 && code <= 299)) + return process_sdp(skb, dptr, datalen, cseq); + + return NF_ACCEPT; +} + +static int process_update_response(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq, unsigned int code) +{ + if ((code >= 100 && code <= 199) || + (code >= 200 && code <= 299)) + return process_sdp(skb, dptr, datalen, cseq); + + return NF_ACCEPT; +} + +static const struct sip_handler sip_handlers[] = { + SIP_HANDLER("INVITE", process_sdp, process_invite_response), + SIP_HANDLER("UPDATE", process_sdp, process_update_response), +}; + +static int process_sip_response(struct sk_buff *skb, + const char **dptr, unsigned int *datalen) +{ + static const struct sip_handler *handler; + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchoff, matchlen; + unsigned int code, cseq, dataoff, i; + + if (*datalen < strlen("SIP/2.0 200")) + return NF_ACCEPT; + code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); + if (!code) + return NF_DROP; + + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ, + &matchoff, &matchlen) <= 0) + return NF_DROP; + cseq = simple_strtoul(*dptr + matchoff, NULL, 10); + if (!cseq) + return NF_DROP; + dataoff = matchoff + matchlen + 1; + + for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { + handler = &sip_handlers[i]; + if (handler->response == NULL) + continue; + if (*datalen < dataoff + handler->len || + strnicmp(*dptr + dataoff, handler->method, handler->len)) + continue; + return handler->response(skb, dptr, datalen, cseq, code); + } + return NF_ACCEPT; +} + +static int process_sip_request(struct sk_buff *skb, + const char **dptr, unsigned int *datalen) +{ + static const struct sip_handler *handler; + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchoff, matchlen; + unsigned int cseq, i; + + for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { + handler = &sip_handlers[i]; + if (handler->request == NULL) + continue; + if (*datalen < handler->len || + strnicmp(*dptr, handler->method, handler->len)) + continue; + + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ, + &matchoff, &matchlen) <= 0) + return NF_DROP; + cseq = simple_strtoul(*dptr + matchoff, NULL, 10); + if (!cseq) + return NF_DROP; + + return handler->request(skb, dptr, datalen, cseq); + } + return NF_ACCEPT; +} static int sip_help(struct sk_buff *skb, unsigned int protoff, @@ -634,15 +726,10 @@ static int sip_help(struct sk_buff *skb, if (datalen < strlen("SIP/2.0 200")) return NF_ACCEPT; - /* RTP info only in some SDP pkts */ - if (strnicmp(dptr, "INVITE", strlen("INVITE")) != 0 && - strnicmp(dptr, "UPDATE", strlen("UPDATE")) != 0 && - strnicmp(dptr, "SIP/2.0 180", strlen("SIP/2.0 180")) != 0 && - strnicmp(dptr, "SIP/2.0 183", strlen("SIP/2.0 183")) != 0 && - strnicmp(dptr, "SIP/2.0 200", strlen("SIP/2.0 200")) != 0) - return NF_ACCEPT; - - return process_sdp(skb, &dptr, &datalen); + if (strnicmp(dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) + return process_sip_request(skb, &dptr, &datalen); + else + return process_sip_response(skb, &dptr, &datalen); } static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; -- cgit v1.2.3-59-g8ed1b From 33cb1e9a93312f0cdd34e0be2bc88e893ff96a33 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:22:37 -0700 Subject: [NETFILTER]: nf_conntrack_sip: perform NAT after parsing Perform NAT last after parsing the packet. This makes no difference currently, but is needed when dealing with registrations to make sure we seen the unNATed addresses. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/nf_nat_sip.c | 3 --- net/netfilter/nf_conntrack_sip.c | 19 +++++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 5b4a5cd23f39..b44281011d6d 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -104,9 +104,6 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, union nf_inet_addr addr; __be16 port; - if (*datalen < strlen("SIP/2.0")) - return NF_ACCEPT; - /* Basic rules: requests and responses. */ if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { if (ct_sip_parse_request(ct, *dptr, *datalen, diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 1be949febab7..29a37d212695 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -700,6 +700,7 @@ static int sip_help(struct sk_buff *skb, { unsigned int dataoff, datalen; const char *dptr; + int ret; typeof(nf_nat_sip_hook) nf_nat_sip; /* No Data ? */ @@ -716,20 +717,22 @@ static int sip_help(struct sk_buff *skb, return NF_ACCEPT; } - nf_nat_sip = rcu_dereference(nf_nat_sip_hook); - if (nf_nat_sip && ct->status & IPS_NAT_MASK) { - if (!nf_nat_sip(skb, &dptr, &datalen)) - return NF_DROP; - } - datalen = skb->len - dataoff; if (datalen < strlen("SIP/2.0 200")) return NF_ACCEPT; if (strnicmp(dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) - return process_sip_request(skb, &dptr, &datalen); + ret = process_sip_request(skb, &dptr, &datalen); else - return process_sip_response(skb, &dptr, &datalen); + ret = process_sip_response(skb, &dptr, &datalen); + + if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { + nf_nat_sip = rcu_dereference(nf_nat_sip_hook); + if (nf_nat_sip && !nf_nat_sip(skb, &dptr, &datalen)) + ret = NF_DROP; + } + + return ret; } static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; -- cgit v1.2.3-59-g8ed1b From 595a8ecb5fa41295a7010678b60cb2f7ab15fe42 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:22:53 -0700 Subject: [NETFILTER]: nf_conntrack_sip: process ACK and PRACK methods Both may contains SDP offers/answers. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_sip.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 29a37d212695..71f744ad7653 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -624,9 +624,22 @@ static int process_update_response(struct sk_buff *skb, return NF_ACCEPT; } +static int process_prack_response(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq, unsigned int code) +{ + if ((code >= 100 && code <= 199) || + (code >= 200 && code <= 299)) + return process_sdp(skb, dptr, datalen, cseq); + + return NF_ACCEPT; +} + static const struct sip_handler sip_handlers[] = { SIP_HANDLER("INVITE", process_sdp, process_invite_response), SIP_HANDLER("UPDATE", process_sdp, process_update_response), + SIP_HANDLER("ACK", process_sdp, NULL), + SIP_HANDLER("PRACK", process_sdp, process_prack_response), }; static int process_sip_response(struct sk_buff *skb, -- cgit v1.2.3-59-g8ed1b From 9467ee380ae881443bc259fbbac9992baf523e2d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:24:04 -0700 Subject: [NETFILTER]: nf_conntrack_sip: flush expectations on call termination Flush the RTP expectations we've created when a call is hung up or terminated otherwise. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_sip.c | 52 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 71f744ad7653..8e7e5b465ffb 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -533,6 +534,22 @@ int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, } EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header); +static void flush_expectations(struct nf_conn *ct) +{ + struct nf_conn_help *help = nfct_help(ct); + struct nf_conntrack_expect *exp; + struct hlist_node *n, *next; + + spin_lock_bh(&nf_conntrack_lock); + hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { + if (!del_timer(&exp->timeout)) + continue; + nf_ct_unlink_expect(exp); + nf_ct_expect_put(exp); + } + spin_unlock_bh(&nf_conntrack_lock); +} + static int set_expected_rtp(struct sk_buff *skb, const char **dptr, unsigned int *datalen, union nf_inet_addr *addr, __be16 port) @@ -606,32 +623,58 @@ static int process_invite_response(struct sk_buff *skb, const char **dptr, unsigned int *datalen, unsigned int cseq, unsigned int code) { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + if ((code >= 100 && code <= 199) || (code >= 200 && code <= 299)) return process_sdp(skb, dptr, datalen, cseq); - - return NF_ACCEPT; + else { + flush_expectations(ct); + return NF_ACCEPT; + } } static int process_update_response(struct sk_buff *skb, const char **dptr, unsigned int *datalen, unsigned int cseq, unsigned int code) { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + if ((code >= 100 && code <= 199) || (code >= 200 && code <= 299)) return process_sdp(skb, dptr, datalen, cseq); - - return NF_ACCEPT; + else { + flush_expectations(ct); + return NF_ACCEPT; + } } static int process_prack_response(struct sk_buff *skb, const char **dptr, unsigned int *datalen, unsigned int cseq, unsigned int code) { + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + if ((code >= 100 && code <= 199) || (code >= 200 && code <= 299)) return process_sdp(skb, dptr, datalen, cseq); + else { + flush_expectations(ct); + return NF_ACCEPT; + } +} + +static int process_bye_request(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + flush_expectations(ct); return NF_ACCEPT; } @@ -640,6 +683,7 @@ static const struct sip_handler sip_handlers[] = { SIP_HANDLER("UPDATE", process_sdp, process_update_response), SIP_HANDLER("ACK", process_sdp, NULL), SIP_HANDLER("PRACK", process_sdp, process_prack_response), + SIP_HANDLER("BYE", process_bye_request, NULL), }; static int process_sip_response(struct sk_buff *skb, -- cgit v1.2.3-59-g8ed1b From 2bbb21168a90c788e12fe722eb66f27e611e7df7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:24:24 -0700 Subject: [NETFILTER]: nf_conntrack_sip: introduce URI and header parameter parsing helpers Introduce URI and header parameter parsing helpers. These are needed by the conntrack helper to parse expiration values in Contact: header parameters and by the NAT helper to properly update the Via-header rport=, received= and maddr= parameters. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 10 ++++++ net/netfilter/nf_conntrack_sip.c | 58 ++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index da93e80804c2..87e402825dba 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -93,6 +93,16 @@ extern int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, enum sip_header_types type, int *in_header, unsigned int *matchoff, unsigned int *matchlen, union nf_inet_addr *addr, __be16 *port); +extern int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + const char *name, + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr); +extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, + unsigned int off, unsigned int datalen, + const char *name, + unsigned int *matchoff, unsigned int *matchen, + unsigned int *val); extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, unsigned int dataoff, unsigned int datalen, diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 8e7e5b465ffb..126f30842d60 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -448,6 +448,64 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, } EXPORT_SYMBOL_GPL(ct_sip_parse_header_uri); +/* Parse address from header parameter and return address, offset and length */ +int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + const char *name, + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr) +{ + const char *limit = dptr + datalen; + const char *start, *end; + + limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(",")); + if (!limit) + limit = dptr + datalen; + + start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name)); + if (!start) + return 0; + + start += strlen(name); + if (!parse_addr(ct, start, &end, addr, limit)) + return 0; + *matchoff = start - dptr; + *matchlen = end - start; + return 1; +} +EXPORT_SYMBOL_GPL(ct_sip_parse_address_param); + +/* Parse numerical header parameter and return value, offset and length */ +int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + const char *name, + unsigned int *matchoff, unsigned int *matchlen, + unsigned int *val) +{ + const char *limit = dptr + datalen; + const char *start; + char *end; + + limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(",")); + if (!limit) + limit = dptr + datalen; + + start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name)); + if (!start) + return 0; + + start += strlen(name); + *val = simple_strtoul(start, &end, 0); + if (start == end) + return 0; + if (matchoff && matchlen) { + *matchoff = start - dptr; + *matchlen = end - start; + } + return 1; +} +EXPORT_SYMBOL_GPL(ct_sip_parse_numerical_param); + /* SDP header parsing: a SDP session description contains an ordered set of * headers, starting with a section containing general session parameters, * optionally followed by multiple media descriptions. -- cgit v1.2.3-59-g8ed1b From 720ac7085ce815ea4caec24396575fed7bd711aa Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:24:41 -0700 Subject: [NETFILTER]: nf_nat_sip: translate all Via headers Update maddr=, received= and rport= Via-header parameters refering to the signalling connection. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/nf_nat_sip.c | 74 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index b44281011d6d..71a4adcfd576 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -100,9 +100,11 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); unsigned int matchoff, matchlen; union nf_inet_addr addr; __be16 port; + int request; /* Basic rules: requests and responses. */ if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { @@ -112,11 +114,81 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, !map_addr(skb, dptr, datalen, matchoff, matchlen, &addr, port)) return NF_DROP; + request = 1; + } else + request = 0; + + /* Translate topmost Via header and parameters */ + if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, + SIP_HDR_VIA, NULL, &matchoff, &matchlen, + &addr, &port) > 0) { + unsigned int matchend, poff, plen, buflen, n; + char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + + /* We're only interested in headers related to this + * connection */ + if (request) { + if (addr.ip != ct->tuplehash[dir].tuple.src.u3.ip || + port != ct->tuplehash[dir].tuple.src.u.udp.port) + goto next; + } else { + if (addr.ip != ct->tuplehash[dir].tuple.dst.u3.ip || + port != ct->tuplehash[dir].tuple.dst.u.udp.port) + goto next; + } + + if (!map_addr(skb, dptr, datalen, matchoff, matchlen, + &addr, port)) + return NF_DROP; + + matchend = matchoff + matchlen; + + /* The maddr= parameter (RFC 2361) specifies where to send + * the reply. */ + if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, + "maddr=", &poff, &plen, + &addr) > 0 && + addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && + addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) { + __be32 ip = ct->tuplehash[!dir].tuple.dst.u3.ip; + buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip)); + if (!mangle_packet(skb, dptr, datalen, poff, plen, + buffer, buflen)) + return NF_DROP; + } + + /* The received= parameter (RFC 2361) contains the address + * from which the server received the request. */ + if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, + "received=", &poff, &plen, + &addr) > 0 && + addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && + addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { + __be32 ip = ct->tuplehash[!dir].tuple.src.u3.ip; + buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip)); + if (!mangle_packet(skb, dptr, datalen, poff, plen, + buffer, buflen)) + return NF_DROP; + } + + /* The rport= parameter (RFC 3581) contains the port number + * from which the server received the request. */ + if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, + "rport=", &poff, &plen, + &n) > 0 && + htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && + htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { + __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; + buflen = sprintf(buffer, "%u", ntohs(p)); + if (!mangle_packet(skb, dptr, datalen, poff, plen, + buffer, buflen)) + return NF_DROP; + } } +next: if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM) || !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO) || - !map_sip_addr(skb, dptr, datalen, SIP_HDR_VIA) || !map_sip_addr(skb, dptr, datalen, SIP_HDR_CONTACT)) return NF_DROP; return NF_ACCEPT; -- cgit v1.2.3-59-g8ed1b From c978cd3a937141deaf7995b849824af6dacdeae7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:24:57 -0700 Subject: [NETFILTER]: nf_nat_sip: translate all Contact headers The SIP message may contain multiple Contact: addresses referring to the NATed endpoint, translate all of them. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/nf_nat_sip.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 71a4adcfd576..b443618a857f 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -101,10 +101,10 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - unsigned int matchoff, matchlen; + unsigned int dataoff, matchoff, matchlen; union nf_inet_addr addr; __be16 port; - int request; + int request, in_header; /* Basic rules: requests and responses. */ if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { @@ -187,9 +187,20 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, } next: + /* Translate Contact headers */ + dataoff = 0; + in_header = 0; + while (ct_sip_parse_header_uri(ct, *dptr, &dataoff, *datalen, + SIP_HDR_CONTACT, &in_header, + &matchoff, &matchlen, + &addr, &port) > 0) { + if (!map_addr(skb, dptr, datalen, matchoff, matchlen, + &addr, port)) + return NF_DROP; + } + if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM) || - !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO) || - !map_sip_addr(skb, dptr, datalen, SIP_HDR_CONTACT)) + !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO)) return NF_DROP; return NF_ACCEPT; } -- cgit v1.2.3-59-g8ed1b From 0f32a40fc91a9ebbbf66e826ac2a829ab37d9cf8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:25:13 -0700 Subject: [NETFILTER]: nf_conntrack_sip: create signalling expectations Create expectations for incoming signalling connections when seeing a REGISTER request. This is needed when the registrar uses a different source port number for signalling messages and for receiving incoming calls from other endpoints than the registrar. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 18 +++ include/net/netfilter/nf_conntrack.h | 4 +- net/ipv4/netfilter/nf_nat_sip.c | 111 +++++++++++--- net/netfilter/nf_conntrack_sip.c | 232 +++++++++++++++++++++++++++-- 4 files changed, 332 insertions(+), 33 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 87e402825dba..7cc84ed0c5da 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -5,6 +5,17 @@ #define SIP_PORT 5060 #define SIP_TIMEOUT 3600 +struct nf_ct_sip_master { + unsigned int register_cseq; +}; + +enum sip_expectation_classes { + SIP_EXPECT_SIGNALLING, + SIP_EXPECT_AUDIO, + __SIP_EXPECT_MAX +}; +#define SIP_EXPECT_MAX (__SIP_EXPECT_MAX - 1) + struct sip_handler { const char *method; unsigned int len; @@ -59,6 +70,7 @@ enum sip_header_types { SIP_HDR_TO, SIP_HDR_CONTACT, SIP_HDR_VIA, + SIP_HDR_EXPIRES, SIP_HDR_CONTENT_LENGTH, }; @@ -75,6 +87,12 @@ enum sdp_header_types { extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, const char **dptr, unsigned int *datalen); +extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + struct nf_conntrack_expect *exp, + unsigned int matchoff, + unsigned int matchlen); extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, const char **dptr, unsigned int *datalen, diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 922877133598..4a4f870d2a5e 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -46,6 +46,7 @@ union nf_conntrack_expect_proto { #include #include #include +#include /* per conntrack: application helper private data */ union nf_conntrack_help { @@ -54,6 +55,7 @@ union nf_conntrack_help { struct nf_ct_pptp_master ct_pptp_info; struct nf_ct_h323_master ct_h323_info; struct nf_ct_sane_master ct_sane_info; + struct nf_ct_sip_master ct_sip_info; }; #include @@ -76,7 +78,7 @@ do { \ struct nf_conntrack_helper; /* Must be kept in sync with the classes defined by helpers */ -#define NF_CT_MAX_EXPECT_CLASSES 1 +#define NF_CT_MAX_EXPECT_CLASSES 2 /* nf_conn feature for connections that have a helper */ struct nf_conn_help { diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index b443618a857f..4b85e21a2a4a 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -205,6 +205,91 @@ next: return NF_ACCEPT; } +/* Handles expected signalling connections and media streams */ +static void ip_nat_sip_expected(struct nf_conn *ct, + struct nf_conntrack_expect *exp) +{ + struct nf_nat_range range; + + /* This must be a fresh one. */ + BUG_ON(ct->status & IPS_NAT_DONE_MASK); + + /* For DST manip, map port here to where it's expected. */ + range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); + range.min = range.max = exp->saved_proto; + range.min_ip = range.max_ip = exp->saved_ip; + nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST); + + /* Change src to where master sends to, but only if the connection + * actually came from the same source. */ + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == + ct->master->tuplehash[exp->dir].tuple.src.u3.ip) { + range.flags = IP_NAT_RANGE_MAP_IPS; + range.min_ip = range.max_ip + = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; + nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC); + } +} + +static unsigned int ip_nat_sip_expect(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + struct nf_conntrack_expect *exp, + unsigned int matchoff, + unsigned int matchlen) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + __be32 newip; + u_int16_t port; + char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; + unsigned buflen; + + /* Connection will come from reply */ + if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip) + newip = exp->tuple.dst.u3.ip; + else + newip = ct->tuplehash[!dir].tuple.dst.u3.ip; + + /* If the signalling port matches the connection's source port in the + * original direction, try to use the destination port in the opposite + * direction. */ + if (exp->tuple.dst.u.udp.port == + ct->tuplehash[dir].tuple.src.u.udp.port) + port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port); + else + port = ntohs(exp->tuple.dst.u.udp.port); + + exp->saved_ip = exp->tuple.dst.u3.ip; + exp->tuple.dst.u3.ip = newip; + exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; + exp->dir = !dir; + exp->expectfn = ip_nat_sip_expected; + + for (; port != 0; port++) { + exp->tuple.dst.u.udp.port = htons(port); + if (nf_ct_expect_related(exp) == 0) + break; + } + + if (port == 0) + return NF_DROP; + + if (exp->tuple.dst.u3.ip != exp->saved_ip || + exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { + buflen = sprintf(buffer, "%u.%u.%u.%u:%u", + NIPQUAD(newip), port); + if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen, + buffer, buflen)) + goto err; + } + return NF_ACCEPT; + +err: + nf_ct_unexpect_related(exp); + return NF_DROP; +} + static int mangle_content_len(struct sk_buff *skb, const char **dptr, unsigned int *datalen) { @@ -275,27 +360,6 @@ static unsigned int mangle_sdp(struct sk_buff *skb, return mangle_content_len(skb, dptr, datalen); } -static void ip_nat_sdp_expect(struct nf_conn *ct, - struct nf_conntrack_expect *exp) -{ - struct nf_nat_range range; - - /* This must be a fresh one. */ - BUG_ON(ct->status & IPS_NAT_DONE_MASK); - - /* For DST manip, map port here to where it's expected. */ - range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); - range.min = range.max = exp->saved_proto; - range.min_ip = range.max_ip = exp->saved_ip; - nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST); - - /* Change src to where master sends to */ - range.flags = IP_NAT_RANGE_MAP_IPS; - range.min_ip = range.max_ip - = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; - nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC); -} - /* So, this packet has hit the connection tracking matching code. Mangle it, and change the expectation to match the new version. */ static unsigned int ip_nat_sdp(struct sk_buff *skb, @@ -322,7 +386,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, /* When you see the packet, we need to NAT it the same as the this one. */ - exp->expectfn = ip_nat_sdp_expect; + exp->expectfn = ip_nat_sip_expected; /* Try to get same port: if not, try to change it. */ for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { @@ -344,6 +408,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, static void __exit nf_nat_sip_fini(void) { rcu_assign_pointer(nf_nat_sip_hook, NULL); + rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); rcu_assign_pointer(nf_nat_sdp_hook, NULL); synchronize_rcu(); } @@ -351,8 +416,10 @@ static void __exit nf_nat_sip_fini(void) static int __init nf_nat_sip_init(void) { BUG_ON(nf_nat_sip_hook != NULL); + BUG_ON(nf_nat_sip_expect_hook != NULL); BUG_ON(nf_nat_sdp_hook != NULL); rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); + rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); return 0; } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 126f30842d60..043aa557e7a8 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -37,11 +37,24 @@ static unsigned int sip_timeout __read_mostly = SIP_TIMEOUT; module_param(sip_timeout, uint, 0600); MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); +static int sip_direct_signalling __read_mostly = 1; +module_param(sip_direct_signalling, int, 0600); +MODULE_PARM_DESC(sip_direct_signalling, "expect incoming calls from registrar " + "only (default 1)"); + unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, const char **dptr, unsigned int *datalen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sip_hook); +unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + struct nf_conntrack_expect *exp, + unsigned int matchoff, + unsigned int matchlen) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); + unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, const char **dptr, unsigned int *datalen, @@ -218,6 +231,7 @@ static const struct sip_header ct_sip_hdrs[] = { [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), [SIP_HDR_VIA] = SIP_HDR("Via", "v", "UDP ", epaddr_len), + [SIP_HDR_EXPIRES] = SIP_HDR("Expires", NULL, NULL, digits_len), [SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len), }; @@ -592,18 +606,50 @@ int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, } EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header); -static void flush_expectations(struct nf_conn *ct) +static int refresh_signalling_expectation(struct nf_conn *ct, + union nf_inet_addr *addr, + __be16 port, + unsigned int expires) { struct nf_conn_help *help = nfct_help(ct); struct nf_conntrack_expect *exp; struct hlist_node *n, *next; + int found = 0; spin_lock_bh(&nf_conntrack_lock); hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { + if (exp->class != SIP_EXPECT_SIGNALLING || + !nf_inet_addr_cmp(&exp->tuple.dst.u3, addr) || + exp->tuple.dst.u.udp.port != port) + continue; + if (!del_timer(&exp->timeout)) + continue; + exp->flags &= ~NF_CT_EXPECT_INACTIVE; + exp->timeout.expires = jiffies + expires * HZ; + add_timer(&exp->timeout); + found = 1; + break; + } + spin_unlock_bh(&nf_conntrack_lock); + return found; +} + +static void flush_expectations(struct nf_conn *ct, bool media) +{ + struct nf_conn_help *help = nfct_help(ct); + struct nf_conntrack_expect *exp; + struct hlist_node *n, *next; + + spin_lock_bh(&nf_conntrack_lock); + hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { + if ((exp->class != SIP_EXPECT_SIGNALLING) ^ media) + continue; if (!del_timer(&exp->timeout)) continue; nf_ct_unlink_expect(exp); nf_ct_expect_put(exp); + if (!media) + break; } spin_unlock_bh(&nf_conntrack_lock); } @@ -623,7 +669,7 @@ static int set_expected_rtp(struct sk_buff *skb, exp = nf_ct_expect_alloc(ct); if (exp == NULL) return NF_DROP; - nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family, + nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, &ct->tuplehash[!dir].tuple.src.u3, addr, IPPROTO_UDP, NULL, &port); @@ -688,7 +734,7 @@ static int process_invite_response(struct sk_buff *skb, (code >= 200 && code <= 299)) return process_sdp(skb, dptr, datalen, cseq); else { - flush_expectations(ct); + flush_expectations(ct, true); return NF_ACCEPT; } } @@ -704,7 +750,7 @@ static int process_update_response(struct sk_buff *skb, (code >= 200 && code <= 299)) return process_sdp(skb, dptr, datalen, cseq); else { - flush_expectations(ct); + flush_expectations(ct, true); return NF_ACCEPT; } } @@ -720,7 +766,7 @@ static int process_prack_response(struct sk_buff *skb, (code >= 200 && code <= 299)) return process_sdp(skb, dptr, datalen, cseq); else { - flush_expectations(ct); + flush_expectations(ct, true); return NF_ACCEPT; } } @@ -732,7 +778,165 @@ static int process_bye_request(struct sk_buff *skb, enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - flush_expectations(ct); + flush_expectations(ct, true); + return NF_ACCEPT; +} + +/* Parse a REGISTER request and create a permanent expectation for incoming + * signalling connections. The expectation is marked inactive and is activated + * when receiving a response indicating success from the registrar. + */ +static int process_register_request(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + struct nf_conn_help *help = nfct_help(ct); + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + unsigned int matchoff, matchlen; + struct nf_conntrack_expect *exp; + union nf_inet_addr *saddr, daddr; + __be16 port; + unsigned int expires = 0; + int ret; + typeof(nf_nat_sip_expect_hook) nf_nat_sip_expect; + + /* Expected connections can not register again. */ + if (ct->status & IPS_EXPECTED) + return NF_ACCEPT; + + /* We must check the expiration time: a value of zero signals the + * registrar to release the binding. We'll remove our expectation + * when receiving the new bindings in the response, but we don't + * want to create new ones. + * + * The expiration time may be contained in Expires: header, the + * Contact: header parameters or the URI parameters. + */ + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) + expires = simple_strtoul(*dptr + matchoff, NULL, 10); + + ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, + SIP_HDR_CONTACT, NULL, + &matchoff, &matchlen, &daddr, &port); + if (ret < 0) + return NF_DROP; + else if (ret == 0) + return NF_ACCEPT; + + /* We don't support third-party registrations */ + if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, &daddr)) + return NF_ACCEPT; + + if (ct_sip_parse_numerical_param(ct, *dptr, + matchoff + matchlen, *datalen, + "expires=", NULL, NULL, &expires) < 0) + return NF_DROP; + + if (expires == 0) { + ret = NF_ACCEPT; + goto store_cseq; + } + + exp = nf_ct_expect_alloc(ct); + if (!exp) + return NF_DROP; + + saddr = NULL; + if (sip_direct_signalling) + saddr = &ct->tuplehash[!dir].tuple.src.u3; + + nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, family, saddr, &daddr, + IPPROTO_UDP, NULL, &port); + exp->timeout.expires = sip_timeout * HZ; + exp->helper = nfct_help(ct)->helper; + exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; + + nf_nat_sip_expect = rcu_dereference(nf_nat_sip_expect_hook); + if (nf_nat_sip_expect && ct->status & IPS_NAT_MASK) + ret = nf_nat_sip_expect(skb, dptr, datalen, exp, + matchoff, matchlen); + else { + if (nf_ct_expect_related(exp) != 0) + ret = NF_DROP; + else + ret = NF_ACCEPT; + } + nf_ct_expect_put(exp); + +store_cseq: + if (ret == NF_ACCEPT) + help->help.ct_sip_info.register_cseq = cseq; + return ret; +} + +static int process_register_response(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + unsigned int cseq, unsigned int code) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + struct nf_conn_help *help = nfct_help(ct); + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + union nf_inet_addr addr; + __be16 port; + unsigned int matchoff, matchlen, dataoff = 0; + unsigned int expires = 0; + int in_contact = 0, ret; + + /* According to RFC 3261, "UAs MUST NOT send a new registration until + * they have received a final response from the registrar for the + * previous one or the previous REGISTER request has timed out". + * + * However, some servers fail to detect retransmissions and send late + * responses, so we store the sequence number of the last valid + * request and compare it here. + */ + if (help->help.ct_sip_info.register_cseq != cseq) + return NF_ACCEPT; + + if (code >= 100 && code <= 199) + return NF_ACCEPT; + if (code < 200 || code > 299) + goto flush; + + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, + &matchoff, &matchlen) > 0) + expires = simple_strtoul(*dptr + matchoff, NULL, 10); + + while (1) { + unsigned int c_expires = expires; + + ret = ct_sip_parse_header_uri(ct, *dptr, &dataoff, *datalen, + SIP_HDR_CONTACT, &in_contact, + &matchoff, &matchlen, + &addr, &port); + if (ret < 0) + return NF_DROP; + else if (ret == 0) + break; + + /* We don't support third-party registrations */ + if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, &addr)) + continue; + + ret = ct_sip_parse_numerical_param(ct, *dptr, + matchoff + matchlen, + *datalen, "expires=", + NULL, NULL, &c_expires); + if (ret < 0) + return NF_DROP; + if (c_expires == 0) + break; + if (refresh_signalling_expectation(ct, &addr, port, c_expires)) + return NF_ACCEPT; + } + +flush: + flush_expectations(ct, false); return NF_ACCEPT; } @@ -742,6 +946,7 @@ static const struct sip_handler sip_handlers[] = { SIP_HANDLER("ACK", process_sdp, NULL), SIP_HANDLER("PRACK", process_sdp, process_prack_response), SIP_HANDLER("BYE", process_bye_request, NULL), + SIP_HANDLER("REGISTER", process_register_request, process_register_response), }; static int process_sip_response(struct sk_buff *skb, @@ -853,9 +1058,15 @@ static int sip_help(struct sk_buff *skb, static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly; -static const struct nf_conntrack_expect_policy sip_exp_policy = { - .max_expected = 2, - .timeout = 3 * 60, +static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = { + [SIP_EXPECT_SIGNALLING] = { + .max_expected = 1, + .timeout = 3 * 60, + }, + [SIP_EXPECT_AUDIO] = { + .max_expected = IP_CT_DIR_MAX, + .timeout = 3 * 60, + }, }; static void nf_conntrack_sip_fini(void) @@ -887,7 +1098,8 @@ static int __init nf_conntrack_sip_init(void) for (j = 0; j < 2; j++) { sip[i][j].tuple.dst.protonum = IPPROTO_UDP; sip[i][j].tuple.src.u.udp.port = htons(ports[i]); - sip[i][j].expect_policy = &sip_exp_policy; + sip[i][j].expect_policy = sip_exp_policy; + sip[i][j].expect_class_max = SIP_EXPECT_MAX; sip[i][j].me = THIS_MODULE; sip[i][j].help = sip_help; -- cgit v1.2.3-59-g8ed1b From d901a9369e6e7d07a7eb4ddb315c6fcbaf8b24d3 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:25:32 -0700 Subject: [NETFILTER]: nf_conntrack_sip: allow media expectations with wildcard source address Media streams can come from anywhere, add a module parameter which controls whether wildcard expectations or expectations between the two signalling endpoints are created. Since the same media description sent on multiple connections may results in multiple identical expections when using a wildcard source, we need to check whether a similar expectation already exists for a different connection before attempting to register it. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_sip.c | 45 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 043aa557e7a8..813aa8c67e4c 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -42,6 +42,11 @@ module_param(sip_direct_signalling, int, 0600); MODULE_PARM_DESC(sip_direct_signalling, "expect incoming calls from registrar " "only (default 1)"); +static int sip_direct_media __read_mostly = 1; +module_param(sip_direct_media, int, 0600); +MODULE_PARM_DESC(sip_direct_media, "Expect Media streams between signalling " + "endpoints only (default 1)"); + unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, const char **dptr, unsigned int *datalen) __read_mostly; @@ -656,21 +661,53 @@ static void flush_expectations(struct nf_conn *ct, bool media) static int set_expected_rtp(struct sk_buff *skb, const char **dptr, unsigned int *datalen, - union nf_inet_addr *addr, __be16 port) + union nf_inet_addr *daddr, __be16 port) { struct nf_conntrack_expect *exp; enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + union nf_inet_addr *saddr; + struct nf_conntrack_tuple tuple; int family = ct->tuplehash[!dir].tuple.src.l3num; - int ret; + int skip_expect = 0, ret; typeof(nf_nat_sdp_hook) nf_nat_sdp; + saddr = NULL; + if (sip_direct_media) { + if (!nf_inet_addr_cmp(daddr, &ct->tuplehash[dir].tuple.src.u3)) + return NF_ACCEPT; + saddr = &ct->tuplehash[!dir].tuple.src.u3; + } + + /* We need to check whether the registration exists before attempting + * to register it since we can see the same media description multiple + * times on different connections in case multiple endpoints receive + * the same call. + */ + memset(&tuple, 0, sizeof(tuple)); + if (saddr) + tuple.src.u3 = *saddr; + tuple.src.l3num = family; + tuple.dst.protonum = IPPROTO_UDP; + tuple.dst.u3 = *daddr; + tuple.dst.u.udp.port = port; + + rcu_read_lock(); + exp = __nf_ct_expect_find(&tuple); + if (exp && exp->master != ct && + nfct_help(exp->master)->helper == nfct_help(ct)->helper && + exp->class == SIP_EXPECT_AUDIO) + skip_expect = 1; + rcu_read_unlock(); + + if (skip_expect) + return NF_ACCEPT; + exp = nf_ct_expect_alloc(ct); if (exp == NULL) return NF_DROP; - nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, - &ct->tuplehash[!dir].tuple.src.u3, addr, + nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, saddr, daddr, IPPROTO_UDP, NULL, &port); nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); -- cgit v1.2.3-59-g8ed1b From a9c1d35917c0c95c8f95a8e497fb91e301419693 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:25:49 -0700 Subject: [NETFILTER]: nf_conntrack_sip: create RTCP expectations Create expectations for the RTCP connections in addition to RTP connections. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 3 +- net/ipv4/netfilter/nf_nat_sip.c | 42 +++++++++++++--------- net/netfilter/nf_conntrack_sip.c | 58 +++++++++++++++++++----------- 3 files changed, 66 insertions(+), 37 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 7cc84ed0c5da..6ddf95f51fb5 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -96,7 +96,8 @@ extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, const char **dptr, unsigned int *datalen, - struct nf_conntrack_expect *exp); + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp); extern int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr, unsigned int datalen, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 4b85e21a2a4a..f73ab4883b75 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -364,7 +364,8 @@ static unsigned int mangle_sdp(struct sk_buff *skb, Mangle it, and change the expectation to match the new version. */ static unsigned int ip_nat_sdp(struct sk_buff *skb, const char **dptr, unsigned int *datalen, - struct nf_conntrack_expect *exp) + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); @@ -375,31 +376,40 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, /* Connection will come from reply */ if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip) - newip = exp->tuple.dst.u3.ip; + newip = rtp_exp->tuple.dst.u3.ip; else newip = ct->tuplehash[!dir].tuple.dst.u3.ip; - exp->saved_ip = exp->tuple.dst.u3.ip; - exp->tuple.dst.u3.ip = newip; - exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; - exp->dir = !dir; - - /* When you see the packet, we need to NAT it the same as the - this one. */ - exp->expectfn = ip_nat_sip_expected; - - /* Try to get same port: if not, try to change it. */ - for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { - exp->tuple.dst.u.udp.port = htons(port); - if (nf_ct_expect_related(exp) == 0) + rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip; + rtp_exp->tuple.dst.u3.ip = newip; + rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; + rtp_exp->dir = !dir; + rtp_exp->expectfn = ip_nat_sip_expected; + + rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip; + rtcp_exp->tuple.dst.u3.ip = newip; + rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; + rtcp_exp->dir = !dir; + rtcp_exp->expectfn = ip_nat_sip_expected; + + /* Try to get same pair of ports: if not, try to change them. */ + for (port = ntohs(rtp_exp->tuple.dst.u.udp.port); + port != 0; port += 2) { + rtp_exp->tuple.dst.u.udp.port = htons(port); + if (nf_ct_expect_related(rtp_exp) != 0) + continue; + rtcp_exp->tuple.dst.u.udp.port = htons(port + 1); + if (nf_ct_expect_related(rtcp_exp) == 0) break; + nf_ct_unexpect_related(rtp_exp); } if (port == 0) return NF_DROP; if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) { - nf_ct_unexpect_related(exp); + nf_ct_unexpect_related(rtp_exp); + nf_ct_unexpect_related(rtcp_exp); return NF_DROP; } return NF_ACCEPT; diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 813aa8c67e4c..217262e23403 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -63,7 +63,9 @@ EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, const char **dptr, unsigned int *datalen, - struct nf_conntrack_expect *exp) __read_mostly; + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp) + __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); static int string_len(const struct nf_conn *ct, const char *dptr, @@ -659,18 +661,20 @@ static void flush_expectations(struct nf_conn *ct, bool media) spin_unlock_bh(&nf_conntrack_lock); } -static int set_expected_rtp(struct sk_buff *skb, - const char **dptr, unsigned int *datalen, - union nf_inet_addr *daddr, __be16 port) +static int set_expected_rtp_rtcp(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + union nf_inet_addr *daddr, __be16 port) { - struct nf_conntrack_expect *exp; + struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp; enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); union nf_inet_addr *saddr; struct nf_conntrack_tuple tuple; int family = ct->tuplehash[!dir].tuple.src.l3num; - int skip_expect = 0, ret; + int skip_expect = 0, ret = NF_DROP; + u_int16_t base_port; + __be16 rtp_port, rtcp_port; typeof(nf_nat_sdp_hook) nf_nat_sdp; saddr = NULL; @@ -704,23 +708,37 @@ static int set_expected_rtp(struct sk_buff *skb, if (skip_expect) return NF_ACCEPT; - exp = nf_ct_expect_alloc(ct); - if (exp == NULL) - return NF_DROP; - nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, saddr, daddr, - IPPROTO_UDP, NULL, &port); + base_port = ntohs(tuple.dst.u.udp.port) & ~1; + rtp_port = htons(base_port); + rtcp_port = htons(base_port + 1); + + rtp_exp = nf_ct_expect_alloc(ct); + if (rtp_exp == NULL) + goto err1; + nf_ct_expect_init(rtp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, + IPPROTO_UDP, NULL, &rtp_port); + + rtcp_exp = nf_ct_expect_alloc(ct); + if (rtcp_exp == NULL) + goto err2; + nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, + IPPROTO_UDP, NULL, &rtcp_port); nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); if (nf_nat_sdp && ct->status & IPS_NAT_MASK) - ret = nf_nat_sdp(skb, dptr, datalen, exp); + ret = nf_nat_sdp(skb, dptr, datalen, rtp_exp, rtcp_exp); else { - if (nf_ct_expect_related(exp) != 0) - ret = NF_DROP; - else - ret = NF_ACCEPT; + if (nf_ct_expect_related(rtp_exp) == 0) { + if (nf_ct_expect_related(rtcp_exp) != 0) + nf_ct_unexpect_related(rtp_exp); + else + ret = NF_ACCEPT; + } } - nf_ct_expect_put(exp); - + nf_ct_expect_put(rtcp_exp); +err2: + nf_ct_expect_put(rtp_exp); +err1: return ret; } @@ -758,7 +776,7 @@ static int process_sdp(struct sk_buff *skb, if (port < 1024 || port > 65535) return NF_DROP; - return set_expected_rtp(skb, dptr, datalen, &addr, htons(port)); + return set_expected_rtp_rtcp(skb, dptr, datalen, &addr, htons(port)); } static int process_invite_response(struct sk_buff *skb, const char **dptr, unsigned int *datalen, @@ -1101,7 +1119,7 @@ static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1 .timeout = 3 * 60, }, [SIP_EXPECT_AUDIO] = { - .max_expected = IP_CT_DIR_MAX, + .max_expected = 2 * IP_CT_DIR_MAX, .timeout = 3 * 60, }, }; -- cgit v1.2.3-59-g8ed1b From 4ab9e64e5e3c0516577818804aaf13a630d67bc9 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:26:08 -0700 Subject: [NETFILTER]: nf_nat_sip: split up SDP mangling The SDP connection addresses may be contained in the payload multiple times (in the session description and/or once per media description), currently only the session description is properly updated. Split up SDP mangling so the function setting up expectations only updates the media port, update connection addresses from media descriptions while parsing them and at the end update the session description when the final addresses are known. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 25 ++++- net/ipv4/netfilter/nf_nat_sip.c | 121 ++++++++++++++++-------- net/netfilter/nf_conntrack_sip.c | 142 +++++++++++++++++++++++------ 3 files changed, 219 insertions(+), 69 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 6ddf95f51fb5..eca3ad3f28dc 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -93,11 +93,26 @@ extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, struct nf_conntrack_expect *exp, unsigned int matchoff, unsigned int matchlen); -extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, - const char **dptr, - unsigned int *datalen, - struct nf_conntrack_expect *rtp_exp, - struct nf_conntrack_expect *rtcp_exp); +extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int dataoff, + unsigned int *datalen, + enum sdp_header_types type, + enum sdp_header_types term, + const union nf_inet_addr *addr); +extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int dataoff, + unsigned int *datalen, + const union nf_inet_addr *addr); +extern unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp, + unsigned int mediaoff, + unsigned int medialen, + union nf_inet_addr *rtp_addr); extern int ct_sip_parse_request(const struct nf_conn *ct, const char *dptr, unsigned int datalen, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index f73ab4883b75..4429069d9b42 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -316,45 +316,77 @@ static int mangle_content_len(struct sk_buff *skb, buffer, buflen); } -static unsigned mangle_sdp_packet(struct sk_buff *skb, - const char **dptr, unsigned int *datalen, +static unsigned mangle_sdp_packet(struct sk_buff *skb, const char **dptr, + unsigned int dataoff, unsigned int *datalen, enum sdp_header_types type, + enum sdp_header_types term, char *buffer, int buflen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchlen, matchoff; - if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, type, SDP_HDR_UNSPEC, + if (ct_sip_get_sdp_header(ct, *dptr, dataoff, *datalen, type, term, &matchoff, &matchlen) <= 0) return 0; return mangle_packet(skb, dptr, datalen, matchoff, matchlen, buffer, buflen); } -static unsigned int mangle_sdp(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, - __be32 newip, u_int16_t port, - const char **dptr, unsigned int *datalen) +static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr, + unsigned int dataoff, + unsigned int *datalen, + enum sdp_header_types type, + enum sdp_header_types term, + const union nf_inet_addr *addr) { char buffer[sizeof("nnn.nnn.nnn.nnn")]; - unsigned int bufflen; + unsigned int buflen; - /* Mangle owner and contact info. */ - bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); - if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_OWNER_IP4, - buffer, bufflen)) + buflen = sprintf(buffer, NIPQUAD_FMT, NIPQUAD(addr->ip)); + if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, type, term, + buffer, buflen)) return 0; - if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_CONNECTION_IP4, - buffer, bufflen)) + return mangle_content_len(skb, dptr, datalen); +} + +static unsigned int ip_nat_sdp_port(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + unsigned int matchoff, + unsigned int matchlen, + u_int16_t port) +{ + char buffer[sizeof("nnnnn")]; + unsigned int buflen; + + buflen = sprintf(buffer, "%u", port); + if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen, + buffer, buflen)) return 0; - /* Mangle media port. */ - bufflen = sprintf(buffer, "%u", port); - if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_MEDIA, - buffer, bufflen)) + return mangle_content_len(skb, dptr, datalen); +} + +static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr, + unsigned int dataoff, + unsigned int *datalen, + const union nf_inet_addr *addr) +{ + char buffer[sizeof("nnn.nnn.nnn.nnn")]; + unsigned int buflen; + + /* Mangle session description owner and contact addresses */ + buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(addr->ip)); + if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, + SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA, + buffer, buflen)) + return 0; + + if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, + SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA, + buffer, buflen)) return 0; return mangle_content_len(skb, dptr, datalen); @@ -362,32 +394,35 @@ static unsigned int mangle_sdp(struct sk_buff *skb, /* So, this packet has hit the connection tracking matching code. Mangle it, and change the expectation to match the new version. */ -static unsigned int ip_nat_sdp(struct sk_buff *skb, - const char **dptr, unsigned int *datalen, - struct nf_conntrack_expect *rtp_exp, - struct nf_conntrack_expect *rtcp_exp) +static unsigned int ip_nat_sdp_media(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp, + unsigned int mediaoff, + unsigned int medialen, + union nf_inet_addr *rtp_addr) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - __be32 newip; u_int16_t port; /* Connection will come from reply */ if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip) - newip = rtp_exp->tuple.dst.u3.ip; + rtp_addr->ip = rtp_exp->tuple.dst.u3.ip; else - newip = ct->tuplehash[!dir].tuple.dst.u3.ip; + rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip; rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip; - rtp_exp->tuple.dst.u3.ip = newip; + rtp_exp->tuple.dst.u3.ip = rtp_addr->ip; rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; rtp_exp->dir = !dir; rtp_exp->expectfn = ip_nat_sip_expected; rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip; - rtcp_exp->tuple.dst.u3.ip = newip; + rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip; rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; rtcp_exp->dir = !dir; rtcp_exp->expectfn = ip_nat_sip_expected; @@ -405,21 +440,29 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, } if (port == 0) - return NF_DROP; + goto err1; + + /* Update media port. */ + if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port && + !ip_nat_sdp_port(skb, dptr, datalen, mediaoff, medialen, port)) + goto err2; - if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) { - nf_ct_unexpect_related(rtp_exp); - nf_ct_unexpect_related(rtcp_exp); - return NF_DROP; - } return NF_ACCEPT; + +err2: + nf_ct_unexpect_related(rtp_exp); + nf_ct_unexpect_related(rtcp_exp); +err1: + return NF_DROP; } static void __exit nf_nat_sip_fini(void) { rcu_assign_pointer(nf_nat_sip_hook, NULL); rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); - rcu_assign_pointer(nf_nat_sdp_hook, NULL); + rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL); + rcu_assign_pointer(nf_nat_sdp_session_hook, NULL); + rcu_assign_pointer(nf_nat_sdp_media_hook, NULL); synchronize_rcu(); } @@ -427,10 +470,14 @@ static int __init nf_nat_sip_init(void) { BUG_ON(nf_nat_sip_hook != NULL); BUG_ON(nf_nat_sip_expect_hook != NULL); - BUG_ON(nf_nat_sdp_hook != NULL); + BUG_ON(nf_nat_sdp_addr_hook != NULL); + BUG_ON(nf_nat_sdp_session_hook != NULL); + BUG_ON(nf_nat_sdp_media_hook != NULL); rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); - rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); + rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr); + rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session); + rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media); return 0; } diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 217262e23403..f929add324f3 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -60,13 +60,34 @@ unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, unsigned int matchlen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); -unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, - const char **dptr, - unsigned int *datalen, - struct nf_conntrack_expect *rtp_exp, - struct nf_conntrack_expect *rtcp_exp) - __read_mostly; -EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); +unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int dataoff, + unsigned int *datalen, + enum sdp_header_types type, + enum sdp_header_types term, + const union nf_inet_addr *addr) + __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook); + +unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int dataoff, + unsigned int *datalen, + const union nf_inet_addr *addr) + __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sdp_session_hook); + +unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + struct nf_conntrack_expect *rtp_exp, + struct nf_conntrack_expect *rtcp_exp, + unsigned int mediaoff, + unsigned int medialen, + union nf_inet_addr *rtp_addr) + __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sdp_media_hook); static int string_len(const struct nf_conn *ct, const char *dptr, const char *limit, int *shift) @@ -613,6 +634,26 @@ int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, } EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header); +static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr, + unsigned int dataoff, unsigned int datalen, + enum sdp_header_types type, + enum sdp_header_types term, + unsigned int *matchoff, unsigned int *matchlen, + union nf_inet_addr *addr) +{ + int ret; + + ret = ct_sip_get_sdp_header(ct, dptr, dataoff, datalen, type, term, + matchoff, matchlen); + if (ret <= 0) + return ret; + + if (!parse_addr(ct, dptr + *matchoff, NULL, addr, + dptr + *matchoff + *matchlen)) + return -1; + return 1; +} + static int refresh_signalling_expectation(struct nf_conn *ct, union nf_inet_addr *addr, __be16 port, @@ -663,7 +704,8 @@ static void flush_expectations(struct nf_conn *ct, bool media) static int set_expected_rtp_rtcp(struct sk_buff *skb, const char **dptr, unsigned int *datalen, - union nf_inet_addr *daddr, __be16 port) + union nf_inet_addr *daddr, __be16 port, + unsigned int mediaoff, unsigned int medialen) { struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp; enum ip_conntrack_info ctinfo; @@ -675,7 +717,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, int skip_expect = 0, ret = NF_DROP; u_int16_t base_port; __be16 rtp_port, rtcp_port; - typeof(nf_nat_sdp_hook) nf_nat_sdp; + typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media; saddr = NULL; if (sip_direct_media) { @@ -724,9 +766,10 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, IPPROTO_UDP, NULL, &rtcp_port); - nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); - if (nf_nat_sdp && ct->status & IPS_NAT_MASK) - ret = nf_nat_sdp(skb, dptr, datalen, rtp_exp, rtcp_exp); + nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); + if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK) + ret = nf_nat_sdp_media(skb, dptr, datalen, rtp_exp, rtcp_exp, + mediaoff, medialen, daddr); else { if (nf_ct_expect_related(rtp_exp) == 0) { if (nf_ct_expect_related(rtcp_exp) != 0) @@ -750,33 +793,78 @@ static int process_sdp(struct sk_buff *skb, struct nf_conn *ct = nf_ct_get(skb, &ctinfo); int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; unsigned int matchoff, matchlen; - union nf_inet_addr addr; + unsigned int mediaoff, medialen; + unsigned int sdpoff; + unsigned int caddr_len, maddr_len; + union nf_inet_addr caddr, maddr, rtp_addr; unsigned int port; - enum sdp_header_types type; + enum sdp_header_types c_hdr; + int ret; + typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr; + typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session; - /* Get address and port from SDP packet. */ - type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : - SDP_HDR_CONNECTION_IP6; + c_hdr = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : + SDP_HDR_CONNECTION_IP6; + /* Find beginning of session description */ if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, - type, SDP_HDR_UNSPEC, + SDP_HDR_VERSION, SDP_HDR_UNSPEC, &matchoff, &matchlen) <= 0) return NF_ACCEPT; - - /* We'll drop only if there are parse problems. */ - if (!parse_addr(ct, *dptr + matchoff, NULL, &addr, *dptr + *datalen)) - return NF_DROP; - - if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, + sdpoff = matchoff; + + /* The connection information is contained in the session description + * and/or once per media description. The first media description marks + * the end of the session description. */ + caddr_len = 0; + if (ct_sip_parse_sdp_addr(ct, *dptr, sdpoff, *datalen, + c_hdr, SDP_HDR_MEDIA, + &matchoff, &matchlen, &caddr) > 0) + caddr_len = matchlen; + + if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, SDP_HDR_MEDIA, SDP_HDR_UNSPEC, - &matchoff, &matchlen) <= 0) + &mediaoff, &medialen) <= 0) return NF_ACCEPT; - port = simple_strtoul(*dptr + matchoff, NULL, 10); + port = simple_strtoul(*dptr + mediaoff, NULL, 10); if (port < 1024 || port > 65535) return NF_DROP; - return set_expected_rtp_rtcp(skb, dptr, datalen, &addr, htons(port)); + /* The media description overrides the session description. */ + maddr_len = 0; + if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen, + c_hdr, SDP_HDR_MEDIA, + &matchoff, &matchlen, &maddr) > 0) { + maddr_len = matchlen; + memcpy(&rtp_addr, &maddr, sizeof(rtp_addr)); + } else if (caddr_len) + memcpy(&rtp_addr, &caddr, sizeof(rtp_addr)); + else + return NF_DROP; + + ret = set_expected_rtp_rtcp(skb, dptr, datalen, &rtp_addr, htons(port), + mediaoff, medialen); + if (ret != NF_ACCEPT) + return ret; + + /* Update media connection address if present */ + if (maddr_len) { + nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook); + if (nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) { + ret = nf_nat_sdp_addr(skb, dptr, mediaoff, datalen, + c_hdr, SDP_HDR_MEDIA, &rtp_addr); + if (ret != NF_ACCEPT) + return ret; + } + } + + /* Update session connection and owner addresses */ + nf_nat_sdp_session = rcu_dereference(nf_nat_sdp_session_hook); + if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK) + ret = nf_nat_sdp_session(skb, dptr, sdpoff, datalen, &rtp_addr); + + return ret; } static int process_invite_response(struct sk_buff *skb, const char **dptr, unsigned int *datalen, -- cgit v1.2.3-59-g8ed1b From 0d0ab0378d67517a4f4ae3497706c13d9dd24af1 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:26:24 -0700 Subject: [NETFILTER]: nf_conntrack_sip: support multiple media channels Add support for multiple media channels and use it to create expectations for video streams when present. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 14 ++++ include/net/netfilter/nf_conntrack.h | 2 +- net/netfilter/nf_conntrack_sip.c | 121 +++++++++++++++++++++-------- 3 files changed, 105 insertions(+), 32 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index eca3ad3f28dc..71fa3eb5f485 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -12,10 +12,24 @@ struct nf_ct_sip_master { enum sip_expectation_classes { SIP_EXPECT_SIGNALLING, SIP_EXPECT_AUDIO, + SIP_EXPECT_VIDEO, __SIP_EXPECT_MAX }; #define SIP_EXPECT_MAX (__SIP_EXPECT_MAX - 1) +struct sdp_media_type { + const char *name; + unsigned int len; + enum sip_expectation_classes class; +}; + +#define SDP_MEDIA_TYPE(__name, __class) \ +{ \ + .name = (__name), \ + .len = sizeof(__name) - 1, \ + .class = (__class), \ +} + struct sip_handler { const char *method; unsigned int len; diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 4a4f870d2a5e..a3567a7a6d67 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -78,7 +78,7 @@ do { \ struct nf_conntrack_helper; /* Must be kept in sync with the classes defined by helpers */ -#define NF_CT_MAX_EXPECT_CLASSES 2 +#define NF_CT_MAX_EXPECT_CLASSES 3 /* nf_conn feature for connections that have a helper */ struct nf_conn_help { diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index f929add324f3..f40a525732d1 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -112,6 +112,21 @@ static int digits_len(const struct nf_conn *ct, const char *dptr, return len; } +/* get media type + port length */ +static int media_len(const struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) +{ + int len = string_len(ct, dptr, limit, shift); + + dptr += len; + if (dptr >= limit || *dptr != ' ') + return 0; + len++; + dptr++; + + return len + digits_len(ct, dptr, limit, shift); +} + static int parse_addr(const struct nf_conn *ct, const char *cp, const char **endp, union nf_inet_addr *addr, const char *limit) @@ -563,7 +578,7 @@ static const struct sip_header ct_sdp_hdrs[] = { [SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len), [SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len), [SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len), - [SDP_HDR_MEDIA] = SDP_HDR("m=", "audio ", digits_len), + [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len), }; /* Linear string search within SDP header values */ @@ -705,6 +720,7 @@ static void flush_expectations(struct nf_conn *ct, bool media) static int set_expected_rtp_rtcp(struct sk_buff *skb, const char **dptr, unsigned int *datalen, union nf_inet_addr *daddr, __be16 port, + enum sip_expectation_classes class, unsigned int mediaoff, unsigned int medialen) { struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp; @@ -743,7 +759,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, exp = __nf_ct_expect_find(&tuple); if (exp && exp->master != ct && nfct_help(exp->master)->helper == nfct_help(ct)->helper && - exp->class == SIP_EXPECT_AUDIO) + exp->class == class) skip_expect = 1; rcu_read_unlock(); @@ -757,13 +773,13 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, rtp_exp = nf_ct_expect_alloc(ct); if (rtp_exp == NULL) goto err1; - nf_ct_expect_init(rtp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, + nf_ct_expect_init(rtp_exp, class, family, saddr, daddr, IPPROTO_UDP, NULL, &rtp_port); rtcp_exp = nf_ct_expect_alloc(ct); if (rtcp_exp == NULL) goto err2; - nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, + nf_ct_expect_init(rtcp_exp, class, family, saddr, daddr, IPPROTO_UDP, NULL, &rtcp_port); nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); @@ -785,6 +801,28 @@ err1: return ret; } +static const struct sdp_media_type sdp_media_types[] = { + SDP_MEDIA_TYPE("audio ", SIP_EXPECT_AUDIO), + SDP_MEDIA_TYPE("video ", SIP_EXPECT_VIDEO), +}; + +static const struct sdp_media_type *sdp_media_type(const char *dptr, + unsigned int matchoff, + unsigned int matchlen) +{ + const struct sdp_media_type *t; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sdp_media_types); i++) { + t = &sdp_media_types[i]; + if (matchlen < t->len || + strncmp(dptr + matchoff, t->name, t->len)) + continue; + return t; + } + return NULL; +} + static int process_sdp(struct sk_buff *skb, const char **dptr, unsigned int *datalen, unsigned int cseq) @@ -796,13 +834,16 @@ static int process_sdp(struct sk_buff *skb, unsigned int mediaoff, medialen; unsigned int sdpoff; unsigned int caddr_len, maddr_len; + unsigned int i; union nf_inet_addr caddr, maddr, rtp_addr; unsigned int port; enum sdp_header_types c_hdr; - int ret; + const struct sdp_media_type *t; + int ret = NF_ACCEPT; typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr; typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session; + nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook); c_hdr = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : SDP_HDR_CONNECTION_IP6; @@ -822,41 +863,55 @@ static int process_sdp(struct sk_buff *skb, &matchoff, &matchlen, &caddr) > 0) caddr_len = matchlen; - if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, - SDP_HDR_MEDIA, SDP_HDR_UNSPEC, - &mediaoff, &medialen) <= 0) - return NF_ACCEPT; + mediaoff = sdpoff; + for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { + if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, + SDP_HDR_MEDIA, SDP_HDR_UNSPEC, + &mediaoff, &medialen) <= 0) + break; - port = simple_strtoul(*dptr + mediaoff, NULL, 10); - if (port < 1024 || port > 65535) - return NF_DROP; + /* Get media type and port number. A media port value of zero + * indicates an inactive stream. */ + t = sdp_media_type(*dptr, mediaoff, medialen); + if (!t) { + mediaoff += medialen; + continue; + } + mediaoff += t->len; + medialen -= t->len; - /* The media description overrides the session description. */ - maddr_len = 0; - if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen, - c_hdr, SDP_HDR_MEDIA, - &matchoff, &matchlen, &maddr) > 0) { - maddr_len = matchlen; - memcpy(&rtp_addr, &maddr, sizeof(rtp_addr)); - } else if (caddr_len) - memcpy(&rtp_addr, &caddr, sizeof(rtp_addr)); - else - return NF_DROP; + port = simple_strtoul(*dptr + mediaoff, NULL, 10); + if (port == 0) + continue; + if (port < 1024 || port > 65535) + return NF_DROP; - ret = set_expected_rtp_rtcp(skb, dptr, datalen, &rtp_addr, htons(port), - mediaoff, medialen); - if (ret != NF_ACCEPT) - return ret; + /* The media description overrides the session description. */ + maddr_len = 0; + if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen, + c_hdr, SDP_HDR_MEDIA, + &matchoff, &matchlen, &maddr) > 0) { + maddr_len = matchlen; + memcpy(&rtp_addr, &maddr, sizeof(rtp_addr)); + } else if (caddr_len) + memcpy(&rtp_addr, &caddr, sizeof(rtp_addr)); + else + return NF_DROP; + + ret = set_expected_rtp_rtcp(skb, dptr, datalen, + &rtp_addr, htons(port), t->class, + mediaoff, medialen); + if (ret != NF_ACCEPT) + return ret; - /* Update media connection address if present */ - if (maddr_len) { - nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook); - if (nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) { + /* Update media connection address if present */ + if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) { ret = nf_nat_sdp_addr(skb, dptr, mediaoff, datalen, c_hdr, SDP_HDR_MEDIA, &rtp_addr); if (ret != NF_ACCEPT) return ret; } + i++; } /* Update session connection and owner addresses */ @@ -1210,6 +1265,10 @@ static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1 .max_expected = 2 * IP_CT_DIR_MAX, .timeout = 3 * 60, }, + [SIP_EXPECT_VIDEO] = { + .max_expected = 2 * IP_CT_DIR_MAX, + .timeout = 3 * 60, + }, }; static void nf_conntrack_sip_fini(void) -- cgit v1.2.3-59-g8ed1b From c7f485abd618e0d249bdd1abdc586bd10fee1954 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:26:43 -0700 Subject: [NETFILTER]: nf_conntrack_sip: RTP routing optimization Optimize call routing between NATed endpoints: when an external registrar sends a media description that contains an existing RTP expectation from a different SNATed connection, the gatekeeper is trying to route the call directly between the two endpoints. We assume both endpoints can reach each other directly and "un-NAT" the addresses, which makes the media stream go between the two endpoints directly. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_sip.h | 6 +++ net/ipv4/netfilter/nf_nat_sip.c | 3 ++ net/netfilter/nf_conntrack_sip.c | 59 +++++++++++++++++++++++++----- 3 files changed, 58 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 71fa3eb5f485..5da04e586a3f 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h @@ -114,6 +114,12 @@ extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, enum sdp_header_types type, enum sdp_header_types term, const union nf_inet_addr *addr); +extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + unsigned int matchoff, + unsigned int matchlen, + u_int16_t port); extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, const char **dptr, unsigned int dataoff, diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 4429069d9b42..bcddccddf768 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -461,6 +461,7 @@ static void __exit nf_nat_sip_fini(void) rcu_assign_pointer(nf_nat_sip_hook, NULL); rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL); + rcu_assign_pointer(nf_nat_sdp_port_hook, NULL); rcu_assign_pointer(nf_nat_sdp_session_hook, NULL); rcu_assign_pointer(nf_nat_sdp_media_hook, NULL); synchronize_rcu(); @@ -471,11 +472,13 @@ static int __init nf_nat_sip_init(void) BUG_ON(nf_nat_sip_hook != NULL); BUG_ON(nf_nat_sip_expect_hook != NULL); BUG_ON(nf_nat_sdp_addr_hook != NULL); + BUG_ON(nf_nat_sdp_port_hook != NULL); BUG_ON(nf_nat_sdp_session_hook != NULL); BUG_ON(nf_nat_sdp_media_hook != NULL); rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr); + rcu_assign_pointer(nf_nat_sdp_port_hook, ip_nat_sdp_port); rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session); rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media); return 0; diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index f40a525732d1..57de22c770a3 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -70,6 +70,14 @@ unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook); +unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, + const char **dptr, + unsigned int *datalen, + unsigned int matchoff, + unsigned int matchlen, + u_int16_t port) __read_mostly; +EXPORT_SYMBOL_GPL(nf_nat_sdp_port_hook); + unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, const char **dptr, unsigned int dataoff, @@ -730,9 +738,10 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, union nf_inet_addr *saddr; struct nf_conntrack_tuple tuple; int family = ct->tuplehash[!dir].tuple.src.l3num; - int skip_expect = 0, ret = NF_DROP; + int direct_rtp = 0, skip_expect = 0, ret = NF_DROP; u_int16_t base_port; __be16 rtp_port, rtcp_port; + typeof(nf_nat_sdp_port_hook) nf_nat_sdp_port; typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media; saddr = NULL; @@ -746,6 +755,14 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, * to register it since we can see the same media description multiple * times on different connections in case multiple endpoints receive * the same call. + * + * RTP optimization: if we find a matching media channel expectation + * and both the expectation and this connection are SNATed, we assume + * both sides can reach each other directly and use the final + * destination address from the expectation. We still need to keep + * the NATed expectations for media that might arrive from the + * outside, and additionally need to expect the direct RTP stream + * in case it passes through us even without NAT. */ memset(&tuple, 0, sizeof(tuple)); if (saddr) @@ -756,20 +773,42 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, tuple.dst.u.udp.port = port; rcu_read_lock(); - exp = __nf_ct_expect_find(&tuple); - if (exp && exp->master != ct && - nfct_help(exp->master)->helper == nfct_help(ct)->helper && - exp->class == class) - skip_expect = 1; - rcu_read_unlock(); + do { + exp = __nf_ct_expect_find(&tuple); - if (skip_expect) - return NF_ACCEPT; + if (!exp || exp->master == ct || + nfct_help(exp->master)->helper != nfct_help(ct)->helper || + exp->class != class) + break; + + if (exp->tuple.src.l3num == AF_INET && !direct_rtp && + (exp->saved_ip != exp->tuple.dst.u3.ip || + exp->saved_proto.udp.port != exp->tuple.dst.u.udp.port) && + ct->status & IPS_NAT_MASK) { + daddr->ip = exp->saved_ip; + tuple.dst.u3.ip = exp->saved_ip; + tuple.dst.u.udp.port = exp->saved_proto.udp.port; + direct_rtp = 1; + } else + skip_expect = 1; + } while (!skip_expect); + rcu_read_unlock(); base_port = ntohs(tuple.dst.u.udp.port) & ~1; rtp_port = htons(base_port); rtcp_port = htons(base_port + 1); + if (direct_rtp) { + nf_nat_sdp_port = rcu_dereference(nf_nat_sdp_port_hook); + if (nf_nat_sdp_port && + !nf_nat_sdp_port(skb, dptr, datalen, + mediaoff, medialen, ntohs(rtp_port))) + goto err1; + } + + if (skip_expect) + return NF_ACCEPT; + rtp_exp = nf_ct_expect_alloc(ct); if (rtp_exp == NULL) goto err1; @@ -783,7 +822,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, IPPROTO_UDP, NULL, &rtcp_port); nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); - if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK) + if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp) ret = nf_nat_sdp_media(skb, dptr, datalen, rtp_exp, rtcp_exp, mediaoff, medialen, daddr); else { -- cgit v1.2.3-59-g8ed1b From f49e1aa133c2c9b74b5dfddca8863609bbda9086 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 25 Mar 2008 20:27:05 -0700 Subject: [NETFILTER]: nf_conntrack_sip: update copyright Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/netfilter/nf_nat_sip.c | 2 ++ net/netfilter/nf_conntrack_sip.c | 2 ++ 2 files changed, 4 insertions(+) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index bcddccddf768..4334d5cabc5b 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -2,6 +2,8 @@ * * (C) 2005 by Christian Hentschel * based on RR's ip_nat_ftp.c and other modules. + * (C) 2007 United Security Providers + * (C) 2007, 2008 Patrick McHardy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 57de22c770a3..da5dec6e6158 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -2,6 +2,8 @@ * * (C) 2005 by Christian Hentschel * based on RR's ip_conntrack_ftp.c and other modules. + * (C) 2007 United Security Providers + * (C) 2007, 2008 Patrick McHardy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as -- cgit v1.2.3-59-g8ed1b From 1577519d6b3777d2d3ba05871dd7ee40112c58ce Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 26 Mar 2008 01:54:18 -0700 Subject: [NETNS][ICMP]: Register pernet subsys to make ICMP sysctls per-net. This includes adding pernet_operations, empty init and exit hooks and a bit of changes in sysctl_ipv4_init just not to have this part in next patches. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/sysctl_net_ipv4.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 88286f35d1e2..c2fca3024d2e 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -811,12 +811,34 @@ struct ctl_path net_ipv4_ctl_path[] = { }; EXPORT_SYMBOL_GPL(net_ipv4_ctl_path); +static __net_init int ipv4_sysctl_init_net(struct net *net) +{ + return 0; +} + +static __net_exit void ipv4_sysctl_exit_net(struct net *net) +{ +} + +static __net_initdata struct pernet_operations ipv4_sysctl_ops = { + .init = ipv4_sysctl_init_net, + .exit = ipv4_sysctl_exit_net, +}; + static __init int sysctl_ipv4_init(void) { struct ctl_table_header *hdr; hdr = register_sysctl_paths(net_ipv4_ctl_path, ipv4_table); - return hdr == NULL ? -ENOMEM : 0; + if (hdr == NULL) + return -ENOMEM; + + if (register_pernet_subsys(&ipv4_sysctl_ops)) { + unregister_sysctl_table(hdr); + return -ENOMEM; + } + + return 0; } __initcall(sysctl_ipv4_init); -- cgit v1.2.3-59-g8ed1b From a24022e1887978decaa28fb11d1ddff63e31497f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 26 Mar 2008 01:55:37 -0700 Subject: [NETNS][ICMP]: Move ICMP sysctls on struct net. Initialization is moved to icmp_sk_init, all the places, that refer to them use init_net for now. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/net/icmp.h | 7 ------ include/net/netns/ipv4.h | 7 ++++++ net/ipv4/icmp.c | 60 ++++++++++++++++++++++++---------------------- net/ipv4/sysctl_net_ipv4.c | 12 +++++----- 4 files changed, 44 insertions(+), 42 deletions(-) (limited to 'net') diff --git a/include/net/icmp.h b/include/net/icmp.h index faba64db8ff0..dddb839ff4b5 100644 --- a/include/net/icmp.h +++ b/include/net/icmp.h @@ -65,11 +65,4 @@ static inline struct raw_sock *raw_sk(const struct sock *sk) return (struct raw_sock *)sk; } -extern int sysctl_icmp_echo_ignore_all; -extern int sysctl_icmp_echo_ignore_broadcasts; -extern int sysctl_icmp_ignore_bogus_error_responses; -extern int sysctl_icmp_errors_use_inbound_ifaddr; -extern int sysctl_icmp_ratelimit; -extern int sysctl_icmp_ratemask; - #endif /* _ICMP_H */ diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index 504fde174525..e3de0ff8ea4b 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -35,5 +35,12 @@ struct netns_ipv4 { struct xt_table *iptable_raw; struct xt_table *arptable_filter; #endif + + int sysctl_icmp_echo_ignore_all; + int sysctl_icmp_echo_ignore_broadcasts; + int sysctl_icmp_ignore_bogus_error_responses; + int sysctl_icmp_ratelimit; + int sysctl_icmp_ratemask; + int sysctl_icmp_errors_use_inbound_ifaddr; }; #endif diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index f38f093ef751..958a38445120 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -188,29 +188,6 @@ struct icmp_err icmp_err_convert[] = { }, }; -/* Control parameters for ECHO replies. */ -int sysctl_icmp_echo_ignore_all __read_mostly; -int sysctl_icmp_echo_ignore_broadcasts __read_mostly = 1; - -/* Control parameter - ignore bogus broadcast responses? */ -int sysctl_icmp_ignore_bogus_error_responses __read_mostly = 1; - -/* - * Configurable global rate limit. - * - * ratelimit defines tokens/packet consumed for dst->rate_token bucket - * ratemask defines which icmp types are ratelimited by setting - * it's bit position. - * - * default: - * dest unreachable (3), source quench (4), - * time exceeded (11), parameter problem (12) - */ - -int sysctl_icmp_ratelimit __read_mostly = 1 * HZ; -int sysctl_icmp_ratemask __read_mostly = 0x1818; -int sysctl_icmp_errors_use_inbound_ifaddr __read_mostly; - /* * ICMP control array. This specifies what to do with each ICMP. */ @@ -310,8 +287,8 @@ static inline int icmpv4_xrlim_allow(struct rtable *rt, int type, int code) goto out; /* Limit if icmp type is enabled in ratemask. */ - if ((1 << type) & sysctl_icmp_ratemask) - rc = xrlim_allow(dst, sysctl_icmp_ratelimit); + if ((1 << type) & init_net.ipv4.sysctl_icmp_ratemask) + rc = xrlim_allow(dst, init_net.ipv4.sysctl_icmp_ratelimit); out: return rc; } @@ -523,7 +500,8 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) if (!(rt->rt_flags & RTCF_LOCAL)) { struct net_device *dev = NULL; - if (rt->fl.iif && sysctl_icmp_errors_use_inbound_ifaddr) + if (rt->fl.iif && + init_net.ipv4.sysctl_icmp_errors_use_inbound_ifaddr) dev = dev_get_by_index(net, rt->fl.iif); if (dev) { @@ -745,7 +723,7 @@ static void icmp_unreach(struct sk_buff *skb) * get the other vendor to fix their kit. */ - if (!sysctl_icmp_ignore_bogus_error_responses && + if (!init_net.ipv4.sysctl_icmp_ignore_bogus_error_responses && inet_addr_type(net, iph->daddr) == RTN_BROADCAST) { if (net_ratelimit()) printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP " @@ -840,7 +818,7 @@ out_err: static void icmp_echo(struct sk_buff *skb) { - if (!sysctl_icmp_echo_ignore_all) { + if (!init_net.ipv4.sysctl_icmp_echo_ignore_all) { struct icmp_bxm icmp_param; icmp_param.data.icmph = *icmp_hdr(skb); @@ -1051,7 +1029,7 @@ int icmp_rcv(struct sk_buff *skb) */ if ((icmph->type == ICMP_ECHO || icmph->type == ICMP_TIMESTAMP) && - sysctl_icmp_echo_ignore_broadcasts) { + init_net.ipv4.sysctl_icmp_echo_ignore_broadcasts) { goto error; } if (icmph->type != ICMP_ECHO && @@ -1195,6 +1173,30 @@ int __net_init icmp_sk_init(struct net *net) */ sk->sk_prot->unhash(sk); } + + /* Control parameters for ECHO replies. */ + net->ipv4.sysctl_icmp_echo_ignore_all = 0; + net->ipv4.sysctl_icmp_echo_ignore_broadcasts = 1; + + /* Control parameter - ignore bogus broadcast responses? */ + net->ipv4.sysctl_icmp_ignore_bogus_error_responses = 1; + + /* + * Configurable global rate limit. + * + * ratelimit defines tokens/packet consumed for dst->rate_token + * bucket ratemask defines which icmp types are ratelimited by + * setting it's bit position. + * + * default: + * dest unreachable (3), source quench (4), + * time exceeded (11), parameter problem (12) + */ + + net->ipv4.sysctl_icmp_ratelimit = 1 * HZ; + net->ipv4.sysctl_icmp_ratemask = 0x1818; + net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr = 0; + return 0; fail: diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index c2fca3024d2e..e9585c02f243 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -406,7 +406,7 @@ static struct ctl_table ipv4_table[] = { { .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_ALL, .procname = "icmp_echo_ignore_all", - .data = &sysctl_icmp_echo_ignore_all, + .data = &init_net.ipv4.sysctl_icmp_echo_ignore_all, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec @@ -414,7 +414,7 @@ static struct ctl_table ipv4_table[] = { { .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS, .procname = "icmp_echo_ignore_broadcasts", - .data = &sysctl_icmp_echo_ignore_broadcasts, + .data = &init_net.ipv4.sysctl_icmp_echo_ignore_broadcasts, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec @@ -422,7 +422,7 @@ static struct ctl_table ipv4_table[] = { { .ctl_name = NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES, .procname = "icmp_ignore_bogus_error_responses", - .data = &sysctl_icmp_ignore_bogus_error_responses, + .data = &init_net.ipv4.sysctl_icmp_ignore_bogus_error_responses, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec @@ -430,7 +430,7 @@ static struct ctl_table ipv4_table[] = { { .ctl_name = NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR, .procname = "icmp_errors_use_inbound_ifaddr", - .data = &sysctl_icmp_errors_use_inbound_ifaddr, + .data = &init_net.ipv4.sysctl_icmp_errors_use_inbound_ifaddr, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec @@ -588,7 +588,7 @@ static struct ctl_table ipv4_table[] = { { .ctl_name = NET_IPV4_ICMP_RATELIMIT, .procname = "icmp_ratelimit", - .data = &sysctl_icmp_ratelimit, + .data = &init_net.ipv4.sysctl_icmp_ratelimit, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec @@ -596,7 +596,7 @@ static struct ctl_table ipv4_table[] = { { .ctl_name = NET_IPV4_ICMP_RATEMASK, .procname = "icmp_ratemask", - .data = &sysctl_icmp_ratemask, + .data = &init_net.ipv4.sysctl_icmp_ratemask, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec -- cgit v1.2.3-59-g8ed1b From 68528f09980a60c8df046d16336333cac4fc0c32 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 26 Mar 2008 01:56:24 -0700 Subject: [NETNS][ICMP]: Make ctl tables for ICMP sysctls per-net. Add some flesh to ipv4_sysctl_init_net and ipv4_sysctl_exit_net, i.e. copy the table, alter .data pointers and register it per-net. Other ipv4_table's sysctls are now global, but this is going to change once sysctl permissions patches migrate from -mm tree to mainline in 2.6.26 merge window :) Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/net/netns/ipv4.h | 1 + net/ipv4/sysctl_net_ipv4.c | 138 +++++++++++++++++++++++++++++---------------- 2 files changed, 91 insertions(+), 48 deletions(-) (limited to 'net') diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index e3de0ff8ea4b..af685f71f4b5 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -17,6 +17,7 @@ struct netns_ipv4 { #ifdef CONFIG_SYSCTL struct ctl_table_header *forw_hdr; struct ctl_table_header *frags_hdr; + struct ctl_table_header *ipv4_hdr; #endif struct ipv4_devconf *devconf_all; struct ipv4_devconf *devconf_dflt; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index e9585c02f243..c437f804ee38 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -403,38 +403,6 @@ static struct ctl_table ipv4_table[] = { .proc_handler = &ipv4_local_port_range, .strategy = &ipv4_sysctl_local_port_range, }, - { - .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_ALL, - .procname = "icmp_echo_ignore_all", - .data = &init_net.ipv4.sysctl_icmp_echo_ignore_all, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS, - .procname = "icmp_echo_ignore_broadcasts", - .data = &init_net.ipv4.sysctl_icmp_echo_ignore_broadcasts, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .ctl_name = NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES, - .procname = "icmp_ignore_bogus_error_responses", - .data = &init_net.ipv4.sysctl_icmp_ignore_bogus_error_responses, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .ctl_name = NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR, - .procname = "icmp_errors_use_inbound_ifaddr", - .data = &init_net.ipv4.sysctl_icmp_errors_use_inbound_ifaddr, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, { .ctl_name = NET_IPV4_ROUTE, .procname = "route", @@ -585,22 +553,6 @@ static struct ctl_table ipv4_table[] = { .mode = 0644, .proc_handler = &proc_dointvec }, - { - .ctl_name = NET_IPV4_ICMP_RATELIMIT, - .procname = "icmp_ratelimit", - .data = &init_net.ipv4.sysctl_icmp_ratelimit, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .ctl_name = NET_IPV4_ICMP_RATEMASK, - .procname = "icmp_ratemask", - .data = &init_net.ipv4.sysctl_icmp_ratemask, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, { .ctl_name = NET_TCP_TW_REUSE, .procname = "tcp_tw_reuse", @@ -804,6 +756,58 @@ static struct ctl_table ipv4_table[] = { { .ctl_name = 0 } }; +static struct ctl_table ipv4_net_table[] = { + { + .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_ALL, + .procname = "icmp_echo_ignore_all", + .data = &init_net.ipv4.sysctl_icmp_echo_ignore_all, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS, + .procname = "icmp_echo_ignore_broadcasts", + .data = &init_net.ipv4.sysctl_icmp_echo_ignore_broadcasts, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES, + .procname = "icmp_ignore_bogus_error_responses", + .data = &init_net.ipv4.sysctl_icmp_ignore_bogus_error_responses, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR, + .procname = "icmp_errors_use_inbound_ifaddr", + .data = &init_net.ipv4.sysctl_icmp_errors_use_inbound_ifaddr, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = NET_IPV4_ICMP_RATELIMIT, + .procname = "icmp_ratelimit", + .data = &init_net.ipv4.sysctl_icmp_ratelimit, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = NET_IPV4_ICMP_RATEMASK, + .procname = "icmp_ratemask", + .data = &init_net.ipv4.sysctl_icmp_ratemask, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { } +}; + struct ctl_path net_ipv4_ctl_path[] = { { .procname = "net", .ctl_name = CTL_NET, }, { .procname = "ipv4", .ctl_name = NET_IPV4, }, @@ -813,11 +817,49 @@ EXPORT_SYMBOL_GPL(net_ipv4_ctl_path); static __net_init int ipv4_sysctl_init_net(struct net *net) { + struct ctl_table *table; + + table = ipv4_net_table; + if (net != &init_net) { + table = kmemdup(table, sizeof(ipv4_net_table), GFP_KERNEL); + if (table == NULL) + goto err_alloc; + + table[0].data = + &net->ipv4.sysctl_icmp_echo_ignore_all; + table[1].data = + &net->ipv4.sysctl_icmp_echo_ignore_broadcasts; + table[2].data = + &net->ipv4.sysctl_icmp_ignore_bogus_error_responses; + table[3].data = + &net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr; + table[4].data = + &net->ipv4.sysctl_icmp_ratelimit; + table[5].data = + &net->ipv4.sysctl_icmp_ratemask; + } + + net->ipv4.ipv4_hdr = register_net_sysctl_table(net, + net_ipv4_ctl_path, table); + if (net->ipv4.ipv4_hdr == NULL) + goto err_reg; + return 0; + +err_reg: + if (net != &init_net) + kfree(table); +err_alloc: + return -ENOMEM; } static __net_exit void ipv4_sysctl_exit_net(struct net *net) { + struct ctl_table *table; + + table = net->ipv4.ipv4_hdr->ctl_table_arg; + unregister_net_sysctl_table(net->ipv4.ipv4_hdr); + kfree(table); } static __net_initdata struct pernet_operations ipv4_sysctl_ops = { -- cgit v1.2.3-59-g8ed1b From b34a95ee6e05579faff2672d7d30356576407653 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 26 Mar 2008 02:00:21 -0700 Subject: [NETNS][ICMP]: Use per-net sysctls in ipv4/icmp.c. This mostly re-uses the net, used in icmp netnsization patches from Denis. After this ICMP sysctls are completely virtualized. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 958a38445120..7049b3f5f3cc 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -270,7 +270,8 @@ int xrlim_allow(struct dst_entry *dst, int timeout) return rc; } -static inline int icmpv4_xrlim_allow(struct rtable *rt, int type, int code) +static inline int icmpv4_xrlim_allow(struct net *net, struct rtable *rt, + int type, int code) { struct dst_entry *dst = &rt->u.dst; int rc = 1; @@ -287,8 +288,8 @@ static inline int icmpv4_xrlim_allow(struct rtable *rt, int type, int code) goto out; /* Limit if icmp type is enabled in ratemask. */ - if ((1 << type) & init_net.ipv4.sysctl_icmp_ratemask) - rc = xrlim_allow(dst, init_net.ipv4.sysctl_icmp_ratelimit); + if ((1 << type) & net->ipv4.sysctl_icmp_ratemask) + rc = xrlim_allow(dst, net->ipv4.sysctl_icmp_ratelimit); out: return rc; } @@ -390,7 +391,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) if (ip_route_output_key(net, &rt, &fl)) goto out_unlock; } - if (icmpv4_xrlim_allow(rt, icmp_param->data.icmph.type, + if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type, icmp_param->data.icmph.code)) icmp_push_reply(icmp_param, &ipc, rt); ip_rt_put(rt); @@ -501,7 +502,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) struct net_device *dev = NULL; if (rt->fl.iif && - init_net.ipv4.sysctl_icmp_errors_use_inbound_ifaddr) + net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr) dev = dev_get_by_index(net, rt->fl.iif); if (dev) { @@ -617,7 +618,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) } route_done: - if (!icmpv4_xrlim_allow(rt, type, code)) + if (!icmpv4_xrlim_allow(net, rt, type, code)) goto ende; /* RFC says return as much as we can without exceeding 576 bytes. */ @@ -723,7 +724,7 @@ static void icmp_unreach(struct sk_buff *skb) * get the other vendor to fix their kit. */ - if (!init_net.ipv4.sysctl_icmp_ignore_bogus_error_responses && + if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses && inet_addr_type(net, iph->daddr) == RTN_BROADCAST) { if (net_ratelimit()) printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP " @@ -818,7 +819,10 @@ out_err: static void icmp_echo(struct sk_buff *skb) { - if (!init_net.ipv4.sysctl_icmp_echo_ignore_all) { + struct net *net; + + net = skb->dst->dev->nd_net; + if (!net->ipv4.sysctl_icmp_echo_ignore_all) { struct icmp_bxm icmp_param; icmp_param.data.icmph = *icmp_hdr(skb); @@ -1021,6 +1025,9 @@ int icmp_rcv(struct sk_buff *skb) */ if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) { + struct net *net; + + net = rt->u.dst.dev->nd_net; /* * RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be * silently ignored (we let user decide with a sysctl). @@ -1029,7 +1036,7 @@ int icmp_rcv(struct sk_buff *skb) */ if ((icmph->type == ICMP_ECHO || icmph->type == ICMP_TIMESTAMP) && - init_net.ipv4.sysctl_icmp_echo_ignore_broadcasts) { + net->ipv4.sysctl_icmp_echo_ignore_broadcasts) { goto error; } if (icmph->type != ICMP_ECHO && -- cgit v1.2.3-59-g8ed1b From 789e41e6f496022ac1639aaae38ea1943606a9d0 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 26 Mar 2008 02:19:25 -0700 Subject: [NETNS][ICMP]: Build fix for NET_NS=n case (dev->nd_net is omitted). Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 7049b3f5f3cc..3697e0528317 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -821,7 +821,7 @@ static void icmp_echo(struct sk_buff *skb) { struct net *net; - net = skb->dst->dev->nd_net; + net = dev_net(skb->dst->dev); if (!net->ipv4.sysctl_icmp_echo_ignore_all) { struct icmp_bxm icmp_param; @@ -1027,7 +1027,7 @@ int icmp_rcv(struct sk_buff *skb) if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) { struct net *net; - net = rt->u.dst.dev->nd_net; + net = dev_net(rt->u.dst.dev); /* * RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be * silently ignored (we let user decide with a sysctl). -- cgit v1.2.3-59-g8ed1b From 67727184f28c38d06013c6659560bb046c1d9f9c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 26 Mar 2008 16:27:22 -0700 Subject: [VLAN]: Reduce memory consumed by vlan_groups Currently each vlan_groupd contains 8 pointers on arrays with 512 pointers on struct net_device each :) Such a construction "in many cases ... wastes memory". My proposal is to allow for some of these arrays pointers be NULL, meaning that there are no devices in it. When a new device is added to the vlan_group, the appropriate array is allocated. The check in vlan_group_get_device's is safe, since the pointer vg->vlan_devices_arrays[x] can only switch from NULL to not-NULL. The vlan_group_prealloc_vid() is guarded with rtnl lock and is also safe. I've checked (I hope that) all the places, that use these arrays and found, that the register_vlan_dev is the only place, that can put a vlan device on an empty vlan_group. Rough calculations shows, that after the patch a setup with a single vlan dev (or up to 512 vlans with sequential vids) will occupy approximately 8 times less memory. The question I have is - does this patch makes sense, or a totally new structures are required to store the vlan_devs? Signed-off-by: Pavel Emelyanov Signed-off-by: Patrick McHardy --- include/linux/if_vlan.h | 2 +- net/8021q/vlan.c | 36 +++++++++++++++++++++++------------- 2 files changed, 24 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 79504b22a932..edd55af7ebd6 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -93,7 +93,7 @@ static inline struct net_device *vlan_group_get_device(struct vlan_group *vg, { struct net_device **array; array = vg->vlan_devices_arrays[vlan_id / VLAN_GROUP_ARRAY_PART_LEN]; - return array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN]; + return array ? array[vlan_id % VLAN_GROUP_ARRAY_PART_LEN] : NULL; } static inline void vlan_group_set_device(struct vlan_group *vg, diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index c35dc230365c..694be86e4490 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -106,29 +106,35 @@ static void vlan_group_free(struct vlan_group *grp) static struct vlan_group *vlan_group_alloc(int ifindex) { struct vlan_group *grp; - unsigned int size; - unsigned int i; grp = kzalloc(sizeof(struct vlan_group), GFP_KERNEL); if (!grp) return NULL; - size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN; - - for (i = 0; i < VLAN_GROUP_ARRAY_SPLIT_PARTS; i++) { - grp->vlan_devices_arrays[i] = kzalloc(size, GFP_KERNEL); - if (!grp->vlan_devices_arrays[i]) - goto err; - } - grp->real_dev_ifindex = ifindex; hlist_add_head_rcu(&grp->hlist, &vlan_group_hash[vlan_grp_hashfn(ifindex)]); return grp; +} -err: - vlan_group_free(grp); - return NULL; +static int vlan_group_prealloc_vid(struct vlan_group *vg, int vid) +{ + struct net_device **array; + unsigned int size; + + ASSERT_RTNL(); + + array = vg->vlan_devices_arrays[vid / VLAN_GROUP_ARRAY_PART_LEN]; + if (array != NULL) + return 0; + + size = sizeof(struct net_device *) * VLAN_GROUP_ARRAY_PART_LEN; + array = kzalloc(size, GFP_KERNEL); + if (array == NULL) + return -ENOBUFS; + + vg->vlan_devices_arrays[vid / VLAN_GROUP_ARRAY_PART_LEN] = array; + return 0; } static void vlan_rcu_free(struct rcu_head *rcu) @@ -247,6 +253,10 @@ int register_vlan_dev(struct net_device *dev) return -ENOBUFS; } + err = vlan_group_prealloc_vid(grp, vlan_id); + if (err < 0) + goto out_free_group; + err = register_netdevice(dev); if (err < 0) goto out_free_group; -- cgit v1.2.3-59-g8ed1b From 9b674e82b73a61844967b32e1b4ecaf8eb9d1805 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 26 Mar 2008 16:48:21 -0700 Subject: [TIPC]: Cosmetic cleanup of TIPC polling logic This patch eliminates an unnecessary poll-related routine by merging it into TIPC's main polling routine, and updates the comments associated with this code. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/socket.c | 78 +++++++++++++++++++++++++------------------------------ 1 file changed, 36 insertions(+), 42 deletions(-) (limited to 'net') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index ae45df060e3a..1b5fb6103ded 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -101,44 +101,6 @@ static void sock_unlock(struct tipc_sock* tsock) spin_unlock_bh(tsock->p->lock); } -/** - * pollmask - determine the current set of poll() events for a socket - * @sock: socket structure - * - * TIPC sets the returned events as follows: - * a) POLLRDNORM and POLLIN are set if the socket's receive queue is non-empty - * or if a connection-oriented socket is does not have an active connection - * (i.e. a read operation will not block). - * b) POLLOUT is set except when a socket's connection has been terminated - * (i.e. a write operation will not block). - * c) POLLHUP is set when a socket's connection has been terminated. - * - * IMPORTANT: The fact that a read or write operation will not block does NOT - * imply that the operation will succeed! - * - * Returns pollmask value - */ - -static u32 pollmask(struct socket *sock) -{ - u32 mask; - - if ((skb_queue_len(&sock->sk->sk_receive_queue) != 0) || - (sock->state == SS_UNCONNECTED) || - (sock->state == SS_DISCONNECTING)) - mask = (POLLRDNORM | POLLIN); - else - mask = 0; - - if (sock->state == SS_DISCONNECTING) - mask |= POLLHUP; - else - mask |= POLLOUT; - - return mask; -} - - /** * advance_queue - discard first buffer in queue * @tsock: TIPC socket @@ -390,15 +352,47 @@ static int get_name(struct socket *sock, struct sockaddr *uaddr, * @sock: socket for which to calculate the poll bits * @wait: ??? * - * Returns the pollmask + * Returns pollmask value + * + * COMMENTARY: + * It appears that the usual socket locking mechanisms are not useful here + * since the pollmask info is potentially out-of-date the moment this routine + * exits. TCP and other protocols seem to rely on higher level poll routines + * to handle any preventable race conditions, so TIPC will do the same ... + * + * TIPC sets the returned events as follows: + * a) POLLRDNORM and POLLIN are set if the socket's receive queue is non-empty + * or if a connection-oriented socket is does not have an active connection + * (i.e. a read operation will not block). + * b) POLLOUT is set except when a socket's connection has been terminated + * (i.e. a write operation will not block). + * c) POLLHUP is set when a socket's connection has been terminated. + * + * IMPORTANT: The fact that a read or write operation will not block does NOT + * imply that the operation will succeed! */ static unsigned int poll(struct file *file, struct socket *sock, poll_table *wait) { - poll_wait(file, sock->sk->sk_sleep, wait); - /* NEED LOCK HERE? */ - return pollmask(sock); + struct sock *sk = sock->sk; + u32 mask; + + poll_wait(file, sk->sk_sleep, wait); + + if (!skb_queue_empty(&sk->sk_receive_queue) || + (sock->state == SS_UNCONNECTED) || + (sock->state == SS_DISCONNECTING)) + mask = (POLLRDNORM | POLLIN); + else + mask = 0; + + if (sock->state == SS_DISCONNECTING) + mask |= POLLHUP; + else + mask |= POLLOUT; + + return mask; } /** -- cgit v1.2.3-59-g8ed1b From a233352506be35aafd49c0ba8c88ca96ebde1c3d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 26 Mar 2008 16:49:40 -0700 Subject: [IPV6]: Fix potential net leak and oops in ipv6 routing code. The commits f3db4851 ([NETNS][IPV6] ip6_fib - fib6_clean_all handle several network namespaces) and 69ddb805 ([NETNS][IPV6] route6 - Make proc entry /proc/net/rt6_stats per namespace) made some proc files per net. Both of them introduced potential OOPS - get_proc_net can return NULL, but this check is lost - and a struct net leak - in case single_open() fails the previously got net is not put. Kill all these bugs with one patch. Signed-off-by: Pavel Emelyanov Acked-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv6/route.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv6/route.c b/net/ipv6/route.c index ac4428371432..cd82b6db35ff 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2390,10 +2390,18 @@ static int ipv6_route_show(struct seq_file *m, void *v) static int ipv6_route_open(struct inode *inode, struct file *file) { + int err; struct net *net = get_proc_net(inode); if (!net) return -ENXIO; - return single_open(file, ipv6_route_show, net); + + err = single_open(file, ipv6_route_show, net); + if (err < 0) { + put_net(net); + return err; + } + + return 0; } static int ipv6_route_release(struct inode *inode, struct file *file) @@ -2429,8 +2437,18 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v) static int rt6_stats_seq_open(struct inode *inode, struct file *file) { + int err; struct net *net = get_proc_net(inode); - return single_open(file, rt6_stats_seq_show, net); + if (!net) + return -ENXIO; + + err = single_open(file, rt6_stats_seq_show, net); + if (err < 0) { + put_net(net); + return err; + } + + return 0; } static int rt6_stats_seq_release(struct inode *inode, struct file *file) -- cgit v1.2.3-59-g8ed1b From 6ab57e7e7fa316552d0f94eaebf1def1d49f18da Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 26 Mar 2008 16:52:32 -0700 Subject: [NETNS][IPV6] anycast - handle several network namespace Make use of the network namespace information to have this protocol to handle several network namespace. Signed-off-by: Daniel Lezcano Signed-off-by: Benjamin Thery Signed-off-by: David S. Miller --- include/net/addrconf.h | 3 ++- include/net/ipv6.h | 17 ++++++----------- net/ipv6/af_inet6.c | 12 ++++++------ net/ipv6/anycast.c | 38 ++++++++++++++++++++++---------------- net/ipv6/ndisc.c | 2 +- 5 files changed, 37 insertions(+), 35 deletions(-) (limited to 'net') diff --git a/include/net/addrconf.h b/include/net/addrconf.h index c9276c72764d..d0c47c306046 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -134,7 +134,8 @@ extern int inet6_ac_check(struct sock *sk, struct in6_addr *addr, int ifindex); extern int ipv6_dev_ac_inc(struct net_device *dev, struct in6_addr *addr); extern int __ipv6_dev_ac_dec(struct inet6_dev *idev, struct in6_addr *addr); -extern int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr); +extern int ipv6_chk_acast_addr(struct net *net, struct net_device *dev, + struct in6_addr *addr); /* Device notifier */ diff --git a/include/net/ipv6.h b/include/net/ipv6.h index e82f1814d96b..1c98e737dbd0 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -591,8 +591,8 @@ extern int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, int __user *optlen); #ifdef CONFIG_PROC_FS -extern int ac6_proc_init(void); -extern void ac6_proc_exit(void); +extern int ac6_proc_init(struct net *net); +extern void ac6_proc_exit(struct net *net); extern int raw6_proc_init(void); extern void raw6_proc_exit(void); extern int tcp6_proc_init(struct net *net); @@ -607,15 +607,10 @@ extern int snmp6_register_dev(struct inet6_dev *idev); extern int snmp6_unregister_dev(struct inet6_dev *idev); #else -static inline int snmp6_register_dev(struct inet6_dev *idev) -{ - return 0; -} - -static inline int snmp6_unregister_dev(struct inet6_dev *idev) -{ - return 0; -} +static inline int ac6_proc_init(struct net *net) { return 0; } +static inline void ac6_proc_exit(struct net *net) { } +static inline int snmp6_register_dev(struct inet6_dev *idev) { return 0; } +static inline int snmp6_unregister_dev(struct inet6_dev *idev) { return 0; } #endif #ifdef CONFIG_SYSCTL diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 12f04e9d3e88..1731b0abf7f5 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -862,11 +862,16 @@ static int inet6_net_init(struct net *net) err = tcp6_proc_init(net); if (err) goto proc_tcp6_fail; + err = ac6_proc_init(net); + if (err) + goto proc_ac6_fail; out: #endif return err; #ifdef CONFIG_PROC_FS +proc_ac6_fail: + tcp6_proc_exit(net); proc_tcp6_fail: udp6_proc_exit(net); goto out; @@ -878,6 +883,7 @@ static void inet6_net_exit(struct net *net) #ifdef CONFIG_PROC_FS udp6_proc_exit(net); tcp6_proc_exit(net); + ac6_proc_exit(net); #endif } @@ -965,9 +971,6 @@ static int __init inet6_init(void) goto proc_udplite6_fail; if (ipv6_misc_proc_init()) goto proc_misc6_fail; - - if (ac6_proc_init()) - goto proc_anycast6_fail; if (if6_proc_init()) goto proc_if6_fail; #endif @@ -1039,8 +1042,6 @@ ip6_route_fail: #ifdef CONFIG_PROC_FS if6_proc_exit(); proc_if6_fail: - ac6_proc_exit(); -proc_anycast6_fail: ipv6_misc_proc_exit(); proc_misc6_fail: udplite6_proc_exit(); @@ -1101,7 +1102,6 @@ static void __exit inet6_exit(void) /* Cleanup code parts. */ if6_proc_exit(); - ac6_proc_exit(); ipv6_misc_proc_exit(); udplite6_proc_exit(); raw6_proc_exit(); diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 96868b994b37..463bd95d6b13 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -82,6 +82,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) struct net_device *dev = NULL; struct inet6_dev *idev; struct ipv6_ac_socklist *pac; + struct net *net = sock_net(sk); int ishost = !ipv6_devconf.forwarding; int err = 0; @@ -89,7 +90,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) return -EPERM; if (ipv6_addr_is_multicast(addr)) return -EINVAL; - if (ipv6_chk_addr(&init_net, addr, NULL, 0)) + if (ipv6_chk_addr(net, addr, NULL, 0)) return -EINVAL; pac = sock_kmalloc(sk, sizeof(struct ipv6_ac_socklist), GFP_KERNEL); @@ -101,7 +102,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) if (ifindex == 0) { struct rt6_info *rt; - rt = rt6_lookup(&init_net, addr, NULL, 0, 0); + rt = rt6_lookup(net, addr, NULL, 0, 0); if (rt) { dev = rt->rt6i_dev; dev_hold(dev); @@ -112,10 +113,10 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) } else { /* router, no matching interface: just pick one */ - dev = dev_get_by_flags(&init_net, IFF_UP, IFF_UP|IFF_LOOPBACK); + dev = dev_get_by_flags(net, IFF_UP, IFF_UP|IFF_LOOPBACK); } } else - dev = dev_get_by_index(&init_net, ifindex); + dev = dev_get_by_index(net, ifindex); if (dev == NULL) { err = -ENODEV; @@ -176,6 +177,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr) struct ipv6_pinfo *np = inet6_sk(sk); struct net_device *dev; struct ipv6_ac_socklist *pac, *prev_pac; + struct net *net = sock_net(sk); write_lock_bh(&ipv6_sk_ac_lock); prev_pac = NULL; @@ -196,7 +198,7 @@ int ipv6_sock_ac_drop(struct sock *sk, int ifindex, struct in6_addr *addr) write_unlock_bh(&ipv6_sk_ac_lock); - dev = dev_get_by_index(&init_net, pac->acl_ifindex); + dev = dev_get_by_index(net, pac->acl_ifindex); if (dev) { ipv6_dev_ac_dec(dev, &pac->acl_addr); dev_put(dev); @@ -210,6 +212,7 @@ void ipv6_sock_ac_close(struct sock *sk) struct ipv6_pinfo *np = inet6_sk(sk); struct net_device *dev = NULL; struct ipv6_ac_socklist *pac; + struct net *net = sock_net(sk); int prev_index; write_lock_bh(&ipv6_sk_ac_lock); @@ -224,7 +227,7 @@ void ipv6_sock_ac_close(struct sock *sk) if (pac->acl_ifindex != prev_index) { if (dev) dev_put(dev); - dev = dev_get_by_index(&init_net, pac->acl_ifindex); + dev = dev_get_by_index(net, pac->acl_ifindex); prev_index = pac->acl_ifindex; } if (dev) @@ -422,14 +425,15 @@ static int ipv6_chk_acast_dev(struct net_device *dev, struct in6_addr *addr) /* * check if given interface (or any, if dev==0) has this anycast address */ -int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr) +int ipv6_chk_acast_addr(struct net *net, struct net_device *dev, + struct in6_addr *addr) { int found = 0; if (dev) return ipv6_chk_acast_dev(dev, addr); read_lock(&dev_base_lock); - for_each_netdev(&init_net, dev) + for_each_netdev(net, dev) if (ipv6_chk_acast_dev(dev, addr)) { found = 1; break; @@ -441,6 +445,7 @@ int ipv6_chk_acast_addr(struct net_device *dev, struct in6_addr *addr) #ifdef CONFIG_PROC_FS struct ac6_iter_state { + struct seq_net_private p; struct net_device *dev; struct inet6_dev *idev; }; @@ -451,9 +456,10 @@ static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq) { struct ifacaddr6 *im = NULL; struct ac6_iter_state *state = ac6_seq_private(seq); + struct net *net = seq_file_net(seq); state->idev = NULL; - for_each_netdev(&init_net, state->dev) { + for_each_netdev(net, state->dev) { struct inet6_dev *idev; idev = in6_dev_get(state->dev); if (!idev) @@ -551,8 +557,8 @@ static const struct seq_operations ac6_seq_ops = { static int ac6_seq_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &ac6_seq_ops, - sizeof(struct ac6_iter_state)); + return seq_open_net(inode, file, &ac6_seq_ops, + sizeof(struct ac6_iter_state)); } static const struct file_operations ac6_seq_fops = { @@ -560,20 +566,20 @@ static const struct file_operations ac6_seq_fops = { .open = ac6_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; -int __init ac6_proc_init(void) +int ac6_proc_init(struct net *net) { - if (!proc_net_fops_create(&init_net, "anycast6", S_IRUGO, &ac6_seq_fops)) + if (!proc_net_fops_create(net, "anycast6", S_IRUGO, &ac6_seq_fops)) return -ENOMEM; return 0; } -void ac6_proc_exit(void) +void ac6_proc_exit(struct net *net) { - proc_net_remove(&init_net, "anycast6"); + proc_net_remove(net, "anycast6"); } #endif diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 79af57f586e8..b4d8e331432e 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -773,7 +773,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) return; } - if (ipv6_chk_acast_addr(dev, &msg->target) || + if (ipv6_chk_acast_addr(dev_net(dev), dev, &msg->target) || (idev->cnf.forwarding && (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && (pneigh = pneigh_lookup(&nd_tbl, dev_net(dev), -- cgit v1.2.3-59-g8ed1b From 60e8fbc4c53d3ef0cbffa393a9e7b77e2a1bae58 Mon Sep 17 00:00:00 2001 From: Benjamin Thery Date: Wed, 26 Mar 2008 16:53:08 -0700 Subject: [NETNS][IPV6] flowlabels - make flowlabels per namespace This patch introduces a new member, fl_net, in struct ip6_flowlabel. This allows to create labels with the same value in different namespaces. Signed-off-by: Benjamin Thery Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- include/net/ipv6.h | 1 + net/ipv6/ip6_flowlabel.c | 72 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 57 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 1c98e737dbd0..296f61d84709 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -202,6 +202,7 @@ struct ip6_flowlabel u32 owner; unsigned long lastuse; unsigned long expires; + struct net *fl_net; }; #define IPV6_FLOWINFO_MASK __constant_htonl(0x0FFFFFFF) diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 2b7d9ee98832..78d1d913e36c 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -62,23 +62,23 @@ static DEFINE_RWLOCK(ip6_fl_lock); static DEFINE_RWLOCK(ip6_sk_fl_lock); -static __inline__ struct ip6_flowlabel * __fl_lookup(__be32 label) +static inline struct ip6_flowlabel *__fl_lookup(struct net *net, __be32 label) { struct ip6_flowlabel *fl; for (fl=fl_ht[FL_HASH(label)]; fl; fl = fl->next) { - if (fl->label == label) + if (fl->label == label && fl->fl_net == net) return fl; } return NULL; } -static struct ip6_flowlabel * fl_lookup(__be32 label) +static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label) { struct ip6_flowlabel *fl; read_lock_bh(&ip6_fl_lock); - fl = __fl_lookup(label); + fl = __fl_lookup(net, label); if (fl) atomic_inc(&fl->users); read_unlock_bh(&ip6_fl_lock); @@ -88,8 +88,10 @@ static struct ip6_flowlabel * fl_lookup(__be32 label) static void fl_free(struct ip6_flowlabel *fl) { - if (fl) + if (fl) { + release_net(fl->fl_net); kfree(fl->opt); + } kfree(fl); } @@ -112,7 +114,6 @@ static void fl_release(struct ip6_flowlabel *fl) time_after(ip6_fl_gc_timer.expires, ttd)) mod_timer(&ip6_fl_gc_timer, ttd); } - write_unlock_bh(&ip6_fl_lock); } @@ -148,13 +149,34 @@ static void ip6_fl_gc(unsigned long dummy) if (!sched && atomic_read(&fl_size)) sched = now + FL_MAX_LINGER; if (sched) { - ip6_fl_gc_timer.expires = sched; - add_timer(&ip6_fl_gc_timer); + mod_timer(&ip6_fl_gc_timer, sched); } write_unlock(&ip6_fl_lock); } -static struct ip6_flowlabel *fl_intern(struct ip6_flowlabel *fl, __be32 label) +static void ip6_fl_purge(struct net *net) +{ + int i; + + write_lock(&ip6_fl_lock); + for (i = 0; i <= FL_HASH_MASK; i++) { + struct ip6_flowlabel *fl, **flp; + flp = &fl_ht[i]; + while ((fl = *flp) != NULL) { + if (fl->fl_net == net && atomic_read(&fl->users) == 0) { + *flp = fl->next; + fl_free(fl); + atomic_dec(&fl_size); + continue; + } + flp = &fl->next; + } + } + write_unlock(&ip6_fl_lock); +} + +static struct ip6_flowlabel *fl_intern(struct net *net, + struct ip6_flowlabel *fl, __be32 label) { struct ip6_flowlabel *lfl; @@ -165,7 +187,7 @@ static struct ip6_flowlabel *fl_intern(struct ip6_flowlabel *fl, __be32 label) for (;;) { fl->label = htonl(net_random())&IPV6_FLOWLABEL_MASK; if (fl->label) { - lfl = __fl_lookup(fl->label); + lfl = __fl_lookup(net, fl->label); if (lfl == NULL) break; } @@ -179,7 +201,7 @@ static struct ip6_flowlabel *fl_intern(struct ip6_flowlabel *fl, __be32 label) * done in ipv6_flowlabel_opt - sock is locked, so new entry * with the same label can only appear on another sock */ - lfl = __fl_lookup(fl->label); + lfl = __fl_lookup(net, fl->label); if (lfl != NULL) { atomic_inc(&lfl->users); write_unlock_bh(&ip6_fl_lock); @@ -298,7 +320,8 @@ static int fl6_renew(struct ip6_flowlabel *fl, unsigned long linger, unsigned lo } static struct ip6_flowlabel * -fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int *err_p) +fl_create(struct net *net, struct in6_flowlabel_req *freq, char __user *optval, + int optlen, int *err_p) { struct ip6_flowlabel *fl; int olen; @@ -343,6 +366,7 @@ fl_create(struct in6_flowlabel_req *freq, char __user *optval, int optlen, int * } } + fl->fl_net = hold_net(net); fl->expires = jiffies; err = fl6_renew(fl, freq->flr_linger, freq->flr_expires); if (err) @@ -441,6 +465,7 @@ static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) { int err; + struct net *net = sock_net(sk); struct ipv6_pinfo *np = inet6_sk(sk); struct in6_flowlabel_req freq; struct ipv6_fl_socklist *sfl1=NULL; @@ -483,7 +508,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) read_unlock_bh(&ip6_sk_fl_lock); if (freq.flr_share == IPV6_FL_S_NONE && capable(CAP_NET_ADMIN)) { - fl = fl_lookup(freq.flr_label); + fl = fl_lookup(net, freq.flr_label); if (fl) { err = fl6_renew(fl, freq.flr_linger, freq.flr_expires); fl_release(fl); @@ -496,7 +521,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) if (freq.flr_label & ~IPV6_FLOWLABEL_MASK) return -EINVAL; - fl = fl_create(&freq, optval, optlen, &err); + fl = fl_create(net, &freq, optval, optlen, &err); if (fl == NULL) return err; sfl1 = kmalloc(sizeof(*sfl1), GFP_KERNEL); @@ -518,7 +543,7 @@ int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) read_unlock_bh(&ip6_sk_fl_lock); if (fl1 == NULL) - fl1 = fl_lookup(freq.flr_label); + fl1 = fl_lookup(net, freq.flr_label); if (fl1) { recheck: err = -EEXIST; @@ -559,7 +584,7 @@ release: if (sfl1 == NULL || (err = mem_check(sk)) != 0) goto done; - fl1 = fl_intern(fl, freq.flr_label); + fl1 = fl_intern(net, fl, freq.flr_label); if (fl1 != NULL) goto recheck; @@ -717,13 +742,28 @@ static inline void ip6_flowlabel_proc_fini(struct net *net) } #endif +static inline void ip6_flowlabel_net_exit(struct net *net) +{ + ip6_fl_purge(net); +} + +static struct pernet_operations ip6_flowlabel_net_ops = { + .exit = ip6_flowlabel_net_exit, +}; + int ip6_flowlabel_init(void) { + int err; + + err = register_pernet_subsys(&ip6_flowlabel_net_ops); + if (err) + return err; return ip6_flowlabel_proc_init(&init_net); } void ip6_flowlabel_cleanup(void) { del_timer(&ip6_fl_gc_timer); + unregister_pernet_subsys(&ip6_flowlabel_net_ops); ip6_flowlabel_proc_fini(&init_net); } -- cgit v1.2.3-59-g8ed1b From 5983a3dff0036d7ef6a2139473564f4f3e7b2a11 Mon Sep 17 00:00:00 2001 From: Benjamin Thery Date: Wed, 26 Mar 2008 16:53:30 -0700 Subject: [NETNS][IPV6] flowlabels - make proc per namespace Make /proc/net/ip6_flowlabel show only flow labels belonging to the current network namespace. Signed-off-by: Benjamin Thery Signed-off-by: Daniel Lezcano Signed-off-by: David S. Miller --- net/ipv6/ip6_flowlabel.c | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 78d1d913e36c..eb7a940310f4 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -611,6 +611,7 @@ done: #ifdef CONFIG_PROC_FS struct ip6fl_iter_state { + struct seq_net_private p; int bucket; }; @@ -620,12 +621,15 @@ static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq) { struct ip6_flowlabel *fl = NULL; struct ip6fl_iter_state *state = ip6fl_seq_private(seq); + struct net *net = seq_file_net(seq); for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) { - if (fl_ht[state->bucket]) { - fl = fl_ht[state->bucket]; + fl = fl_ht[state->bucket]; + + while (fl && fl->fl_net != net) + fl = fl->next; + if (fl) break; - } } return fl; } @@ -633,12 +637,18 @@ static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq) static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flowlabel *fl) { struct ip6fl_iter_state *state = ip6fl_seq_private(seq); + struct net *net = seq_file_net(seq); fl = fl->next; +try_again: + while (fl && fl->fl_net != net) + fl = fl->next; + while (!fl) { - if (++state->bucket <= FL_HASH_MASK) + if (++state->bucket <= FL_HASH_MASK) { fl = fl_ht[state->bucket]; - else + goto try_again; + } else break; } return fl; @@ -708,8 +718,8 @@ static const struct seq_operations ip6fl_seq_ops = { static int ip6fl_seq_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &ip6fl_seq_ops, - sizeof(struct ip6fl_iter_state)); + return seq_open_net(inode, file, &ip6fl_seq_ops, + sizeof(struct ip6fl_iter_state)); } static const struct file_operations ip6fl_seq_fops = { @@ -717,12 +727,13 @@ static const struct file_operations ip6fl_seq_fops = { .open = ip6fl_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; static int ip6_flowlabel_proc_init(struct net *net) { - if (!proc_net_fops_create(net, "ip6_flowlabel", S_IRUGO, &ip6fl_seq_fops)) + if (!proc_net_fops_create(net, "ip6_flowlabel", + S_IRUGO, &ip6fl_seq_fops)) return -ENOMEM; return 0; } @@ -745,25 +756,21 @@ static inline void ip6_flowlabel_proc_fini(struct net *net) static inline void ip6_flowlabel_net_exit(struct net *net) { ip6_fl_purge(net); + ip6_flowlabel_proc_fini(net); } static struct pernet_operations ip6_flowlabel_net_ops = { + .init = ip6_flowlabel_proc_init, .exit = ip6_flowlabel_net_exit, }; int ip6_flowlabel_init(void) { - int err; - - err = register_pernet_subsys(&ip6_flowlabel_net_ops); - if (err) - return err; - return ip6_flowlabel_proc_init(&init_net); + return register_pernet_subsys(&ip6_flowlabel_net_ops); } void ip6_flowlabel_cleanup(void) { del_timer(&ip6_fl_gc_timer); unregister_pernet_subsys(&ip6_flowlabel_net_ops); - ip6_flowlabel_proc_fini(&init_net); } -- cgit v1.2.3-59-g8ed1b From be892471c42f70e47541e42b8dba7ff91cebd026 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 25 Mar 2008 11:43:15 -0400 Subject: mac80211: silently accept deletion of non-existant key Otherwise, 'iwconfig wlan0 key off' with no key set results in: Error for wireless request "Set Encode" (8B2A) : SET failed on device wlan0 ; No such file or directory. Signed-off-by: John W. Linville --- net/mac80211/ieee80211_ioctl.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 5af23d318726..b047eebb6330 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -55,9 +55,6 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, key = sta->key; } - if (!key) - return -ENOENT; - ieee80211_key_free(key); return 0; } else { -- cgit v1.2.3-59-g8ed1b From 24709182754625829e499b5d628affa881d1dba0 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Tue, 25 Mar 2008 16:33:39 -0700 Subject: mac80211: fix wrong Rx A-MPDU control via debugfs This patch eliminate the use of buf_size as a trigger in favor of a new flag to control Rx A-MPDU sessions through debugfs Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- net/mac80211/debugfs_sta.c | 6 ++++-- net/mac80211/sta_info.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index fc2c1a192ed2..62354de0199f 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -230,11 +230,13 @@ static ssize_t sta_agg_status_write(struct file *file, strcpy(state, "off "); ieee80211_sta_stop_rx_ba_session(dev, da, tid_num, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); - sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0xFF; + sta->ampdu_mlme.tid_rx[tid_num].state |= + HT_AGG_STATE_DEBUGFS_CTL; tid_static_rx[tid_num] = 0; } else { strcpy(state, "on "); - sta->ampdu_mlme.tid_rx[tid_num].buf_size = 0x00; + sta->ampdu_mlme.tid_rx[tid_num].state &= + ~HT_AGG_STATE_DEBUGFS_CTL; tid_static_rx[tid_num] = 1; } printk(KERN_DEBUG "debugfs - try switching tid %u %s\n", diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index f166c8039f2b..5d6b43652e18 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -63,6 +63,7 @@ enum ieee80211_sta_info_flags { #define HT_AGG_STATE_OPERATIONAL (HT_ADDBA_REQUESTED_MSK | \ HT_ADDBA_DRV_READY_MSK | \ HT_ADDBA_RECEIVED_MSK) +#define HT_AGG_STATE_DEBUGFS_CTL BIT(7) /** * struct tid_ampdu_tx - TID aggregation information (Tx). -- cgit v1.2.3-59-g8ed1b From 6c507cd0400cb51dd2ee251c1b8756b9375a1128 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Mar 2008 14:14:55 +0100 Subject: cfg80211: don't export ieee80211_get_channel This patch makes ieee80211_get_channel a static inline defined in cfg80211's header file which simply calls __ieee80211_get_channel to avoid symbol clashes with the ieee80211 code. The problem was pointed out by David Miller, thanks! Signed-off-by: Johannes Berg Cc: David Miller Signed-off-by: John W. Linville --- include/net/wireless.h | 18 +++++++++++++++--- net/wireless/util.c | 6 +++--- 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/include/net/wireless.h b/include/net/wireless.h index f4b77ab66bae..667b4080d30f 100644 --- a/include/net/wireless.h +++ b/include/net/wireless.h @@ -304,10 +304,22 @@ extern int ieee80211_channel_to_frequency(int chan); */ extern int ieee80211_frequency_to_channel(int freq); +/* + * Name indirection necessary because the ieee80211 code also has + * a function named "ieee80211_get_channel", so if you include + * cfg80211's header file you get cfg80211's version, if you try + * to include both header files you'll (rightfully!) get a symbol + * clash. + */ +extern struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, + int freq); + /** * ieee80211_get_channel - get channel struct from wiphy for specified frequency */ -extern struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, - int freq); - +static inline struct ieee80211_channel * +ieee80211_get_channel(struct wiphy *wiphy, int freq) +{ + return __ieee80211_get_channel(wiphy, freq); +} #endif /* __NET_WIRELESS_H */ diff --git a/net/wireless/util.c b/net/wireless/util.c index f3e623df3515..f54424693a38 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -33,8 +33,8 @@ int ieee80211_frequency_to_channel(int freq) } EXPORT_SYMBOL(ieee80211_frequency_to_channel); -struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, - int freq) +struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy, + int freq) { enum ieee80211_band band; struct ieee80211_supported_band *sband; @@ -54,7 +54,7 @@ struct ieee80211_channel *ieee80211_get_channel(struct wiphy *wiphy, return NULL; } -EXPORT_SYMBOL(ieee80211_get_channel); +EXPORT_SYMBOL(__ieee80211_get_channel); static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, enum ieee80211_band band) -- cgit v1.2.3-59-g8ed1b From cee24a3e580f1062c8bb8b1692b95014d882bc7d Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Wed, 26 Mar 2008 20:36:03 +0200 Subject: mac80211: A-MPDU MLME use dynamic allocation This patch alters the A-MPDU MLME in sta_info to use dynamic allocation, thus drastically improving memory usage - from a constant ~2 Kbyte in the previous (static) allocation to a lower limit of ~200 Byte and an upper limit of ~2 Kbyte. Signed-off-by: Ron Rindjunsky Signed-off-by: Tomas Winkler Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 2 +- net/mac80211/debugfs_sta.c | 17 +++--- net/mac80211/ieee80211.c | 64 +++++++++++++++-------- net/mac80211/ieee80211_sta.c | 84 +++++++++++++++++++----------- net/mac80211/rx.c | 10 ++-- net/mac80211/sta_info.c | 30 ++++++----- net/mac80211/sta_info.h | 44 ++++++++-------- 7 files changed, 151 insertions(+), 100 deletions(-) (limited to 'net') diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 7d7ce7489ab5..735eadd57d18 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -397,7 +397,7 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, DECLARE_MAC_BUF(mac); spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); - state = sta->ampdu_mlme.tid_tx[tid].state; + state = sta->ampdu_mlme.tid_state_tx[tid]; spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); if (state == HT_AGG_STATE_IDLE && diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 62354de0199f..256ea880d28b 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -169,27 +169,30 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, p += scnprintf(p, sizeof(buf)+buf-p, "\n RX :"); for (i = 0; i < STA_TID_NUM; i++) p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_rx[i].state); + sta->ampdu_mlme.tid_state_rx[i]); p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:"); for (i = 0; i < STA_TID_NUM; i++) p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_rx[i].dialog_token); + sta->ampdu_mlme.tid_state_rx[i]? + sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); p += scnprintf(p, sizeof(buf)+buf-p, "\n TX :"); for (i = 0; i < STA_TID_NUM; i++) p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_tx[i].state); + sta->ampdu_mlme.tid_state_tx[i]); p += scnprintf(p, sizeof(buf)+buf-p, "\n DTKN:"); for (i = 0; i < STA_TID_NUM; i++) p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_tx[i].dialog_token); + sta->ampdu_mlme.tid_state_tx[i]? + sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); p += scnprintf(p, sizeof(buf)+buf-p, "\n SSN :"); for (i = 0; i < STA_TID_NUM; i++) p += scnprintf(p, sizeof(buf)+buf-p, "%5d", - sta->ampdu_mlme.tid_tx[i].ssn); + sta->ampdu_mlme.tid_state_tx[i]? + sta->ampdu_mlme.tid_tx[i]->ssn : 0); p += scnprintf(p, sizeof(buf)+buf-p, "\n"); @@ -230,12 +233,12 @@ static ssize_t sta_agg_status_write(struct file *file, strcpy(state, "off "); ieee80211_sta_stop_rx_ba_session(dev, da, tid_num, 0, WLAN_REASON_QSTA_REQUIRE_SETUP); - sta->ampdu_mlme.tid_rx[tid_num].state |= + sta->ampdu_mlme.tid_state_rx[tid_num] |= HT_AGG_STATE_DEBUGFS_CTL; tid_static_rx[tid_num] = 0; } else { strcpy(state, "on "); - sta->ampdu_mlme.tid_rx[tid_num].state &= + sta->ampdu_mlme.tid_state_rx[tid_num] &= ~HT_AGG_STATE_DEBUGFS_CTL; tid_static_rx[tid_num] = 1; } diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 616ce10d2a38..8c0f782d21e3 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -569,12 +569,12 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); /* we have tried too many times, receiver does not want A-MPDU */ - if (sta->ampdu_mlme.tid_tx[tid].addba_req_num > HT_AGG_MAX_RETRIES) { + if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { ret = -EBUSY; goto start_ba_exit; } - state = &sta->ampdu_mlme.tid_tx[tid].state; + state = &sta->ampdu_mlme.tid_state_tx[tid]; /* check if the TID is not in aggregation flow already */ if (*state != HT_AGG_STATE_IDLE) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -585,6 +585,23 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) goto start_ba_exit; } + /* prepare A-MPDU MLME for Tx aggregation */ + sta->ampdu_mlme.tid_tx[tid] = + kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); + if (!sta->ampdu_mlme.tid_tx[tid]) { + if (net_ratelimit()) + printk(KERN_ERR "allocate tx mlme to tid %d failed\n", + tid); + ret = -ENOMEM; + goto start_ba_exit; + } + /* Tx timer */ + sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = + sta_addba_resp_timer_expired; + sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data = + (unsigned long)&sta->timer_to_tid[tid]; + init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); + /* ensure that TX flow won't interrupt us * until the end of the call to requeue function */ spin_lock_bh(&local->mdev->queue_lock); @@ -596,11 +613,10 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) * don't switch to aggregation */ if (ret) { #ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "BA request denied - no queue available for" + printk(KERN_DEBUG "BA request denied - queue unavailable for" " tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - spin_unlock_bh(&local->mdev->queue_lock); - goto start_ba_exit; + goto start_ba_err; } sdata = sta->sdata; @@ -618,38 +634,40 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) * allocated queue */ ieee80211_ht_agg_queue_remove(local, sta, tid, 0); #ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "BA request denied - HW or queue unavailable" - " for tid %d\n", tid); + printk(KERN_DEBUG "BA request denied - HW unavailable for" + " tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - spin_unlock_bh(&local->mdev->queue_lock); *state = HT_AGG_STATE_IDLE; - goto start_ba_exit; + goto start_ba_err; } /* Will put all the packets in the new SW queue */ ieee80211_requeue(local, ieee802_1d_to_ac[tid]); spin_unlock_bh(&local->mdev->queue_lock); - /* We have most probably almost emptied the legacy queue */ - /* ieee80211_wake_queue(local_to_hw(local), ieee802_1d_to_ac[tid]); */ - /* send an addBA request */ sta->ampdu_mlme.dialog_token_allocator++; - sta->ampdu_mlme.tid_tx[tid].dialog_token = + sta->ampdu_mlme.tid_tx[tid]->dialog_token = sta->ampdu_mlme.dialog_token_allocator; - sta->ampdu_mlme.tid_tx[tid].ssn = start_seq_num; + sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; ieee80211_send_addba_request(sta->sdata->dev, ra, tid, - sta->ampdu_mlme.tid_tx[tid].dialog_token, - sta->ampdu_mlme.tid_tx[tid].ssn, + sta->ampdu_mlme.tid_tx[tid]->dialog_token, + sta->ampdu_mlme.tid_tx[tid]->ssn, 0x40, 5000); /* activate the timer for the recipient's addBA response */ - sta->ampdu_mlme.tid_tx[tid].addba_resp_timer.expires = + sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = jiffies + ADDBA_RESP_INTERVAL; - add_timer(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer); + add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); + goto start_ba_exit; +start_ba_err: + kfree(sta->ampdu_mlme.tid_tx[tid]); + sta->ampdu_mlme.tid_tx[tid] = NULL; + spin_unlock_bh(&local->mdev->queue_lock); + ret = -EBUSY; start_ba_exit: spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); rcu_read_unlock(); @@ -683,7 +701,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, } /* check if the TID is in aggregation */ - state = &sta->ampdu_mlme.tid_tx[tid].state; + state = &sta->ampdu_mlme.tid_state_tx[tid]; spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); if (*state != HT_AGG_STATE_OPERATIONAL) { @@ -741,7 +759,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) return; } - state = &sta->ampdu_mlme.tid_tx[tid].state; + state = &sta->ampdu_mlme.tid_state_tx[tid]; spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); if (!(*state & HT_ADDBA_REQUESTED_MSK)) { @@ -790,7 +808,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) rcu_read_unlock(); return; } - state = &sta->ampdu_mlme.tid_tx[tid].state; + state = &sta->ampdu_mlme.tid_state_tx[tid]; spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { @@ -819,7 +837,9 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) * necessarily stopped */ netif_schedule(local->mdev); *state = HT_AGG_STATE_IDLE; - sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0; + sta->ampdu_mlme.addba_req_num[tid] = 0; + kfree(sta->ampdu_mlme.tid_tx[tid]); + sta->ampdu_mlme.tid_tx[tid] = NULL; spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); rcu_read_unlock(); diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index cf51ca6804dd..f9cf2f187893 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1216,12 +1216,11 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, buf_size = buf_size << sband->ht_info.ampdu_factor; } - tid_agg_rx = &sta->ampdu_mlme.tid_rx[tid]; /* examine state machine */ spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); - if (tid_agg_rx->state != HT_AGG_STATE_IDLE) { + if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "unexpected AddBA Req from " @@ -1231,6 +1230,24 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, goto end; } + /* prepare A-MPDU MLME for Rx aggregation */ + sta->ampdu_mlme.tid_rx[tid] = + kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); + if (!sta->ampdu_mlme.tid_rx[tid]) { + if (net_ratelimit()) + printk(KERN_ERR "allocate rx mlme to tid %d failed\n", + tid); + goto end; + } + /* rx timer */ + sta->ampdu_mlme.tid_rx[tid]->session_timer.function = + sta_rx_agg_session_timer_expired; + sta->ampdu_mlme.tid_rx[tid]->session_timer.data = + (unsigned long)&sta->timer_to_tid[tid]; + init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer); + + tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; + /* prepare reordering buffer */ tid_agg_rx->reorder_buf = kmalloc(buf_size * sizeof(struct sk_buf *), GFP_ATOMIC); @@ -1238,6 +1255,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, if (net_ratelimit()) printk(KERN_ERR "can not allocate reordering buffer " "to tid %d\n", tid); + kfree(sta->ampdu_mlme.tid_rx[tid]); goto end; } memset(tid_agg_rx->reorder_buf, 0, @@ -1252,11 +1270,13 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, if (ret) { kfree(tid_agg_rx->reorder_buf); + kfree(tid_agg_rx); + sta->ampdu_mlme.tid_rx[tid] = NULL; goto end; } /* change state and send addba resp */ - tid_agg_rx->state = HT_AGG_STATE_OPERATIONAL; + sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL; tid_agg_rx->dialog_token = dialog_token; tid_agg_rx->ssn = start_seq_num; tid_agg_rx->head_seq_num = start_seq_num; @@ -1295,39 +1315,37 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; - state = &sta->ampdu_mlme.tid_tx[tid].state; + state = &sta->ampdu_mlme.tid_state_tx[tid]; spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" + "%d\n", *state); + goto addba_resp_exit; + } + if (mgmt->u.action.u.addba_resp.dialog_token != - sta->ampdu_mlme.tid_tx[tid].dialog_token) { + sta->ampdu_mlme.tid_tx[tid]->dialog_token) { spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - rcu_read_unlock(); - return; + goto addba_resp_exit; } - del_timer_sync(&sta->ampdu_mlme.tid_tx[tid].addba_resp_timer); + del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) == WLAN_STATUS_SUCCESS) { - if (!(*state & HT_ADDBA_REQUESTED_MSK)) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" - "%d\n", *state); - rcu_read_unlock(); - return; - } - if (*state & HT_ADDBA_RECEIVED_MSK) printk(KERN_DEBUG "double addBA response\n"); *state |= HT_ADDBA_RECEIVED_MSK; - sta->ampdu_mlme.tid_tx[tid].addba_req_num = 0; + sta->ampdu_mlme.addba_req_num[tid] = 0; if (*state == HT_AGG_STATE_OPERATIONAL) { printk(KERN_DEBUG "Aggregation on for tid %d \n", tid); @@ -1339,13 +1357,15 @@ static void ieee80211_sta_process_addba_resp(struct net_device *dev, } else { printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid); - sta->ampdu_mlme.tid_tx[tid].addba_req_num++; + sta->ampdu_mlme.addba_req_num[tid]++; /* this will allow the state check in stop_BA_session */ *state = HT_AGG_STATE_OPERATIONAL; spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); ieee80211_stop_tx_ba_session(hw, sta->addr, tid, WLAN_BACK_INITIATOR); } + +addba_resp_exit: rcu_read_unlock(); } @@ -1411,13 +1431,13 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, /* check if TID is in operational state */ spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); - if (sta->ampdu_mlme.tid_rx[tid].state + if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) { spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); rcu_read_unlock(); return; } - sta->ampdu_mlme.tid_rx[tid].state = + sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); @@ -1434,25 +1454,27 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, /* shutdown timer has not expired */ if (initiator != WLAN_BACK_TIMER) - del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]. - session_timer); + del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer); /* check if this is a self generated aggregation halt */ if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER) ieee80211_send_delba(dev, ra, tid, 0, reason); /* free the reordering buffer */ - for (i = 0; i < sta->ampdu_mlme.tid_rx[tid].buf_size; i++) { - if (sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]) { + for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) { + if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) { /* release the reordered frames */ - dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid].reorder_buf[i]); - sta->ampdu_mlme.tid_rx[tid].stored_mpdu_num--; - sta->ampdu_mlme.tid_rx[tid].reorder_buf[i] = NULL; + dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]); + sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--; + sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL; } } - kfree(sta->ampdu_mlme.tid_rx[tid].reorder_buf); + /* free resources */ + kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); + kfree(sta->ampdu_mlme.tid_rx[tid]); + sta->ampdu_mlme.tid_rx[tid] = NULL; + sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE; - sta->ampdu_mlme.tid_rx[tid].state = HT_AGG_STATE_IDLE; rcu_read_unlock(); } @@ -1491,7 +1513,7 @@ static void ieee80211_sta_process_delba(struct net_device *dev, WLAN_BACK_INITIATOR, 0); else { /* WLAN_BACK_RECIPIENT */ spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); - sta->ampdu_mlme.tid_tx[tid].state = + sta->ampdu_mlme.tid_state_tx[tid] = HT_AGG_STATE_OPERATIONAL; spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, @@ -1528,7 +1550,7 @@ void sta_addba_resp_timer_expired(unsigned long data) return; } - state = &sta->ampdu_mlme.tid_tx[tid].state; + state = &sta->ampdu_mlme.tid_state_tx[tid]; /* check if the TID waits for addBA response */ spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); if (!(*state & HT_ADDBA_REQUESTED_MSK)) { diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 644d2774469d..d9c6ed5be4fc 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1514,9 +1514,10 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) if (!rx->sta) return RX_CONTINUE; tid = le16_to_cpu(bar->control) >> 12; - tid_agg_rx = &(rx->sta->ampdu_mlme.tid_rx[tid]); - if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL) + if (rx->sta->ampdu_mlme.tid_state_rx[tid] + != HT_AGG_STATE_OPERATIONAL) return RX_CONTINUE; + tid_agg_rx = rx->sta->ampdu_mlme.tid_rx[tid]; start_seq_num = le16_to_cpu(bar->start_seq_num) >> 4; @@ -2123,11 +2124,12 @@ static u8 ieee80211_rx_reorder_ampdu(struct ieee80211_local *local, qc = skb->data + ieee80211_get_hdrlen(fc) - QOS_CONTROL_LEN; tid = qc[0] & QOS_CONTROL_TID_MASK; - tid_agg_rx = &(sta->ampdu_mlme.tid_rx[tid]); - if (tid_agg_rx->state != HT_AGG_STATE_OPERATIONAL) + if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_OPERATIONAL) goto end_reorder; + tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; + /* null data frames are excluded */ if (unlikely(fc & IEEE80211_STYPE_NULLFUNC)) goto end_reorder; diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 3b84c16cf054..f708367092d1 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -170,9 +170,16 @@ void sta_info_destroy(struct sta_info *sta) dev_kfree_skb_any(skb); for (i = 0; i < STA_TID_NUM; i++) { - del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); - del_timer_sync(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); + spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + if (sta->ampdu_mlme.tid_rx[i]) + del_timer_sync(&sta->ampdu_mlme.tid_rx[i]->session_timer); + spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + if (sta->ampdu_mlme.tid_tx[i]) + del_timer_sync(&sta->ampdu_mlme.tid_tx[i]->addba_resp_timer); + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); } + rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); rate_control_put(sta->rate_ctrl); @@ -227,18 +234,13 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, sta->timer_to_tid[i] = i; /* tid to tx queue: initialize according to HW (0 is valid) */ sta->tid_to_tx_q[i] = local->hw.queues; - /* rx timers */ - sta->ampdu_mlme.tid_rx[i].session_timer.function = - sta_rx_agg_session_timer_expired; - sta->ampdu_mlme.tid_rx[i].session_timer.data = - (unsigned long)&sta->timer_to_tid[i]; - init_timer(&sta->ampdu_mlme.tid_rx[i].session_timer); - /* tx timers */ - sta->ampdu_mlme.tid_tx[i].addba_resp_timer.function = - sta_addba_resp_timer_expired; - sta->ampdu_mlme.tid_tx[i].addba_resp_timer.data = - (unsigned long)&sta->timer_to_tid[i]; - init_timer(&sta->ampdu_mlme.tid_tx[i].addba_resp_timer); + /* rx */ + sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE; + sta->ampdu_mlme.tid_rx[i] = NULL; + /* tx */ + sta->ampdu_mlme.tid_state_tx[i] = HT_AGG_STATE_IDLE; + sta->ampdu_mlme.tid_tx[i] = NULL; + sta->ampdu_mlme.addba_req_num[i] = 0; } skb_queue_head_init(&sta->ps_tx_buf); skb_queue_head_init(&sta->tx_filtered); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 5d6b43652e18..af5a791e21f3 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -68,43 +68,37 @@ enum ieee80211_sta_info_flags { /** * struct tid_ampdu_tx - TID aggregation information (Tx). * - * @state: TID's state in session state machine. - * @dialog_token: dialog token for aggregation session - * @ssn: Starting Sequence Number expected to be aggregated. * @addba_resp_timer: timer for peer's response to addba request - * @addba_req_num: number of times addBA request has been sent. + * @ssn: Starting Sequence Number expected to be aggregated. + * @dialog_token: dialog token for aggregation session */ struct tid_ampdu_tx { - u8 state; - u8 dialog_token; - u16 ssn; struct timer_list addba_resp_timer; - u8 addba_req_num; + u16 ssn; + u8 dialog_token; }; /** * struct tid_ampdu_rx - TID aggregation information (Rx). * - * @state: TID's state in session state machine. - * @dialog_token: dialog token for aggregation session - * @ssn: Starting Sequence Number expected to be aggregated. - * @buf_size: buffer size for incoming A-MPDUs - * @timeout: reset timer value. * @head_seq_num: head sequence number in reordering buffer. * @stored_mpdu_num: number of MPDUs in reordering buffer * @reorder_buf: buffer to reorder incoming aggregated MPDUs * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) + * @ssn: Starting Sequence Number expected to be aggregated. + * @buf_size: buffer size for incoming A-MPDUs + * @timeout: reset timer value. + * @dialog_token: dialog token for aggregation session */ struct tid_ampdu_rx { - u8 state; - u8 dialog_token; - u16 ssn; - u16 buf_size; - u16 timeout; u16 head_seq_num; u16 stored_mpdu_num; struct sk_buff **reorder_buf; struct timer_list session_timer; + u16 ssn; + u16 buf_size; + u16 timeout; + u8 dialog_token; }; /** @@ -133,16 +127,24 @@ enum plink_state { /** * struct sta_ampdu_mlme - STA aggregation information. * + * @tid_state_rx: TID's state in Rx session state machine. * @tid_rx: aggregation info for Rx per TID - * @tid_tx: aggregation info for Tx per TID * @ampdu_rx: for locking sections in aggregation Rx flow + * @tid_state_tx: TID's state in Tx session state machine. + * @tid_tx: aggregation info for Tx per TID + * @addba_req_num: number of times addBA request has been sent. * @ampdu_tx: for locking sectionsi in aggregation Tx flow * @dialog_token_allocator: dialog token enumerator for each new session; */ struct sta_ampdu_mlme { - struct tid_ampdu_rx tid_rx[STA_TID_NUM]; - struct tid_ampdu_tx tid_tx[STA_TID_NUM]; + /* rx */ + u8 tid_state_rx[STA_TID_NUM]; + struct tid_ampdu_rx *tid_rx[STA_TID_NUM]; spinlock_t ampdu_rx; + /* tx */ + u8 tid_state_tx[STA_TID_NUM]; + struct tid_ampdu_tx *tid_tx[STA_TID_NUM]; + u8 addba_req_num[STA_TID_NUM]; spinlock_t ampdu_tx; u8 dialog_token_allocator; }; -- cgit v1.2.3-59-g8ed1b From 056cdd599d004e36de64c925b8a13f6676451360 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 26 Mar 2008 23:21:47 +0100 Subject: mac80211: reorder fields to make some structures smaller This patch reorders some fields in various structures to have less padding within the structures, making them smaller. It doesn't yet make any type adjustments, but often size_t is used for example for IE lengths which is total overkill since size_t will be 8 bytes long on 64-bit yet the length can at most fill a u8. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 50 +++++++++++++++++++++++++--------------------- net/mac80211/sta_info.h | 8 ++++---- 2 files changed, 31 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index a6485f01b3c8..7ab806602183 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -73,11 +73,12 @@ struct ieee80211_fragment_entry { struct ieee80211_sta_bss { struct list_head list; struct ieee80211_sta_bss *hnext; + size_t ssid_len; + atomic_t users; u8 bssid[ETH_ALEN]; u8 ssid[IEEE80211_MAX_SSID_LEN]; - size_t ssid_len; u16 capability; /* host byte order */ enum ieee80211_band band; int freq; @@ -98,8 +99,8 @@ struct ieee80211_sta_bss { #define IEEE80211_MAX_SUPP_RATES 32 u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; size_t supp_rates_len; - int beacon_int; u64 timestamp; + int beacon_int; int probe_resp; unsigned long last_update; @@ -154,9 +155,7 @@ struct ieee80211_tx_data { struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; struct sta_info *sta; - u16 fc, ethertype; struct ieee80211_key *key; - unsigned int flags; struct ieee80211_tx_control *control; struct ieee80211_channel *channel; @@ -168,8 +167,11 @@ struct ieee80211_tx_data { /* Extra fragments (in addition to the first fragment * in skb) */ - int num_extra_frag; struct sk_buff **extra_frag; + int num_extra_frag; + + u16 fc, ethertype; + unsigned int flags; }; @@ -192,12 +194,12 @@ struct ieee80211_rx_data { struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; struct sta_info *sta; - u16 fc, ethertype; struct ieee80211_key *key; - unsigned int flags; - struct ieee80211_rx_status *status; struct ieee80211_rate *rate; + + u16 fc, ethertype; + unsigned int flags; int sent_ps_buffered; int queue; int load; @@ -222,9 +224,9 @@ struct ieee80211_tx_packet_data { struct ieee80211_tx_stored_packet { struct ieee80211_tx_control control; struct sk_buff *skb; - int num_extra_frag; struct sk_buff **extra_frag; struct ieee80211_rate *last_frag_rate; + int num_extra_frag; unsigned int last_frag_rate_ctrl_probe; }; @@ -246,8 +248,8 @@ struct ieee80211_if_ap { * bitmap_empty :) * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]; - atomic_t num_sta_ps; /* number of stations in PS mode */ struct sk_buff_head ps_bc_buf; + atomic_t num_sta_ps; /* number of stations in PS mode */ int dtim_count; int force_unicast_rateidx; /* forced TX rateidx for unicast frames */ int max_ratectrl_rateidx; /* max TX rateidx for rate control */ @@ -255,8 +257,8 @@ struct ieee80211_if_ap { }; struct ieee80211_if_wds { - u8 remote_addr[ETH_ALEN]; struct sta_info *sta; + u8 remote_addr[ETH_ALEN]; }; struct ieee80211_if_vlan { @@ -290,12 +292,12 @@ struct mesh_config { u8 dot11MeshTTL; bool auto_open_plinks; /* HWMP parameters */ - u32 dot11MeshHWMPactivePathTimeout; - u16 dot11MeshHWMPpreqMinInterval; - u16 dot11MeshHWMPnetDiameterTraversalTime; u8 dot11MeshHWMPmaxPREQretries; u32 path_refresh_time; u16 min_discovery_timeout; + u32 dot11MeshHWMPactivePathTimeout; + u16 dot11MeshHWMPpreqMinInterval; + u16 dot11MeshHWMPnetDiameterTraversalTime; }; @@ -314,23 +316,22 @@ struct mesh_config { #define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) #define IEEE80211_STA_PRIVACY_INVOKED BIT(13) struct ieee80211_if_sta { + struct timer_list timer; + struct work_struct work; + u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; + u8 ssid[IEEE80211_MAX_SSID_LEN]; enum { IEEE80211_DISABLED, IEEE80211_AUTHENTICATE, IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED, IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED, IEEE80211_MESH_UP } state; - struct timer_list timer; - struct work_struct work; - u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN]; - u8 ssid[IEEE80211_MAX_SSID_LEN]; size_t ssid_len; u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; size_t scan_ssid_len; #ifdef CONFIG_MAC80211_MESH struct timer_list mesh_path_timer; u8 mesh_id[IEEE80211_MAX_MESH_ID_LEN]; - bool accepting_plinks; size_t mesh_id_len; /* Active Path Selection Protocol Identifier */ u8 mesh_pp_id[4]; @@ -354,6 +355,7 @@ struct ieee80211_if_sta { struct mesh_stats mshstats; struct mesh_config mshcfg; u8 mesh_seqnum[3]; + bool accepting_plinks; #endif u16 aid; u16 ap_capab, capab; @@ -364,16 +366,18 @@ struct ieee80211_if_sta { u8 *assocreq_ies, *assocresp_ies; size_t assocreq_ies_len, assocresp_ies_len; + struct sk_buff_head skb_queue; + int auth_tries, assoc_tries; + unsigned long request; + + unsigned long last_probe; + unsigned int flags; #define IEEE80211_STA_REQ_SCAN 0 #define IEEE80211_STA_REQ_AUTH 1 #define IEEE80211_STA_REQ_RUN 2 - unsigned long request; - struct sk_buff_head skb_queue; - - unsigned long last_probe; #define IEEE80211_AUTH_ALG_OPEN BIT(0) #define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index af5a791e21f3..5e39a4164b9b 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -81,20 +81,20 @@ struct tid_ampdu_tx { /** * struct tid_ampdu_rx - TID aggregation information (Rx). * - * @head_seq_num: head sequence number in reordering buffer. - * @stored_mpdu_num: number of MPDUs in reordering buffer * @reorder_buf: buffer to reorder incoming aggregated MPDUs * @session_timer: check if peer keeps Tx-ing on the TID (by timeout value) + * @head_seq_num: head sequence number in reordering buffer. + * @stored_mpdu_num: number of MPDUs in reordering buffer * @ssn: Starting Sequence Number expected to be aggregated. * @buf_size: buffer size for incoming A-MPDUs * @timeout: reset timer value. * @dialog_token: dialog token for aggregation session */ struct tid_ampdu_rx { - u16 head_seq_num; - u16 stored_mpdu_num; struct sk_buff **reorder_buf; struct timer_list session_timer; + u16 head_seq_num; + u16 stored_mpdu_num; u16 ssn; u16 buf_size; u16 timeout; -- cgit v1.2.3-59-g8ed1b From 0dde3e16485dca16eb682dd59da1a598bf62e284 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Thu, 27 Mar 2008 17:43:41 -0700 Subject: [NET]: uninline skb_put, de-bloats a lot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allyesconfig (v2.6.24-mm1): ~500 files changed ... 869 funcs, 198 +, 111003 -, diff: -110805 --- skb_put skb_put | +104 Without number of debug related CONFIGs (v2.6.25-rc2-mm1): -60744 855 funcs, 861 +, 61605 -, diff: -60744 --- skb_put skb_put | +57 Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller --- include/linux/skbuff.h | 21 +-------------------- net/core/skbuff.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 7beb239d2ee0..f085955cb5a7 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -892,6 +892,7 @@ static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset) /* * Add data to an sk_buff */ +extern unsigned char *skb_put(struct sk_buff *skb, unsigned int len); static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len) { unsigned char *tmp = skb_tail_pointer(skb); @@ -901,26 +902,6 @@ static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len) return tmp; } -/** - * skb_put - add data to a buffer - * @skb: buffer to use - * @len: amount of data to add - * - * This function extends the used data area of the buffer. If this would - * exceed the total buffer size the kernel will panic. A pointer to the - * first byte of the extra data is returned. - */ -static inline unsigned char *skb_put(struct sk_buff *skb, unsigned int len) -{ - unsigned char *tmp = skb_tail_pointer(skb); - SKB_LINEAR_ASSERT(skb); - skb->tail += len; - skb->len += len; - if (unlikely(skb->tail > skb->end)) - skb_over_panic(skb, len, current_text_addr()); - return tmp; -} - static inline unsigned char *__skb_push(struct sk_buff *skb, unsigned int len) { skb->data -= len; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 0d0fd28a9041..3402eca768f8 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -857,6 +857,27 @@ free_skb: return err; } +/** + * skb_put - add data to a buffer + * @skb: buffer to use + * @len: amount of data to add + * + * This function extends the used data area of the buffer. If this would + * exceed the total buffer size the kernel will panic. A pointer to the + * first byte of the extra data is returned. + */ +unsigned char *skb_put(struct sk_buff *skb, unsigned int len) +{ + unsigned char *tmp = skb_tail_pointer(skb); + SKB_LINEAR_ASSERT(skb); + skb->tail += len; + skb->len += len; + if (unlikely(skb->tail > skb->end)) + skb_over_panic(skb, len, __builtin_return_address(0)); + return tmp; +} +EXPORT_SYMBOL(skb_put); + /* Trims skb to length len. It can change skb pointers. */ -- cgit v1.2.3-59-g8ed1b From 6be8ac2fdc5e69dec53913a42312a92dbfbd4907 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Thu, 27 Mar 2008 17:47:24 -0700 Subject: [NET]: uninline skb_pull, de-bloats a lot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allyesconfig (v2.6.24-mm1): -28162 354 funcs, 3005 +, 31167 -, diff: -28162 --- skb_pull Without number of debug related CONFIGs (v2.6.25-rc2-mm1): -9697 338 funcs, 221 +, 9918 -, diff: -9697 --- skb_pull skb_pull | +44 Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller --- include/linux/skbuff.h | 16 +--------------- net/core/skbuff.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index f085955cb5a7..6d6cde7b243c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -927,6 +927,7 @@ static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len) return skb->data; } +extern unsigned char *skb_pull(struct sk_buff *skb, unsigned int len); static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len) { skb->len -= len; @@ -934,21 +935,6 @@ static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len) return skb->data += len; } -/** - * skb_pull - remove data from the start of a buffer - * @skb: buffer to use - * @len: amount of data to remove - * - * This function removes data from the start of a buffer, returning - * the memory to the headroom. A pointer to the next data in the buffer - * is returned. Once the data has been pulled future pushes will overwrite - * the old data. - */ -static inline unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) -{ - return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len); -} - extern unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta); static inline unsigned char *__pskb_pull(struct sk_buff *skb, unsigned int len) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 3402eca768f8..cf489b6329e8 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -878,6 +878,22 @@ unsigned char *skb_put(struct sk_buff *skb, unsigned int len) } EXPORT_SYMBOL(skb_put); +/** + * skb_pull - remove data from the start of a buffer + * @skb: buffer to use + * @len: amount of data to remove + * + * This function removes data from the start of a buffer, returning + * the memory to the headroom. A pointer to the next data in the buffer + * is returned. Once the data has been pulled future pushes will overwrite + * the old data. + */ +unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) +{ + return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len); +} +EXPORT_SYMBOL(skb_pull); + /* Trims skb to length len. It can change skb pointers. */ -- cgit v1.2.3-59-g8ed1b From f58518e678e5eef430c8d5cdcc7cd28d285f1980 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Thu, 27 Mar 2008 17:51:31 -0700 Subject: [NET]: uninline dev_alloc_skb, de-bloats a lot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allyesconfig (v2.6.24-mm1): -23668 392 funcs, 104 +, 23772 -, diff: -23668 --- dev_alloc_skb Without many debug CONFIGs (v2.6.25-rc2-mm1): -12178 382 funcs, 157 +, 12335 -, diff: -12178 --- dev_alloc_skb dev_alloc_skb | +37 Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller --- include/linux/skbuff.h | 17 +---------------- net/core/skbuff.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 6d6cde7b243c..01a11b0c0291 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1272,22 +1272,7 @@ static inline struct sk_buff *__dev_alloc_skb(unsigned int length, return skb; } -/** - * dev_alloc_skb - allocate an skbuff for receiving - * @length: length to allocate - * - * Allocate a new &sk_buff and assign it a usage count of one. The - * buffer has unspecified headroom built in. Users should allocate - * the headroom they think they need without accounting for the - * built in space. The built in space is used for optimisations. - * - * %NULL is returned if there is no free memory. Although this function - * allocates memory it can be called from an interrupt. - */ -static inline struct sk_buff *dev_alloc_skb(unsigned int length) -{ - return __dev_alloc_skb(length, GFP_ATOMIC); -} +extern struct sk_buff *dev_alloc_skb(unsigned int length); extern struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int length, gfp_t gfp_mask); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index cf489b6329e8..0daf5c0e5b8d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -263,6 +263,24 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, return skb; } +/** + * dev_alloc_skb - allocate an skbuff for receiving + * @length: length to allocate + * + * Allocate a new &sk_buff and assign it a usage count of one. The + * buffer has unspecified headroom built in. Users should allocate + * the headroom they think they need without accounting for the + * built in space. The built in space is used for optimisations. + * + * %NULL is returned if there is no free memory. Although this function + * allocates memory it can be called from an interrupt. + */ +struct sk_buff *dev_alloc_skb(unsigned int length) +{ + return __dev_alloc_skb(length, GFP_ATOMIC); +} +EXPORT_SYMBOL(dev_alloc_skb); + static void skb_drop_list(struct sk_buff **listp) { struct sk_buff *list = *listp; -- cgit v1.2.3-59-g8ed1b From c2aa270ad73d385bd6cdebf5d741bdf18a3e17ad Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Thu, 27 Mar 2008 17:52:40 -0700 Subject: [NET]: uninline skb_push, de-bloats a lot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allyesconfig (v2.6.24-mm1): -21593 356 funcs, 2418 +, 24011 -, diff: -21593 --- skb_push Without many debug related CONFIGs (v2.6.25-rc2-mm1): -13890 341 funcs, 189 +, 14079 -, diff: -13890 --- skb_push skb_push | +46 Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller --- include/linux/skbuff.h | 19 +------------------ net/core/skbuff.c | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 01a11b0c0291..1baf4d43bb2d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -902,6 +902,7 @@ static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len) return tmp; } +extern unsigned char *skb_push(struct sk_buff *skb, unsigned int len); static inline unsigned char *__skb_push(struct sk_buff *skb, unsigned int len) { skb->data -= len; @@ -909,24 +910,6 @@ static inline unsigned char *__skb_push(struct sk_buff *skb, unsigned int len) return skb->data; } -/** - * skb_push - add data to the start of a buffer - * @skb: buffer to use - * @len: amount of data to add - * - * This function extends the used data area of the buffer at the buffer - * start. If this would exceed the total buffer headroom the kernel will - * panic. A pointer to the first byte of the extra data is returned. - */ -static inline unsigned char *skb_push(struct sk_buff *skb, unsigned int len) -{ - skb->data -= len; - skb->len += len; - if (unlikely(skb->datahead)) - skb_under_panic(skb, len, current_text_addr()); - return skb->data; -} - extern unsigned char *skb_pull(struct sk_buff *skb, unsigned int len); static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len) { diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 0daf5c0e5b8d..a37127b5899c 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -896,6 +896,25 @@ unsigned char *skb_put(struct sk_buff *skb, unsigned int len) } EXPORT_SYMBOL(skb_put); +/** + * skb_push - add data to the start of a buffer + * @skb: buffer to use + * @len: amount of data to add + * + * This function extends the used data area of the buffer at the buffer + * start. If this would exceed the total buffer headroom the kernel will + * panic. A pointer to the first byte of the extra data is returned. + */ +unsigned char *skb_push(struct sk_buff *skb, unsigned int len) +{ + skb->data -= len; + skb->len += len; + if (unlikely(skb->datahead)) + skb_under_panic(skb, len, __builtin_return_address(0)); + return skb->data; +} +EXPORT_SYMBOL(skb_push); + /** * skb_pull - remove data from the start of a buffer * @skb: buffer to use -- cgit v1.2.3-59-g8ed1b From 8d3308687f7f1eaa1bb5d202d14752d5f90068eb Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Thu, 27 Mar 2008 17:53:31 -0700 Subject: [NET]: uninline dst_release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codiff stats (allyesconfig, v2.6.24-mm1): -16420 187 funcs, 103 +, 16523 -, diff: -16420 --- dst_release Without number of debug related CONFIGs (v2.6.25-rc2-mm1): -7257 186 funcs, 70 +, 7327 -, diff: -7257 --- dst_release dst_release | +40 Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller --- include/net/dst.h | 10 +--------- net/core/dst.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/net/dst.h b/include/net/dst.h index ae13370e8484..002500e631f5 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -163,15 +163,7 @@ struct dst_entry * dst_clone(struct dst_entry * dst) return dst; } -static inline -void dst_release(struct dst_entry * dst) -{ - if (dst) { - WARN_ON(atomic_read(&dst->__refcnt) < 1); - smp_mb__before_atomic_dec(); - atomic_dec(&dst->__refcnt); - } -} +extern void dst_release(struct dst_entry *dst); /* Children define the path of the packet through the * Linux networking. Thus, destinations are stackable. diff --git a/net/core/dst.c b/net/core/dst.c index 694cd2a3f6d2..fe03266130b6 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -259,6 +259,16 @@ again: return NULL; } +void dst_release(struct dst_entry *dst) +{ + if (dst) { + WARN_ON(atomic_read(&dst->__refcnt) < 1); + smp_mb__before_atomic_dec(); + atomic_dec(&dst->__refcnt); + } +} +EXPORT_SYMBOL(dst_release); + /* Dirty hack. We did it in 2.2 (in __dst_free), * we have _very_ good reasons not to repeat * this mistake in 2.3, but we have no choice -- cgit v1.2.3-59-g8ed1b From 419ae74ecc9494e58928a5c6652f4c072f3ca744 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Thu, 27 Mar 2008 17:54:01 -0700 Subject: [NET]: uninline skb_trim, de-bloats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allyesconfig (v2.6.24-mm1): -10976 209 funcs, 123 +, 11099 -, diff: -10976 --- skb_trim Without number of debug related CONFIGs (v2.6.25-rc2-mm1): -7360 192 funcs, 131 +, 7491 -, diff: -7360 --- skb_trim skb_trim | +42 Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller --- include/linux/skbuff.h | 16 +--------------- net/core/skbuff.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 1baf4d43bb2d..ff72145d5d9e 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1158,21 +1158,7 @@ static inline void __skb_trim(struct sk_buff *skb, unsigned int len) skb_set_tail_pointer(skb, len); } -/** - * skb_trim - remove end from a buffer - * @skb: buffer to alter - * @len: new length - * - * Cut the length of a buffer down by removing data from the tail. If - * the buffer is already under the length specified it is not modified. - * The skb must be linear. - */ -static inline void skb_trim(struct sk_buff *skb, unsigned int len) -{ - if (skb->len > len) - __skb_trim(skb, len); -} - +extern void skb_trim(struct sk_buff *skb, unsigned int len); static inline int __pskb_trim(struct sk_buff *skb, unsigned int len) { diff --git a/net/core/skbuff.c b/net/core/skbuff.c index a37127b5899c..86e5682728be 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -931,6 +931,22 @@ unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) } EXPORT_SYMBOL(skb_pull); +/** + * skb_trim - remove end from a buffer + * @skb: buffer to alter + * @len: new length + * + * Cut the length of a buffer down by removing data from the tail. If + * the buffer is already under the length specified it is not modified. + * The skb must be linear. + */ +void skb_trim(struct sk_buff *skb, unsigned int len) +{ + if (skb->len > len) + __skb_trim(skb, len); +} +EXPORT_SYMBOL(skb_trim); + /* Trims skb to length len. It can change skb pointers. */ -- cgit v1.2.3-59-g8ed1b From bc09dff198e67a98a82c42000006b39f6d502031 Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Thu, 27 Mar 2008 17:54:29 -0700 Subject: [SCTP]: Remove sctp_add_cmd_sf wrapper bloat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With a was number of callsites sctp_add_cmd_sf wrapper bloats kernel by some amount. Due to unlikely tracking allyesconfig, with the initial result were around ~7kB (thus caught my attention) while a non-debug config produced only ~2.3kB effect. I (ij) proposed first a patch to uninline it but Vlad responded with a patch that removed the only sctp_add_cmd call which is wrapped by sctp_add_cmd_sf (I wasn't sure if I could do that). I did minor cleanup to Vlad's patch. Signed-off-by: Ilpo Järvinen Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- include/net/sctp/command.h | 3 +-- include/net/sctp/sm.h | 8 -------- net/sctp/command.c | 10 ++-------- net/sctp/sm_statefuns.c | 8 ++------ 4 files changed, 5 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index 10ae2da6f93b..4263af857794 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -205,12 +205,11 @@ typedef struct { int sctp_init_cmd_seq(sctp_cmd_seq_t *seq); /* Add a command to an sctp_cmd_seq_t. - * Return 0 if the command sequence is full. * * Use the SCTP_* constructors defined by SCTP_ARG_CONSTRUCTOR() above * to wrap data which goes in the obj argument. */ -int sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj); +void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj); /* Return the next command structure in an sctp_cmd_seq. * Return NULL at the end of the sequence. diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index ef9e7ed2c82e..24811732bdb2 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -385,14 +385,6 @@ static inline int ADDIP_SERIAL_gte(__u16 s, __u16 t) return (((s) == (t)) || (((t) - (s)) & ADDIP_SERIAL_SIGN_BIT)); } - -/* Run sctp_add_cmd() generating a BUG() if there is a failure. */ -static inline void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) -{ - if (unlikely(!sctp_add_cmd(seq, verb, obj))) - BUG(); -} - /* Check VTAG of the packet matches the sender's own tag. */ static inline int sctp_vtag_verify(const struct sctp_chunk *chunk, diff --git a/net/sctp/command.c b/net/sctp/command.c index bb977330002a..c0044019db9e 100644 --- a/net/sctp/command.c +++ b/net/sctp/command.c @@ -52,18 +52,12 @@ int sctp_init_cmd_seq(sctp_cmd_seq_t *seq) /* Add a command to a sctp_cmd_seq_t. * Return 0 if the command sequence is full. */ -int sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) +void sctp_add_cmd_sf(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj) { - if (seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS) - goto fail; + BUG_ON(seq->next_free_slot >= SCTP_MAX_NUM_COMMANDS); seq->cmds[seq->next_free_slot].verb = verb; seq->cmds[seq->next_free_slot++].obj = obj; - - return 1; - -fail: - return 0; } /* Return the next command structure in a sctp_cmd_seq. diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 6545b5fcbc73..b534dbef864f 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -3135,12 +3135,8 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep, if (!ev) goto nomem; - if (!sctp_add_cmd(commands, SCTP_CMD_EVENT_ULP, - SCTP_ULPEVENT(ev))) { - sctp_ulpevent_free(ev); - goto nomem; - } - + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, + SCTP_ULPEVENT(ev)); sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR, SCTP_CHUNK(chunk)); } -- cgit v1.2.3-59-g8ed1b From 0a204500f913974b4ca9b6f509a43e1544239c6d Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Mon, 24 Mar 2008 18:39:10 +0900 Subject: [NET] NEIGHBOUR: Make each EXPORT_SYMBOL{,_GPL}() immediately follow its function/variable. Signed-off-by: YOSHIFUJI Hideaki --- net/core/neighbour.c | 53 ++++++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 29 deletions(-) (limited to 'net') diff --git a/net/core/neighbour.c b/net/core/neighbour.c index d8d0ca99c651..d4fae81e5d0d 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -123,6 +123,7 @@ unsigned long neigh_rand_reach_time(unsigned long base) { return (base ? (net_random() % base) + (base >> 1) : 0); } +EXPORT_SYMBOL(neigh_rand_reach_time); static int neigh_forced_gc(struct neigh_table *tbl) @@ -241,6 +242,7 @@ void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev) neigh_flush_dev(tbl, dev); write_unlock_bh(&tbl->lock); } +EXPORT_SYMBOL(neigh_changeaddr); int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) { @@ -253,6 +255,7 @@ int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) pneigh_queue_purge(&tbl->proxy_queue); return 0; } +EXPORT_SYMBOL(neigh_ifdown); static struct neighbour *neigh_alloc(struct neigh_table *tbl) { @@ -374,6 +377,7 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey, read_unlock_bh(&tbl->lock); return n; } +EXPORT_SYMBOL(neigh_lookup); struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net, const void *pkey) @@ -397,6 +401,7 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net, read_unlock_bh(&tbl->lock); return n; } +EXPORT_SYMBOL(neigh_lookup_nodev); struct neighbour *neigh_create(struct neigh_table *tbl, const void *pkey, struct net_device *dev) @@ -465,6 +470,7 @@ out_neigh_release: neigh_release(n); goto out; } +EXPORT_SYMBOL(neigh_create); struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl, struct net *net, const void *pkey, struct net_device *dev) @@ -487,6 +493,7 @@ struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl, return n; } +EXPORT_SYMBOL_GPL(__pneigh_lookup); struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, struct net *net, const void *pkey, @@ -546,6 +553,7 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, out: return n; } +EXPORT_SYMBOL(pneigh_lookup); int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey, @@ -653,6 +661,7 @@ void neigh_destroy(struct neighbour *neigh) atomic_dec(&neigh->tbl->entries); kmem_cache_free(neigh->tbl->kmem_cachep, neigh); } +EXPORT_SYMBOL(neigh_destroy); /* Neighbour state is suspicious; disable fast path. @@ -933,6 +942,7 @@ out_unlock_bh: write_unlock_bh(&neigh->lock); return rc; } +EXPORT_SYMBOL(__neigh_event_send); static void neigh_update_hhs(struct neighbour *neigh) { @@ -1105,6 +1115,7 @@ out: return err; } +EXPORT_SYMBOL(neigh_update); struct neighbour *neigh_event_ns(struct neigh_table *tbl, u8 *lladdr, void *saddr, @@ -1117,6 +1128,7 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl, NEIGH_UPDATE_F_OVERRIDE); return neigh; } +EXPORT_SYMBOL(neigh_event_ns); static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst, __be16 protocol) @@ -1171,6 +1183,7 @@ int neigh_compat_output(struct sk_buff *skb) return dev_queue_xmit(skb); } +EXPORT_SYMBOL(neigh_compat_output); /* Slow and careful. */ @@ -1216,6 +1229,7 @@ out_kfree_skb: kfree_skb(skb); goto out; } +EXPORT_SYMBOL(neigh_resolve_output); /* As fast as possible without hh cache */ @@ -1240,6 +1254,7 @@ int neigh_connected_output(struct sk_buff *skb) } return err; } +EXPORT_SYMBOL(neigh_connected_output); static void neigh_proxy_process(unsigned long arg) { @@ -1301,6 +1316,7 @@ void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, mod_timer(&tbl->proxy_timer, sched_next); spin_unlock(&tbl->proxy_queue.lock); } +EXPORT_SYMBOL(pneigh_enqueue); static inline struct neigh_parms *lookup_neigh_params(struct neigh_table *tbl, struct net *net, int ifindex) @@ -1353,6 +1369,7 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, } return p; } +EXPORT_SYMBOL(neigh_parms_alloc); static void neigh_rcu_free_parms(struct rcu_head *head) { @@ -1383,6 +1400,7 @@ void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) write_unlock_bh(&tbl->lock); NEIGH_PRINTK1("neigh_parms_release: not found\n"); } +EXPORT_SYMBOL(neigh_parms_release); static void neigh_parms_destroy(struct neigh_parms *parms) { @@ -1445,6 +1463,7 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl) tbl->last_flush = now; tbl->last_rand = now + tbl->parms.reachable_time * 20; } +EXPORT_SYMBOL(neigh_table_init_no_netlink); void neigh_table_init(struct neigh_table *tbl) { @@ -1466,6 +1485,7 @@ void neigh_table_init(struct neigh_table *tbl) dump_stack(); } } +EXPORT_SYMBOL(neigh_table_init); int neigh_table_clear(struct neigh_table *tbl) { @@ -1503,6 +1523,7 @@ int neigh_table_clear(struct neigh_table *tbl) return 0; } +EXPORT_SYMBOL(neigh_table_clear); static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { @@ -2536,6 +2557,7 @@ void neigh_app_ns(struct neighbour *n) { __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST); } +EXPORT_SYMBOL(neigh_app_ns); #endif /* CONFIG_ARPD */ #ifdef CONFIG_SYSCTL @@ -2782,6 +2804,7 @@ free: err: return -ENOBUFS; } +EXPORT_SYMBOL(neigh_sysctl_register); void neigh_sysctl_unregister(struct neigh_parms *p) { @@ -2793,6 +2816,7 @@ void neigh_sysctl_unregister(struct neigh_parms *p) kfree(t); } } +EXPORT_SYMBOL(neigh_sysctl_unregister); #endif /* CONFIG_SYSCTL */ @@ -2810,32 +2834,3 @@ static int __init neigh_init(void) subsys_initcall(neigh_init); -EXPORT_SYMBOL(__neigh_event_send); -EXPORT_SYMBOL(neigh_changeaddr); -EXPORT_SYMBOL(neigh_compat_output); -EXPORT_SYMBOL(neigh_connected_output); -EXPORT_SYMBOL(neigh_create); -EXPORT_SYMBOL(neigh_destroy); -EXPORT_SYMBOL(neigh_event_ns); -EXPORT_SYMBOL(neigh_ifdown); -EXPORT_SYMBOL(neigh_lookup); -EXPORT_SYMBOL(neigh_lookup_nodev); -EXPORT_SYMBOL(neigh_parms_alloc); -EXPORT_SYMBOL(neigh_parms_release); -EXPORT_SYMBOL(neigh_rand_reach_time); -EXPORT_SYMBOL(neigh_resolve_output); -EXPORT_SYMBOL(neigh_table_clear); -EXPORT_SYMBOL(neigh_table_init); -EXPORT_SYMBOL(neigh_table_init_no_netlink); -EXPORT_SYMBOL(neigh_update); -EXPORT_SYMBOL(pneigh_enqueue); -EXPORT_SYMBOL(pneigh_lookup); -EXPORT_SYMBOL_GPL(__pneigh_lookup); - -#ifdef CONFIG_ARPD -EXPORT_SYMBOL(neigh_app_ns); -#endif -#ifdef CONFIG_SYSCTL -EXPORT_SYMBOL(neigh_sysctl_register); -EXPORT_SYMBOL(neigh_sysctl_unregister); -#endif -- cgit v1.2.3-59-g8ed1b From be01d655d9b07c1350b19bf3d80eae0059254b4b Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Fri, 28 Mar 2008 12:46:53 +0900 Subject: [NET] NEIGHBOUR: Extract hash/lookup functions for pneigh entries. Extract hash function for pneigh entries from pneigh_lookup(), __pneigh_lookup() and pneigh_delete() as pneigh_hash(). Extract core of pneigh_lookup() and __pneigh_lookup() as __pneigh_lookup_1(). Signed-off-by: YOSHIFUJI Hideaki --- net/core/neighbour.c | 61 +++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 32 deletions(-) (limited to 'net') diff --git a/net/core/neighbour.c b/net/core/neighbour.c index d4fae81e5d0d..75075c303c44 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -472,26 +472,40 @@ out_neigh_release: } EXPORT_SYMBOL(neigh_create); -struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl, - struct net *net, const void *pkey, struct net_device *dev) +static u32 pneigh_hash(const void *pkey, int key_len) { - struct pneigh_entry *n; - int key_len = tbl->key_len; u32 hash_val = *(u32 *)(pkey + key_len - 4); - hash_val ^= (hash_val >> 16); hash_val ^= hash_val >> 8; hash_val ^= hash_val >> 4; hash_val &= PNEIGH_HASHMASK; + return hash_val; +} - for (n = tbl->phash_buckets[hash_val]; n; n = n->next) { +static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n, + struct net *net, + const void *pkey, + int key_len, + struct net_device *dev) +{ + while (n) { if (!memcmp(n->key, pkey, key_len) && - (pneigh_net(n) == net) && + net_eq(pneigh_net(n), net) && (n->dev == dev || !n->dev)) - break; + return n; + n = n->next; } + return NULL; +} - return n; +struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl, + struct net *net, const void *pkey, struct net_device *dev) +{ + int key_len = tbl->key_len; + u32 hash_val = pneigh_hash(pkey, key_len); + + return __pneigh_lookup_1(tbl->phash_buckets[hash_val], + net, pkey, key_len, dev); } EXPORT_SYMBOL_GPL(__pneigh_lookup); @@ -501,26 +515,14 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, { struct pneigh_entry *n; int key_len = tbl->key_len; - u32 hash_val = *(u32 *)(pkey + key_len - 4); - - hash_val ^= (hash_val >> 16); - hash_val ^= hash_val >> 8; - hash_val ^= hash_val >> 4; - hash_val &= PNEIGH_HASHMASK; + u32 hash_val = pneigh_hash(pkey, key_len); read_lock_bh(&tbl->lock); - - for (n = tbl->phash_buckets[hash_val]; n; n = n->next) { - if (!memcmp(n->key, pkey, key_len) && - net_eq(pneigh_net(n), net) && - (n->dev == dev || !n->dev)) { - read_unlock_bh(&tbl->lock); - goto out; - } - } + n = __pneigh_lookup_1(tbl->phash_buckets[hash_val], + net, pkey, key_len, dev); read_unlock_bh(&tbl->lock); - n = NULL; - if (!creat) + + if (n || !creat) goto out; ASSERT_RTNL(); @@ -561,12 +563,7 @@ int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey, { struct pneigh_entry *n, **np; int key_len = tbl->key_len; - u32 hash_val = *(u32 *)(pkey + key_len - 4); - - hash_val ^= (hash_val >> 16); - hash_val ^= hash_val >> 8; - hash_val ^= hash_val >> 4; - hash_val &= PNEIGH_HASHMASK; + u32 hash_val = pneigh_hash(pkey, key_len); write_lock_bh(&tbl->lock); for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL; -- cgit v1.2.3-59-g8ed1b From 0736ffc04eec239cce9fd3c6ae5dce54e14c25c7 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Fri, 28 Mar 2008 13:37:58 +0900 Subject: [IPV6] NEIGH: Optimize is_router check. Our interest is not the whole entry of proxy neighbor but the NTF_ROUTER flag. Let's test it explicitly. Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/ndisc.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index e77b74edfd63..510aa747a404 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -661,18 +661,19 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) } } -static struct pneigh_entry *pndisc_check_router(struct net_device *dev, - struct in6_addr *addr, int *is_router) +static int pndisc_is_router(const void *pkey, + struct net_device *dev) { struct pneigh_entry *n; + int ret = -1; read_lock_bh(&nd_tbl.lock); - n = __pneigh_lookup(&nd_tbl, dev_net(dev), addr, dev); - if (n != NULL) - *is_router = (n->flags & NTF_ROUTER); + n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev); + if (n) + ret = !!(n->flags & NTF_ROUTER); read_unlock_bh(&nd_tbl.lock); - return n; + return ret; } static void ndisc_recv_ns(struct sk_buff *skb) @@ -688,10 +689,9 @@ static void ndisc_recv_ns(struct sk_buff *skb) struct inet6_ifaddr *ifp; struct inet6_dev *idev = NULL; struct neighbour *neigh; - struct pneigh_entry *pneigh = NULL; int dad = ipv6_addr_any(saddr); int inc; - int is_router = 0; + int is_router = -1; if (ipv6_addr_is_multicast(&msg->target)) { ND_PRINTK2(KERN_WARNING @@ -790,8 +790,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) if (ipv6_chk_acast_addr(dev_net(dev), dev, &msg->target) || (idev->cnf.forwarding && (ipv6_devconf.proxy_ndp || idev->cnf.proxy_ndp) && - (pneigh = pndisc_check_router(dev, &msg->target, - &is_router)) != NULL)) { + (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) { if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && skb->pkt_type != PACKET_HOST && inc != 0 && @@ -812,7 +811,8 @@ static void ndisc_recv_ns(struct sk_buff *skb) goto out; } - is_router = !!(pneigh ? is_router : idev->cnf.forwarding); + if (is_router < 0) + is_router = !!idev->cnf.forwarding; if (dad) { struct in6_addr maddr; -- cgit v1.2.3-59-g8ed1b From 1483b8744e1a189b2018e2a1bd82f343d6bb52d2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 28 Mar 2008 15:57:39 -0700 Subject: [NET]: Add inline intent commentary to dev_alloc_skb(). Signed-off-by: Denys Vlasenko Signed-off-by: David S. Miller --- net/core/skbuff.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 86e5682728be..6ef7008a3ef3 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -277,6 +277,10 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev, */ struct sk_buff *dev_alloc_skb(unsigned int length) { + /* + * There is more code here than it seems: + * __def_alloc_skb is an inline + */ return __dev_alloc_skb(length, GFP_ATOMIC); } EXPORT_SYMBOL(dev_alloc_skb); -- cgit v1.2.3-59-g8ed1b From bc578a54f0fd489d0722303f9a52508495ccaf9a Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 28 Mar 2008 16:35:27 -0700 Subject: [NET]: Rename inet_frag.h identifiers COMPLETE, FIRST_IN, LAST_IN to INET_FRAG_* On Fri, 2008-03-28 at 03:24 -0700, Andrew Morton wrote: > they should all be renamed. Done for include/net and net Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- include/net/inet_frag.h | 6 +++--- net/ipv4/inet_fragment.c | 10 +++++----- net/ipv4/ip_fragment.c | 17 +++++++++-------- net/ipv6/netfilter/nf_conntrack_reasm.c | 15 ++++++++------- net/ipv6/reassembly.c | 17 +++++++++-------- 5 files changed, 34 insertions(+), 31 deletions(-) (limited to 'net') diff --git a/include/net/inet_frag.h b/include/net/inet_frag.h index 7374251b9787..e081eefd6f47 100644 --- a/include/net/inet_frag.h +++ b/include/net/inet_frag.h @@ -25,9 +25,9 @@ struct inet_frag_queue { int meat; __u8 last_in; /* first/last segment arrived? */ -#define COMPLETE 4 -#define FIRST_IN 2 -#define LAST_IN 1 +#define INET_FRAG_COMPLETE 4 +#define INET_FRAG_FIRST_IN 2 +#define INET_FRAG_LAST_IN 1 }; #define INETFRAGS_HASHSZ 64 diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index 724d69aed031..93170bfcc22e 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -104,10 +104,10 @@ void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f) if (del_timer(&fq->timer)) atomic_dec(&fq->refcnt); - if (!(fq->last_in & COMPLETE)) { + if (!(fq->last_in & INET_FRAG_COMPLETE)) { fq_unlink(fq, f); atomic_dec(&fq->refcnt); - fq->last_in |= COMPLETE; + fq->last_in |= INET_FRAG_COMPLETE; } } @@ -131,7 +131,7 @@ void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f, struct sk_buff *fp; struct netns_frags *nf; - BUG_TRAP(q->last_in & COMPLETE); + BUG_TRAP(q->last_in & INET_FRAG_COMPLETE); BUG_TRAP(del_timer(&q->timer) == 0); /* Release all fragment data. */ @@ -174,7 +174,7 @@ int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f) read_unlock(&f->lock); spin_lock(&q->lock); - if (!(q->last_in & COMPLETE)) + if (!(q->last_in & INET_FRAG_COMPLETE)) inet_frag_kill(q, f); spin_unlock(&q->lock); @@ -206,7 +206,7 @@ static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, if (qp->net == nf && f->match(qp, arg)) { atomic_inc(&qp->refcnt); write_unlock(&f->lock); - qp_in->last_in |= COMPLETE; + qp_in->last_in |= INET_FRAG_COMPLETE; inet_frag_put(qp_in, f); return qp; } diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index fcb60e76b234..02ae470fe60c 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -194,7 +194,7 @@ static void ip_expire(unsigned long arg) spin_lock(&qp->q.lock); - if (qp->q.last_in & COMPLETE) + if (qp->q.last_in & INET_FRAG_COMPLETE) goto out; ipq_kill(qp); @@ -202,7 +202,7 @@ static void ip_expire(unsigned long arg) IP_INC_STATS_BH(IPSTATS_MIB_REASMTIMEOUT); IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); - if ((qp->q.last_in&FIRST_IN) && qp->q.fragments != NULL) { + if ((qp->q.last_in & INET_FRAG_FIRST_IN) && qp->q.fragments != NULL) { struct sk_buff *head = qp->q.fragments; struct net *net; @@ -301,7 +301,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) int ihl, end; int err = -ENOENT; - if (qp->q.last_in & COMPLETE) + if (qp->q.last_in & INET_FRAG_COMPLETE) goto err; if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) && @@ -327,9 +327,9 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) * or have different end, the segment is corrrupted. */ if (end < qp->q.len || - ((qp->q.last_in & LAST_IN) && end != qp->q.len)) + ((qp->q.last_in & INET_FRAG_LAST_IN) && end != qp->q.len)) goto err; - qp->q.last_in |= LAST_IN; + qp->q.last_in |= INET_FRAG_LAST_IN; qp->q.len = end; } else { if (end&7) { @@ -339,7 +339,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) } if (end > qp->q.len) { /* Some bits beyond end -> corruption. */ - if (qp->q.last_in & LAST_IN) + if (qp->q.last_in & INET_FRAG_LAST_IN) goto err; qp->q.len = end; } @@ -438,9 +438,10 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) qp->q.meat += skb->len; atomic_add(skb->truesize, &qp->q.net->mem); if (offset == 0) - qp->q.last_in |= FIRST_IN; + qp->q.last_in |= INET_FRAG_FIRST_IN; - if (qp->q.last_in == (FIRST_IN | LAST_IN) && qp->q.meat == qp->q.len) + if (qp->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && + qp->q.meat == qp->q.len) return ip_frag_reasm(qp, prev, dev); write_lock(&ip4_frags.lock); diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 2a0d698b24d5..ad8066200f9d 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -183,7 +183,7 @@ static void nf_ct_frag6_expire(unsigned long data) spin_lock(&fq->q.lock); - if (fq->q.last_in & COMPLETE) + if (fq->q.last_in & INET_FRAG_COMPLETE) goto out; fq_kill(fq); @@ -225,7 +225,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, struct sk_buff *prev, *next; int offset, end; - if (fq->q.last_in & COMPLETE) { + if (fq->q.last_in & INET_FRAG_COMPLETE) { pr_debug("Allready completed\n"); goto err; } @@ -252,11 +252,11 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, * or have different end, the segment is corrupted. */ if (end < fq->q.len || - ((fq->q.last_in & LAST_IN) && end != fq->q.len)) { + ((fq->q.last_in & INET_FRAG_LAST_IN) && end != fq->q.len)) { pr_debug("already received last fragment\n"); goto err; } - fq->q.last_in |= LAST_IN; + fq->q.last_in |= INET_FRAG_LAST_IN; fq->q.len = end; } else { /* Check if the fragment is rounded to 8 bytes. @@ -271,7 +271,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, } if (end > fq->q.len) { /* Some bits beyond end -> corruption. */ - if (fq->q.last_in & LAST_IN) { + if (fq->q.last_in & INET_FRAG_LAST_IN) { pr_debug("last packet already reached.\n"); goto err; } @@ -383,7 +383,7 @@ static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, */ if (offset == 0) { fq->nhoffset = nhoff; - fq->q.last_in |= FIRST_IN; + fq->q.last_in |= INET_FRAG_FIRST_IN; } write_lock(&nf_frags.lock); list_move_tail(&fq->q.lru_list, &nf_init_frags.lru_list); @@ -645,7 +645,8 @@ struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb) goto ret_orig; } - if (fq->q.last_in == (FIRST_IN|LAST_IN) && fq->q.meat == fq->q.len) { + if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && + fq->q.meat == fq->q.len) { ret_skb = nf_ct_frag6_reasm(fq, dev); if (ret_skb == NULL) pr_debug("Can't reassemble fragmented packets\n"); diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index 4e1447634f36..7b247e3a16fe 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -202,7 +202,7 @@ static void ip6_frag_expire(unsigned long data) spin_lock(&fq->q.lock); - if (fq->q.last_in & COMPLETE) + if (fq->q.last_in & INET_FRAG_COMPLETE) goto out; fq_kill(fq); @@ -217,7 +217,7 @@ static void ip6_frag_expire(unsigned long data) rcu_read_unlock(); /* Don't send error if the first segment did not arrive. */ - if (!(fq->q.last_in&FIRST_IN) || !fq->q.fragments) + if (!(fq->q.last_in & INET_FRAG_FIRST_IN) || !fq->q.fragments) goto out; /* @@ -265,7 +265,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, struct net_device *dev; int offset, end; - if (fq->q.last_in & COMPLETE) + if (fq->q.last_in & INET_FRAG_COMPLETE) goto err; offset = ntohs(fhdr->frag_off) & ~0x7; @@ -294,9 +294,9 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, * or have different end, the segment is corrupted. */ if (end < fq->q.len || - ((fq->q.last_in & LAST_IN) && end != fq->q.len)) + ((fq->q.last_in & INET_FRAG_LAST_IN) && end != fq->q.len)) goto err; - fq->q.last_in |= LAST_IN; + fq->q.last_in |= INET_FRAG_LAST_IN; fq->q.len = end; } else { /* Check if the fragment is rounded to 8 bytes. @@ -314,7 +314,7 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, } if (end > fq->q.len) { /* Some bits beyond end -> corruption. */ - if (fq->q.last_in & LAST_IN) + if (fq->q.last_in & INET_FRAG_LAST_IN) goto err; fq->q.len = end; } @@ -417,10 +417,11 @@ static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, */ if (offset == 0) { fq->nhoffset = nhoff; - fq->q.last_in |= FIRST_IN; + fq->q.last_in |= INET_FRAG_FIRST_IN; } - if (fq->q.last_in == (FIRST_IN | LAST_IN) && fq->q.meat == fq->q.len) + if (fq->q.last_in == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && + fq->q.meat == fq->q.len) return ip6_frag_reasm(fq, prev, dev); write_lock(&ip6_frags.lock); -- cgit v1.2.3-59-g8ed1b From 13ff3d6fa4e6d8b6ee7c64245a0078e6a0e6f977 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Mar 2008 16:38:17 -0700 Subject: [SOCK]: Enumerate struct proto-s to facilitate percpu inuse accounting (v2). The inuse counters are going to become a per-cpu array. Introduce an index for this array on the struct proto. To handle the case of proto register-unregister-register loop the bitmap is used. All its bits manipulations are protected with proto_list_lock and a sanity check for the bitmap being exhausted is also added. Signed-off-by: Pavel Emelyanov Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 1 + net/core/sock.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) (limited to 'net') diff --git a/include/net/sock.h b/include/net/sock.h index 1c9d059223ee..abc6341f536f 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -562,6 +562,7 @@ struct proto { /* Keeping track of sockets in use */ #ifdef CONFIG_PROC_FS + unsigned int inuse_idx; struct pcounter inuse; #endif diff --git a/net/core/sock.c b/net/core/sock.c index 3ee95060dbd0..7d2c8add5f5a 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1940,6 +1940,38 @@ EXPORT_SYMBOL(sk_common_release); static DEFINE_RWLOCK(proto_list_lock); static LIST_HEAD(proto_list); +#ifdef CONFIG_PROC_FS +#define PROTO_INUSE_NR 64 /* should be enough for the first time */ + +static DECLARE_BITMAP(proto_inuse_idx, PROTO_INUSE_NR); + +static void assign_proto_idx(struct proto *prot) +{ + prot->inuse_idx = find_first_zero_bit(proto_inuse_idx, PROTO_INUSE_NR); + + if (unlikely(prot->inuse_idx == PROTO_INUSE_NR - 1)) { + printk(KERN_ERR "PROTO_INUSE_NR exhausted\n"); + return; + } + + set_bit(prot->inuse_idx, proto_inuse_idx); +} + +static void release_proto_idx(struct proto *prot) +{ + if (prot->inuse_idx != PROTO_INUSE_NR - 1) + clear_bit(prot->inuse_idx, proto_inuse_idx); +} +#else +static inline void assign_proto_idx(struct proto *prot) +{ +} + +static inline void release_proto_idx(struct proto *prot) +{ +} +#endif + int proto_register(struct proto *prot, int alloc_slab) { char *request_sock_slab_name = NULL; @@ -2000,6 +2032,7 @@ int proto_register(struct proto *prot, int alloc_slab) write_lock(&proto_list_lock); list_add(&prot->node, &proto_list); + assign_proto_idx(prot); write_unlock(&proto_list_lock); return 0; @@ -2026,6 +2059,7 @@ EXPORT_SYMBOL(proto_register); void proto_unregister(struct proto *prot) { write_lock(&proto_list_lock); + release_proto_idx(prot); list_del(&prot->node); write_unlock(&proto_list_lock); -- cgit v1.2.3-59-g8ed1b From 1338d466d9c3f8a65cc6d83c629cd906f2a989f8 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Mar 2008 16:38:43 -0700 Subject: [SOCK]: Introduce a percpu inuse counters array (v2). And redirect sock_prot_inuse_add and _get to use one. As far as the dereferences are concerned. Before the patch we made 1 dereference to proto->inuse.add call, the call itself and then called the __get_cpu_var() on a static variable. After the patch we make a direct call, then one dereference to proto->inuse_idx and then the same __get_cpu_var() on a still static variable. So this patch doesn't seem to produce performance penalty on SMP. This is not per-net yet, but I will deliberately make NET_NS=y case separated from NET_NS=n one, since it'll cost us one-or-two more dereferences to get the struct net and the inuse counter. Signed-off-by: Pavel Emelyanov Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 13 +++++-------- net/core/sock.c | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/net/sock.h b/include/net/sock.h index abc6341f536f..ebf9552664b2 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -639,18 +639,15 @@ static inline void sk_refcnt_debug_release(const struct sock *sk) # define DEFINE_PROTO_INUSE(NAME) DEFINE_PCOUNTER(NAME) # define REF_PROTO_INUSE(NAME) PCOUNTER_MEMBER_INITIALIZER(NAME, .inuse) /* Called with local bh disabled */ -static inline void sock_prot_inuse_add(struct proto *prot, int inc) -{ - pcounter_add(&prot->inuse, inc); -} +extern void sock_prot_inuse_add(struct proto *prot, int inc); + static inline int sock_prot_inuse_init(struct proto *proto) { return pcounter_alloc(&proto->inuse); } -static inline int sock_prot_inuse_get(struct proto *proto) -{ - return pcounter_getval(&proto->inuse); -} + +extern int sock_prot_inuse_get(struct proto *proto); + static inline void sock_prot_inuse_free(struct proto *proto) { pcounter_free(&proto->inuse); diff --git a/net/core/sock.c b/net/core/sock.c index 7d2c8add5f5a..174c64bc7a43 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1942,8 +1942,30 @@ static LIST_HEAD(proto_list); #ifdef CONFIG_PROC_FS #define PROTO_INUSE_NR 64 /* should be enough for the first time */ +struct prot_inuse { + int val[PROTO_INUSE_NR]; +}; static DECLARE_BITMAP(proto_inuse_idx, PROTO_INUSE_NR); +static DEFINE_PER_CPU(struct prot_inuse, prot_inuse); + +void sock_prot_inuse_add(struct proto *prot, int val) +{ + __get_cpu_var(prot_inuse).val[prot->inuse_idx] += val; +} +EXPORT_SYMBOL_GPL(sock_prot_inuse_add); + +int sock_prot_inuse_get(struct proto *prot) +{ + int cpu, idx = prot->inuse_idx; + int res = 0; + + for_each_possible_cpu(cpu) + res += per_cpu(prot_inuse, cpu).val[idx]; + + return res >= 0 ? res : 0; +} +EXPORT_SYMBOL_GPL(sock_prot_inuse_get); static void assign_proto_idx(struct proto *prot) { -- cgit v1.2.3-59-g8ed1b From 60e7663d462af3994f292cb3691ea4f7371a9220 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Mar 2008 16:39:10 -0700 Subject: [SOCK]: Drop per-proto inuse init and fre functions (v2). Constructive part of the set is finished here. We have to remove the pcounter, so start with its init and free functions. Signed-off-by: Pavel Emelyanov Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 18 ------------------ net/core/sock.c | 11 +---------- 2 files changed, 1 insertion(+), 28 deletions(-) (limited to 'net') diff --git a/include/net/sock.h b/include/net/sock.h index ebf9552664b2..1f4294252dd7 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -640,31 +640,13 @@ static inline void sk_refcnt_debug_release(const struct sock *sk) # define REF_PROTO_INUSE(NAME) PCOUNTER_MEMBER_INITIALIZER(NAME, .inuse) /* Called with local bh disabled */ extern void sock_prot_inuse_add(struct proto *prot, int inc); - -static inline int sock_prot_inuse_init(struct proto *proto) -{ - return pcounter_alloc(&proto->inuse); -} - extern int sock_prot_inuse_get(struct proto *proto); - -static inline void sock_prot_inuse_free(struct proto *proto) -{ - pcounter_free(&proto->inuse); -} #else # define DEFINE_PROTO_INUSE(NAME) # define REF_PROTO_INUSE(NAME) static void inline sock_prot_inuse_add(struct proto *prot, int inc) { } -static int inline sock_prot_inuse_init(struct proto *proto) -{ - return 0; -} -static void inline sock_prot_inuse_free(struct proto *proto) -{ -} #endif diff --git a/net/core/sock.c b/net/core/sock.c index 174c64bc7a43..c1ae56eb96ec 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1999,11 +1999,6 @@ int proto_register(struct proto *prot, int alloc_slab) char *request_sock_slab_name = NULL; char *timewait_sock_slab_name; - if (sock_prot_inuse_init(prot) != 0) { - printk(KERN_CRIT "%s: Can't alloc inuse counters!\n", prot->name); - goto out; - } - if (alloc_slab) { prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0, SLAB_HWCACHE_ALIGN, NULL); @@ -2011,7 +2006,7 @@ int proto_register(struct proto *prot, int alloc_slab) if (prot->slab == NULL) { printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n", prot->name); - goto out_free_inuse; + goto out; } if (prot->rsk_prot != NULL) { @@ -2070,8 +2065,6 @@ out_free_request_sock_slab_name: out_free_sock_slab: kmem_cache_destroy(prot->slab); prot->slab = NULL; -out_free_inuse: - sock_prot_inuse_free(prot); out: return -ENOBUFS; } @@ -2085,8 +2078,6 @@ void proto_unregister(struct proto *prot) list_del(&prot->node); write_unlock(&proto_list_lock); - sock_prot_inuse_free(prot); - if (prot->slab != NULL) { kmem_cache_destroy(prot->slab); prot->slab = NULL; -- cgit v1.2.3-59-g8ed1b From bdcde3d71a67e97f25e851f3ca97c9bb5ef03e7f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 28 Mar 2008 16:39:33 -0700 Subject: [SOCK]: Drop inuse pcounter from struct proto (v2). An uppercut - do not use the pcounter on struct proto. Signed-off-by: Pavel Emelyanov Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/sock.h | 6 ------ net/dccp/ipv4.c | 3 --- net/dccp/ipv6.c | 3 --- net/ipv4/raw.c | 3 --- net/ipv4/tcp_ipv4.c | 3 --- net/ipv4/udp.c | 3 --- net/ipv4/udplite.c | 3 --- net/ipv6/raw.c | 3 --- net/ipv6/tcp_ipv6.c | 3 --- net/ipv6/udp.c | 3 --- net/ipv6/udplite.c | 3 --- net/sctp/socket.c | 5 ----- 12 files changed, 41 deletions(-) (limited to 'net') diff --git a/include/net/sock.h b/include/net/sock.h index 1f4294252dd7..2a3344f666aa 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -47,7 +47,6 @@ #include #include #include -#include #include /* struct sk_buff */ #include #include @@ -563,7 +562,6 @@ struct proto { /* Keeping track of sockets in use */ #ifdef CONFIG_PROC_FS unsigned int inuse_idx; - struct pcounter inuse; #endif /* Memory pressure */ @@ -636,14 +634,10 @@ static inline void sk_refcnt_debug_release(const struct sock *sk) #ifdef CONFIG_PROC_FS -# define DEFINE_PROTO_INUSE(NAME) DEFINE_PCOUNTER(NAME) -# define REF_PROTO_INUSE(NAME) PCOUNTER_MEMBER_INITIALIZER(NAME, .inuse) /* Called with local bh disabled */ extern void sock_prot_inuse_add(struct proto *prot, int inc); extern int sock_prot_inuse_get(struct proto *proto); #else -# define DEFINE_PROTO_INUSE(NAME) -# define REF_PROTO_INUSE(NAME) static void inline sock_prot_inuse_add(struct proto *prot, int inc) { } diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 4ca8b0c93c80..7d62f7eb6134 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -915,8 +915,6 @@ static struct timewait_sock_ops dccp_timewait_sock_ops = { .twsk_obj_size = sizeof(struct inet_timewait_sock), }; -DEFINE_PROTO_INUSE(dccp_v4) - static struct proto dccp_v4_prot = { .name = "DCCP", .owner = THIS_MODULE, @@ -946,7 +944,6 @@ static struct proto dccp_v4_prot = { .compat_setsockopt = compat_dccp_setsockopt, .compat_getsockopt = compat_dccp_getsockopt, #endif - REF_PROTO_INUSE(dccp_v4) }; static struct net_protocol dccp_v4_protocol = { diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 2fec1af1a8c3..ea3f32648618 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1100,8 +1100,6 @@ static struct timewait_sock_ops dccp6_timewait_sock_ops = { .twsk_obj_size = sizeof(struct dccp6_timewait_sock), }; -DEFINE_PROTO_INUSE(dccp_v6) - static struct proto dccp_v6_prot = { .name = "DCCPv6", .owner = THIS_MODULE, @@ -1131,7 +1129,6 @@ static struct proto dccp_v6_prot = { .compat_setsockopt = compat_dccp_setsockopt, .compat_getsockopt = compat_dccp_getsockopt, #endif - REF_PROTO_INUSE(dccp_v6) }; static struct inet6_protocol dccp_v6_protocol = { diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index d965f0a39c84..349205048557 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -818,8 +818,6 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) } } -DEFINE_PROTO_INUSE(raw) - struct proto raw_prot = { .name = "RAW", .owner = THIS_MODULE, @@ -842,7 +840,6 @@ struct proto raw_prot = { .compat_setsockopt = compat_raw_setsockopt, .compat_getsockopt = compat_raw_getsockopt, #endif - REF_PROTO_INUSE(raw) }; #ifdef CONFIG_PROC_FS diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 2a5881c81778..ef141b841d2f 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2451,8 +2451,6 @@ void tcp4_proc_exit(void) } #endif /* CONFIG_PROC_FS */ -DEFINE_PROTO_INUSE(tcp) - struct proto tcp_prot = { .name = "TCP", .owner = THIS_MODULE, @@ -2488,7 +2486,6 @@ struct proto tcp_prot = { .compat_setsockopt = compat_tcp_setsockopt, .compat_getsockopt = compat_tcp_getsockopt, #endif - REF_PROTO_INUSE(tcp) }; void __init tcp_v4_init(void) diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 80007c79f12f..0255f373b3e5 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1467,8 +1467,6 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) } -DEFINE_PROTO_INUSE(udp) - struct proto udp_prot = { .name = "UDP", .owner = THIS_MODULE, @@ -1496,7 +1494,6 @@ struct proto udp_prot = { .compat_setsockopt = compat_udp_setsockopt, .compat_getsockopt = compat_udp_getsockopt, #endif - REF_PROTO_INUSE(udp) }; /* ------------------------------------------------------------------------ */ diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 53f3ed496328..7c1e0271c0db 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -34,8 +34,6 @@ static struct net_protocol udplite_protocol = { .netns_ok = 1, }; -DEFINE_PROTO_INUSE(udplite) - struct proto udplite_prot = { .name = "UDP-Lite", .owner = THIS_MODULE, @@ -60,7 +58,6 @@ struct proto udplite_prot = { .compat_setsockopt = compat_udp_setsockopt, .compat_getsockopt = compat_udp_getsockopt, #endif - REF_PROTO_INUSE(udplite) }; static struct inet_protosw udplite4_protosw = { diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 830da4603697..c1e495f105ad 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -1171,8 +1171,6 @@ static int rawv6_init_sk(struct sock *sk) return(0); } -DEFINE_PROTO_INUSE(rawv6) - struct proto rawv6_prot = { .name = "RAWv6", .owner = THIS_MODULE, @@ -1196,7 +1194,6 @@ struct proto rawv6_prot = { .compat_setsockopt = compat_rawv6_setsockopt, .compat_getsockopt = compat_rawv6_getsockopt, #endif - REF_PROTO_INUSE(rawv6) }; #ifdef CONFIG_PROC_FS diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 323c7e06ef43..6d851c3c3db9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2140,8 +2140,6 @@ void tcp6_proc_exit(struct net *net) } #endif -DEFINE_PROTO_INUSE(tcpv6) - struct proto tcpv6_prot = { .name = "TCPv6", .owner = THIS_MODULE, @@ -2177,7 +2175,6 @@ struct proto tcpv6_prot = { .compat_setsockopt = compat_tcp_setsockopt, .compat_getsockopt = compat_tcp_getsockopt, #endif - REF_PROTO_INUSE(tcpv6) }; static struct inet6_protocol tcpv6_protocol = { diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index aacbc82ecf0f..463ae4d448a3 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -999,8 +999,6 @@ void udp6_proc_exit(struct net *net) { /* ------------------------------------------------------------------------ */ -DEFINE_PROTO_INUSE(udpv6) - struct proto udpv6_prot = { .name = "UDPv6", .owner = THIS_MODULE, @@ -1027,7 +1025,6 @@ struct proto udpv6_prot = { .compat_setsockopt = compat_udpv6_setsockopt, .compat_getsockopt = compat_udpv6_getsockopt, #endif - REF_PROTO_INUSE(udpv6) }; static struct inet_protosw udpv6_protosw = { diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 706c5c375a01..c5f5357d115d 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -35,8 +35,6 @@ static struct inet6_protocol udplitev6_protocol = { .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; -DEFINE_PROTO_INUSE(udplitev6) - struct proto udplitev6_prot = { .name = "UDPLITEv6", .owner = THIS_MODULE, @@ -60,7 +58,6 @@ struct proto udplitev6_prot = { .compat_setsockopt = compat_udpv6_setsockopt, .compat_getsockopt = compat_udpv6_getsockopt, #endif - REF_PROTO_INUSE(udplitev6) }; static struct inet_protosw udplite6_protosw = { diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 76c747056dd7..00ebd0610be2 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -6513,8 +6513,6 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk, } -DEFINE_PROTO_INUSE(sctp) - /* This proto struct describes the ULP interface for SCTP. */ struct proto sctp_prot = { .name = "SCTP", @@ -6544,11 +6542,9 @@ struct proto sctp_prot = { .enter_memory_pressure = sctp_enter_memory_pressure, .memory_allocated = &sctp_memory_allocated, .sockets_allocated = &sctp_sockets_allocated, - REF_PROTO_INUSE(sctp) }; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -DEFINE_PROTO_INUSE(sctpv6) struct proto sctpv6_prot = { .name = "SCTPv6", @@ -6578,6 +6574,5 @@ struct proto sctpv6_prot = { .enter_memory_pressure = sctp_enter_memory_pressure, .memory_allocated = &sctp_memory_allocated, .sockets_allocated = &sctp_sockets_allocated, - REF_PROTO_INUSE(sctpv6) }; #endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ -- cgit v1.2.3-59-g8ed1b From a0f55e0e833009c6a4eeb2626b807e3c21b128c8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 28 Mar 2008 18:22:32 -0700 Subject: [NET]: Fix dev_alloc_skb() typo. Noticed by Joe Perches. Signed-off-by: David S. Miller --- net/core/skbuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6ef7008a3ef3..e4259215607f 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -279,7 +279,7 @@ struct sk_buff *dev_alloc_skb(unsigned int length) { /* * There is more code here than it seems: - * __def_alloc_skb is an inline + * __dev_alloc_skb is an inline */ return __dev_alloc_skb(length, GFP_ATOMIC); } -- cgit v1.2.3-59-g8ed1b From 6f191efe48af62dd5f8917dd21d187f896cd6c81 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 28 Mar 2008 18:23:33 -0700 Subject: [UDP]: Replace struct net on udp_iter_state with seq_net_private. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/udp.h | 2 +- net/ipv4/udp.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/net/udp.h b/include/net/udp.h index 635940d374ab..77af7d46d868 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -194,7 +194,7 @@ struct udp_seq_afinfo { }; struct udp_iter_state { - struct net *net; + struct seq_net_private p; sa_family_t family; struct hlist_head *hashtable; int bucket; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 0255f373b3e5..d695097be2dc 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1503,7 +1503,7 @@ static struct sock *udp_get_first(struct seq_file *seq) { struct sock *sk; struct udp_iter_state *state = seq->private; - struct net *net = state->net; + struct net *net = seq_file_net(seq); for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { struct hlist_node *node; @@ -1522,7 +1522,7 @@ found: static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) { struct udp_iter_state *state = seq->private; - struct net *net = state->net; + struct net *net = seq_file_net(seq); do { sk = sk_next(sk); @@ -1595,7 +1595,7 @@ static int udp_seq_open(struct inode *inode, struct file *file) s->seq_ops.next = udp_seq_next; s->seq_ops.show = afinfo->seq_show; s->seq_ops.stop = udp_seq_stop; - s->net = net; + s->p.net = net; rc = seq_open(file, &s->seq_ops); if (rc) @@ -1617,7 +1617,7 @@ static int udp_seq_release(struct inode *inode, struct file *file) struct seq_file *seq = file->private_data; struct udp_iter_state *s = seq->private; - put_net(s->net); + put_net(s->p.net); seq_release_private(inode, file); return 0; } -- cgit v1.2.3-59-g8ed1b From 997feb5e7a24ce155c1d3bea9d0b5c6530bb6197 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 28 Mar 2008 18:24:01 -0700 Subject: [UDP]: No need to check afinfo != NULL in udp_proc_(un)register. udp_proc_register/udp_proc_unregister are called with a static pointer only. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/udp.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'net') diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index d695097be2dc..eb0c64da2634 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1628,8 +1628,6 @@ int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) struct proc_dir_entry *p; int rc = 0; - if (!afinfo) - return -EINVAL; afinfo->seq_fops->owner = afinfo->owner; afinfo->seq_fops->open = udp_seq_open; afinfo->seq_fops->read = seq_read; @@ -1646,8 +1644,6 @@ int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo) { - if (!afinfo) - return; proc_net_remove(net, afinfo->name); memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } -- cgit v1.2.3-59-g8ed1b From dda61925f84d89e2f2a4597d6298a05a2bc05c20 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 28 Mar 2008 18:24:26 -0700 Subject: [UDP]: Move seq_ops from udp_iter_state to udp_seq_afinfo. No need to create seq_operations for each instance of 'netstat'. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/udp.h | 3 +-- net/ipv4/udp.c | 14 ++++++++------ net/ipv4/udplite.c | 4 +++- net/ipv6/udp.c | 4 +++- net/ipv6/udplite.c | 4 +++- 5 files changed, 18 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/include/net/udp.h b/include/net/udp.h index 77af7d46d868..0079d17fd3a3 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -189,8 +189,8 @@ struct udp_seq_afinfo { char *name; sa_family_t family; struct hlist_head *hashtable; - int (*seq_show) (struct seq_file *m, void *v); struct file_operations *seq_fops; + struct seq_operations seq_ops; }; struct udp_iter_state { @@ -198,7 +198,6 @@ struct udp_iter_state { sa_family_t family; struct hlist_head *hashtable; int bucket; - struct seq_operations seq_ops; }; #ifdef CONFIG_PROC_FS diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index eb0c64da2634..bae94b3eaa43 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1591,13 +1591,9 @@ static int udp_seq_open(struct inode *inode, struct file *file) s->family = afinfo->family; s->hashtable = afinfo->hashtable; - s->seq_ops.start = udp_seq_start; - s->seq_ops.next = udp_seq_next; - s->seq_ops.show = afinfo->seq_show; - s->seq_ops.stop = udp_seq_stop; s->p.net = net; - rc = seq_open(file, &s->seq_ops); + rc = seq_open(file, &afinfo->seq_ops); if (rc) goto out_put_net; @@ -1634,6 +1630,10 @@ int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) afinfo->seq_fops->llseek = seq_lseek; afinfo->seq_fops->release = udp_seq_release; + afinfo->seq_ops.start = udp_seq_start; + afinfo->seq_ops.next = udp_seq_next; + afinfo->seq_ops.stop = udp_seq_stop; + p = proc_net_fops_create(net, afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) p->data = afinfo; @@ -1690,8 +1690,10 @@ static struct udp_seq_afinfo udp4_seq_afinfo = { .name = "udp", .family = AF_INET, .hashtable = udp_hash, - .seq_show = udp4_seq_show, .seq_fops = &udp4_seq_fops, + .seq_ops = { + .show = udp4_seq_show, + }, }; static int udp4_proc_init_net(struct net *net) diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 7c1e0271c0db..4add87553bce 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -77,8 +77,10 @@ static struct udp_seq_afinfo udplite4_seq_afinfo = { .name = "udplite", .family = AF_INET, .hashtable = udplite_hash, - .seq_show = udp4_seq_show, .seq_fops = &udplite4_seq_fops, + .seq_ops = { + .show = udp4_seq_show, + }, }; static int udplite4_proc_init_net(struct net *net) diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 463ae4d448a3..e35921a46689 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -983,8 +983,10 @@ static struct udp_seq_afinfo udp6_seq_afinfo = { .name = "udp6", .family = AF_INET6, .hashtable = udp_hash, - .seq_show = udp6_seq_show, .seq_fops = &udp6_seq_fops, + .seq_ops = { + .show = udp6_seq_show, + }, }; int udp6_proc_init(struct net *net) diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index c5f5357d115d..710366c3f0a6 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -102,8 +102,10 @@ static struct udp_seq_afinfo udplite6_seq_afinfo = { .name = "udplite6", .family = AF_INET6, .hashtable = udplite_hash, - .seq_show = udp6_seq_show, .seq_fops = &udplite6_seq_fops, + .seq_ops = { + .show = udp6_seq_show, + }, }; static int udplite6_proc_init_net(struct net *net) -- cgit v1.2.3-59-g8ed1b From a2be75c182cd16bc104919e33451ffda8b6f65b4 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 28 Mar 2008 18:25:06 -0700 Subject: [UDP]: Cleanup /proc/udp[6] creation/removal. Replace seq_open with seq_open_net and remove udp_seq_release completely. seq_release_net will do this job just fine. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/udp.c | 46 +++++++++------------------------------------- 1 file changed, 9 insertions(+), 37 deletions(-) (limited to 'net') diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index bae94b3eaa43..e716d2d55e1e 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1576,46 +1576,18 @@ static void udp_seq_stop(struct seq_file *seq, void *v) static int udp_seq_open(struct inode *inode, struct file *file) { struct udp_seq_afinfo *afinfo = PDE(inode)->data; - struct seq_file *seq; - struct net *net; - int rc = -ENOMEM; - struct udp_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); - - if (!s) - goto out; + struct udp_iter_state *s; + int err; - rc = -ENXIO; - net = get_proc_net(inode); - if (!net) - goto out_kfree; + err = seq_open_net(inode, file, &afinfo->seq_ops, + sizeof(struct udp_iter_state)); + if (err < 0) + return err; + s = ((struct seq_file *)file->private_data)->private; s->family = afinfo->family; s->hashtable = afinfo->hashtable; - s->p.net = net; - - rc = seq_open(file, &afinfo->seq_ops); - if (rc) - goto out_put_net; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_put_net: - put_net(net); -out_kfree: - kfree(s); - goto out; -} - -static int udp_seq_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - struct udp_iter_state *s = seq->private; - - put_net(s->p.net); - seq_release_private(inode, file); - return 0; + return err; } /* ------------------------------------------------------------------------ */ @@ -1628,7 +1600,7 @@ int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) afinfo->seq_fops->open = udp_seq_open; afinfo->seq_fops->read = seq_read; afinfo->seq_fops->llseek = seq_lseek; - afinfo->seq_fops->release = udp_seq_release; + afinfo->seq_fops->release = seq_release_net; afinfo->seq_ops.start = udp_seq_start; afinfo->seq_ops.next = udp_seq_next; -- cgit v1.2.3-59-g8ed1b From 3ba9441bdf07370670a684e6d95dfc523476677f Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 28 Mar 2008 18:25:32 -0700 Subject: [UDP]: Place file operations directly into udp_seq_afinfo. No need to have separate never-used variable. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/udp.h | 2 +- net/ipv4/udp.c | 15 ++++++--------- net/ipv4/udplite.c | 2 -- net/ipv6/udp.c | 2 -- net/ipv6/udplite.c | 2 -- 5 files changed, 7 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/net/udp.h b/include/net/udp.h index 0079d17fd3a3..5cf0e593dda7 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -189,7 +189,7 @@ struct udp_seq_afinfo { char *name; sa_family_t family; struct hlist_head *hashtable; - struct file_operations *seq_fops; + struct file_operations seq_fops; struct seq_operations seq_ops; }; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index e716d2d55e1e..a95dff8063a4 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1596,17 +1596,17 @@ int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) struct proc_dir_entry *p; int rc = 0; - afinfo->seq_fops->owner = afinfo->owner; - afinfo->seq_fops->open = udp_seq_open; - afinfo->seq_fops->read = seq_read; - afinfo->seq_fops->llseek = seq_lseek; - afinfo->seq_fops->release = seq_release_net; + afinfo->seq_fops.owner = afinfo->owner; + afinfo->seq_fops.open = udp_seq_open; + afinfo->seq_fops.read = seq_read; + afinfo->seq_fops.llseek = seq_lseek; + afinfo->seq_fops.release = seq_release_net; afinfo->seq_ops.start = udp_seq_start; afinfo->seq_ops.next = udp_seq_next; afinfo->seq_ops.stop = udp_seq_stop; - p = proc_net_fops_create(net, afinfo->name, S_IRUGO, afinfo->seq_fops); + p = proc_net_fops_create(net, afinfo->name, S_IRUGO, &afinfo->seq_fops); if (p) p->data = afinfo; else @@ -1617,7 +1617,6 @@ int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo) { proc_net_remove(net, afinfo->name); - memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } /* ------------------------------------------------------------------------ */ @@ -1656,13 +1655,11 @@ int udp4_seq_show(struct seq_file *seq, void *v) } /* ------------------------------------------------------------------------ */ -static struct file_operations udp4_seq_fops; static struct udp_seq_afinfo udp4_seq_afinfo = { .owner = THIS_MODULE, .name = "udp", .family = AF_INET, .hashtable = udp_hash, - .seq_fops = &udp4_seq_fops, .seq_ops = { .show = udp4_seq_show, }, diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 4add87553bce..148ae72af111 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -71,13 +71,11 @@ static struct inet_protosw udplite4_protosw = { }; #ifdef CONFIG_PROC_FS -static struct file_operations udplite4_seq_fops; static struct udp_seq_afinfo udplite4_seq_afinfo = { .owner = THIS_MODULE, .name = "udplite", .family = AF_INET, .hashtable = udplite_hash, - .seq_fops = &udplite4_seq_fops, .seq_ops = { .show = udp4_seq_show, }, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index e35921a46689..ff8d53ecdd60 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -977,13 +977,11 @@ int udp6_seq_show(struct seq_file *seq, void *v) return 0; } -static struct file_operations udp6_seq_fops; static struct udp_seq_afinfo udp6_seq_afinfo = { .owner = THIS_MODULE, .name = "udp6", .family = AF_INET6, .hashtable = udp_hash, - .seq_fops = &udp6_seq_fops, .seq_ops = { .show = udp6_seq_show, }, diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 710366c3f0a6..5adf651d0721 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -96,13 +96,11 @@ void udplitev6_exit(void) } #ifdef CONFIG_PROC_FS -static struct file_operations udplite6_seq_fops; static struct udp_seq_afinfo udplite6_seq_afinfo = { .owner = THIS_MODULE, .name = "udplite6", .family = AF_INET6, .hashtable = udplite_hash, - .seq_fops = &udplite6_seq_fops, .seq_ops = { .show = udp6_seq_show, }, -- cgit v1.2.3-59-g8ed1b From 4ad96d39a2d74c1b2e400b602da2594f5098fc26 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Fri, 28 Mar 2008 18:25:53 -0700 Subject: [UDP]: Remove owner from udp_seq_afinfo. Move it to udp_seq_afinfo->seq_fops as should be. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/udp.h | 1 - net/ipv4/udp.c | 5 +++-- net/ipv4/udplite.c | 4 +++- net/ipv6/udp.c | 4 +++- net/ipv6/udplite.c | 4 +++- 5 files changed, 12 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/include/net/udp.h b/include/net/udp.h index 5cf0e593dda7..24a41fa31641 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -185,7 +185,6 @@ DECLARE_SNMP_STAT(struct udp_mib, udplite_stats_in6); /* /proc */ struct udp_seq_afinfo { - struct module *owner; char *name; sa_family_t family; struct hlist_head *hashtable; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index a95dff8063a4..9143645f9a1b 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1596,7 +1596,6 @@ int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) struct proc_dir_entry *p; int rc = 0; - afinfo->seq_fops.owner = afinfo->owner; afinfo->seq_fops.open = udp_seq_open; afinfo->seq_fops.read = seq_read; afinfo->seq_fops.llseek = seq_lseek; @@ -1656,10 +1655,12 @@ int udp4_seq_show(struct seq_file *seq, void *v) /* ------------------------------------------------------------------------ */ static struct udp_seq_afinfo udp4_seq_afinfo = { - .owner = THIS_MODULE, .name = "udp", .family = AF_INET, .hashtable = udp_hash, + .seq_fops = { + .owner = THIS_MODULE, + }, .seq_ops = { .show = udp4_seq_show, }, diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 148ae72af111..72ce26b6c4d3 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -72,10 +72,12 @@ static struct inet_protosw udplite4_protosw = { #ifdef CONFIG_PROC_FS static struct udp_seq_afinfo udplite4_seq_afinfo = { - .owner = THIS_MODULE, .name = "udplite", .family = AF_INET, .hashtable = udplite_hash, + .seq_fops = { + .owner = THIS_MODULE, + }, .seq_ops = { .show = udp4_seq_show, }, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index ff8d53ecdd60..30ef7dc5d403 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -978,10 +978,12 @@ int udp6_seq_show(struct seq_file *seq, void *v) } static struct udp_seq_afinfo udp6_seq_afinfo = { - .owner = THIS_MODULE, .name = "udp6", .family = AF_INET6, .hashtable = udp_hash, + .seq_fops = { + .owner = THIS_MODULE, + }, .seq_ops = { .show = udp6_seq_show, }, diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 5adf651d0721..491efd00a866 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -97,10 +97,12 @@ void udplitev6_exit(void) #ifdef CONFIG_PROC_FS static struct udp_seq_afinfo udplite6_seq_afinfo = { - .owner = THIS_MODULE, .name = "udplite6", .family = AF_INET6, .hashtable = udplite_hash, + .seq_fops = { + .owner = THIS_MODULE, + }, .seq_ops = { .show = udp6_seq_show, }, -- cgit v1.2.3-59-g8ed1b From 8efa6e93cb2666dceafc4844057fdcb9aa324fb7 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 31 Mar 2008 19:41:14 -0700 Subject: [NETNS]: Introduce a netns_core structure. There's already some stuff on the struct net, that should better be folded into netns_core structure. I'm making the per-proto inuse counter be per-net also, which is also a candidate for this, so introduce this structure and populate it a bit. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/net/net_namespace.h | 6 ++---- include/net/netns/core.h | 13 +++++++++++++ net/core/sysctl_net_core.c | 12 ++++++------ net/socket.c | 2 +- 4 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 include/net/netns/core.h (limited to 'net') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index f8f3d1a5fc35..c01d45fe08c3 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -46,10 +47,7 @@ struct net { struct sock *rtnl; /* rtnetlink socket */ - /* core sysctls */ - struct ctl_table_header *sysctl_core_hdr; - int sysctl_somaxconn; - + struct netns_core core; struct netns_packet packet; struct netns_unix unx; struct netns_ipv4 ipv4; diff --git a/include/net/netns/core.h b/include/net/netns/core.h new file mode 100644 index 000000000000..0e8c0f8435d4 --- /dev/null +++ b/include/net/netns/core.h @@ -0,0 +1,13 @@ +#ifndef __NETNS_CORE_H__ +#define __NETNS_CORE_H__ + +struct ctl_table_header; + +struct netns_core { + /* core sysctls */ + struct ctl_table_header *sysctl_hdr; + + int sysctl_somaxconn; +}; + +#endif diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index 130338f83ae5..5fc801057244 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -127,7 +127,7 @@ static struct ctl_table net_core_table[] = { { .ctl_name = NET_CORE_SOMAXCONN, .procname = "somaxconn", - .data = &init_net.sysctl_somaxconn, + .data = &init_net.core.sysctl_somaxconn, .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec @@ -161,7 +161,7 @@ static __net_init int sysctl_core_net_init(struct net *net) { struct ctl_table *tbl, *tmp; - net->sysctl_somaxconn = SOMAXCONN; + net->core.sysctl_somaxconn = SOMAXCONN; tbl = net_core_table; if (net != &init_net) { @@ -178,9 +178,9 @@ static __net_init int sysctl_core_net_init(struct net *net) } } - net->sysctl_core_hdr = register_net_sysctl_table(net, + net->core.sysctl_hdr = register_net_sysctl_table(net, net_core_path, tbl); - if (net->sysctl_core_hdr == NULL) + if (net->core.sysctl_hdr == NULL) goto err_reg; return 0; @@ -196,8 +196,8 @@ static __net_exit void sysctl_core_net_exit(struct net *net) { struct ctl_table *tbl; - tbl = net->sysctl_core_hdr->ctl_table_arg; - unregister_net_sysctl_table(net->sysctl_core_hdr); + tbl = net->core.sysctl_hdr->ctl_table_arg; + unregister_net_sysctl_table(net->core.sysctl_hdr); BUG_ON(tbl == net_core_table); kfree(tbl); } diff --git a/net/socket.c b/net/socket.c index 79e5382fd110..9b5c917f8a6b 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1375,7 +1375,7 @@ asmlinkage long sys_listen(int fd, int backlog) sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock) { - somaxconn = sock_net(sock->sk)->sysctl_somaxconn; + somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn; if ((unsigned)backlog > somaxconn) backlog = somaxconn; -- cgit v1.2.3-59-g8ed1b From c29a0bc4dfc4d833eb702b1929cec96a3eeb9f7a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 31 Mar 2008 19:41:46 -0700 Subject: [SOCK][NETNS]: Add a struct net argument to sock_prot_inuse_add and _get. This counter is about to become per-proto-and-per-net, so we'll need two arguments to determine which cell in this "table" to work with. All the places, but proc already pass proper net to it - proc will be tuned a bit later. Some indentation with spaces in proc files is done to keep the file coding style consistent. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/net/sock.h | 7 ++++--- include/net/udp.h | 2 +- net/core/sock.c | 4 ++-- net/ipv4/inet_hashtables.c | 8 ++++---- net/ipv4/inet_timewait_sock.c | 2 +- net/ipv4/proc.c | 11 +++++++---- net/ipv4/raw.c | 4 ++-- net/ipv4/udp.c | 2 +- net/ipv6/inet6_hashtables.c | 4 ++-- net/ipv6/ipv6_sockglue.c | 10 ++++++---- net/ipv6/proc.c | 8 ++++---- 11 files changed, 34 insertions(+), 28 deletions(-) (limited to 'net') diff --git a/include/net/sock.h b/include/net/sock.h index 2a3344f666aa..f4fdd101c9a2 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -635,10 +635,11 @@ static inline void sk_refcnt_debug_release(const struct sock *sk) #ifdef CONFIG_PROC_FS /* Called with local bh disabled */ -extern void sock_prot_inuse_add(struct proto *prot, int inc); -extern int sock_prot_inuse_get(struct proto *proto); +extern void sock_prot_inuse_add(struct net *net, struct proto *prot, int inc); +extern int sock_prot_inuse_get(struct net *net, struct proto *proto); #else -static void inline sock_prot_inuse_add(struct proto *prot, int inc) +static void inline sock_prot_inuse_add(struct net *net, struct proto *prot, + int inc) { } #endif diff --git a/include/net/udp.h b/include/net/udp.h index 24a41fa31641..3e55a99b0ba3 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -115,7 +115,7 @@ static inline void udp_lib_unhash(struct sock *sk) write_lock_bh(&udp_hash_lock); if (sk_del_node_init(sk)) { inet_sk(sk)->num = 0; - sock_prot_inuse_add(sk->sk_prot, -1); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); } write_unlock_bh(&udp_hash_lock); } diff --git a/net/core/sock.c b/net/core/sock.c index c1ae56eb96ec..6f36ab91bb59 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1949,13 +1949,13 @@ struct prot_inuse { static DECLARE_BITMAP(proto_inuse_idx, PROTO_INUSE_NR); static DEFINE_PER_CPU(struct prot_inuse, prot_inuse); -void sock_prot_inuse_add(struct proto *prot, int val) +void sock_prot_inuse_add(struct net *net, struct proto *prot, int val) { __get_cpu_var(prot_inuse).val[prot->inuse_idx] += val; } EXPORT_SYMBOL_GPL(sock_prot_inuse_add); -int sock_prot_inuse_get(struct proto *prot) +int sock_prot_inuse_get(struct net *net, struct proto *prot) { int cpu, idx = prot->inuse_idx; int res = 0; diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 1b6ff513c75d..32ca2f8b581c 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -288,7 +288,7 @@ unique: sk->sk_hash = hash; BUG_TRAP(sk_unhashed(sk)); __sk_add_node(sk, &head->chain); - sock_prot_inuse_add(sk->sk_prot, 1); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); write_unlock(lock); if (twp) { @@ -332,7 +332,7 @@ void __inet_hash_nolisten(struct sock *sk) write_lock(lock); __sk_add_node(sk, list); - sock_prot_inuse_add(sk->sk_prot, 1); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); write_unlock(lock); } EXPORT_SYMBOL_GPL(__inet_hash_nolisten); @@ -354,7 +354,7 @@ static void __inet_hash(struct sock *sk) inet_listen_wlock(hashinfo); __sk_add_node(sk, list); - sock_prot_inuse_add(sk->sk_prot, 1); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); write_unlock(lock); wake_up(&hashinfo->lhash_wait); } @@ -387,7 +387,7 @@ void inet_unhash(struct sock *sk) } if (__sk_del_node_init(sk)) - sock_prot_inuse_add(sk->sk_prot, -1); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); write_unlock_bh(lock); out: if (sk->sk_state == TCP_LISTEN) diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index f12bc24de46f..a74137866fbc 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -91,7 +91,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, /* Step 2: Remove SK from established hash. */ if (__sk_del_node_init(sk)) - sock_prot_inuse_add(sk->sk_prot, -1); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); /* Step 3: Hash TW into TIMEWAIT chain. */ inet_twsk_add_node(tw, &ehead->twchain); diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index d63474c6b400..8156c26f9337 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -53,14 +53,17 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) { socket_seq_show(seq); seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %d\n", - sock_prot_inuse_get(&tcp_prot), + sock_prot_inuse_get(&init_net, &tcp_prot), atomic_read(&tcp_orphan_count), tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated), atomic_read(&tcp_memory_allocated)); - seq_printf(seq, "UDP: inuse %d mem %d\n", sock_prot_inuse_get(&udp_prot), + seq_printf(seq, "UDP: inuse %d mem %d\n", + sock_prot_inuse_get(&init_net, &udp_prot), atomic_read(&udp_memory_allocated)); - seq_printf(seq, "UDPLITE: inuse %d\n", sock_prot_inuse_get(&udplite_prot)); - seq_printf(seq, "RAW: inuse %d\n", sock_prot_inuse_get(&raw_prot)); + seq_printf(seq, "UDPLITE: inuse %d\n", + sock_prot_inuse_get(&init_net, &udplite_prot)); + seq_printf(seq, "RAW: inuse %d\n", + sock_prot_inuse_get(&init_net, &raw_prot)); seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues(&init_net), ip_frag_mem(&init_net)); return 0; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 349205048557..11d7f753a820 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -93,7 +93,7 @@ void raw_hash_sk(struct sock *sk) write_lock_bh(&h->lock); sk_add_node(sk, head); - sock_prot_inuse_add(sk->sk_prot, 1); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); write_unlock_bh(&h->lock); } EXPORT_SYMBOL_GPL(raw_hash_sk); @@ -104,7 +104,7 @@ void raw_unhash_sk(struct sock *sk) write_lock_bh(&h->lock); if (sk_del_node_init(sk)) - sock_prot_inuse_add(sk->sk_prot, -1); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); write_unlock_bh(&h->lock); } EXPORT_SYMBOL_GPL(raw_unhash_sk); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 9143645f9a1b..03bd70697481 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -231,7 +231,7 @@ gotit: if (sk_unhashed(sk)) { head = &udptable[snum & (UDP_HTABLE_SIZE - 1)]; sk_add_node(sk, head); - sock_prot_inuse_add(sk->sk_prot, 1); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); } error = 0; fail: diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 340c7d42b83a..580014aea4d6 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -43,7 +43,7 @@ void __inet6_hash(struct sock *sk) } __sk_add_node(sk, list); - sock_prot_inuse_add(sk->sk_prot, 1); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); write_unlock(lock); } EXPORT_SYMBOL(__inet6_hash); @@ -204,7 +204,7 @@ unique: BUG_TRAP(sk_unhashed(sk)); __sk_add_node(sk, &head->chain); sk->sk_hash = hash; - sock_prot_inuse_add(sk->sk_prot, 1); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); write_unlock(lock); if (twp != NULL) { diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index d3d93d752e10..4195ac92345e 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -155,10 +155,11 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, if (sk->sk_protocol == IPPROTO_TCP) { struct inet_connection_sock *icsk = inet_csk(sk); + struct net *net = sock_net(sk); local_bh_disable(); - sock_prot_inuse_add(sk->sk_prot, -1); - sock_prot_inuse_add(&tcp_prot, 1); + sock_prot_inuse_add(net, sk->sk_prot, -1); + sock_prot_inuse_add(net, &tcp_prot, 1); local_bh_enable(); sk->sk_prot = &tcp_prot; icsk->icsk_af_ops = &ipv4_specific; @@ -167,12 +168,13 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); } else { struct proto *prot = &udp_prot; + struct net *net = sock_net(sk); if (sk->sk_protocol == IPPROTO_UDPLITE) prot = &udplite_prot; local_bh_disable(); - sock_prot_inuse_add(sk->sk_prot, -1); - sock_prot_inuse_add(prot, 1); + sock_prot_inuse_add(net, sk->sk_prot, -1); + sock_prot_inuse_add(net, prot, 1); local_bh_enable(); sk->sk_prot = prot; sk->sk_socket->ops = &inet_dgram_ops; diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 364dc332532c..4b9d5a905725 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -36,13 +36,13 @@ static struct proc_dir_entry *proc_net_devsnmp6; static int sockstat6_seq_show(struct seq_file *seq, void *v) { seq_printf(seq, "TCP6: inuse %d\n", - sock_prot_inuse_get(&tcpv6_prot)); + sock_prot_inuse_get(&init_net, &tcpv6_prot)); seq_printf(seq, "UDP6: inuse %d\n", - sock_prot_inuse_get(&udpv6_prot)); + sock_prot_inuse_get(&init_net, &udpv6_prot)); seq_printf(seq, "UDPLITE6: inuse %d\n", - sock_prot_inuse_get(&udplitev6_prot)); + sock_prot_inuse_get(&init_net, &udplitev6_prot)); seq_printf(seq, "RAW6: inuse %d\n", - sock_prot_inuse_get(&rawv6_prot)); + sock_prot_inuse_get(&init_net, &rawv6_prot)); seq_printf(seq, "FRAG6: inuse %d memory %d\n", ip6_frag_nqueues(&init_net), ip6_frag_mem(&init_net)); return 0; -- cgit v1.2.3-59-g8ed1b From 70ee115942be6ce52ff10e5e813fb4da82cdb25a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 31 Mar 2008 19:42:16 -0700 Subject: [SOCK][NETNS]: Add the percpu prot_inuse counter in the struct net. Such an accounting would cost us two more dereferences to get the percpu variable from the struct net, so I make sock_prot_inuse_get and _add calls work differently depending on CONFIG_NET_NS - without it old optimized routines are used. The per-cpu counter for init_net is prepared in core_initcall, so that even af_inet, that starts as fs_initcall, will already have the init_net prepared. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/net/netns/core.h | 3 +++ net/core/sock.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) (limited to 'net') diff --git a/include/net/netns/core.h b/include/net/netns/core.h index 0e8c0f8435d4..24d4be76bbd1 100644 --- a/include/net/netns/core.h +++ b/include/net/netns/core.h @@ -2,12 +2,15 @@ #define __NETNS_CORE_H__ struct ctl_table_header; +struct prot_inuse; struct netns_core { /* core sysctls */ struct ctl_table_header *sysctl_hdr; int sysctl_somaxconn; + + struct prot_inuse *inuse; }; #endif diff --git a/net/core/sock.c b/net/core/sock.c index 6f36ab91bb59..83e11f7260ff 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1947,6 +1947,53 @@ struct prot_inuse { }; static DECLARE_BITMAP(proto_inuse_idx, PROTO_INUSE_NR); + +#ifdef CONFIG_NET_NS +void sock_prot_inuse_add(struct net *net, struct proto *prot, int val) +{ + int cpu = smp_processor_id(); + per_cpu_ptr(net->core.inuse, cpu)->val[prot->inuse_idx] += val; +} +EXPORT_SYMBOL_GPL(sock_prot_inuse_add); + +int sock_prot_inuse_get(struct net *net, struct proto *prot) +{ + int cpu, idx = prot->inuse_idx; + int res = 0; + + for_each_possible_cpu(cpu) + res += per_cpu_ptr(net->core.inuse, cpu)->val[idx]; + + return res >= 0 ? res : 0; +} +EXPORT_SYMBOL_GPL(sock_prot_inuse_get); + +static int sock_inuse_init_net(struct net *net) +{ + net->core.inuse = alloc_percpu(struct prot_inuse); + return net->core.inuse ? 0 : -ENOMEM; +} + +static void sock_inuse_exit_net(struct net *net) +{ + free_percpu(net->core.inuse); +} + +static struct pernet_operations net_inuse_ops = { + .init = sock_inuse_init_net, + .exit = sock_inuse_exit_net, +}; + +static __init int net_inuse_init(void) +{ + if (register_pernet_subsys(&net_inuse_ops)) + panic("Cannot initialize net inuse counters"); + + return 0; +} + +core_initcall(net_inuse_init); +#else static DEFINE_PER_CPU(struct prot_inuse, prot_inuse); void sock_prot_inuse_add(struct net *net, struct proto *prot, int val) @@ -1966,6 +2013,7 @@ int sock_prot_inuse_get(struct net *net, struct proto *prot) return res >= 0 ? res : 0; } EXPORT_SYMBOL_GPL(sock_prot_inuse_get); +#endif static void assign_proto_idx(struct proto *prot) { -- cgit v1.2.3-59-g8ed1b From d0538ca3554a3985c09921903cf8f5e38fa56123 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 31 Mar 2008 19:42:37 -0700 Subject: [SOCK][NETNS]: Register sockstat(6) files in each net. Currently they live in init_net only, but now almost all the info they can provide is available per-net. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/proc.c | 27 ++++++++++++++++++++++----- net/ipv6/proc.c | 29 ++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 8156c26f9337..24ae23bb5124 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -426,25 +426,42 @@ static const struct file_operations netstat_seq_fops = { .release = single_release, }; +static __net_init int ip_proc_init_net(struct net *net) +{ + if (!proc_net_fops_create(net, "sockstat", S_IRUGO, &sockstat_seq_fops)) + return -ENOMEM; + return 0; +} + +static __net_exit void ip_proc_exit_net(struct net *net) +{ + proc_net_remove(net, "sockstat"); +} + +static __net_initdata struct pernet_operations ip_proc_ops = { + .init = ip_proc_init_net, + .exit = ip_proc_exit_net, +}; + int __init ip_misc_proc_init(void) { int rc = 0; + if (register_pernet_subsys(&ip_proc_ops)) + goto out_pernet; + if (!proc_net_fops_create(&init_net, "netstat", S_IRUGO, &netstat_seq_fops)) goto out_netstat; if (!proc_net_fops_create(&init_net, "snmp", S_IRUGO, &snmp_seq_fops)) goto out_snmp; - - if (!proc_net_fops_create(&init_net, "sockstat", S_IRUGO, &sockstat_seq_fops)) - goto out_sockstat; out: return rc; -out_sockstat: - proc_net_remove(&init_net, "snmp"); out_snmp: proc_net_remove(&init_net, "netstat"); out_netstat: + unregister_pernet_subsys(&ip_proc_ops); +out_pernet: rc = -ENOMEM; goto out; } diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 4b9d5a905725..562366015e54 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -243,27 +243,45 @@ int snmp6_unregister_dev(struct inet6_dev *idev) return 0; } +static int ipv6_proc_init_net(struct net *net) +{ + if (!proc_net_fops_create(net, "sockstat6", S_IRUGO, + &sockstat6_seq_fops)) + return -ENOMEM; + return 0; +} + +static void ipv6_proc_exit_net(struct net *net) +{ + proc_net_remove(net, "sockstat6"); +} + +static struct pernet_operations ipv6_proc_ops = { + .init = ipv6_proc_init_net, + .exit = ipv6_proc_exit_net, +}; + int __init ipv6_misc_proc_init(void) { int rc = 0; + if (register_pernet_subsys(&ipv6_proc_ops)) + goto proc_net_fail; + if (!proc_net_fops_create(&init_net, "snmp6", S_IRUGO, &snmp6_seq_fops)) goto proc_snmp6_fail; proc_net_devsnmp6 = proc_mkdir("dev_snmp6", init_net.proc_net); if (!proc_net_devsnmp6) goto proc_dev_snmp6_fail; - - if (!proc_net_fops_create(&init_net, "sockstat6", S_IRUGO, &sockstat6_seq_fops)) - goto proc_sockstat6_fail; out: return rc; -proc_sockstat6_fail: - proc_net_remove(&init_net, "dev_snmp6"); proc_dev_snmp6_fail: proc_net_remove(&init_net, "snmp6"); proc_snmp6_fail: + unregister_pernet_subsys(&ipv6_proc_ops); +proc_net_fail: rc = -ENOMEM; goto out; } @@ -273,5 +291,6 @@ void ipv6_misc_proc_exit(void) proc_net_remove(&init_net, "sockstat6"); proc_net_remove(&init_net, "dev_snmp6"); proc_net_remove(&init_net, "snmp6"); + unregister_pernet_subsys(&ipv6_proc_ops); } -- cgit v1.2.3-59-g8ed1b From fd4e7b50455330403ed5b1060055f9d411ecdc57 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 31 Mar 2008 19:43:18 -0700 Subject: [IPV4][NETNS]: Display per-net info in sockstat file. Besides, now we can see per-net fragments statistics in the same file, since this stats is already per-net. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/proc.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 24ae23bb5124..552169b41b16 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -51,27 +51,54 @@ */ static int sockstat_seq_show(struct seq_file *seq, void *v) { + struct net *net = seq->private; + socket_seq_show(seq); seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %d\n", - sock_prot_inuse_get(&init_net, &tcp_prot), + sock_prot_inuse_get(net, &tcp_prot), atomic_read(&tcp_orphan_count), tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated), atomic_read(&tcp_memory_allocated)); seq_printf(seq, "UDP: inuse %d mem %d\n", - sock_prot_inuse_get(&init_net, &udp_prot), + sock_prot_inuse_get(net, &udp_prot), atomic_read(&udp_memory_allocated)); seq_printf(seq, "UDPLITE: inuse %d\n", - sock_prot_inuse_get(&init_net, &udplite_prot)); + sock_prot_inuse_get(net, &udplite_prot)); seq_printf(seq, "RAW: inuse %d\n", - sock_prot_inuse_get(&init_net, &raw_prot)); + sock_prot_inuse_get(net, &raw_prot)); seq_printf(seq, "FRAG: inuse %d memory %d\n", - ip_frag_nqueues(&init_net), ip_frag_mem(&init_net)); + ip_frag_nqueues(net), ip_frag_mem(net)); return 0; } static int sockstat_seq_open(struct inode *inode, struct file *file) { - return single_open(file, sockstat_seq_show, NULL); + int err; + struct net *net; + + err = -ENXIO; + net = get_proc_net(inode); + if (net == NULL) + goto err_net; + + err = single_open(file, sockstat_seq_show, net); + if (err < 0) + goto err_open; + + return 0; + +err_open: + put_net(net); +err_net: + return err; +} + +static int sockstat_seq_release(struct inode *inode, struct file *file) +{ + struct net *net = ((struct seq_file *)file->private_data)->private; + + put_net(net); + return single_release(inode, file); } static const struct file_operations sockstat_seq_fops = { @@ -79,7 +106,7 @@ static const struct file_operations sockstat_seq_fops = { .open = sockstat_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = sockstat_seq_release, }; /* snmp items */ -- cgit v1.2.3-59-g8ed1b From dfb12eb70fc926562488515a9596c88b8eadc545 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 31 Mar 2008 19:43:43 -0700 Subject: [IPV6][NETNS]: Display per-net info in sockstat6 file. Do with the sockstat6 file what we've already done for the sockstat. Same good side effect - ipv6 reassembling stats are now shown per-net. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/proc.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c index 562366015e54..ca8b82f96fe5 100644 --- a/net/ipv6/proc.c +++ b/net/ipv6/proc.c @@ -35,16 +35,18 @@ static struct proc_dir_entry *proc_net_devsnmp6; static int sockstat6_seq_show(struct seq_file *seq, void *v) { + struct net *net = seq->private; + seq_printf(seq, "TCP6: inuse %d\n", - sock_prot_inuse_get(&init_net, &tcpv6_prot)); + sock_prot_inuse_get(net, &tcpv6_prot)); seq_printf(seq, "UDP6: inuse %d\n", - sock_prot_inuse_get(&init_net, &udpv6_prot)); + sock_prot_inuse_get(net, &udpv6_prot)); seq_printf(seq, "UDPLITE6: inuse %d\n", - sock_prot_inuse_get(&init_net, &udplitev6_prot)); + sock_prot_inuse_get(net, &udplitev6_prot)); seq_printf(seq, "RAW6: inuse %d\n", - sock_prot_inuse_get(&init_net, &rawv6_prot)); + sock_prot_inuse_get(net, &rawv6_prot)); seq_printf(seq, "FRAG6: inuse %d memory %d\n", - ip6_frag_nqueues(&init_net), ip6_frag_mem(&init_net)); + ip6_frag_nqueues(net), ip6_frag_mem(net)); return 0; } @@ -183,7 +185,32 @@ static int snmp6_seq_show(struct seq_file *seq, void *v) static int sockstat6_seq_open(struct inode *inode, struct file *file) { - return single_open(file, sockstat6_seq_show, NULL); + int err; + struct net *net; + + err = -ENXIO; + net = get_proc_net(inode); + if (net == NULL) + goto err_net; + + err = single_open(file, sockstat6_seq_show, net); + if (err < 0) + goto err_open; + + return 0; + +err_open: + put_net(net); +err_net: + return err; +} + +static int sockstat6_seq_release(struct inode *inode, struct file *file) +{ + struct net *net = ((struct seq_file *)file->private_data)->private; + + put_net(net); + return single_release(inode, file); } static const struct file_operations sockstat6_seq_fops = { @@ -191,7 +218,7 @@ static const struct file_operations sockstat6_seq_fops = { .open = sockstat6_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = sockstat6_seq_release, }; static int snmp6_seq_open(struct inode *inode, struct file *file) -- cgit v1.2.3-59-g8ed1b From 0675abdbfbcb8e0253a970c0dfe8d23b112888f3 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 27 Mar 2008 23:25:27 -0700 Subject: net/mac80211/debugfs_netdev.c: use of bool triggers a gcc bug This bool causes my gcc-4.1.0 alpha cross compiler to go into an infinite loop. Switching it to u8 works around that. Cc: Johannes Berg Cc: Luis Carlos Cobo Signed-off-by: Andrew Morton Signed-off-by: John W. Linville --- net/mac80211/debugfs_netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 107b0fe778d6..0e921aef8ecf 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -222,7 +222,7 @@ IEEE80211_IF_WFILE(dot11MeshConfirmTimeout, IEEE80211_IF_WFILE(dot11MeshHoldingTimeout, u.sta.mshcfg.dot11MeshHoldingTimeout, DEC, u16); IEEE80211_IF_WFILE(dot11MeshTTL, u.sta.mshcfg.dot11MeshTTL, DEC, u8); -IEEE80211_IF_WFILE(auto_open_plinks, u.sta.mshcfg.auto_open_plinks, DEC, bool); +IEEE80211_IF_WFILE(auto_open_plinks, u.sta.mshcfg.auto_open_plinks, DEC, u8); IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks, u.sta.mshcfg.dot11MeshMaxPeerLinks, DEC, u16); IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout, -- cgit v1.2.3-59-g8ed1b From 9dd6aed05b8859265cd79f1e47e4f844bbe1548b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 31 Mar 2008 19:22:59 +0200 Subject: mac80211 ibss: flush only stations belonging to current interface When joining a new IBSS, all old stations are flushed, but currently all stations belonging to all virtual interfaces are flushed, which is wrong. This patch fixes it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index f9cf2f187893..baa68575b98a 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2253,8 +2253,10 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + /* Remove possible STA entries from other IBSS networks. */ - sta_info_flush(local, NULL); + sta_info_flush(local, sdata); if (local->ops->reset_tsf) { /* Reset own TSF to allow time synchronization work. */ @@ -2267,7 +2269,6 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); sdata->drop_unencrypted = bss->capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0; -- cgit v1.2.3-59-g8ed1b From 97bff8ecf4e4e26749a67dcfbb7565d8a0f4acb4 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 31 Mar 2008 19:23:00 +0200 Subject: mac80211: fix sta_info_destroy(NULL) sta_info_destroy(NULL) should be valid, but currently isn't because the argument is dereferenced before the NULL check. There are no users that currently pass in NULL, i.e. all check before calling the function, but I want to change that. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f708367092d1..2a5a2f067bae 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -129,16 +129,18 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, void sta_info_destroy(struct sta_info *sta) { - struct ieee80211_local *local = sta->local; + struct ieee80211_local *local; struct sk_buff *skb; int i; DECLARE_MAC_BUF(mbuf); + ASSERT_RTNL(); + might_sleep(); + if (!sta) return; - ASSERT_RTNL(); - might_sleep(); + local = sta->local; rate_control_remove_sta_debugfs(sta); ieee80211_sta_debugfs_remove(sta); -- cgit v1.2.3-59-g8ed1b From 93e5deb1ae39b56f4743955e76c72251256f23c1 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 1 Apr 2008 15:21:00 +0200 Subject: mac80211: automatically free sta struct when insertion fails When STA structure insertion fails, it has been allocated but isn't really alive yet, it isn't reachable by any other code and also can't yet have much configured. This patch changes the code so that when the insertion fails, the resulting STA pointer is no longer valid because it is freed. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 2 +- net/mac80211/ieee80211.c | 2 +- net/mac80211/ieee80211_sta.c | 5 +-- net/mac80211/mesh_plink.c | 6 ++-- net/mac80211/sta_info.c | 80 +++++++++++++++++++++++++++++++------------- 5 files changed, 64 insertions(+), 31 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 6b183a3526b0..fbd462c78e18 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -672,7 +672,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, err = sta_info_insert(sta); if (err) { - sta_info_destroy(sta); + /* STA has been freed */ rcu_read_unlock(); return err; } diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 8c0f782d21e3..5ee431b6256c 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -268,7 +268,7 @@ static int ieee80211_open(struct net_device *dev) res = sta_info_insert(sta); if (res) { - sta_info_destroy(sta); + /* STA has been freed */ return res; } break; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index baa68575b98a..00fde111c268 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1942,7 +1942,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, if (err) { printk(KERN_DEBUG "%s: failed to insert STA entry for" " the AP (error %d)\n", dev->name, err); - sta_info_destroy(sta); rcu_read_unlock(); return; } @@ -4172,10 +4171,8 @@ struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, rate_control_rate_init(sta, local); - if (sta_info_insert(sta)) { - sta_info_destroy(sta); + if (sta_info_insert(sta)) return NULL; - } return sta; } diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 18fe52436c47..56c54e321b38 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -89,6 +89,10 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta) sta->plink_retries = 0; } +/* + * NOTE: This is just an alias for sta_info_alloc(), see notes + * on it in the lifecycle management section! + */ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr, u64 rates) { @@ -235,7 +239,6 @@ void mesh_neighbour_update(u8 *hw_addr, u64 rates, struct net_device *dev, return; } if (sta_info_insert(sta)) { - sta_info_destroy(sta); rcu_read_unlock(); return; } @@ -506,7 +509,6 @@ void mesh_rx_plink_frame(struct net_device *dev, struct ieee80211_mgmt *mgmt, return; } if (sta_info_insert(sta)) { - sta_info_destroy(sta); rcu_read_unlock(); return; } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 2a5a2f067bae..5497ca1843fe 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -36,16 +36,23 @@ * (which is pretty useless) or insert it into the hash table using * sta_info_insert() which demotes the reference from ownership to a regular * RCU-protected reference; if the function is called without protection by an - * RCU critical section the reference is instantly invalidated. + * RCU critical section the reference is instantly invalidated. Note that the + * caller may not do much with the STA info before inserting it, in particular, + * it may not start any mesh peer link management or add encryption keys. + * + * When the insertion fails (sta_info_insert()) returns non-zero), the + * structure will have been freed by sta_info_insert()! * * Because there are debugfs entries for each station, and adding those * must be able to sleep, it is also possible to "pin" a station entry, * that means it can be removed from the hash table but not be freed. - * See the comment in __sta_info_unlink() for more information. + * See the comment in __sta_info_unlink() for more information, this is + * an internal capability only. * * In order to remove a STA info structure, the caller needs to first * unlink it (sta_info_unlink()) from the list and hash tables and - * then wait for an RCU synchronisation before it can be freed. Due to + * then destroy it while holding the RTNL; sta_info_destroy() will wait + * for an RCU grace period to elapse before actually freeing it. Due to * the pinning and the possibility of multiple callers trying to remove * the same STA info at the same time, sta_info_unlink() can clear the * STA info pointer it is passed to indicate that the STA info is owned @@ -127,12 +134,35 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, return NULL; } +/** + * __sta_info_free - internal STA free helper + * + * @sta: STA info to free + * + * This function must undo everything done by sta_info_alloc() + * that may happen before sta_info_insert(). + */ +static void __sta_info_free(struct ieee80211_local *local, + struct sta_info *sta) +{ + DECLARE_MAC_BUF(mbuf); + + rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); + rate_control_put(sta->rate_ctrl); + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: Destroyed STA %s\n", + wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr)); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + + kfree(sta); +} + void sta_info_destroy(struct sta_info *sta) { struct ieee80211_local *local; struct sk_buff *skb; int i; - DECLARE_MAC_BUF(mbuf); ASSERT_RTNL(); might_sleep(); @@ -182,15 +212,7 @@ void sta_info_destroy(struct sta_info *sta) spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); } - rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); - rate_control_put(sta->rate_ctrl); - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Destroyed STA %s\n", - wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->addr)); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - - kfree(sta); + __sta_info_free(local, sta); } @@ -266,6 +288,7 @@ int sta_info_insert(struct sta_info *sta) struct ieee80211_local *local = sta->local; struct ieee80211_sub_if_data *sdata = sta->sdata; unsigned long flags; + int err = 0; DECLARE_MAC_BUF(mac); /* @@ -273,20 +296,23 @@ int sta_info_insert(struct sta_info *sta) * something inserts a STA (on one CPU) without holding the RTNL * and another CPU turns off the net device. */ - if (unlikely(!netif_running(sdata->dev))) - return -ENETDOWN; - - if (WARN_ON(compare_ether_addr(sta->addr, sdata->dev->dev_addr) == 0)) - return -EINVAL; + if (unlikely(!netif_running(sdata->dev))) { + err = -ENETDOWN; + goto out_free; + } - if (WARN_ON(is_multicast_ether_addr(sta->addr))) - return -EINVAL; + if (WARN_ON(compare_ether_addr(sta->addr, sdata->dev->dev_addr) == 0 || + is_multicast_ether_addr(sta->addr))) { + err = -EINVAL; + goto out_free; + } spin_lock_irqsave(&local->sta_lock, flags); /* check if STA exists already */ if (__sta_info_find(local, sta->addr)) { spin_unlock_irqrestore(&local->sta_lock, flags); - return -EEXIST; + err = -EEXIST; + goto out_free; } list_add(&sta->list, &local->sta_list); local->num_sta++; @@ -309,9 +335,13 @@ int sta_info_insert(struct sta_info *sta) spin_unlock_irqrestore(&local->sta_lock, flags); #ifdef CONFIG_MAC80211_DEBUGFS - /* debugfs entry adding might sleep, so schedule process + /* + * Debugfs entry adding might sleep, so schedule process * context task for adding entry for STAs that do not yet - * have one. */ + * have one. + * NOTE: due to auto-freeing semantics this may only be done + * if the insertion is successful! + */ queue_work(local->hw.workqueue, &local->sta_debugfs_add); #endif @@ -319,6 +349,10 @@ int sta_info_insert(struct sta_info *sta) mesh_accept_plinks_update(sdata); return 0; + out_free: + BUG_ON(!err); + __sta_info_free(local, sta); + return err; } static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) -- cgit v1.2.3-59-g8ed1b From 4f6fab472c4c7c21d577f85fabec7628d4a05637 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 31 Mar 2008 19:23:02 +0200 Subject: mac80211: clean up sta_info_destroy() users wrt. RCU/locking Calling sta_info_destroy() doesn't require RCU-synchronisation before-hand because it does that internally. However, it does require rtnl-locking so insert that where necessary. Also clean up the code doing it internally to be a bit clearer and not synchronize twice if keys are configured. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 6 +----- net/mac80211/ieee80211_sta.c | 1 - net/mac80211/sta_info.c | 33 +++++++++++++++++++-------------- 3 files changed, 20 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fbd462c78e18..5f8db5cab65d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -700,11 +700,7 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, return -ENOENT; sta_info_unlink(&sta); - - if (sta) { - synchronize_rcu(); - sta_info_destroy(sta); - } + sta_info_destroy(sta); } else sta_info_flush(local, sdata); diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 00fde111c268..c5a47f8d873a 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -939,7 +939,6 @@ static void ieee80211_associated(struct net_device *dev, rcu_read_unlock(); if (disassoc && sta) { - synchronize_rcu(); rtnl_lock(); sta_info_destroy(sta); rtnl_unlock(); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 5497ca1843fe..dfca96e05d69 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -180,13 +180,22 @@ void sta_info_destroy(struct sta_info *sta) mesh_plink_deactivate(sta); #endif - /* - * NOTE: This will call synchronize_rcu() internally to - * make sure no key references can be in use. We rely on - * that here for the mesh code! - */ - ieee80211_key_free(sta->key); - WARN_ON(sta->key); + if (sta->key) { + /* + * NOTE: This will call synchronize_rcu() internally to + * make sure no key references can be in use. We rely on + * that when we take this branch to make sure nobody can + * reference this STA struct any longer! + */ + ieee80211_key_free(sta->key); + WARN_ON(sta->key); + } else { + /* + * Make sure that nobody can reference this STA struct + * any longer. + */ + synchronize_rcu(); + } #ifdef CONFIG_MAC80211_MESH if (ieee80211_vif_is_mesh(&sta->sdata->vif)) @@ -628,11 +637,9 @@ static void sta_info_debugfs_add_work(struct work_struct *work) rate_control_add_sta_debugfs(sta); sta = __sta_info_unpin(sta); - - if (sta) { - synchronize_rcu(); - sta_info_destroy(sta); - } + rtnl_lock(); + sta_info_destroy(sta); + rtnl_unlock(); } } #endif @@ -694,8 +701,6 @@ int sta_info_flush(struct ieee80211_local *local, } spin_unlock_irqrestore(&local->sta_lock, flags); - synchronize_rcu(); - list_for_each_entry_safe(sta, tmp, &tmp_list, list) sta_info_destroy(sta); -- cgit v1.2.3-59-g8ed1b From dc6676b7f2c2072ec05254aaca32e99f87a8a417 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 31 Mar 2008 19:23:03 +0200 Subject: mac80211: sta_info_flush() fixes When the IBSS code tries to flush the STA list, it does so in an atomic context. Flushing isn't safe there, however, and requires the RTNL, so we need to defer it to a workqueue. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/ieee80211_sta.c | 2 +- net/mac80211/key.c | 9 ++++++ net/mac80211/sta_info.c | 70 ++++++++++++++++++++++++++++++++++++++++++++ net/mac80211/sta_info.h | 2 ++ 5 files changed, 84 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7ab806602183..0997a0f96203 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -606,6 +606,8 @@ struct ieee80211_local { spinlock_t sta_lock; unsigned long num_sta; struct list_head sta_list; + struct list_head sta_flush_list; + struct work_struct sta_flush_work; struct sta_info *sta_hash[STA_HASH_SIZE]; struct timer_list sta_cleanup; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index c5a47f8d873a..75b96a754333 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2254,7 +2254,7 @@ static int ieee80211_sta_join_ibss(struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); /* Remove possible STA entries from other IBSS networks. */ - sta_info_flush(local, sdata); + sta_info_flush_delayed(sdata); if (local->ops->reset_tsf) { /* Reset own TSF to allow time synchronization work. */ diff --git a/net/mac80211/key.c b/net/mac80211/key.c index f91fb4092652..5df9e0cc009f 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -73,6 +73,15 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) if (!key->local->ops->set_key) return; + /* + * This makes sure that all pending flushes have + * actually completed prior to uploading new key + * material to the hardware. That is necessary to + * avoid races between flushing STAs and adding + * new keys for them. + */ + __ieee80211_run_pending_flush(key->local); + addr = get_mac_for_key(key); ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index dfca96e05d69..f5c65e891288 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -644,10 +644,41 @@ static void sta_info_debugfs_add_work(struct work_struct *work) } #endif +void __ieee80211_run_pending_flush(struct ieee80211_local *local) +{ + struct sta_info *sta; + unsigned long flags; + + ASSERT_RTNL(); + + spin_lock_irqsave(&local->sta_lock, flags); + while (!list_empty(&local->sta_flush_list)) { + sta = list_first_entry(&local->sta_flush_list, + struct sta_info, list); + list_del(&sta->list); + spin_unlock_irqrestore(&local->sta_lock, flags); + sta_info_destroy(sta); + spin_lock_irqsave(&local->sta_lock, flags); + } + spin_unlock_irqrestore(&local->sta_lock, flags); +} + +static void ieee80211_sta_flush_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, sta_flush_work); + + rtnl_lock(); + __ieee80211_run_pending_flush(local); + rtnl_unlock(); +} + void sta_info_init(struct ieee80211_local *local) { spin_lock_init(&local->sta_lock); INIT_LIST_HEAD(&local->sta_list); + INIT_LIST_HEAD(&local->sta_flush_list); + INIT_WORK(&local->sta_flush_work, ieee80211_sta_flush_work); setup_timer(&local->sta_cleanup, sta_info_cleanup, (unsigned long)local); @@ -668,7 +699,12 @@ int sta_info_start(struct ieee80211_local *local) void sta_info_stop(struct ieee80211_local *local) { del_timer(&local->sta_cleanup); + cancel_work_sync(&local->sta_flush_work); + + rtnl_lock(); sta_info_flush(local, NULL); + __ieee80211_run_pending_flush(local); + rtnl_unlock(); } /** @@ -688,6 +724,7 @@ int sta_info_flush(struct ieee80211_local *local, unsigned long flags; might_sleep(); + ASSERT_RTNL(); spin_lock_irqsave(&local->sta_lock, flags); list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { @@ -706,3 +743,36 @@ int sta_info_flush(struct ieee80211_local *local, return ret; } + +/** + * sta_info_flush_delayed - flush matching STA entries from the STA table + * + * This function unlinks all stations for a given interface and queues + * them for freeing. Note that the workqueue function scheduled here has + * to run before any new keys can be added to the system to avoid set_key() + * callback ordering issues. + * + * @sdata: the interface + */ +void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct sta_info *sta, *tmp; + unsigned long flags; + bool work = false; + + spin_lock_irqsave(&local->sta_lock, flags); + list_for_each_entry_safe(sta, tmp, &local->sta_list, list) { + if (sdata == sta->sdata) { + __sta_info_unlink(&sta); + if (sta) { + list_add_tail(&sta->list, + &local->sta_flush_list); + work = true; + } + } + } + if (work) + schedule_work(&local->sta_flush_work); + spin_unlock_irqrestore(&local->sta_lock, flags); +} diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 5e39a4164b9b..b09861eb124e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -357,5 +357,7 @@ int sta_info_start(struct ieee80211_local *local); void sta_info_stop(struct ieee80211_local *local); int sta_info_flush(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); +void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata); +void __ieee80211_run_pending_flush(struct ieee80211_local *local); #endif /* STA_INFO_H */ -- cgit v1.2.3-59-g8ed1b From 7e879b551f1ada78d66fa5c6914aa1744b9c97d2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 31 Mar 2008 19:23:04 +0200 Subject: mac80211: fix sparse complaint in ieee80211_sta_def_wmm_params A variable 'i' is being shadowed by another one, but the second one can just be removed. Signed-off-by: Johannes Berg Cc: Vladimir Koutny Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 75b96a754333..b836948a0b40 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -244,7 +244,6 @@ static void ieee80211_sta_def_wmm_params(struct net_device *dev, if (local->ops->conf_tx) { struct ieee80211_tx_queue_params qparam; - int i; memset(&qparam, 0, sizeof(qparam)); -- cgit v1.2.3-59-g8ed1b From 73bb3e4a7a9f1b8d5f89c3991bd0c904ab0b8e27 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Mon, 31 Mar 2008 15:10:22 -0700 Subject: mac80211: fix deadlocks in debugfs_netdev.c The bug shows up with CONFIG_PREEMPT enabled. Pointed out by Andrew Morton. Cc: Andrew Morton Cc: Johannes Berg Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- net/mac80211/debugfs_netdev.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 0e921aef8ecf..3e19d42e61cb 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -31,11 +31,13 @@ static ssize_t ieee80211_if_read( ssize_t ret = -EINVAL; read_lock(&dev_base_lock); - if (sdata->dev->reg_state == NETREG_REGISTERED) { + if (sdata->dev->reg_state == NETREG_REGISTERED) ret = (*format)(sdata, buf, sizeof(buf)); - ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret); - } read_unlock(&dev_base_lock); + + if (ret != -EINVAL) + ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret); + return ret; } @@ -51,13 +53,13 @@ static ssize_t ieee80211_if_write( memset(buf, 0x00, sizeof(buf)); buf_size = min(count, (sizeof(buf)-1)); - read_lock(&dev_base_lock); if (copy_from_user(buf, userbuf, buf_size)) - goto endwrite; + return count; + read_lock(&dev_base_lock); if (sdata->dev->reg_state == NETREG_REGISTERED) (*format)(sdata, buf); -endwrite: read_unlock(&dev_base_lock); + return count; } #endif -- cgit v1.2.3-59-g8ed1b From cb585bccfedab0c228344ffa258950c417dea6b5 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Mon, 31 Mar 2008 15:21:23 -0700 Subject: mac80211: fix spinlock recursion on sta expiration Signed-off-by: Luis Carlos Cobo Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 2 +- net/mac80211/sta_info.c | 2 +- net/mac80211/sta_info.h | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index b836948a0b40..152682d4bb1a 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -3079,7 +3079,7 @@ static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time) if (time_after(jiffies, sta->last_rx + exp_time)) { printk(KERN_DEBUG "%s: expiring inactive STA %s\n", dev->name, print_mac(mac, sta->addr)); - sta_info_unlink(&sta); + __sta_info_unlink(&sta); if (sta) list_add(&sta->list, &tmp_list); } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index f5c65e891288..7e1e87257647 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -454,7 +454,7 @@ static struct sta_info *__sta_info_unpin(struct sta_info *sta) return ret; } -static void __sta_info_unlink(struct sta_info **sta) +void __sta_info_unlink(struct sta_info **sta) { struct ieee80211_local *local = (*sta)->local; struct ieee80211_sub_if_data *sdata = (*sta)->sdata; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b09861eb124e..ebb7b2b4d0b9 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -347,6 +347,7 @@ int sta_info_insert(struct sta_info *sta); * has already unlinked it. */ void sta_info_unlink(struct sta_info **sta); +void __sta_info_unlink(struct sta_info **sta); void sta_info_destroy(struct sta_info *sta); void sta_info_set_tim_bit(struct sta_info *sta); -- cgit v1.2.3-59-g8ed1b From 966a54282257ce1c43a5410dab2f2778a6f4dcf9 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Mon, 31 Mar 2008 15:33:39 -0700 Subject: mac80211: use recent multicast table for all mesh multicast frames ...not only broadcast. Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- net/mac80211/rx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index d9c6ed5be4fc..0ac6db5c09ea 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -433,7 +433,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx) } } else if ((rx->fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA && - is_broadcast_ether_addr(hdr->addr1) && + is_multicast_ether_addr(hdr->addr1) && mesh_rmc_check(hdr->addr4, msh_h_get(hdr, hdrlen), rx->dev)) return RX_DROP_MONITOR; #undef msh_h_get -- cgit v1.2.3-59-g8ed1b From 05e5e88373d91c75e9262a3f984be511960e510d Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Mon, 31 Mar 2008 16:00:13 -0700 Subject: mac80211: check for mesh_config length on incoming management frames Signed-off-by: Luis Carlos Cobo Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 152682d4bb1a..927ffbfe8582 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -2150,11 +2150,14 @@ ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len, static struct ieee80211_sta_bss * ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len, - u8 *mesh_cfg, int freq) + u8 *mesh_cfg, int mesh_config_len, int freq) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_sta_bss *bss; + if (mesh_config_len != MESH_CFG_LEN) + return NULL; + bss = kzalloc(sizeof(*bss), GFP_ATOMIC); if (!bss) return NULL; @@ -2528,7 +2531,8 @@ static void ieee80211_rx_bss_info(struct net_device *dev, #ifdef CONFIG_MAC80211_MESH if (elems.mesh_config) bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id, - elems.mesh_id_len, elems.mesh_config, freq); + elems.mesh_id_len, elems.mesh_config, + elems.mesh_config_len, freq); else #endif bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, -- cgit v1.2.3-59-g8ed1b From 6c4711b4697d93424e4b1f76a9929ba844d714a5 Mon Sep 17 00:00:00 2001 From: Luis Carlos Cobo Date: Mon, 31 Mar 2008 17:39:18 -0700 Subject: mac80211: use a struct for bss->mesh_config This allows cleaner code when accesing bss->mesh_config components. Signed-off-by: Luis Carlos Cobo Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 13 +++++++++++-- net/mac80211/ieee80211_sta.c | 32 ++++++++++++++++++++------------ net/mac80211/mesh.c | 4 ---- net/mac80211/mesh.h | 10 ++++++++++ 4 files changed, 41 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0997a0f96203..6c62dd42f915 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -69,6 +69,14 @@ struct ieee80211_fragment_entry { u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ }; +struct bss_mesh_config { + u32 path_proto_id; + u32 path_metric_id; + u32 cong_control_id; + u32 channel_precedence; + u8 mesh_version; +}; + struct ieee80211_sta_bss { struct list_head list; @@ -94,7 +102,7 @@ struct ieee80211_sta_bss { #ifdef CONFIG_MAC80211_MESH u8 *mesh_id; size_t mesh_id_len; - u8 *mesh_cfg; + struct bss_mesh_config *mesh_cfg; #endif #define IEEE80211_MAX_SUPP_RATES 32 u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; @@ -113,7 +121,8 @@ struct ieee80211_sta_bss { u8 erp_value; }; -static inline u8 *bss_mesh_cfg(struct ieee80211_sta_bss *bss) +static inline +struct bss_mesh_config *bss_mesh_cfg(struct ieee80211_sta_bss *bss) { #ifdef CONFIG_MAC80211_MESH return bss->mesh_cfg; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 927ffbfe8582..110eaf3ab58c 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include "ieee80211_i.h" @@ -2123,6 +2124,11 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, } #ifdef CONFIG_MAC80211_MESH +static inline u32 bss_mesh_cfg_get(u8 *mesh_cfg, u8 offset) +{ + return be32_to_cpu(get_unaligned((__be32 *) (mesh_cfg + offset))); +} + static struct ieee80211_sta_bss * ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len, u8 *mesh_cfg, int freq) @@ -2162,7 +2168,7 @@ ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len, if (!bss) return NULL; - bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC); + bss->mesh_cfg = kmalloc(sizeof(struct bss_mesh_config), GFP_ATOMIC); if (!bss->mesh_cfg) { kfree(bss); return NULL; @@ -2180,7 +2186,12 @@ ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len, atomic_inc(&bss->users); atomic_inc(&bss->users); - memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN); + bss->mesh_cfg->mesh_version = mesh_cfg[0]; + bss->mesh_cfg->path_proto_id = bss_mesh_cfg_get(mesh_cfg, PP_OFFSET); + bss->mesh_cfg->path_metric_id = bss_mesh_cfg_get(mesh_cfg, PM_OFFSET); + bss->mesh_cfg->cong_control_id = bss_mesh_cfg_get(mesh_cfg, CC_OFFSET); + bss->mesh_cfg->channel_precedence = bss_mesh_cfg_get(mesh_cfg, + CP_OFFSET); bss->mesh_id_len = mesh_id_len; bss->freq = freq; spin_lock_bh(&local->sta_bss_lock); @@ -4057,36 +4068,33 @@ ieee80211_sta_scan_result(struct net_device *dev, if (bss_mesh_cfg(bss)) { char *buf; - u8 *cfg = bss_mesh_cfg(bss); + struct bss_mesh_config *cfg = bss_mesh_cfg(bss); buf = kmalloc(50, GFP_ATOMIC); if (buf) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; - sprintf(buf, "Mesh network (version %d)", cfg[0]); + sprintf(buf, "Mesh network (version %d)", + cfg->mesh_version); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); sprintf(buf, "Path Selection Protocol ID: " - "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], - cfg[4]); + "0x%08X", cfg->path_proto_id); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); sprintf(buf, "Path Selection Metric ID: " - "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], - cfg[8]); + "0x%08X", cfg->path_metric_id); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); sprintf(buf, "Congestion Control Mode ID: " - "0x%02X%02X%02X%02X", cfg[9], cfg[10], - cfg[11], cfg[12]); + "0x%08X", cfg->cong_control_id); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); sprintf(buf, "Channel Precedence: " - "0x%02X%02X%02X%02X", cfg[13], cfg[14], - cfg[15], cfg[16]); + "0x%08X", cfg->channel_precedence); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 594a3356a508..b10f1e543a94 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -11,10 +11,6 @@ #include "ieee80211_i.h" #include "mesh.h" -#define PP_OFFSET 1 /* Path Selection Protocol */ -#define PM_OFFSET 5 /* Path Selection Metric */ -#define CC_OFFSET 9 /* Congestion Control Mode */ -#define CAPAB_OFFSET 17 #define ACCEPT_PLINKS 0x80 int mesh_allocated; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 742003d3a841..8ff46ea0f1d7 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -157,6 +157,16 @@ struct mesh_rmc { */ #define MESH_CFG_CMP_LEN 17 +/* + * Components offset within the mesh configuration IE + */ +#define PP_OFFSET 1 /* Path Selection Protocol */ +#define PM_OFFSET 5 /* Path Selection Metric */ +#define CC_OFFSET 9 /* Congestion Control Mode */ +#define CP_OFFSET 13 /* Channel Precedence */ +#define CAPAB_OFFSET 17 /* Mesh Capabilities */ + + /* Default values, timeouts in ms */ #define MESH_TTL 5 #define MESH_MAX_RETR 3 -- cgit v1.2.3-59-g8ed1b From f0bdb7ba5af5a7028479e9067ee74e9d66eea6df Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 1 Apr 2008 23:57:36 -0700 Subject: [IPV6] RAW: Remove ancient comment. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/raw.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'net') diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index c1e495f105ad..aae6cedf1709 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -168,11 +168,6 @@ static int ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) read_lock(&raw_v6_hashinfo.lock); sk = sk_head(&raw_v6_hashinfo.ht[hash]); - /* - * The first socket found will be delivered after - * delivery to transport protocols. - */ - if (sk == NULL) goto out; -- cgit v1.2.3-59-g8ed1b From fadf6bf06069138f8e97c9a963be38348ba2708b Mon Sep 17 00:00:00 2001 From: "Templin, Fred L" Date: Tue, 11 Mar 2008 18:35:59 -0400 Subject: [IPV6] SIT: Add PRL management for ISATAP. This patch updates the Linux the Intra-Site Automatic Tunnel Addressing Protocol (ISATAP) implementation. It places the ISATAP potential router list (PRL) in the kernel and adds three new private ioctls for PRL management. [Add several changes of structure name, constant names etc. - yoshfuji] Signed-off-by: Fred L. Templin Signed-off-by: YOSHIFUJI Hideaki --- include/linux/if_tunnel.h | 18 ++++- include/linux/skbuff.h | 3 +- include/net/ipip.h | 7 ++ include/net/ndisc.h | 9 +++ net/ipv6/ndisc.c | 24 ++++++ net/ipv6/route.c | 2 - net/ipv6/sit.c | 186 +++++++++++++++++++++++++++++++++++----------- 7 files changed, 199 insertions(+), 50 deletions(-) (limited to 'net') diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index 228eb4eb3129..f20c224d544c 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -7,6 +7,9 @@ #define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1) #define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2) #define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3) +#define SIOCADDPRL (SIOCDEVPRIVATE + 5) +#define SIOCDELPRL (SIOCDEVPRIVATE + 6) +#define SIOCCHGPRL (SIOCDEVPRIVATE + 7) #define GRE_CSUM __constant_htons(0x8000) #define GRE_ROUTING __constant_htons(0x4000) @@ -17,9 +20,6 @@ #define GRE_FLAGS __constant_htons(0x00F8) #define GRE_VERSION __constant_htons(0x0007) -/* i_flags values for SIT mode */ -#define SIT_ISATAP 0x0001 - struct ip_tunnel_parm { char name[IFNAMSIZ]; @@ -31,4 +31,16 @@ struct ip_tunnel_parm struct iphdr iph; }; +/* SIT-mode i_flags */ +#define SIT_ISATAP 0x0001 + +struct ip_tunnel_prl { + __be32 addr; + __u16 flags; + __u16 __reserved; +}; + +/* PRL flags */ +#define PRL_DEFAULT 0x0001 + #endif /* _IF_TUNNEL_H_ */ diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index ff72145d5d9e..e10e55c9b081 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -313,7 +313,8 @@ struct sk_buff { __u16 tc_verd; /* traffic control verdict */ #endif #endif - /* 2 byte hole */ + __u8 ndisc_nodetype:2; + /* 14 bit hole */ #ifdef CONFIG_NET_DMA dma_cookie_t dma_cookie; diff --git a/include/net/ipip.h b/include/net/ipip.h index 549e132bca9c..205536a014e8 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -24,6 +24,13 @@ struct ip_tunnel int mlink; struct ip_tunnel_parm parms; + struct ip_tunnel_prl_entry *prl; /* potential router list */ +}; + +struct ip_tunnel_prl_entry +{ + struct ip_tunnel_prl_entry *next; + struct ip_tunnel_prl entry; }; #define IPTUNNEL_XMIT() do { \ diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 5aedf324de66..9f2bae68d28c 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -11,6 +11,15 @@ #define NDISC_NEIGHBOUR_ADVERTISEMENT 136 #define NDISC_REDIRECT 137 +/* + * Router type: cross-layer information from link-layer to + * IPv6 layer reported by certain link types (e.g., RFC4214). + */ +#define NDISC_NODETYPE_UNSPEC 0 /* unspecified (default) */ +#define NDISC_NODETYPE_HOST 1 /* host or unauthorized router */ +#define NDISC_NODETYPE_NODEFAULT 2 /* non-default router */ +#define NDISC_NODETYPE_DEFAULT 3 /* default router */ + /* * ndisc options */ diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 510aa747a404..53b546019fd5 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1092,6 +1092,12 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } + if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) { + ND_PRINTK2(KERN_WARNING + "ICMPv6 RA: from host or unauthorized router\n"); + return; + } + /* * set the RA_RECV flag in the interface */ @@ -1115,6 +1121,10 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } + /* skip link-specific parameters from interior routers */ + if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) + goto skip_linkparms; + if (in6_dev->if_flags & IF_RS_SENT) { /* * flag that an RA was received after an RS was sent @@ -1229,6 +1239,8 @@ skip_defrtr: } } +skip_linkparms: + /* * Process options. */ @@ -1268,6 +1280,10 @@ skip_defrtr: } #endif + /* skip link-specific ndopts from interior routers */ + if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) + goto out; + if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { struct nd_opt_hdr *p; for (p = ndopts.nd_opts_pi; @@ -1331,6 +1347,14 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) int optlen; u8 *lladdr = NULL; + switch (skb->ndisc_nodetype) { + case NDISC_NODETYPE_HOST: + case NDISC_NODETYPE_NODEFAULT: + ND_PRINTK2(KERN_WARNING + "ICMPv6 Redirect: from host or unauthorized router\n"); + return; + } + if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { ND_PRINTK2(KERN_WARNING "ICMPv6 Redirect: source address is not link-local.\n"); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index cd82b6db35ff..f17b2f61891e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1699,8 +1699,6 @@ struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *d return rt; } -EXPORT_SYMBOL(rt6_get_dflt_router); - struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr, struct net_device *dev, unsigned int pref) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 1b8196c8d145..4786419ade0e 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -16,7 +16,7 @@ * Changes: * Roger Venning : 6to4 support * Nate Thompson : 6to4 support - * Fred L. Templin : isatap support + * Fred Templin : isatap support */ #include @@ -197,6 +197,119 @@ failed: return NULL; } +static struct ip_tunnel_prl_entry * +ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) +{ + struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL; + + for (p = t->prl; p; p = p->next) + if (p->entry.addr == addr) + break; + return p; + +} + +static int +ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) +{ + struct ip_tunnel_prl_entry *p; + + for (p = t->prl; p; p = p->next) { + if (p->entry.addr == a->addr) { + if (chg) { + p->entry = *a; + return 0; + } + return -EEXIST; + } + } + + if (chg) + return -ENXIO; + + p = kzalloc(sizeof(struct ip_tunnel_prl_entry), GFP_KERNEL); + if (!p) + return -ENOBUFS; + + p->entry = *a; + p->next = t->prl; + t->prl = p; + return 0; +} + +static int +ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) +{ + struct ip_tunnel_prl_entry *x, **p; + + if (a) { + for (p = &t->prl; *p; p = &(*p)->next) { + if ((*p)->entry.addr == a->addr) { + x = *p; + *p = x->next; + kfree(x); + return 0; + } + } + return -ENXIO; + } else { + while (t->prl) { + x = t->prl; + t->prl = t->prl->next; + kfree(x); + } + } + return 0; +} + +/* copied directly from anycast.c */ +static int +ipip6_onlink(struct in6_addr *addr, struct net_device *dev) +{ + struct inet6_dev *idev; + struct inet6_ifaddr *ifa; + int onlink; + + onlink = 0; + rcu_read_lock(); + idev = __in6_dev_get(dev); + if (idev) { + read_lock_bh(&idev->lock); + for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) { + onlink = ipv6_prefix_equal(addr, &ifa->addr, + ifa->prefix_len); + if (onlink) + break; + } + read_unlock_bh(&idev->lock); + } + rcu_read_unlock(); + return onlink; +} + +static int +isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) +{ + struct ip_tunnel_prl_entry *p = ipip6_tunnel_locate_prl(t, iph->saddr); + int ok = 1; + + if (p) { + if (p->entry.flags & PRL_DEFAULT) + skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT; + else + skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT; + } else { + struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr; + if (ipv6_addr_is_isatap(addr6) && + (addr6->s6_addr32[3] == iph->saddr) && + ipip6_onlink(addr6, t->dev)) + skb->ndisc_nodetype = NDISC_NODETYPE_HOST; + else + ok = 0; + } + return ok; +} + static void ipip6_tunnel_uninit(struct net_device *dev) { if (dev == ipip6_fb_tunnel_dev) { @@ -206,6 +319,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev) dev_put(dev); } else { ipip6_tunnel_unlink(netdev_priv(dev)); + ipip6_tunnel_del_prl(netdev_priv(dev), 0); dev_put(dev); } } @@ -365,48 +479,6 @@ static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) IP6_ECN_set_ce(ipv6_hdr(skb)); } -/* ISATAP (RFC4214) - check source address */ -static int -isatap_srcok(struct sk_buff *skb, struct iphdr *iph, struct net_device *dev) -{ - struct neighbour *neigh; - struct dst_entry *dst; - struct rt6_info *rt; - struct flowi fl; - struct in6_addr *addr6; - struct in6_addr rtr; - struct ipv6hdr *iph6; - int ok = 0; - - /* from onlink default router */ - ipv6_addr_set(&rtr, htonl(0xFE800000), 0, 0, 0); - ipv6_isatap_eui64(rtr.s6_addr + 8, iph->saddr); - if ((rt = rt6_get_dflt_router(&rtr, dev))) { - dst_release(&rt->u.dst); - return 1; - } - - iph6 = ipv6_hdr(skb); - memset(&fl, 0, sizeof(fl)); - fl.proto = iph6->nexthdr; - ipv6_addr_copy(&fl.fl6_dst, &iph6->saddr); - fl.oif = dev->ifindex; - security_skb_classify_flow(skb, &fl); - - dst = ip6_route_output(&init_net, NULL, &fl); - if (!dst->error && (dst->dev == dev) && (neigh = dst->neighbour)) { - - addr6 = (struct in6_addr*)&neigh->primary_key; - - /* from correct previous hop */ - if (ipv6_addr_is_isatap(addr6) && - (addr6->s6_addr32[3] == iph->saddr)) - ok = 1; - } - dst_release(dst); - return ok; -} - static int ipip6_rcv(struct sk_buff *skb) { struct iphdr *iph; @@ -427,7 +499,7 @@ static int ipip6_rcv(struct sk_buff *skb) skb->pkt_type = PACKET_HOST; if ((tunnel->dev->priv_flags & IFF_ISATAP) && - !isatap_srcok(skb, iph, tunnel->dev)) { + !isatap_chksrc(skb, iph, tunnel)) { tunnel->stat.rx_errors++; read_unlock(&ipip6_lock); kfree_skb(skb); @@ -707,6 +779,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) { int err = 0; struct ip_tunnel_parm p; + struct ip_tunnel_prl prl; struct ip_tunnel *t; switch (cmd) { @@ -806,6 +879,31 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) err = 0; break; + case SIOCADDPRL: + case SIOCDELPRL: + case SIOCCHGPRL: + err = -EPERM; + if (!capable(CAP_NET_ADMIN)) + goto done; + err = -EINVAL; + if (dev == ipip6_fb_tunnel_dev) + goto done; + err = -EFAULT; + if (copy_from_user(&prl, ifr->ifr_ifru.ifru_data, sizeof(prl))) + goto done; + err = -ENOENT; + if (!(t = netdev_priv(dev))) + goto done; + + ipip6_tunnel_unlink(t); + if (cmd == SIOCDELPRL) + err = ipip6_tunnel_del_prl(t, &prl); + else + err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); + ipip6_tunnel_link(t); + netdev_state_change(dev); + break; + default: err = -EINVAL; } -- cgit v1.2.3-59-g8ed1b From 3fcfa12904e83cc291cf2b7b05ff2530068920a4 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sat, 22 Mar 2008 17:42:57 +0900 Subject: [IPV6] SIT: Fix locking issues in PRL management. To protect PRL list, use ipip6_lock. Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/sit.c | 49 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 4786419ade0e..ee0cc2851691 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -198,7 +198,7 @@ failed: } static struct ip_tunnel_prl_entry * -ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) +__ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) { struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL; @@ -213,34 +213,46 @@ static int ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) { struct ip_tunnel_prl_entry *p; + int err = 0; + + write_lock(&ipip6_lock); for (p = t->prl; p; p = p->next) { if (p->entry.addr == a->addr) { - if (chg) { - p->entry = *a; - return 0; - } - return -EEXIST; + if (chg) + goto update; + err = -EEXIST; + goto out; } } - if (chg) - return -ENXIO; + if (chg) { + err = -ENXIO; + goto out; + } p = kzalloc(sizeof(struct ip_tunnel_prl_entry), GFP_KERNEL); - if (!p) - return -ENOBUFS; + if (!p) { + err = -ENOBUFS; + goto out; + } - p->entry = *a; p->next = t->prl; t->prl = p; - return 0; +update: + p->entry = *a; +out: + write_unlock(&ipip6_lock); + return err; } static int ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) { struct ip_tunnel_prl_entry *x, **p; + int err = 0; + + write_lock(&ipip6_lock); if (a) { for (p = &t->prl; *p; p = &(*p)->next) { @@ -248,10 +260,10 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) x = *p; *p = x->next; kfree(x); - return 0; + goto out; } } - return -ENXIO; + err = -ENXIO; } else { while (t->prl) { x = t->prl; @@ -259,6 +271,8 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) kfree(x); } } +out: + write_unlock(&ipip6_lock); return 0; } @@ -290,9 +304,11 @@ ipip6_onlink(struct in6_addr *addr, struct net_device *dev) static int isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) { - struct ip_tunnel_prl_entry *p = ipip6_tunnel_locate_prl(t, iph->saddr); + struct ip_tunnel_prl_entry *p; int ok = 1; + read_lock(&ipip6_lock); + p = __ipip6_tunnel_locate_prl(t, iph->saddr); if (p) { if (p->entry.flags & PRL_DEFAULT) skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT; @@ -307,6 +323,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) else ok = 0; } + read_unlock(&ipip6_lock); return ok; } @@ -895,12 +912,10 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (!(t = netdev_priv(dev))) goto done; - ipip6_tunnel_unlink(t); if (cmd == SIOCDELPRL) err = ipip6_tunnel_del_prl(t, &prl); else err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); - ipip6_tunnel_link(t); netdev_state_change(dev); break; -- cgit v1.2.3-59-g8ed1b From 0009ae1f50fb10178b5f54216ce567f3cb1d7267 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sat, 22 Mar 2008 17:50:59 +0900 Subject: [IPV6] SIT: Disallow 0.0.0.0 in PRL and Flush PRL if given for DEL. Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/sit.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index ee0cc2851691..84c1ed246afb 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -215,6 +215,9 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) struct ip_tunnel_prl_entry *p; int err = 0; + if (a->addr == htonl(INADDR_ANY)) + return -EINVAL; + write_lock(&ipip6_lock); for (p = t->prl; p; p = p->next) { @@ -254,7 +257,7 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) write_lock(&ipip6_lock); - if (a) { + if (a && a->addr != htonl(INADDR_ANY)) { for (p = &t->prl; *p; p = &(*p)->next) { if ((*p)->entry.addr == a->addr) { x = *p; -- cgit v1.2.3-59-g8ed1b From 300aaeeaab5f447fcf40e911afe96df3de28f0db Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Mon, 24 Mar 2008 18:28:39 +0900 Subject: [IPV6] SIT: Add SIOCGETPRL ioctl to get/dump PRL. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/if_tunnel.h | 4 ++ include/net/ipip.h | 5 ++- net/ipv6/sit.c | 96 ++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 95 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/linux/if_tunnel.h b/include/linux/if_tunnel.h index f20c224d544c..f1fbe9c930d7 100644 --- a/include/linux/if_tunnel.h +++ b/include/linux/if_tunnel.h @@ -7,6 +7,7 @@ #define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1) #define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2) #define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3) +#define SIOCGETPRL (SIOCDEVPRIVATE + 4) #define SIOCADDPRL (SIOCDEVPRIVATE + 5) #define SIOCDELPRL (SIOCDEVPRIVATE + 6) #define SIOCCHGPRL (SIOCDEVPRIVATE + 7) @@ -38,6 +39,9 @@ struct ip_tunnel_prl { __be32 addr; __u16 flags; __u16 __reserved; + __u32 datalen; + __u32 __reserved2; + void __user *data; }; /* PRL flags */ diff --git a/include/net/ipip.h b/include/net/ipip.h index 205536a014e8..633ed4def8e3 100644 --- a/include/net/ipip.h +++ b/include/net/ipip.h @@ -24,13 +24,16 @@ struct ip_tunnel int mlink; struct ip_tunnel_parm parms; + struct ip_tunnel_prl_entry *prl; /* potential router list */ + unsigned int prl_count; /* # of entries in PRL */ }; struct ip_tunnel_prl_entry { struct ip_tunnel_prl_entry *next; - struct ip_tunnel_prl entry; + __be32 addr; + u16 flags; }; #define IPTUNNEL_XMIT() do { \ diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 84c1ed246afb..08a483a8de50 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -203,12 +203,73 @@ __ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) struct ip_tunnel_prl_entry *p = (struct ip_tunnel_prl_entry *)NULL; for (p = t->prl; p; p = p->next) - if (p->entry.addr == addr) + if (p->addr == addr) break; return p; } +static int ipip6_tunnel_get_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) +{ + struct ip_tunnel_prl *kp; + struct ip_tunnel_prl_entry *prl; + unsigned int cmax, c = 0, ca, len; + int ret = 0; + + cmax = a->datalen / sizeof(*a); + if (cmax > 1 && a->addr != htonl(INADDR_ANY)) + cmax = 1; + + /* For simple GET or for root users, + * we try harder to allocate. + */ + kp = (cmax <= 1 || capable(CAP_NET_ADMIN)) ? + kcalloc(cmax, sizeof(*kp), GFP_KERNEL) : + NULL; + + read_lock(&ipip6_lock); + + ca = t->prl_count < cmax ? t->prl_count : cmax; + + if (!kp) { + /* We don't try hard to allocate much memory for + * non-root users. + * For root users, retry allocating enough memory for + * the answer. + */ + kp = kcalloc(ca, sizeof(*kp), GFP_ATOMIC); + if (!kp) { + ret = -ENOMEM; + goto out; + } + } + + c = 0; + for (prl = t->prl; prl; prl = prl->next) { + if (c > cmax) + break; + if (a->addr != htonl(INADDR_ANY) && prl->addr != a->addr) + continue; + kp[c].addr = prl->addr; + kp[c].flags = prl->flags; + c++; + if (a->addr != htonl(INADDR_ANY)) + break; + } +out: + read_unlock(&ipip6_lock); + + len = sizeof(*kp) * c; + ret = len ? copy_to_user(a->data, kp, len) : 0; + + kfree(kp); + if (ret) + return -EFAULT; + + a->datalen = len; + return 0; +} + static int ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) { @@ -221,7 +282,7 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) write_lock(&ipip6_lock); for (p = t->prl; p; p = p->next) { - if (p->entry.addr == a->addr) { + if (p->addr == a->addr) { if (chg) goto update; err = -EEXIST; @@ -242,8 +303,10 @@ ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) p->next = t->prl; t->prl = p; + t->prl_count++; update: - p->entry = *a; + p->addr = a->addr; + p->flags = a->flags; out: write_unlock(&ipip6_lock); return err; @@ -259,10 +322,11 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) if (a && a->addr != htonl(INADDR_ANY)) { for (p = &t->prl; *p; p = &(*p)->next) { - if ((*p)->entry.addr == a->addr) { + if ((*p)->addr == a->addr) { x = *p; *p = x->next; kfree(x); + t->prl_count--; goto out; } } @@ -272,6 +336,7 @@ ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) x = t->prl; t->prl = t->prl->next; kfree(x); + t->prl_count--; } } out: @@ -313,7 +378,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) read_lock(&ipip6_lock); p = __ipip6_tunnel_locate_prl(t, iph->saddr); if (p) { - if (p->entry.flags & PRL_DEFAULT) + if (p->flags & PRL_DEFAULT) skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT; else skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT; @@ -899,11 +964,12 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) err = 0; break; + case SIOCGETPRL: case SIOCADDPRL: case SIOCDELPRL: case SIOCCHGPRL: err = -EPERM; - if (!capable(CAP_NET_ADMIN)) + if (cmd != SIOCGETPRL && !capable(CAP_NET_ADMIN)) goto done; err = -EINVAL; if (dev == ipip6_fb_tunnel_dev) @@ -915,11 +981,23 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (!(t = netdev_priv(dev))) goto done; - if (cmd == SIOCDELPRL) + switch (cmd) { + case SIOCGETPRL: + err = ipip6_tunnel_get_prl(t, &prl); + if (!err && copy_to_user(ifr->ifr_ifru.ifru_data, + &prl, sizeof(prl))) + err = -EFAULT; + break; + case SIOCDELPRL: err = ipip6_tunnel_del_prl(t, &prl); - else + break; + case SIOCADDPRL: + case SIOCCHGPRL: err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); - netdev_state_change(dev); + break; + } + if (cmd != SIOCGETPRL) + netdev_state_change(dev); break; default: -- cgit v1.2.3-59-g8ed1b From 6294e000736401d4415ad41f408e56e14aaaf7b4 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sat, 15 Mar 2008 23:56:52 -0400 Subject: [IPV6] NDISC: Ignore route information with /0 prefix from interior router. Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/ndisc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 53b546019fd5..16273e11e53d 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1272,7 +1272,13 @@ skip_linkparms: for (p = ndopts.nd_opts_ri; p; p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) { - if (((struct route_info *)p)->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) + struct route_info *ri = (struct route_info *)p; +#ifdef CONFIG_IPV6_NDISC_NODETYPE + if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT && + ri->prefix_len == 0) + continue; +#endif + if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) continue; rt6_route_rcv(skb->dev, (u8*)p, (p->nd_opt_len) << 3, &ipv6_hdr(skb)->saddr); -- cgit v1.2.3-59-g8ed1b From 52eeeb8481d705e61e2e9aae974e7799a93783e9 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sat, 15 Mar 2008 22:54:23 -0400 Subject: [IPV6]: Unify ip6_onlink() and ipip6_onlink(). Both are identical, let's create ipv6_chk_prefix() and use it in both places. --- include/net/addrconf.h | 4 ++++ net/ipv6/addrconf.c | 25 +++++++++++++++++++++++++ net/ipv6/anycast.c | 25 +------------------------ net/ipv6/sit.c | 27 +-------------------------- 4 files changed, 31 insertions(+), 50 deletions(-) (limited to 'net') diff --git a/include/net/addrconf.h b/include/net/addrconf.h index d89b0bc7ab75..bdcc863a60a4 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -71,6 +71,10 @@ extern int ipv6_chk_addr(struct net *net, extern int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr); #endif + +extern int ipv6_chk_prefix(struct in6_addr *addr, + struct net_device *dev); + extern struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, struct in6_addr *addr, struct net_device *dev, diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 5ab9973571ef..c17f8c0b933e 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1249,6 +1249,31 @@ int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, return ifp != NULL; } +int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev) +{ + struct inet6_dev *idev; + struct inet6_ifaddr *ifa; + int onlink; + + onlink = 0; + rcu_read_lock(); + idev = __in6_dev_get(dev); + if (idev) { + read_lock_bh(&idev->lock); + for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) { + onlink = ipv6_prefix_equal(addr, &ifa->addr, + ifa->prefix_len); + if (onlink) + break; + } + read_unlock_bh(&idev->lock); + } + rcu_read_unlock(); + return onlink; +} + +EXPORT_SYMBOL(ipv6_chk_prefix); + struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, struct in6_addr *addr, struct net_device *dev, int strict) { diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 463bd95d6b13..36e817492095 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -48,29 +48,6 @@ static int ipv6_dev_ac_dec(struct net_device *dev, struct in6_addr *addr); /* Big ac list lock for all the sockets */ static DEFINE_RWLOCK(ipv6_sk_ac_lock); -static int -ip6_onlink(struct in6_addr *addr, struct net_device *dev) -{ - struct inet6_dev *idev; - struct inet6_ifaddr *ifa; - int onlink; - - onlink = 0; - rcu_read_lock(); - idev = __in6_dev_get(dev); - if (idev) { - read_lock_bh(&idev->lock); - for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) { - onlink = ipv6_prefix_equal(addr, &ifa->addr, - ifa->prefix_len); - if (onlink) - break; - } - read_unlock_bh(&idev->lock); - } - rcu_read_unlock(); - return onlink; -} /* * socket join an anycast group @@ -142,7 +119,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, struct in6_addr *addr) * This obviates the need for propagating anycast routes while * still allowing some non-router anycast participation. */ - if (!ip6_onlink(addr, dev)) { + if (!ipv6_chk_prefix(addr, dev)) { if (ishost) err = -EADDRNOTAVAIL; if (err) diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 08a483a8de50..cc16fe07bbff 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -344,31 +344,6 @@ out: return 0; } -/* copied directly from anycast.c */ -static int -ipip6_onlink(struct in6_addr *addr, struct net_device *dev) -{ - struct inet6_dev *idev; - struct inet6_ifaddr *ifa; - int onlink; - - onlink = 0; - rcu_read_lock(); - idev = __in6_dev_get(dev); - if (idev) { - read_lock_bh(&idev->lock); - for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) { - onlink = ipv6_prefix_equal(addr, &ifa->addr, - ifa->prefix_len); - if (onlink) - break; - } - read_unlock_bh(&idev->lock); - } - rcu_read_unlock(); - return onlink; -} - static int isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) { @@ -386,7 +361,7 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr; if (ipv6_addr_is_isatap(addr6) && (addr6->s6_addr32[3] == iph->saddr) && - ipip6_onlink(addr6, t->dev)) + ipv6_chk_prefix(addr6, t->dev)) skb->ndisc_nodetype = NDISC_NODETYPE_HOST; else ok = 0; -- cgit v1.2.3-59-g8ed1b From de357cc01334a468e4d5b7ba66a17b0d3ca9d63e Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sat, 15 Mar 2008 23:59:18 -0400 Subject: [IPV6] NDISC: Don't rely on node-type hint from L2 unless required. Signed-off-by: YOSHIFUJI Hideaki --- include/linux/skbuff.h | 2 ++ net/ipv6/Kconfig | 4 ++++ net/ipv6/ndisc.c | 10 ++++++++++ 3 files changed, 16 insertions(+) (limited to 'net') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index e10e55c9b081..e517701c25ba 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -313,7 +313,9 @@ struct sk_buff { __u16 tc_verd; /* traffic control verdict */ #endif #endif +#ifdef CONFIG_IPV6_NDISC_NODETYPE __u8 ndisc_nodetype:2; +#endif /* 14 bit hole */ #ifdef CONFIG_NET_DMA diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 47263e45bacb..7d2e7f0941ac 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -168,6 +168,7 @@ config IPV6_SIT tristate "IPv6: IPv6-in-IPv4 tunnel (SIT driver)" depends on IPV6 select INET_TUNNEL + select IPV6_NDISC_NODETYPE default y ---help--- Tunneling means encapsulating data of one protocol type within @@ -178,6 +179,9 @@ config IPV6_SIT Saying M here will produce a module called sit.ko. If unsure, say Y. +config IPV6_NDISC_NODETYPE + bool + config IPV6_TUNNEL tristate "IPv6: IP-in-IPv6 tunnel (RFC2473)" select INET6_TUNNEL diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 16273e11e53d..c400b874097a 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1092,11 +1092,13 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } +#ifdef CONFIG_IPV6_NDISC_NODETYPE if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) { ND_PRINTK2(KERN_WARNING "ICMPv6 RA: from host or unauthorized router\n"); return; } +#endif /* * set the RA_RECV flag in the interface @@ -1121,9 +1123,11 @@ static void ndisc_router_discovery(struct sk_buff *skb) return; } +#ifdef CONFIG_IPV6_NDISC_NODETYPE /* skip link-specific parameters from interior routers */ if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) goto skip_linkparms; +#endif if (in6_dev->if_flags & IF_RS_SENT) { /* @@ -1239,7 +1243,9 @@ skip_defrtr: } } +#ifdef CONFIG_IPV6_NDISC_NODETYPE skip_linkparms: +#endif /* * Process options. @@ -1286,9 +1292,11 @@ skip_linkparms: } #endif +#ifdef CONFIG_IPV6_NDISC_NODETYPE /* skip link-specific ndopts from interior routers */ if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) goto out; +#endif if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { struct nd_opt_hdr *p; @@ -1353,6 +1361,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) int optlen; u8 *lladdr = NULL; +#ifdef CONFIG_IPV6_NDISC_NODETYPE switch (skb->ndisc_nodetype) { case NDISC_NODETYPE_HOST: case NDISC_NODETYPE_NODEFAULT: @@ -1360,6 +1369,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) "ICMPv6 Redirect: from host or unauthorized router\n"); return; } +#endif if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { ND_PRINTK2(KERN_WARNING -- cgit v1.2.3-59-g8ed1b From 14c0c8e8e0fb85e7a57e88606c009377746b39d9 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 14:19:38 -0700 Subject: [TCP]: Replace socket with sock for reset sending. Replace tcp_socket with tcp_sock. This is more effective (less derefferences on fast paths). Additionally, the approach is unified to one used in ICMP. Signed-off-by: Denis V. Lunev Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index ef141b841d2f..1d77f37d7708 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -89,7 +89,7 @@ int sysctl_tcp_low_latency __read_mostly; #define ICMP_MIN_LENGTH 8 /* Socket used for sending RSTs */ -static struct socket *tcp_socket __read_mostly; +static struct sock *tcp_sock __read_mostly; void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); @@ -598,7 +598,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) sizeof(struct tcphdr), IPPROTO_TCP, 0); arg.csumoffset = offsetof(struct tcphdr, check) / 2; - ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len); + ip_send_reply(tcp_sock, skb, &arg, arg.iov[0].iov_len); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); @@ -693,7 +693,7 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, if (twsk) arg.bound_dev_if = twsk->tw_sk.tw_bound_dev_if; - ip_send_reply(tcp_socket->sk, skb, &arg, arg.iov[0].iov_len); + ip_send_reply(tcp_sock, skb, &arg, arg.iov[0].iov_len); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); } @@ -2490,9 +2490,11 @@ struct proto tcp_prot = { void __init tcp_v4_init(void) { - if (inet_csk_ctl_sock_create(&tcp_socket, PF_INET, SOCK_RAW, + struct socket *__tcp_socket; + if (inet_csk_ctl_sock_create(&__tcp_socket, PF_INET, SOCK_RAW, IPPROTO_TCP) < 0) panic("Failed to create the TCP control socket.\n"); + tcp_sock = __tcp_socket->sk; } EXPORT_SYMBOL(ipv4_specific); -- cgit v1.2.3-59-g8ed1b From 7630f026810a63464e47391ab1e03674c33eb1b8 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 14:20:52 -0700 Subject: [DCCP]: Replace socket with sock for reset sending. Replace dccp_v(4|6)_ctl_socket with sock to unify a code with TCP/ICMP. Signed-off-by: Denis V. Lunev Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/dccp.h | 2 +- net/dccp/ipv4.c | 16 +++++++++------- net/dccp/ipv6.c | 10 ++++++---- net/dccp/output.c | 6 +++--- 4 files changed, 19 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index e1b7c9c6a623..fe7726b0018f 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -296,7 +296,7 @@ extern unsigned int dccp_poll(struct file *file, struct socket *sock, extern int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); -extern struct sk_buff *dccp_ctl_make_reset(struct socket *ctl, +extern struct sk_buff *dccp_ctl_make_reset(struct sock *sk, struct sk_buff *skb); extern int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code); extern void dccp_send_close(struct sock *sk, const int active); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 7d62f7eb6134..f97049bf22c0 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -36,7 +36,7 @@ * the Out-of-the-blue (OOTB) packets. A control sock will be created * for this socket at the initialization time. */ -static struct socket *dccp_v4_ctl_socket; +static struct sock *dccp_v4_ctl_sk; int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { @@ -514,11 +514,11 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) if (rxskb->rtable->rt_type != RTN_LOCAL) return; - dst = dccp_v4_route_skb(dccp_v4_ctl_socket->sk, rxskb); + dst = dccp_v4_route_skb(dccp_v4_ctl_sk, rxskb); if (dst == NULL) return; - skb = dccp_ctl_make_reset(dccp_v4_ctl_socket, rxskb); + skb = dccp_ctl_make_reset(dccp_v4_ctl_sk, rxskb); if (skb == NULL) goto out; @@ -527,10 +527,10 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) rxiph->daddr); skb->dst = dst_clone(dst); - bh_lock_sock(dccp_v4_ctl_socket->sk); - err = ip_build_and_send_pkt(skb, dccp_v4_ctl_socket->sk, + bh_lock_sock(dccp_v4_ctl_sk); + err = ip_build_and_send_pkt(skb, dccp_v4_ctl_sk, rxiph->daddr, rxiph->saddr, NULL); - bh_unlock_sock(dccp_v4_ctl_socket->sk); + bh_unlock_sock(dccp_v4_ctl_sk); if (net_xmit_eval(err) == 0) { DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); @@ -991,6 +991,7 @@ static struct inet_protosw dccp_v4_protosw = { static int __init dccp_v4_init(void) { + struct socket *socket; int err = proto_register(&dccp_v4_prot, 1); if (err != 0) @@ -1002,10 +1003,11 @@ static int __init dccp_v4_init(void) inet_register_protosw(&dccp_v4_protosw); - err = inet_csk_ctl_sock_create(&dccp_v4_ctl_socket, PF_INET, + err = inet_csk_ctl_sock_create(&socket, PF_INET, SOCK_DCCP, IPPROTO_DCCP); if (err) goto out_unregister_protosw; + dccp_v4_ctl_sk = socket->sk; out: return err; out_unregister_protosw: diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index ea3f32648618..44e8b3323170 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -34,7 +34,7 @@ #include "feat.h" /* Socket used for sending RSTs and ACKs */ -static struct socket *dccp_v6_ctl_socket; +static struct sock *dccp_v6_ctl_sk; static struct inet_connection_sock_af_ops dccp_ipv6_mapped; static struct inet_connection_sock_af_ops dccp_ipv6_af_ops; @@ -303,7 +303,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) if (!ipv6_unicast_destination(rxskb)) return; - skb = dccp_ctl_make_reset(dccp_v6_ctl_socket, rxskb); + skb = dccp_ctl_make_reset(dccp_v6_ctl_sk, rxskb); if (skb == NULL) return; @@ -324,7 +324,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) /* sk = NULL, but it is safe for now. RST socket required. */ if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { - ip6_xmit(dccp_v6_ctl_socket->sk, skb, &fl, NULL, 0); + ip6_xmit(dccp_v6_ctl_sk, skb, &fl, NULL, 0); DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); return; @@ -1173,6 +1173,7 @@ static struct inet_protosw dccp_v6_protosw = { static int __init dccp_v6_init(void) { + struct socket *socket; int err = proto_register(&dccp_v6_prot, 1); if (err != 0) @@ -1184,10 +1185,11 @@ static int __init dccp_v6_init(void) inet6_register_protosw(&dccp_v6_protosw); - err = inet_csk_ctl_sock_create(&dccp_v6_ctl_socket, PF_INET6, + err = inet_csk_ctl_sock_create(&socket, PF_INET6, SOCK_DCCP, IPPROTO_DCCP); if (err != 0) goto out_unregister_protosw; + dccp_v6_ctl_sk = socket->sk; out: return err; out_unregister_protosw: diff --git a/net/dccp/output.c b/net/dccp/output.c index 3b763db3d863..f32a84ef757b 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -348,7 +348,7 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, EXPORT_SYMBOL_GPL(dccp_make_response); /* answer offending packet in @rcv_skb with Reset from control socket @ctl */ -struct sk_buff *dccp_ctl_make_reset(struct socket *ctl, struct sk_buff *rcv_skb) +struct sk_buff *dccp_ctl_make_reset(struct sock *sk, struct sk_buff *rcv_skb) { struct dccp_hdr *rxdh = dccp_hdr(rcv_skb), *dh; struct dccp_skb_cb *dcb = DCCP_SKB_CB(rcv_skb); @@ -358,11 +358,11 @@ struct sk_buff *dccp_ctl_make_reset(struct socket *ctl, struct sk_buff *rcv_skb) struct dccp_hdr_reset *dhr; struct sk_buff *skb; - skb = alloc_skb(ctl->sk->sk_prot->max_header, GFP_ATOMIC); + skb = alloc_skb(sk->sk_prot->max_header, GFP_ATOMIC); if (skb == NULL) return NULL; - skb_reserve(skb, ctl->sk->sk_prot->max_header); + skb_reserve(skb, sk->sk_prot->max_header); /* Swap the send and the receive. */ dh = dccp_zeroed_hdr(skb, dccp_hdr_reset_len); -- cgit v1.2.3-59-g8ed1b From 4f049b4f33d07bd11335c3a074ebef14213a3e37 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 14:21:33 -0700 Subject: [DCCP]: dccp_v(4|6)_ctl_socket is leaked. This seems a purism as module can't be unloaded, but though if cleanup method is present it should be correct and clean all staff created. Signed-off-by: Denis V. Lunev Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ipv4.c | 1 + net/dccp/ipv6.c | 1 + 2 files changed, 2 insertions(+) (limited to 'net') diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index f97049bf22c0..6d8f684a7a49 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -1020,6 +1020,7 @@ out_proto_unregister: static void __exit dccp_v4_exit(void) { + sock_release(dccp_v4_ctl_sk->sk_socket); inet_unregister_protosw(&dccp_v4_protosw); inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); proto_unregister(&dccp_v4_prot); diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 44e8b3323170..c5d9d1be56f3 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1202,6 +1202,7 @@ out_unregister_proto: static void __exit dccp_v6_exit(void) { + sock_release(dccp_v6_ctl_sk->sk_socket); inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); inet6_unregister_protosw(&dccp_v6_protosw); proto_unregister(&dccp_v6_prot); -- cgit v1.2.3-59-g8ed1b From 3d58b5fa8e4c461ab09afdacd3d1754fccca06ad Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 14:22:32 -0700 Subject: [INET]: Rename inet_csk_ctl_sock_create to inet_ctl_sock_create. This call is nothing common with INET connection sockets code. It simply creates an unhashes kernel sockets for protocol messages. Move the new call into af_inet.c after the rename. Signed-off-by: Denis V. Lunev Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- include/net/inet_common.h | 5 +++++ include/net/inet_connection_sock.h | 5 ----- net/dccp/ipv4.c | 4 ++-- net/dccp/ipv6.c | 4 ++-- net/ipv4/af_inet.c | 19 +++++++++++++++++++ net/ipv4/inet_connection_sock.c | 19 ------------------- net/ipv4/tcp_ipv4.c | 4 ++-- net/ipv6/tcp_ipv6.c | 3 ++- 8 files changed, 32 insertions(+), 31 deletions(-) (limited to 'net') diff --git a/include/net/inet_common.h b/include/net/inet_common.h index 38d5a1e9980d..d6238bdefbaf 100644 --- a/include/net/inet_common.h +++ b/include/net/inet_common.h @@ -39,6 +39,11 @@ extern int inet_getname(struct socket *sock, extern int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); +extern int inet_ctl_sock_create(struct socket **sock, + unsigned short family, + unsigned short type, + unsigned char protocol); + #endif diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h index f00f0573627b..2ff545a56fb5 100644 --- a/include/net/inet_connection_sock.h +++ b/include/net/inet_connection_sock.h @@ -327,11 +327,6 @@ extern void inet_csk_listen_stop(struct sock *sk); extern void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr); -extern int inet_csk_ctl_sock_create(struct socket **sock, - unsigned short family, - unsigned short type, - unsigned char protocol); - extern int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen); extern int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname, diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 6d8f684a7a49..feb3fa5b7141 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -1003,8 +1003,8 @@ static int __init dccp_v4_init(void) inet_register_protosw(&dccp_v4_protosw); - err = inet_csk_ctl_sock_create(&socket, PF_INET, - SOCK_DCCP, IPPROTO_DCCP); + err = inet_ctl_sock_create(&socket, PF_INET, + SOCK_DCCP, IPPROTO_DCCP); if (err) goto out_unregister_protosw; dccp_v4_ctl_sk = socket->sk; diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index c5d9d1be56f3..5690fbd3bf68 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1185,8 +1185,8 @@ static int __init dccp_v6_init(void) inet6_register_protosw(&dccp_v6_protosw); - err = inet_csk_ctl_sock_create(&socket, PF_INET6, - SOCK_DCCP, IPPROTO_DCCP); + err = inet_ctl_sock_create(&socket, PF_INET6, + SOCK_DCCP, IPPROTO_DCCP); if (err != 0) goto out_unregister_protosw; dccp_v6_ctl_sk = socket->sk; diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 5882a1316441..7ab0bd64c9d1 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1250,6 +1250,25 @@ out: return segs; } +int inet_ctl_sock_create(struct socket **sock, unsigned short family, + unsigned short type, unsigned char protocol) +{ + int rc = sock_create_kern(family, type, protocol, sock); + + if (rc == 0) { + (*sock)->sk->sk_allocation = GFP_ATOMIC; + inet_sk((*sock)->sk)->uc_ttl = -1; + /* + * Unhash it so that IP input processing does not even see it, + * we do not wish this socket to see incoming packets. + */ + (*sock)->sk->sk_prot->unhash((*sock)->sk); + } + return rc; +} + +EXPORT_SYMBOL_GPL(inet_ctl_sock_create); + unsigned long snmp_fold_field(void *mib[], int offt) { unsigned long res = 0; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index a7fcaf205644..ee55678a987d 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -651,25 +651,6 @@ void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr) EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr); -int inet_csk_ctl_sock_create(struct socket **sock, unsigned short family, - unsigned short type, unsigned char protocol) -{ - int rc = sock_create_kern(family, type, protocol, sock); - - if (rc == 0) { - (*sock)->sk->sk_allocation = GFP_ATOMIC; - inet_sk((*sock)->sk)->uc_ttl = -1; - /* - * Unhash it so that IP input processing does not even see it, - * we do not wish this socket to see incoming packets. - */ - (*sock)->sk->sk_prot->unhash((*sock)->sk); - } - return rc; -} - -EXPORT_SYMBOL_GPL(inet_csk_ctl_sock_create); - #ifdef CONFIG_COMPAT int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1d77f37d7708..edf5a37bb5c3 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2491,8 +2491,8 @@ struct proto tcp_prot = { void __init tcp_v4_init(void) { struct socket *__tcp_socket; - if (inet_csk_ctl_sock_create(&__tcp_socket, PF_INET, SOCK_RAW, - IPPROTO_TCP) < 0) + if (inet_ctl_sock_create(&__tcp_socket, PF_INET, SOCK_RAW, + IPPROTO_TCP) < 0) panic("Failed to create the TCP control socket.\n"); tcp_sock = __tcp_socket->sk; } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 6d851c3c3db9..d98222fba041 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -60,6 +60,7 @@ #include #include #include +#include #include @@ -2202,7 +2203,7 @@ static int tcpv6_net_init(struct net *net) struct socket *sock; struct sock *sk; - err = inet_csk_ctl_sock_create(&sock, PF_INET6, SOCK_RAW, IPPROTO_TCP); + err = inet_ctl_sock_create(&sock, PF_INET6, SOCK_RAW, IPPROTO_TCP); if (err) return err; -- cgit v1.2.3-59-g8ed1b From 4ffe0225e0628a5812168570b50d828f541c6b06 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 14:26:36 -0700 Subject: [SCTP]: Use inet_ctl_sock_create for control socket creation. sk->sk_proc->(un)hash is noop right now, so the unification is correct. Signed-off-by: Denis V. Lunev Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/sctp/protocol.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 5aea91137fbb..6a3be58f606d 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -680,16 +680,13 @@ static int sctp_ctl_sock_init(void) else family = PF_INET; - err = sock_create_kern(family, SOCK_SEQPACKET, IPPROTO_SCTP, - &sctp_ctl_socket); + err = inet_ctl_sock_create(&sctp_ctl_socket, family, + SOCK_SEQPACKET, IPPROTO_SCTP); if (err < 0) { printk(KERN_ERR "SCTP: Failed to create the SCTP control socket.\n"); return err; } - sctp_ctl_socket->sk->sk_allocation = GFP_ATOMIC; - inet_sk(sctp_ctl_socket->sk)->uc_ttl = -1; - return 0; } -- cgit v1.2.3-59-g8ed1b From 8258175c811440e93baa15ab1962a5905686dda3 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 14:27:26 -0700 Subject: [SCTP]: Replace socket with sock for SCTP control socket. Signed-off-by: Denis V. Lunev Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/sctp/protocol.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 6a3be58f606d..ac0833c19450 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -74,7 +74,7 @@ DEFINE_SPINLOCK(sctp_assocs_id_lock); * the Out-of-the-blue (OOTB) packets. A control sock will be created * for this socket at the initialization time. */ -static struct socket *sctp_ctl_socket; +static struct sock *sctp_ctl_sock; static struct sctp_pf *sctp_pf_inet6_specific; static struct sctp_pf *sctp_pf_inet_specific; @@ -91,7 +91,7 @@ int sysctl_sctp_wmem[3]; /* Return the address of the control sock. */ struct sock *sctp_get_ctl_sock(void) { - return sctp_ctl_socket->sk; + return sctp_ctl_sock; } /* Set up the proc fs entry for the SCTP protocol. */ @@ -674,19 +674,21 @@ static int sctp_ctl_sock_init(void) { int err; sa_family_t family; + struct socket *socket; if (sctp_get_pf_specific(PF_INET6)) family = PF_INET6; else family = PF_INET; - err = inet_ctl_sock_create(&sctp_ctl_socket, family, + err = inet_ctl_sock_create(&socket, family, SOCK_SEQPACKET, IPPROTO_SCTP); if (err < 0) { printk(KERN_ERR "SCTP: Failed to create the SCTP control socket.\n"); return err; } + sctp_ctl_sock = socket->sk; return 0; } @@ -1284,7 +1286,7 @@ err_v6_add_protocol: sctp_v6_del_protocol(); err_add_protocol: sctp_v4_del_protocol(); - sock_release(sctp_ctl_socket); + sock_release(sctp_ctl_sock->sk_socket); err_ctl_sock_init: sctp_v6_protosw_exit(); err_v6_protosw_init: @@ -1328,7 +1330,7 @@ SCTP_STATIC __exit void sctp_exit(void) sctp_v4_del_protocol(); /* Free the control endpoint. */ - sock_release(sctp_ctl_socket); + sock_release(sctp_ctl_sock->sk_socket); /* Free protosw registrations */ sctp_v6_protosw_exit(); -- cgit v1.2.3-59-g8ed1b From eee4fe4ded6e9c196168aee8f9787771f4df9c90 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 14:27:58 -0700 Subject: [INET]: Let inet_ctl_sock_create return sock rather than socket. All upper protocol layers are already use sock internally. Signed-off-by: Denis V. Lunev Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- include/net/inet_common.h | 2 +- net/dccp/ipv4.c | 4 +--- net/dccp/ipv6.c | 4 +--- net/ipv4/af_inet.c | 12 +++++++----- net/ipv4/tcp_ipv4.c | 4 +--- net/ipv6/tcp_ipv6.c | 5 ++--- net/sctp/protocol.c | 4 +--- 7 files changed, 14 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/include/net/inet_common.h b/include/net/inet_common.h index d6238bdefbaf..4bfcf3f3555f 100644 --- a/include/net/inet_common.h +++ b/include/net/inet_common.h @@ -39,7 +39,7 @@ extern int inet_getname(struct socket *sock, extern int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); -extern int inet_ctl_sock_create(struct socket **sock, +extern int inet_ctl_sock_create(struct sock **sk, unsigned short family, unsigned short type, unsigned char protocol); diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index feb3fa5b7141..5669c895c873 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -991,7 +991,6 @@ static struct inet_protosw dccp_v4_protosw = { static int __init dccp_v4_init(void) { - struct socket *socket; int err = proto_register(&dccp_v4_prot, 1); if (err != 0) @@ -1003,11 +1002,10 @@ static int __init dccp_v4_init(void) inet_register_protosw(&dccp_v4_protosw); - err = inet_ctl_sock_create(&socket, PF_INET, + err = inet_ctl_sock_create(&dccp_v4_ctl_sk, PF_INET, SOCK_DCCP, IPPROTO_DCCP); if (err) goto out_unregister_protosw; - dccp_v4_ctl_sk = socket->sk; out: return err; out_unregister_protosw: diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 5690fbd3bf68..cf598bfc6a18 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1173,7 +1173,6 @@ static struct inet_protosw dccp_v6_protosw = { static int __init dccp_v6_init(void) { - struct socket *socket; int err = proto_register(&dccp_v6_prot, 1); if (err != 0) @@ -1185,11 +1184,10 @@ static int __init dccp_v6_init(void) inet6_register_protosw(&dccp_v6_protosw); - err = inet_ctl_sock_create(&socket, PF_INET6, + err = inet_ctl_sock_create(&dccp_v6_ctl_sk, PF_INET6, SOCK_DCCP, IPPROTO_DCCP); if (err != 0) goto out_unregister_protosw; - dccp_v6_ctl_sk = socket->sk; out: return err; out_unregister_protosw: diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 7ab0bd64c9d1..cad664bf3f2e 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1250,19 +1250,21 @@ out: return segs; } -int inet_ctl_sock_create(struct socket **sock, unsigned short family, +int inet_ctl_sock_create(struct sock **sk, unsigned short family, unsigned short type, unsigned char protocol) { - int rc = sock_create_kern(family, type, protocol, sock); + struct socket *sock; + int rc = sock_create_kern(family, type, protocol, &sock); if (rc == 0) { - (*sock)->sk->sk_allocation = GFP_ATOMIC; - inet_sk((*sock)->sk)->uc_ttl = -1; + *sk = sock->sk; + (*sk)->sk_allocation = GFP_ATOMIC; + inet_sk(*sk)->uc_ttl = -1; /* * Unhash it so that IP input processing does not even see it, * we do not wish this socket to see incoming packets. */ - (*sock)->sk->sk_prot->unhash((*sock)->sk); + (*sk)->sk_prot->unhash(*sk); } return rc; } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index edf5a37bb5c3..cfe5df76e14b 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2490,11 +2490,9 @@ struct proto tcp_prot = { void __init tcp_v4_init(void) { - struct socket *__tcp_socket; - if (inet_ctl_sock_create(&__tcp_socket, PF_INET, SOCK_RAW, + if (inet_ctl_sock_create(&tcp_sock, PF_INET, SOCK_RAW, IPPROTO_TCP) < 0) panic("Failed to create the TCP control socket.\n"); - tcp_sock = __tcp_socket->sk; } EXPORT_SYMBOL(ipv4_specific); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index d98222fba041..2882cc51669e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2200,14 +2200,13 @@ static struct inet_protosw tcpv6_protosw = { static int tcpv6_net_init(struct net *net) { int err; - struct socket *sock; struct sock *sk; - err = inet_ctl_sock_create(&sock, PF_INET6, SOCK_RAW, IPPROTO_TCP); + err = inet_ctl_sock_create(&sk, PF_INET6, SOCK_RAW, IPPROTO_TCP); if (err) return err; - net->ipv6.tcp_sk = sk = sock->sk; + net->ipv6.tcp_sk = sk; sk_change_net(sk, net); return err; } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index ac0833c19450..3c08d334d4a8 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -674,21 +674,19 @@ static int sctp_ctl_sock_init(void) { int err; sa_family_t family; - struct socket *socket; if (sctp_get_pf_specific(PF_INET6)) family = PF_INET6; else family = PF_INET; - err = inet_ctl_sock_create(&socket, family, + err = inet_ctl_sock_create(&sctp_ctl_sock, family, SOCK_SEQPACKET, IPPROTO_SCTP); if (err < 0) { printk(KERN_ERR "SCTP: Failed to create the SCTP control socket.\n"); return err; } - sctp_ctl_sock = socket->sk; return 0; } -- cgit v1.2.3-59-g8ed1b From 5677242f432102dea9e6eceec1dc089e2f709ca4 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 14:28:30 -0700 Subject: [NETNS]: Inet control socket should not hold a namespace. This is a generic requirement, so make inet_ctl_sock_create namespace aware and create a inet_ctl_sock_destroy wrapper around sk_release_kernel. Signed-off-by: Denis V. Lunev Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- include/net/inet_common.h | 8 +++++++- net/dccp/ipv4.c | 4 ++-- net/dccp/ipv6.c | 4 ++-- net/ipv4/af_inet.c | 5 ++++- net/ipv4/tcp_ipv4.c | 2 +- net/ipv6/tcp_ipv6.c | 14 +++----------- net/sctp/protocol.c | 6 +++--- 7 files changed, 22 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/include/net/inet_common.h b/include/net/inet_common.h index 4bfcf3f3555f..18c773286b91 100644 --- a/include/net/inet_common.h +++ b/include/net/inet_common.h @@ -42,7 +42,13 @@ extern int inet_ioctl(struct socket *sock, extern int inet_ctl_sock_create(struct sock **sk, unsigned short family, unsigned short type, - unsigned char protocol); + unsigned char protocol, + struct net *net); + +static inline void inet_ctl_sock_destroy(struct sock *sk) +{ + sk_release_kernel(sk); +} #endif diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 5669c895c873..b12803bcba56 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -1003,7 +1003,7 @@ static int __init dccp_v4_init(void) inet_register_protosw(&dccp_v4_protosw); err = inet_ctl_sock_create(&dccp_v4_ctl_sk, PF_INET, - SOCK_DCCP, IPPROTO_DCCP); + SOCK_DCCP, IPPROTO_DCCP, &init_net); if (err) goto out_unregister_protosw; out: @@ -1018,7 +1018,7 @@ out_proto_unregister: static void __exit dccp_v4_exit(void) { - sock_release(dccp_v4_ctl_sk->sk_socket); + inet_ctl_sock_destroy(dccp_v4_ctl_sk); inet_unregister_protosw(&dccp_v4_protosw); inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); proto_unregister(&dccp_v4_prot); diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index cf598bfc6a18..94d749e6d494 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1185,7 +1185,7 @@ static int __init dccp_v6_init(void) inet6_register_protosw(&dccp_v6_protosw); err = inet_ctl_sock_create(&dccp_v6_ctl_sk, PF_INET6, - SOCK_DCCP, IPPROTO_DCCP); + SOCK_DCCP, IPPROTO_DCCP, &init_net); if (err != 0) goto out_unregister_protosw; out: @@ -1200,7 +1200,7 @@ out_unregister_proto: static void __exit dccp_v6_exit(void) { - sock_release(dccp_v6_ctl_sk->sk_socket); + inet_ctl_sock_destroy(dccp_v6_ctl_sk); inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); inet6_unregister_protosw(&dccp_v6_protosw); proto_unregister(&dccp_v6_prot); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index cad664bf3f2e..cf766ad15776 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1251,7 +1251,8 @@ out: } int inet_ctl_sock_create(struct sock **sk, unsigned short family, - unsigned short type, unsigned char protocol) + unsigned short type, unsigned char protocol, + struct net *net) { struct socket *sock; int rc = sock_create_kern(family, type, protocol, &sock); @@ -1265,6 +1266,8 @@ int inet_ctl_sock_create(struct sock **sk, unsigned short family, * we do not wish this socket to see incoming packets. */ (*sk)->sk_prot->unhash(*sk); + + sk_change_net(*sk, net); } return rc; } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index cfe5df76e14b..dc8c3dc75fe5 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2491,7 +2491,7 @@ struct proto tcp_prot = { void __init tcp_v4_init(void) { if (inet_ctl_sock_create(&tcp_sock, PF_INET, SOCK_RAW, - IPPROTO_TCP) < 0) + IPPROTO_TCP, &init_net) < 0) panic("Failed to create the TCP control socket.\n"); } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 2882cc51669e..378cc4002a76 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2199,21 +2199,13 @@ static struct inet_protosw tcpv6_protosw = { static int tcpv6_net_init(struct net *net) { - int err; - struct sock *sk; - - err = inet_ctl_sock_create(&sk, PF_INET6, SOCK_RAW, IPPROTO_TCP); - if (err) - return err; - - net->ipv6.tcp_sk = sk; - sk_change_net(sk, net); - return err; + return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6, + SOCK_RAW, IPPROTO_TCP, net); } static void tcpv6_net_exit(struct net *net) { - sk_release_kernel(net->ipv6.tcp_sk); + inet_ctl_sock_destroy(net->ipv6.tcp_sk); } static struct pernet_operations tcpv6_net_ops = { diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 3c08d334d4a8..067c8a1658d6 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -681,7 +681,7 @@ static int sctp_ctl_sock_init(void) family = PF_INET; err = inet_ctl_sock_create(&sctp_ctl_sock, family, - SOCK_SEQPACKET, IPPROTO_SCTP); + SOCK_SEQPACKET, IPPROTO_SCTP, &init_net); if (err < 0) { printk(KERN_ERR "SCTP: Failed to create the SCTP control socket.\n"); @@ -1284,7 +1284,7 @@ err_v6_add_protocol: sctp_v6_del_protocol(); err_add_protocol: sctp_v4_del_protocol(); - sock_release(sctp_ctl_sock->sk_socket); + inet_ctl_sock_destroy(sctp_ctl_sock); err_ctl_sock_init: sctp_v6_protosw_exit(); err_v6_protosw_init: @@ -1328,7 +1328,7 @@ SCTP_STATIC __exit void sctp_exit(void) sctp_v4_del_protocol(); /* Free the control endpoint. */ - sock_release(sctp_ctl_sock->sk_socket); + inet_ctl_sock_destroy(sctp_ctl_sock); /* Free protosw registrations */ sctp_v6_protosw_exit(); -- cgit v1.2.3-59-g8ed1b From c1e9894d486dc249331f4f04859c26147a778154 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 14:29:00 -0700 Subject: [ICMP]: Simplify ICMP control socket creation. Replace sock_create_kern with inet_ctl_sock_create. Signed-off-by: Denis V. Lunev Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) (limited to 'net') diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 803bc9f173a7..efc7cbe759c9 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -93,6 +93,7 @@ #include #include #include +#include /* * Build xmit assembly blocks @@ -1136,7 +1137,7 @@ static void __net_exit icmp_sk_exit(struct net *net) int i; for_each_possible_cpu(i) - sk_release_kernel(net->ipv4.icmp_sk[i]); + inet_ctl_sock_destroy(net->ipv4.icmp_sk[i]); kfree(net->ipv4.icmp_sk); net->ipv4.icmp_sk = NULL; } @@ -1152,17 +1153,13 @@ int __net_init icmp_sk_init(struct net *net) for_each_possible_cpu(i) { struct sock *sk; - struct socket *sock; - struct inet_sock *inet; - err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP, &sock); + err = inet_ctl_sock_create(&sk, PF_INET, + SOCK_RAW, IPPROTO_ICMP, net); if (err < 0) goto fail; - net->ipv4.icmp_sk[i] = sk = sock->sk; - sk_change_net(sk, net); - - sk->sk_allocation = GFP_ATOMIC; + net->ipv4.icmp_sk[i] = sk; /* Enough space for 2 64K ICMP packets, including * sk_buff struct overhead. @@ -1170,15 +1167,7 @@ int __net_init icmp_sk_init(struct net *net) sk->sk_sndbuf = (2 * ((64 * 1024) + sizeof(struct sk_buff))); - inet = inet_sk(sk); - inet->uc_ttl = -1; - inet->pmtudisc = IP_PMTUDISC_DONT; - - /* Unhash it so that IP input processing does not even - * see it, we do not wish this socket to see incoming - * packets. - */ - sk->sk_prot->unhash(sk); + inet_sk(sk)->pmtudisc = IP_PMTUDISC_DONT; } /* Control parameters for ECHO replies. */ @@ -1208,7 +1197,7 @@ int __net_init icmp_sk_init(struct net *net) fail: for_each_possible_cpu(i) - sk_release_kernel(net->ipv4.icmp_sk[i]); + inet_ctl_sock_destroy(net->ipv4.icmp_sk[i]); kfree(net->ipv4.icmp_sk); return err; } -- cgit v1.2.3-59-g8ed1b From 5616bdd6dfeb4e36be499dbac245e4d3be90a138 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 14:30:12 -0700 Subject: [INET]: uc_ttl assignment in inet_ctl_sock_create is redundant. uc_ttl is initialized in inet(6)_create and never changed except setsockopt ioctl. Remove this assignment. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index cf766ad15776..72ae8ed5a3d7 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1260,7 +1260,6 @@ int inet_ctl_sock_create(struct sock **sk, unsigned short family, if (rc == 0) { *sk = sock->sk; (*sk)->sk_allocation = GFP_ATOMIC; - inet_sk(*sk)->uc_ttl = -1; /* * Unhash it so that IP input processing does not even see it, * we do not wish this socket to see incoming packets. -- cgit v1.2.3-59-g8ed1b From 1ed8516f09e510e4595bc900ad9266c15aacfdd2 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 14:31:03 -0700 Subject: [IPV6]: Simplify IPv6 control sockets creation. Do this by replacing sock_create_kern with inet_ctl_sock_create. Signed-off-by: Denis V. Lunev Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/ipv6/icmp.c | 16 ++++++---------- net/ipv6/mcast.c | 19 ++++++------------- net/ipv6/ndisc.c | 12 +++++------- 3 files changed, 17 insertions(+), 30 deletions(-) (limited to 'net') diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 227ce3d2339d..195086114e63 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -64,6 +64,7 @@ #include #include #include +#include #include #include @@ -808,9 +809,8 @@ static int __net_init icmpv6_sk_init(struct net *net) return -ENOMEM; for_each_possible_cpu(i) { - struct socket *sock; - err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, - &sock); + err = inet_ctl_sock_create(&sk, PF_INET6, + SOCK_RAW, IPPROTO_ICMPV6, net); if (err < 0) { printk(KERN_ERR "Failed to initialize the ICMP6 control socket " @@ -819,10 +819,8 @@ static int __net_init icmpv6_sk_init(struct net *net) goto fail; } - net->ipv6.icmp_sk[i] = sk = sock->sk; - sk_change_net(sk, net); + net->ipv6.icmp_sk[i] = sk; - sk->sk_allocation = GFP_ATOMIC; /* * Split off their lock-class, because sk->sk_dst_lock * gets used from softirqs, which is safe for @@ -837,14 +835,12 @@ static int __net_init icmpv6_sk_init(struct net *net) */ sk->sk_sndbuf = (2 * ((64 * 1024) + sizeof(struct sk_buff))); - - sk->sk_prot->unhash(sk); } return 0; fail: for (j = 0; j < i; j++) - sk_release_kernel(net->ipv6.icmp_sk[j]); + inet_ctl_sock_destroy(net->ipv6.icmp_sk[j]); kfree(net->ipv6.icmp_sk); return err; } @@ -854,7 +850,7 @@ static void __net_exit icmpv6_sk_exit(struct net *net) int i; for_each_possible_cpu(i) { - sk_release_kernel(net->ipv6.icmp_sk[i]); + inet_ctl_sock_destroy(net->ipv6.icmp_sk[i]); } kfree(net->ipv6.icmp_sk); } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index d810cff818cf..2e6a53f3cc38 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -59,6 +59,7 @@ #include #include #include +#include #include @@ -2672,12 +2673,10 @@ static void igmp6_proc_exit(struct net *net) static int igmp6_net_init(struct net *net) { - struct ipv6_pinfo *np; - struct socket *sock; - struct sock *sk; int err; - err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock); + err = inet_ctl_sock_create(&net->ipv6.igmp_sk, PF_INET6, + SOCK_RAW, IPPROTO_ICMPV6, net); if (err < 0) { printk(KERN_ERR "Failed to initialize the IGMP6 control socket (err %d).\n", @@ -2685,13 +2684,7 @@ static int igmp6_net_init(struct net *net) goto out; } - net->ipv6.igmp_sk = sk = sock->sk; - sk_change_net(sk, net); - sk->sk_allocation = GFP_ATOMIC; - sk->sk_prot->unhash(sk); - - np = inet6_sk(sk); - np->hop_limit = 1; + inet6_sk(net->ipv6.igmp_sk)->hop_limit = 1; err = igmp6_proc_init(net); if (err) @@ -2700,13 +2693,13 @@ out: return err; out_sock_create: - sk_release_kernel(net->ipv6.igmp_sk); + inet_ctl_sock_destroy(net->ipv6.igmp_sk); goto out; } static void igmp6_net_exit(struct net *net) { - sk_release_kernel(net->ipv6.igmp_sk); + inet_ctl_sock_destroy(net->ipv6.igmp_sk); igmp6_proc_exit(net); } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 510aa747a404..06d80c6dc5ce 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -84,6 +84,7 @@ #include #include +#include #include #include @@ -1731,12 +1732,12 @@ static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name, static int ndisc_net_init(struct net *net) { - struct socket *sock; struct ipv6_pinfo *np; struct sock *sk; int err; - err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock); + err = inet_ctl_sock_create(&sk, PF_INET6, + SOCK_RAW, IPPROTO_ICMPV6, net); if (err < 0) { ND_PRINTK0(KERN_ERR "ICMPv6 NDISC: Failed to initialize the control socket (err %d).\n", @@ -1744,22 +1745,19 @@ static int ndisc_net_init(struct net *net) return err; } - net->ipv6.ndisc_sk = sk = sock->sk; - sk_change_net(sk, net); + net->ipv6.ndisc_sk = sk; np = inet6_sk(sk); - sk->sk_allocation = GFP_ATOMIC; np->hop_limit = 255; /* Do not loopback ndisc messages */ np->mc_loop = 0; - sk->sk_prot->unhash(sk); return 0; } static void ndisc_net_exit(struct net *net) { - sk_release_kernel(net->ipv6.ndisc_sk); + inet_ctl_sock_destroy(net->ipv6.ndisc_sk); } static struct pernet_operations ndisc_net_ops = { -- cgit v1.2.3-59-g8ed1b From 046ee902357adc046d041441956ec7eeb30c77c4 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 14:31:33 -0700 Subject: [NETNS]: Create tcp control socket in the each namespace. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/netns/ipv4.h | 1 + net/ipv4/tcp_ipv4.c | 21 +++++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index af685f71f4b5..34ee348a2cf2 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -28,6 +28,7 @@ struct netns_ipv4 { struct sock *fibnl; struct sock **icmp_sk; + struct sock *tcp_sock; struct netns_frags frags; #ifdef CONFIG_NETFILTER diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index dc8c3dc75fe5..1d4a77acdc0b 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2488,11 +2488,28 @@ struct proto tcp_prot = { #endif }; + +static int __net_init tcp_sk_init(struct net *net) +{ + return inet_ctl_sock_create(&net->ipv4.tcp_sock, + PF_INET, SOCK_RAW, IPPROTO_TCP, net); +} + +static void __net_exit tcp_sk_exit(struct net *net) +{ + inet_ctl_sock_destroy(net->ipv4.tcp_sock); +} + +static struct pernet_operations __net_initdata tcp_sk_ops = { + .init = tcp_sk_init, + .exit = tcp_sk_exit, +}; + void __init tcp_v4_init(void) { - if (inet_ctl_sock_create(&tcp_sock, PF_INET, SOCK_RAW, - IPPROTO_TCP, &init_net) < 0) + if (register_pernet_device(&tcp_sk_ops)) panic("Failed to create the TCP control socket.\n"); + tcp_sock = init_net.ipv4.tcp_sock; } EXPORT_SYMBOL(ipv4_specific); -- cgit v1.2.3-59-g8ed1b From 7feb49c82a74bc7c091b8ab2a3f96baa33d08ece Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 3 Apr 2008 14:32:00 -0700 Subject: [NETNS]: Use TCP control socket from a correct namespace. Signed-off-by: Denis V.Lunev Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 1d4a77acdc0b..df89a566a5a1 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -88,9 +88,6 @@ int sysctl_tcp_low_latency __read_mostly; /* Check TCP sequence numbers in ICMP packets. */ #define ICMP_MIN_LENGTH 8 -/* Socket used for sending RSTs */ -static struct sock *tcp_sock __read_mostly; - void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); #ifdef CONFIG_TCP_MD5SIG @@ -598,7 +595,8 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) sizeof(struct tcphdr), IPPROTO_TCP, 0); arg.csumoffset = offsetof(struct tcphdr, check) / 2; - ip_send_reply(tcp_sock, skb, &arg, arg.iov[0].iov_len); + ip_send_reply(dev_net(skb->dst->dev)->ipv4.tcp_sock, skb, + &arg, arg.iov[0].iov_len); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); TCP_INC_STATS_BH(TCP_MIB_OUTRSTS); @@ -693,7 +691,8 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, if (twsk) arg.bound_dev_if = twsk->tw_sk.tw_bound_dev_if; - ip_send_reply(tcp_sock, skb, &arg, arg.iov[0].iov_len); + ip_send_reply(dev_net(skb->dev)->ipv4.tcp_sock, skb, + &arg, arg.iov[0].iov_len); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); } @@ -2509,7 +2508,6 @@ void __init tcp_v4_init(void) { if (register_pernet_device(&tcp_sk_ops)) panic("Failed to create the TCP control socket.\n"); - tcp_sock = init_net.ipv4.tcp_sock; } EXPORT_SYMBOL(ipv4_specific); -- cgit v1.2.3-59-g8ed1b From f6a07b293f11d97bfbcd9b6a3ab4ad9c418a36ff Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Tue, 25 Mar 2008 00:25:11 +0900 Subject: [IPV6] ADDRCONF: Fix array size for sysctls. We have been using __NET_IPV6_MAX for adjusting the size of array for sysctl table, but it does not work any longer because of the deprecation of NET_IPV6_xxx constants. Let's use DEVCONF_MAX instead. Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/addrconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 87f688857ade..11037615bc73 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -3877,7 +3877,7 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table, static struct addrconf_sysctl_table { struct ctl_table_header *sysctl_header; - ctl_table addrconf_vars[__NET_IPV6_MAX]; + ctl_table addrconf_vars[DEVCONF_MAX+1]; char *dev_name; } addrconf_sysctl __read_mostly = { .sysctl_header = NULL, -- cgit v1.2.3-59-g8ed1b From 7bc570c8b4f75ddb3fd5dbeb38127cdc4acbcc9c Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 3 Apr 2008 09:22:53 +0900 Subject: [IPV6] MROUTE: Support multicast forwarding. Based on ancient patch by Mickael Hoerdt , which is available at . Signed-off-by: YOSHIFUJI Hideaki --- include/linux/Kbuild | 1 + include/linux/ipv6.h | 5 + include/linux/mroute6.h | 227 ++++++++ net/ipv6/Kconfig | 7 + net/ipv6/Makefile | 2 + net/ipv6/addrconf.c | 15 +- net/ipv6/af_inet6.c | 6 + net/ipv6/ip6_input.c | 87 ++- net/ipv6/ip6_output.c | 6 +- net/ipv6/ip6mr.c | 1384 ++++++++++++++++++++++++++++++++++++++++++++++ net/ipv6/ipv6_sockglue.c | 7 + net/ipv6/raw.c | 7 +- net/ipv6/route.c | 30 +- 13 files changed, 1754 insertions(+), 30 deletions(-) create mode 100644 include/linux/mroute6.h create mode 100644 net/ipv6/ip6mr.c (limited to 'net') diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 84736acb4b99..29ab9b95d376 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -261,6 +261,7 @@ unifdef-y += mempolicy.h unifdef-y += mii.h unifdef-y += mman.h unifdef-y += mroute.h +unifdef-y += mroute6.h unifdef-y += msdos_fs.h unifdef-y += msg.h unifdef-y += nbd.h diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index b90d3d461d4e..f53e4764fc05 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -159,6 +159,9 @@ struct ipv6_devconf { __s32 accept_source_route; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD __s32 optimistic_dad; +#endif +#ifdef CONFIG_IPV6_MROUTE + __s32 mc_forwarding; #endif void *sysctl; }; @@ -190,6 +193,7 @@ enum { DEVCONF_PROXY_NDP, DEVCONF_OPTIMISTIC_DAD, DEVCONF_ACCEPT_SOURCE_ROUTE, + DEVCONF_MC_FORWARDING, DEVCONF_MAX }; @@ -230,6 +234,7 @@ struct inet6_skb_parm { #endif #define IP6SKB_XFRM_TRANSFORMED 1 +#define IP6SKB_FORWARDED 2 }; #define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb)) diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h new file mode 100644 index 000000000000..b92190304e0b --- /dev/null +++ b/include/linux/mroute6.h @@ -0,0 +1,227 @@ +#ifndef __LINUX_MROUTE6_H +#define __LINUX_MROUTE6_H + +#include +#include + +/* + * Based on the MROUTING 3.5 defines primarily to keep + * source compatibility with BSD. + * + * See the pim6sd code for the original history. + * + * Protocol Independent Multicast (PIM) data structures included + * Carlos Picoto (cap@di.fc.ul.pt) + * + */ + +#define MRT6_BASE 200 +#define MRT6_INIT (MRT6_BASE) /* Activate the kernel mroute code */ +#define MRT6_DONE (MRT6_BASE+1) /* Shutdown the kernel mroute */ +#define MRT6_ADD_MIF (MRT6_BASE+2) /* Add a virtual interface */ +#define MRT6_DEL_MIF (MRT6_BASE+3) /* Delete a virtual interface */ +#define MRT6_ADD_MFC (MRT6_BASE+4) /* Add a multicast forwarding entry */ +#define MRT6_DEL_MFC (MRT6_BASE+5) /* Delete a multicast forwarding entry */ +#define MRT6_VERSION (MRT6_BASE+6) /* Get the kernel multicast version */ + +#define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */ +#define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1) +#define SIOCGETRPF (SIOCPROTOPRIVATE+2) + +#define MAXMIFS 32 +typedef unsigned long mifbitmap_t; /* User mode code depends on this lot */ +typedef unsigned short mifi_t; +#define ALL_MIFS ((mifi_t)(-1)) + +#ifndef IF_SETSIZE +#define IF_SETSIZE 256 +#endif + +typedef __u32 if_mask; +#define NIFBITS (sizeof(if_mask) * 8) /* bits per mask */ + +#if !defined(__KERNEL__) && !defined(DIV_ROUND_UP) +#define DIV_ROUND_UP(x,y) (((x) + ((y) - 1)) / (y)) +#endif + +typedef struct if_set { + if_mask ifs_bits[DIV_ROUND_UP(IF_SETSIZE, NIFBITS)]; +} if_set; + +#define IF_SET(n, p) ((p)->ifs_bits[(n)/NIFBITS] |= (1 << ((n) % NIFBITS))) +#define IF_CLR(n, p) ((p)->ifs_bits[(n)/NIFBITS] &= ~(1 << ((n) % NIFBITS))) +#define IF_ISSET(n, p) ((p)->ifs_bits[(n)/NIFBITS] & (1 << ((n) % NIFBITS))) +#define IF_COPY(f, t) bcopy(f, t, sizeof(*(f))) +#define IF_ZERO(p) bzero(p, sizeof(*(p))) + +/* + * Passed by mrouted for an MRT_ADD_MIF - again we use the + * mrouted 3.6 structures for compatibility + */ + +struct mif6ctl { + mifi_t mif6c_mifi; /* Index of MIF */ + unsigned char mif6c_flags; /* MIFF_ flags */ + unsigned char vifc_threshold; /* ttl limit */ + u_short mif6c_pifi; /* the index of the physical IF */ + unsigned int vifc_rate_limit; /* Rate limiter values (NI) */ +}; + +#define MIFF_REGISTER 0x1 /* register vif */ + +/* + * Cache manipulation structures for mrouted and PIMd + */ + +struct mf6cctl +{ + struct sockaddr_in6 mf6cc_origin; /* Origin of mcast */ + struct sockaddr_in6 mf6cc_mcastgrp; /* Group in question */ + mifi_t mf6cc_parent; /* Where it arrived */ + struct if_set mf6cc_ifset; /* Where it is going */ +}; + +/* + * Group count retrieval for pim6sd + */ + +struct sioc_sg_req6 +{ + struct sockaddr_in6 src; + struct sockaddr_in6 grp; + unsigned long pktcnt; + unsigned long bytecnt; + unsigned long wrong_if; +}; + +/* + * To get vif packet counts + */ + +struct sioc_mif_req6 +{ + mifi_t mifi; /* Which iface */ + unsigned long icount; /* In packets */ + unsigned long ocount; /* Out packets */ + unsigned long ibytes; /* In bytes */ + unsigned long obytes; /* Out bytes */ +}; + +/* + * That's all usermode folks + */ + +#ifdef __KERNEL__ + +#include /* for struct sk_buff_head */ + +struct net_device; +struct inet6_dev *ipv6_find_idev(struct net_device *dev); + +#ifdef CONFIG_IPV6_MROUTE +static inline int ip6_mroute_opt(int opt) +{ + return (opt >= MRT6_BASE) && (opt <= MRT6_BASE + 10); +} +#else +static inline int ip6_mroute_opt(int opt) +{ + return 0; +} +#endif + +struct sock; + +extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, int); +extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *); +extern int ip6_mr_input(struct sk_buff *skb); +extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg); +extern void ip6_mr_init(void); + +struct mif_device +{ + struct net_device *dev; /* Device we are using */ + unsigned long bytes_in,bytes_out; + unsigned long pkt_in,pkt_out; /* Statistics */ + unsigned long rate_limit; /* Traffic shaping (NI) */ + unsigned char threshold; /* TTL threshold */ + unsigned short flags; /* Control flags */ + int link; /* Physical interface index */ +}; + +#define VIFF_STATIC 0x8000 + +struct mfc6_cache +{ + struct mfc6_cache *next; /* Next entry on cache line */ + struct in6_addr mf6c_mcastgrp; /* Group the entry belongs to */ + struct in6_addr mf6c_origin; /* Source of packet */ + mifi_t mf6c_parent; /* Source interface */ + int mfc_flags; /* Flags on line */ + + union { + struct { + unsigned long expires; + struct sk_buff_head unresolved; /* Unresolved buffers */ + } unres; + struct { + unsigned long last_assert; + int minvif; + int maxvif; + unsigned long bytes; + unsigned long pkt; + unsigned long wrong_if; + unsigned char ttls[MAXMIFS]; /* TTL thresholds */ + } res; + } mfc_un; +}; + +#define MFC_STATIC 1 +#define MFC_NOTIFY 2 + +#define MFC6_LINES 64 + +#define MFC6_HASH(a, g) (((__force u32)(a)->s6_addr32[0] ^ \ + (__force u32)(a)->s6_addr32[1] ^ \ + (__force u32)(a)->s6_addr32[2] ^ \ + (__force u32)(a)->s6_addr32[3] ^ \ + (__force u32)(g)->s6_addr32[0] ^ \ + (__force u32)(g)->s6_addr32[1] ^ \ + (__force u32)(g)->s6_addr32[2] ^ \ + (__force u32)(g)->s6_addr32[3]) % MFC6_LINES) + +#define MFC_ASSERT_THRESH (3*HZ) /* Maximal freq. of asserts */ + +#endif + +#ifdef __KERNEL__ +struct rtmsg; +extern int ip6mr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait); + +#ifdef CONFIG_IPV6_MROUTE +extern struct sock *mroute6_socket; +extern int ip6mr_sk_done(struct sock *sk); +#else +#define mroute6_socket NULL +static inline int ip6mr_sk_done(struct sock *sk) { return 0; } +#endif +#endif + +/* + * Structure used to communicate from kernel to multicast router. + * We'll overlay the structure onto an MLD header (not an IPv6 heder like igmpmsg{} + * used for IPv4 implementation). This is because this structure will be passed via an + * IPv6 raw socket, on wich an application will only receiver the payload i.e the data after + * the IPv6 header and all the extension headers. (See section 3 of RFC 3542) + */ + +struct mrt6msg { +#define MRT6MSG_NOCACHE 1 + __u8 im6_mbz; /* must be zero */ + __u8 im6_msgtype; /* what type of message */ + __u16 im6_mif; /* mif rec'd on */ + __u32 im6_pad; /* padding for 64 bit arch */ + struct in6_addr im6_src, im6_dst; +}; + +#endif diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 47263e45bacb..9a2ea81e499f 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -209,3 +209,10 @@ config IPV6_SUBTREES If unsure, say N. +config IPV6_MROUTE + bool "IPv6: multicast routing (EXPERIMENTAL)" + depends on IPV6 && EXPERIMENTAL + ---help--- + Experimental support for IPv6 multicast forwarding. + If unsure, say N. + diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index ae14617e607f..686934acfac1 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile @@ -11,6 +11,8 @@ ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o +ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o + ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ xfrm6_output.o ipv6-$(CONFIG_NETFILTER) += netfilter.o diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 11037615bc73..dbc51af69017 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -412,7 +412,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) return ndev; } -static struct inet6_dev * ipv6_find_idev(struct net_device *dev) +struct inet6_dev * ipv6_find_idev(struct net_device *dev) { struct inet6_dev *idev; @@ -3547,6 +3547,9 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, #ifdef CONFIG_IPV6_OPTIMISTIC_DAD array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad; #endif +#ifdef CONFIG_IPV6_MROUTE + array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; +#endif } static inline size_t inet6_if_nlmsg_size(void) @@ -4094,6 +4097,16 @@ static struct addrconf_sysctl_table .proc_handler = &proc_dointvec, }, +#endif +#ifdef CONFIG_IPV6_MROUTE + { + .ctl_name = CTL_UNNUMBERED, + .procname = "mc_forwarding", + .data = &ipv6_devconf.mc_forwarding, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #endif { .ctl_name = 0, /* sentinel */ diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 1731b0abf7f5..3c6aafb02183 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -61,6 +61,9 @@ #include #include +#ifdef CONFIG_IPV6_MROUTE +#include +#endif MODULE_AUTHOR("Cast of dozens"); MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); @@ -953,6 +956,9 @@ static int __init inet6_init(void) err = icmpv6_init(); if (err) goto icmp_fail; +#ifdef CONFIG_IPV6_MROUTE + ip6_mr_init(); +#endif err = ndisc_init(); if (err) goto ndisc_fail; diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 43a617e2268b..09a3201e408a 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -236,36 +237,84 @@ int ip6_mc_input(struct sk_buff *skb) hdr = ipv6_hdr(skb); deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL); +#ifdef CONFIG_IPV6_MROUTE /* - * IPv6 multicast router mode isnt currently supported. + * IPv6 multicast router mode is now supported ;) */ -#if 0 - if (ipv6_config.multicast_route) { - int addr_type; - - addr_type = ipv6_addr_type(&hdr->daddr); - - if (!(addr_type & (IPV6_ADDR_LOOPBACK | IPV6_ADDR_LINKLOCAL))) { - struct sk_buff *skb2; - struct dst_entry *dst; + if (ipv6_devconf.mc_forwarding && + likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) { + /* + * Okay, we try to forward - split and duplicate + * packets. + */ + struct sk_buff *skb2; + struct inet6_skb_parm *opt = IP6CB(skb); + + /* Check for MLD */ + if (unlikely(opt->ra)) { + /* Check if this is a mld message */ + u8 *ptr = skb_network_header(skb) + opt->ra; + struct icmp6hdr *icmp6; + u8 nexthdr = hdr->nexthdr; + int offset; + + /* Check if the value of Router Alert + * is for MLD (0x0000). + */ + if ((ptr[2] | ptr[3]) == 0) { + if (!ipv6_ext_hdr(nexthdr)) { + /* BUG */ + goto discard; + } + offset = ipv6_skip_exthdr(skb, sizeof(*hdr), + &nexthdr); + if (offset < 0) + goto discard; + + if (nexthdr != IPPROTO_ICMPV6) + goto discard; + + if (!pskb_may_pull(skb, (skb_network_header(skb) + + offset + 1 - skb->data))) + goto discard; + + icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset); + + switch (icmp6->icmp6_type) { + case ICMPV6_MGM_QUERY: + case ICMPV6_MGM_REPORT: + case ICMPV6_MGM_REDUCTION: + case ICMPV6_MLD2_REPORT: + break; + default: + /* Bogus */ + goto discard; + } + deliver = 1; + goto out; + } + /* unknown RA - process it normally */ + } - dst = skb->dst; + if (deliver) + skb2 = skb_clone(skb, GFP_ATOMIC); + else { + skb2 = skb; + skb = NULL; + } - if (deliver) { - skb2 = skb_clone(skb, GFP_ATOMIC); - dst_output(skb2); - } else { - dst_output(skb); - return 0; - } + if (skb2) { + skb2->dev = skb2->dst->dev; + ip6_mr_input(skb2); } } #endif - +out: if (likely(deliver)) { ip6_input(skb); return 0; } +discard: /* discard */ kfree_skb(skb); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index a8b4da25b0a7..c0dbe549cc42 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -55,6 +55,7 @@ #include #include #include +#include static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)); @@ -137,8 +138,9 @@ static int ip6_output2(struct sk_buff *skb) struct inet6_dev *idev = ip6_dst_idev(skb->dst); if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && - ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, - &ipv6_hdr(skb)->saddr)) { + ((mroute6_socket && !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || + ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, + &ipv6_hdr(skb)->saddr))) { struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); /* Do not check for IFF_ALLMULTI; multicast routing diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c new file mode 100644 index 000000000000..1bdf3c177d58 --- /dev/null +++ b/net/ipv6/ip6mr.c @@ -0,0 +1,1384 @@ +/* + * Linux IPv6 multicast routing support for BSD pim6sd + * Based on net/ipv4/ipmr.c. + * + * (c) 2004 Mickael Hoerdt, + * LSIIT Laboratory, Strasbourg, France + * (c) 2004 Jean-Philippe Andriot, + * 6WIND, Paris, France + * Copyright (C)2007,2008 USAGI/WIDE Project + * YOSHIFUJI Hideaki + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct sock *mroute6_socket; + + +/* Big lock, protecting vif table, mrt cache and mroute socket state. + Note that the changes are semaphored via rtnl_lock. + */ + +static DEFINE_RWLOCK(mrt_lock); + +/* + * Multicast router control variables + */ + +static struct mif_device vif6_table[MAXMIFS]; /* Devices */ +static int maxvif; + +#define MIF_EXISTS(idx) (vif6_table[idx].dev != NULL) + +static struct mfc6_cache *mfc6_cache_array[MFC_LINES]; /* Forwarding cache */ + +static struct mfc6_cache *mfc_unres_queue; /* Queue of unresolved entries */ +static atomic_t cache_resolve_queue_len; /* Size of unresolved */ + +/* Special spinlock for queue of unresolved entries */ +static DEFINE_SPINLOCK(mfc_unres_lock); + +/* We return to original Alan's scheme. Hash table of resolved + entries is changed only in process context and protected + with weak lock mrt_lock. Queue of unresolved entries is protected + with strong spinlock mfc_unres_lock. + + In this case data path is free of exclusive locks at all. + */ + +static struct kmem_cache *mrt_cachep __read_mostly; + +static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache); +static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert); +static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm); + +static struct timer_list ipmr_expire_timer; + + +#ifdef CONFIG_PROC_FS + +struct ipmr_mfc_iter { + struct mfc6_cache **cache; + int ct; +}; + + +static struct mfc6_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos) +{ + struct mfc6_cache *mfc; + + it->cache = mfc6_cache_array; + read_lock(&mrt_lock); + for (it->ct = 0; it->ct < ARRAY_SIZE(mfc6_cache_array); it->ct++) + for (mfc = mfc6_cache_array[it->ct]; mfc; mfc = mfc->next) + if (pos-- == 0) + return mfc; + read_unlock(&mrt_lock); + + it->cache = &mfc_unres_queue; + spin_lock_bh(&mfc_unres_lock); + for (mfc = mfc_unres_queue; mfc; mfc = mfc->next) + if (pos-- == 0) + return mfc; + spin_unlock_bh(&mfc_unres_lock); + + it->cache = NULL; + return NULL; +} + + + + +/* + * The /proc interfaces to multicast routing /proc/ip6_mr_cache /proc/ip6_mr_vif + */ + +struct ipmr_vif_iter { + int ct; +}; + +static struct mif_device *ip6mr_vif_seq_idx(struct ipmr_vif_iter *iter, + loff_t pos) +{ + for (iter->ct = 0; iter->ct < maxvif; ++iter->ct) { + if (!MIF_EXISTS(iter->ct)) + continue; + if (pos-- == 0) + return &vif6_table[iter->ct]; + } + return NULL; +} + +static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(mrt_lock) +{ + read_lock(&mrt_lock); + return (*pos ? ip6mr_vif_seq_idx(seq->private, *pos - 1) + : SEQ_START_TOKEN); +} + +static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct ipmr_vif_iter *iter = seq->private; + + ++*pos; + if (v == SEQ_START_TOKEN) + return ip6mr_vif_seq_idx(iter, 0); + + while (++iter->ct < maxvif) { + if (!MIF_EXISTS(iter->ct)) + continue; + return &vif6_table[iter->ct]; + } + return NULL; +} + +static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v) + __releases(mrt_lock) +{ + read_unlock(&mrt_lock); +} + +static int ip6mr_vif_seq_show(struct seq_file *seq, void *v) +{ + if (v == SEQ_START_TOKEN) { + seq_puts(seq, + "Interface BytesIn PktsIn BytesOut PktsOut Flags\n"); + } else { + const struct mif_device *vif = v; + const char *name = vif->dev ? vif->dev->name : "none"; + + seq_printf(seq, + "%2Zd %-10s %8ld %7ld %8ld %7ld %05X\n", + vif - vif6_table, + name, vif->bytes_in, vif->pkt_in, + vif->bytes_out, vif->pkt_out, + vif->flags); + } + return 0; +} + +static struct seq_operations ip6mr_vif_seq_ops = { + .start = ip6mr_vif_seq_start, + .next = ip6mr_vif_seq_next, + .stop = ip6mr_vif_seq_stop, + .show = ip6mr_vif_seq_show, +}; + +static int ip6mr_vif_open(struct inode *inode, struct file *file) +{ + return seq_open_private(file, &ip6mr_vif_seq_ops, + sizeof(struct ipmr_vif_iter)); +} + +static struct file_operations ip6mr_vif_fops = { + .owner = THIS_MODULE, + .open = ip6mr_vif_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos) +{ + return (*pos ? ipmr_mfc_seq_idx(seq->private, *pos - 1) + : SEQ_START_TOKEN); +} + +static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct mfc6_cache *mfc = v; + struct ipmr_mfc_iter *it = seq->private; + + ++*pos; + + if (v == SEQ_START_TOKEN) + return ipmr_mfc_seq_idx(seq->private, 0); + + if (mfc->next) + return mfc->next; + + if (it->cache == &mfc_unres_queue) + goto end_of_list; + + BUG_ON(it->cache != mfc6_cache_array); + + while (++it->ct < ARRAY_SIZE(mfc6_cache_array)) { + mfc = mfc6_cache_array[it->ct]; + if (mfc) + return mfc; + } + + /* exhausted cache_array, show unresolved */ + read_unlock(&mrt_lock); + it->cache = &mfc_unres_queue; + it->ct = 0; + + spin_lock_bh(&mfc_unres_lock); + mfc = mfc_unres_queue; + if (mfc) + return mfc; + + end_of_list: + spin_unlock_bh(&mfc_unres_lock); + it->cache = NULL; + + return NULL; +} + +static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v) +{ + struct ipmr_mfc_iter *it = seq->private; + + if (it->cache == &mfc_unres_queue) + spin_unlock_bh(&mfc_unres_lock); + else if (it->cache == mfc6_cache_array) + read_unlock(&mrt_lock); +} + +static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) +{ + int n; + + if (v == SEQ_START_TOKEN) { + seq_puts(seq, + "Group " + "Origin " + "Iif Pkts Bytes Wrong Oifs\n"); + } else { + const struct mfc6_cache *mfc = v; + const struct ipmr_mfc_iter *it = seq->private; + + seq_printf(seq, + NIP6_FMT " " NIP6_FMT " %-3d %8ld %8ld %8ld", + NIP6(mfc->mf6c_mcastgrp), NIP6(mfc->mf6c_origin), + mfc->mf6c_parent, + mfc->mfc_un.res.pkt, + mfc->mfc_un.res.bytes, + mfc->mfc_un.res.wrong_if); + + if (it->cache != &mfc_unres_queue) { + for (n = mfc->mfc_un.res.minvif; + n < mfc->mfc_un.res.maxvif; n++) { + if (MIF_EXISTS(n) && + mfc->mfc_un.res.ttls[n] < 255) + seq_printf(seq, + " %2d:%-3d", + n, mfc->mfc_un.res.ttls[n]); + } + } + seq_putc(seq, '\n'); + } + return 0; +} + +static struct seq_operations ipmr_mfc_seq_ops = { + .start = ipmr_mfc_seq_start, + .next = ipmr_mfc_seq_next, + .stop = ipmr_mfc_seq_stop, + .show = ipmr_mfc_seq_show, +}; + +static int ipmr_mfc_open(struct inode *inode, struct file *file) +{ + return seq_open_private(file, &ipmr_mfc_seq_ops, + sizeof(struct ipmr_mfc_iter)); +} + +static struct file_operations ip6mr_mfc_fops = { + .owner = THIS_MODULE, + .open = ipmr_mfc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; +#endif + +/* + * Delete a VIF entry + */ + +static int mif6_delete(int vifi) +{ + struct mif_device *v; + struct net_device *dev; + if (vifi < 0 || vifi >= maxvif) + return -EADDRNOTAVAIL; + + v = &vif6_table[vifi]; + + write_lock_bh(&mrt_lock); + dev = v->dev; + v->dev = NULL; + + if (!dev) { + write_unlock_bh(&mrt_lock); + return -EADDRNOTAVAIL; + } + + if (vifi + 1 == maxvif) { + int tmp; + for (tmp = vifi - 1; tmp >= 0; tmp--) { + if (MIF_EXISTS(tmp)) + break; + } + maxvif = tmp + 1; + } + + write_unlock_bh(&mrt_lock); + + dev_set_allmulti(dev, -1); + + if (v->flags & MIFF_REGISTER) + unregister_netdevice(dev); + + dev_put(dev); + return 0; +} + +/* Destroy an unresolved cache entry, killing queued skbs + and reporting error to netlink readers. + */ + +static void ip6mr_destroy_unres(struct mfc6_cache *c) +{ + struct sk_buff *skb; + + atomic_dec(&cache_resolve_queue_len); + + while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) { + if (ipv6_hdr(skb)->version == 0) { + struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); + nlh->nlmsg_type = NLMSG_ERROR; + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); + skb_trim(skb, nlh->nlmsg_len); + ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -ETIMEDOUT; + rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid); + } else + kfree_skb(skb); + } + + kmem_cache_free(mrt_cachep, c); +} + + +/* Single timer process for all the unresolved queue. */ + +static void ipmr_do_expire_process(unsigned long dummy) +{ + unsigned long now = jiffies; + unsigned long expires = 10 * HZ; + struct mfc6_cache *c, **cp; + + cp = &mfc_unres_queue; + + while ((c = *cp) != NULL) { + if (time_after(c->mfc_un.unres.expires, now)) { + /* not yet... */ + unsigned long interval = c->mfc_un.unres.expires - now; + if (interval < expires) + expires = interval; + cp = &c->next; + continue; + } + + *cp = c->next; + ip6mr_destroy_unres(c); + } + + if (atomic_read(&cache_resolve_queue_len)) + mod_timer(&ipmr_expire_timer, jiffies + expires); +} + +static void ipmr_expire_process(unsigned long dummy) +{ + if (!spin_trylock(&mfc_unres_lock)) { + mod_timer(&ipmr_expire_timer, jiffies + 1); + return; + } + + if (atomic_read(&cache_resolve_queue_len)) + ipmr_do_expire_process(dummy); + + spin_unlock(&mfc_unres_lock); +} + +/* Fill oifs list. It is called under write locked mrt_lock. */ + +static void ip6mr_update_thresholds(struct mfc6_cache *cache, unsigned char *ttls) +{ + int vifi; + + cache->mfc_un.res.minvif = MAXVIFS; + cache->mfc_un.res.maxvif = 0; + memset(cache->mfc_un.res.ttls, 255, MAXVIFS); + + for (vifi = 0; vifi < maxvif; vifi++) { + if (MIF_EXISTS(vifi) && ttls[vifi] && ttls[vifi] < 255) { + cache->mfc_un.res.ttls[vifi] = ttls[vifi]; + if (cache->mfc_un.res.minvif > vifi) + cache->mfc_un.res.minvif = vifi; + if (cache->mfc_un.res.maxvif <= vifi) + cache->mfc_un.res.maxvif = vifi + 1; + } + } +} + +static int mif6_add(struct mif6ctl *vifc, int mrtsock) +{ + int vifi = vifc->mif6c_mifi; + struct mif_device *v = &vif6_table[vifi]; + struct net_device *dev; + + /* Is vif busy ? */ + if (MIF_EXISTS(vifi)) + return -EADDRINUSE; + + switch (vifc->mif6c_flags) { + case 0: + dev = dev_get_by_index(&init_net, vifc->mif6c_pifi); + if (!dev) + return -EADDRNOTAVAIL; + dev_put(dev); + break; + default: + return -EINVAL; + } + + dev_set_allmulti(dev, 1); + + /* + * Fill in the VIF structures + */ + v->rate_limit = vifc->vifc_rate_limit; + v->flags = vifc->mif6c_flags; + if (!mrtsock) + v->flags |= VIFF_STATIC; + v->threshold = vifc->vifc_threshold; + v->bytes_in = 0; + v->bytes_out = 0; + v->pkt_in = 0; + v->pkt_out = 0; + v->link = dev->ifindex; + if (v->flags & MIFF_REGISTER) + v->link = dev->iflink; + + /* And finish update writing critical data */ + write_lock_bh(&mrt_lock); + dev_hold(dev); + v->dev = dev; + if (vifi + 1 > maxvif) + maxvif = vifi + 1; + write_unlock_bh(&mrt_lock); + return 0; +} + +static struct mfc6_cache *ip6mr_cache_find(struct in6_addr *origin, struct in6_addr *mcastgrp) +{ + int line = MFC6_HASH(mcastgrp, origin); + struct mfc6_cache *c; + + for (c = mfc6_cache_array[line]; c; c = c->next) { + if (ipv6_addr_equal(&c->mf6c_origin, origin) && + ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp)) + break; + } + return c; +} + +/* + * Allocate a multicast cache entry + */ +static struct mfc6_cache *ip6mr_cache_alloc(void) +{ + struct mfc6_cache *c = kmem_cache_alloc(mrt_cachep, GFP_KERNEL); + if (c == NULL) + return NULL; + memset(c, 0, sizeof(*c)); + c->mfc_un.res.minvif = MAXVIFS; + return c; +} + +static struct mfc6_cache *ip6mr_cache_alloc_unres(void) +{ + struct mfc6_cache *c = kmem_cache_alloc(mrt_cachep, GFP_ATOMIC); + if (c == NULL) + return NULL; + memset(c, 0, sizeof(*c)); + skb_queue_head_init(&c->mfc_un.unres.unresolved); + c->mfc_un.unres.expires = jiffies + 10 * HZ; + return c; +} + +/* + * A cache entry has gone into a resolved state from queued + */ + +static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c) +{ + struct sk_buff *skb; + + /* + * Play the pending entries through our router + */ + + while((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) { + if (ipv6_hdr(skb)->version == 0) { + int err; + struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); + + if (ip6mr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) { + nlh->nlmsg_len = skb->tail - (u8 *)nlh; + } else { + nlh->nlmsg_type = NLMSG_ERROR; + nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); + skb_trim(skb, nlh->nlmsg_len); + ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE; + } + err = rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid); + } else + ip6_mr_forward(skb, c); + } +} + +/* + * Bounce a cache query up to pim6sd. We could use netlink for this but pim6sd + * expects the following bizarre scheme. + * + * Called under mrt_lock. + */ + +static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) +{ + struct sk_buff *skb; + struct mrt6msg *msg; + int ret; + + skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC); + + if (!skb) + return -ENOBUFS; + + /* I suppose that internal messages + * do not require checksums */ + + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* + * Copy the IP header + */ + + skb_put(skb, sizeof(struct ipv6hdr)); + skb_reset_network_header(skb); + skb_copy_to_linear_data(skb, ipv6_hdr(pkt), sizeof(struct ipv6hdr)); + + /* + * Add our header + */ + skb_put(skb, sizeof(*msg)); + skb_reset_transport_header(skb); + msg = (struct mrt6msg *)skb_transport_header(skb); + + msg->im6_mbz = 0; + msg->im6_msgtype = assert; + msg->im6_mif = vifi; + msg->im6_pad = 0; + ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr); + ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr); + + skb->dst = dst_clone(pkt->dst); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + skb_pull(skb, sizeof(struct ipv6hdr)); + + if (mroute6_socket == NULL) { + kfree_skb(skb); + return -EINVAL; + } + + /* + * Deliver to user space multicast routing algorithms + */ + if ((ret = sock_queue_rcv_skb(mroute6_socket, skb)) < 0) { + if (net_ratelimit()) + printk(KERN_WARNING "mroute6: pending queue full, dropping entries.\n"); + kfree_skb(skb); + } + + return ret; +} + +/* + * Queue a packet for resolution. It gets locked cache entry! + */ + +static int +ip6mr_cache_unresolved(vifi_t vifi, struct sk_buff *skb) +{ + int err; + struct mfc6_cache *c; + + spin_lock_bh(&mfc_unres_lock); + for (c = mfc_unres_queue; c; c = c->next) { + if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) && + ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) + break; + } + + if (c == NULL) { + /* + * Create a new entry if allowable + */ + + if (atomic_read(&cache_resolve_queue_len) >= 10 || + (c = ip6mr_cache_alloc_unres()) == NULL) { + spin_unlock_bh(&mfc_unres_lock); + + kfree_skb(skb); + return -ENOBUFS; + } + + /* + * Fill in the new cache entry + */ + c->mf6c_parent = -1; + c->mf6c_origin = ipv6_hdr(skb)->saddr; + c->mf6c_mcastgrp = ipv6_hdr(skb)->daddr; + + /* + * Reflect first query at pim6sd + */ + if ((err = ip6mr_cache_report(skb, vifi, MRT6MSG_NOCACHE)) < 0) { + /* If the report failed throw the cache entry + out - Brad Parker + */ + spin_unlock_bh(&mfc_unres_lock); + + kmem_cache_free(mrt_cachep, c); + kfree_skb(skb); + return err; + } + + atomic_inc(&cache_resolve_queue_len); + c->next = mfc_unres_queue; + mfc_unres_queue = c; + + ipmr_do_expire_process(1); + } + + /* + * See if we can append the packet + */ + if (c->mfc_un.unres.unresolved.qlen > 3) { + kfree_skb(skb); + err = -ENOBUFS; + } else { + skb_queue_tail(&c->mfc_un.unres.unresolved, skb); + err = 0; + } + + spin_unlock_bh(&mfc_unres_lock); + return err; +} + +/* + * MFC6 cache manipulation by user space + */ + +static int ip6mr_mfc_delete(struct mf6cctl *mfc) +{ + int line; + struct mfc6_cache *c, **cp; + + line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr); + + for (cp = &mfc6_cache_array[line]; (c = *cp) != NULL; cp = &c->next) { + if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && + ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { + write_lock_bh(&mrt_lock); + *cp = c->next; + write_unlock_bh(&mrt_lock); + + kmem_cache_free(mrt_cachep, c); + return 0; + } + } + return -ENOENT; +} + +static int ip6mr_device_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *dev = ptr; + struct mif_device *v; + int ct; + + if (dev_net(dev) != &init_net) + return NOTIFY_DONE; + + if (event != NETDEV_UNREGISTER) + return NOTIFY_DONE; + + v = &vif6_table[0]; + for (ct = 0; ct < maxvif; ct++, v++) { + if (v->dev == dev) + mif6_delete(ct); + } + return NOTIFY_DONE; +} + +static struct notifier_block ip6_mr_notifier = { + .notifier_call = ip6mr_device_event +}; + +/* + * Setup for IP multicast routing + */ + +void __init ip6_mr_init(void) +{ + mrt_cachep = kmem_cache_create("ip6_mrt_cache", + sizeof(struct mfc6_cache), + 0, SLAB_HWCACHE_ALIGN, + NULL); + if (!mrt_cachep) + panic("cannot allocate ip6_mrt_cache"); + + setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); + register_netdevice_notifier(&ip6_mr_notifier); +#ifdef CONFIG_PROC_FS + proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops); + proc_net_fops_create(&init_net, "ip6_mr_cache", 0, &ip6mr_mfc_fops); +#endif +} + + +static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock) +{ + int line; + struct mfc6_cache *uc, *c, **cp; + unsigned char ttls[MAXVIFS]; + int i; + + memset(ttls, 255, MAXVIFS); + for (i = 0; i < MAXVIFS; i++) { + if (IF_ISSET(i, &mfc->mf6cc_ifset)) + ttls[i] = 1; + + } + + line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr); + + for (cp = &mfc6_cache_array[line]; (c = *cp) != NULL; cp = &c->next) { + if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && + ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) + break; + } + + if (c != NULL) { + write_lock_bh(&mrt_lock); + c->mf6c_parent = mfc->mf6cc_parent; + ip6mr_update_thresholds(c, ttls); + if (!mrtsock) + c->mfc_flags |= MFC_STATIC; + write_unlock_bh(&mrt_lock); + return 0; + } + + if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr)) + return -EINVAL; + + c = ip6mr_cache_alloc(); + if (c == NULL) + return -ENOMEM; + + c->mf6c_origin = mfc->mf6cc_origin.sin6_addr; + c->mf6c_mcastgrp = mfc->mf6cc_mcastgrp.sin6_addr; + c->mf6c_parent = mfc->mf6cc_parent; + ip6mr_update_thresholds(c, ttls); + if (!mrtsock) + c->mfc_flags |= MFC_STATIC; + + write_lock_bh(&mrt_lock); + c->next = mfc6_cache_array[line]; + mfc6_cache_array[line] = c; + write_unlock_bh(&mrt_lock); + + /* + * Check to see if we resolved a queued list. If so we + * need to send on the frames and tidy up. + */ + spin_lock_bh(&mfc_unres_lock); + for (cp = &mfc_unres_queue; (uc = *cp) != NULL; + cp = &uc->next) { + if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) && + ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) { + *cp = uc->next; + if (atomic_dec_and_test(&cache_resolve_queue_len)) + del_timer(&ipmr_expire_timer); + break; + } + } + spin_unlock_bh(&mfc_unres_lock); + + if (uc) { + ip6mr_cache_resolve(uc, c); + kmem_cache_free(mrt_cachep, uc); + } + return 0; +} + +/* + * Close the multicast socket, and clear the vif tables etc + */ + +static void mroute_clean_tables(struct sock *sk) +{ + int i; + + /* + * Shut down all active vif entries + */ + for (i = 0; i < maxvif; i++) { + if (!(vif6_table[i].flags & VIFF_STATIC)) + mif6_delete(i); + } + + /* + * Wipe the cache + */ + for (i = 0; i < ARRAY_SIZE(mfc6_cache_array); i++) { + struct mfc6_cache *c, **cp; + + cp = &mfc6_cache_array[i]; + while ((c = *cp) != NULL) { + if (c->mfc_flags & MFC_STATIC) { + cp = &c->next; + continue; + } + write_lock_bh(&mrt_lock); + *cp = c->next; + write_unlock_bh(&mrt_lock); + + kmem_cache_free(mrt_cachep, c); + } + } + + if (atomic_read(&cache_resolve_queue_len) != 0) { + struct mfc6_cache *c; + + spin_lock_bh(&mfc_unres_lock); + while (mfc_unres_queue != NULL) { + c = mfc_unres_queue; + mfc_unres_queue = c->next; + spin_unlock_bh(&mfc_unres_lock); + + ip6mr_destroy_unres(c); + + spin_lock_bh(&mfc_unres_lock); + } + spin_unlock_bh(&mfc_unres_lock); + } +} + +static int ip6mr_sk_init(struct sock *sk) +{ + int err = 0; + + rtnl_lock(); + write_lock_bh(&mrt_lock); + if (likely(mroute6_socket == NULL)) + mroute6_socket = sk; + else + err = -EADDRINUSE; + write_unlock_bh(&mrt_lock); + + rtnl_unlock(); + + return err; +} + +int ip6mr_sk_done(struct sock *sk) +{ + int err = 0; + + rtnl_lock(); + if (sk == mroute6_socket) { + write_lock_bh(&mrt_lock); + mroute6_socket = NULL; + write_unlock_bh(&mrt_lock); + + mroute_clean_tables(sk); + } else + err = -EACCES; + rtnl_unlock(); + + return err; +} + +/* + * Socket options and virtual interface manipulation. The whole + * virtual interface system is a complete heap, but unfortunately + * that's how BSD mrouted happens to think. Maybe one day with a proper + * MOSPF/PIM router set up we can clean this up. + */ + +int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int optlen) +{ + int ret; + struct mif6ctl vif; + struct mf6cctl mfc; + mifi_t mifi; + + if (optname != MRT6_INIT) { + if (sk != mroute6_socket && !capable(CAP_NET_ADMIN)) + return -EACCES; + } + + switch (optname) { + case MRT6_INIT: + if (sk->sk_type != SOCK_RAW || + inet_sk(sk)->num != IPPROTO_ICMPV6) + return -EOPNOTSUPP; + if (optlen < sizeof(int)) + return -EINVAL; + + return ip6mr_sk_init(sk); + + case MRT6_DONE: + return ip6mr_sk_done(sk); + + case MRT6_ADD_MIF: + if (optlen < sizeof(vif)) + return -EINVAL; + if (copy_from_user(&vif, optval, sizeof(vif))) + return -EFAULT; + if (vif.mif6c_mifi >= MAXVIFS) + return -ENFILE; + rtnl_lock(); + ret = mif6_add(&vif, sk == mroute6_socket); + rtnl_unlock(); + return ret; + + case MRT6_DEL_MIF: + if (optlen < sizeof(mifi_t)) + return -EINVAL; + if (copy_from_user(&mifi, optval, sizeof(mifi_t))) + return -EFAULT; + rtnl_lock(); + ret = mif6_delete(mifi); + rtnl_unlock(); + return ret; + + /* + * Manipulate the forwarding caches. These live + * in a sort of kernel/user symbiosis. + */ + case MRT6_ADD_MFC: + case MRT6_DEL_MFC: + if (optlen < sizeof(mfc)) + return -EINVAL; + if (copy_from_user(&mfc, optval, sizeof(mfc))) + return -EFAULT; + rtnl_lock(); + if (optname == MRT6_DEL_MFC) + ret = ip6mr_mfc_delete(&mfc); + else + ret = ip6mr_mfc_add(&mfc, sk == mroute6_socket); + rtnl_unlock(); + return ret; + + /* + * Spurious command, or MRT_VERSION which you cannot + * set. + */ + default: + return -ENOPROTOOPT; + } +} + +/* + * Getsock opt support for the multicast routing system. + */ + +int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, + int __user *optlen) +{ + int olr; + int val; + + switch (optname) { + case MRT6_VERSION: + val = 0x0305; + break; + default: + return -ENOPROTOOPT; + } + + if (get_user(olr, optlen)) + return -EFAULT; + + olr = min_t(int, olr, sizeof(int)); + if (olr < 0) + return -EINVAL; + + if (put_user(olr, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, olr)) + return -EFAULT; + return 0; +} + +/* + * The IP multicast ioctl support routines. + */ + +int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) +{ + struct sioc_sg_req6 sr; + struct sioc_mif_req6 vr; + struct mif_device *vif; + struct mfc6_cache *c; + + switch (cmd) { + case SIOCGETMIFCNT_IN6: + if (copy_from_user(&vr, arg, sizeof(vr))) + return -EFAULT; + if (vr.mifi >= maxvif) + return -EINVAL; + read_lock(&mrt_lock); + vif = &vif6_table[vr.mifi]; + if (MIF_EXISTS(vr.mifi)) { + vr.icount = vif->pkt_in; + vr.ocount = vif->pkt_out; + vr.ibytes = vif->bytes_in; + vr.obytes = vif->bytes_out; + read_unlock(&mrt_lock); + + if (copy_to_user(arg, &vr, sizeof(vr))) + return -EFAULT; + return 0; + } + read_unlock(&mrt_lock); + return -EADDRNOTAVAIL; + case SIOCGETSGCNT_IN6: + if (copy_from_user(&sr, arg, sizeof(sr))) + return -EFAULT; + + read_lock(&mrt_lock); + c = ip6mr_cache_find(&sr.src.sin6_addr, &sr.grp.sin6_addr); + if (c) { + sr.pktcnt = c->mfc_un.res.pkt; + sr.bytecnt = c->mfc_un.res.bytes; + sr.wrong_if = c->mfc_un.res.wrong_if; + read_unlock(&mrt_lock); + + if (copy_to_user(arg, &sr, sizeof(sr))) + return -EFAULT; + return 0; + } + read_unlock(&mrt_lock); + return -EADDRNOTAVAIL; + default: + return -ENOIOCTLCMD; + } +} + + +static inline int ip6mr_forward2_finish(struct sk_buff *skb) +{ + /* XXX stats */ + return dst_output(skb); +} + +/* + * Processing handlers for ip6mr_forward + */ + +static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi) +{ + struct ipv6hdr *ipv6h; + struct mif_device *vif = &vif6_table[vifi]; + struct net_device *dev; + struct dst_entry *dst; + struct flowi fl; + + if (vif->dev == NULL) + goto out_free; + + ipv6h = ipv6_hdr(skb); + + fl = (struct flowi) { + .oif = vif->link, + .nl_u = { .ip6_u = + { .daddr = ipv6h->daddr, } + } + }; + + dst = ip6_route_output(&init_net, NULL, &fl); + if (!dst) + goto out_free; + + dst_release(skb->dst); + skb->dst = dst; + + /* + * RFC1584 teaches, that DVMRP/PIM router must deliver packets locally + * not only before forwarding, but after forwarding on all output + * interfaces. It is clear, if mrouter runs a multicasting + * program, it should receive packets not depending to what interface + * program is joined. + * If we will not make it, the program will have to join on all + * interfaces. On the other hand, multihoming host (or router, but + * not mrouter) cannot join to more than one interface - it will + * result in receiving multiple packets. + */ + dev = vif->dev; + skb->dev = dev; + vif->pkt_out++; + vif->bytes_out += skb->len; + + /* We are about to write */ + /* XXX: extension headers? */ + if (skb_cow(skb, sizeof(*ipv6h) + LL_RESERVED_SPACE(dev))) + goto out_free; + + ipv6h = ipv6_hdr(skb); + ipv6h->hop_limit--; + + IP6CB(skb)->flags |= IP6SKB_FORWARDED; + + return NF_HOOK(PF_INET6, NF_INET_FORWARD, skb, skb->dev, dev, + ip6mr_forward2_finish); + +out_free: + kfree_skb(skb); + return 0; +} + +static int ip6mr_find_vif(struct net_device *dev) +{ + int ct; + for (ct = maxvif - 1; ct >= 0; ct--) { + if (vif6_table[ct].dev == dev) + break; + } + return ct; +} + +static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache) +{ + int psend = -1; + int vif, ct; + + vif = cache->mf6c_parent; + cache->mfc_un.res.pkt++; + cache->mfc_un.res.bytes += skb->len; + + vif6_table[vif].pkt_in++; + vif6_table[vif].bytes_in += skb->len; + + /* + * Forward the frame + */ + for (ct = cache->mfc_un.res.maxvif - 1; ct >= cache->mfc_un.res.minvif; ct--) { + if (ipv6_hdr(skb)->hop_limit > cache->mfc_un.res.ttls[ct]) { + if (psend != -1) { + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) + ip6mr_forward2(skb2, cache, psend); + } + psend = ct; + } + } + if (psend != -1) { + ip6mr_forward2(skb, cache, psend); + return 0; + } + + kfree_skb(skb); + return 0; +} + + +/* + * Multicast packets for forwarding arrive here + */ + +int ip6_mr_input(struct sk_buff *skb) +{ + struct mfc6_cache *cache; + + read_lock(&mrt_lock); + cache = ip6mr_cache_find(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); + + /* + * No usable cache entry + */ + if (cache == NULL) { + int vif; + + vif = ip6mr_find_vif(skb->dev); + if (vif >= 0) { + int err = ip6mr_cache_unresolved(vif, skb); + read_unlock(&mrt_lock); + + return err; + } + read_unlock(&mrt_lock); + kfree_skb(skb); + return -ENODEV; + } + + ip6_mr_forward(skb, cache); + + read_unlock(&mrt_lock); + + return 0; +} + + +static int +ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm) +{ + int ct; + struct rtnexthop *nhp; + struct net_device *dev = vif6_table[c->mf6c_parent].dev; + u8 *b = skb->tail; + struct rtattr *mp_head; + + if (dev) + RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex); + + mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0)); + + for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { + if (c->mfc_un.res.ttls[ct] < 255) { + if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) + goto rtattr_failure; + nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); + nhp->rtnh_flags = 0; + nhp->rtnh_hops = c->mfc_un.res.ttls[ct]; + nhp->rtnh_ifindex = vif6_table[ct].dev->ifindex; + nhp->rtnh_len = sizeof(*nhp); + } + } + mp_head->rta_type = RTA_MULTIPATH; + mp_head->rta_len = skb->tail - (u8 *)mp_head; + rtm->rtm_type = RTN_MULTICAST; + return 1; + +rtattr_failure: + nlmsg_trim(skb, b); + return -EMSGSIZE; +} + +int ip6mr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait) +{ + int err; + struct mfc6_cache *cache; + struct rt6_info *rt = (struct rt6_info *)skb->dst; + + read_lock(&mrt_lock); + cache = ip6mr_cache_find(&rt->rt6i_src.addr, &rt->rt6i_dst.addr); + + if (!cache) { + struct sk_buff *skb2; + struct ipv6hdr *iph; + struct net_device *dev; + int vif; + + if (nowait) { + read_unlock(&mrt_lock); + return -EAGAIN; + } + + dev = skb->dev; + if (dev == NULL || (vif = ip6mr_find_vif(dev)) < 0) { + read_unlock(&mrt_lock); + return -ENODEV; + } + + /* really correct? */ + skb2 = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC); + if (!skb2) { + read_unlock(&mrt_lock); + return -ENOMEM; + } + + skb_reset_transport_header(skb2); + + skb_put(skb2, sizeof(struct ipv6hdr)); + skb_reset_network_header(skb2); + + iph = ipv6_hdr(skb2); + iph->version = 0; + iph->priority = 0; + iph->flow_lbl[0] = 0; + iph->flow_lbl[1] = 0; + iph->flow_lbl[2] = 0; + iph->payload_len = 0; + iph->nexthdr = IPPROTO_NONE; + iph->hop_limit = 0; + ipv6_addr_copy(&iph->saddr, &rt->rt6i_src.addr); + ipv6_addr_copy(&iph->daddr, &rt->rt6i_dst.addr); + + err = ip6mr_cache_unresolved(vif, skb2); + read_unlock(&mrt_lock); + + return err; + } + + if (!nowait && (rtm->rtm_flags&RTM_F_NOTIFY)) + cache->mfc_flags |= MFC_NOTIFY; + + err = ip6mr_fill_mroute(skb, cache, rtm); + read_unlock(&mrt_lock); + return err; +} + diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 4195ac92345e..99624109c010 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -118,6 +119,9 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, valbool = (val!=0); + if (ip6_mroute_opt(optname)) + return ip6_mroute_setsockopt(sk, optname, optval, optlen); + lock_sock(sk); switch (optname) { @@ -790,6 +794,9 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, int len; int val; + if (ip6_mroute_opt(optname)) + return ip6_mroute_getsockopt(sk, optname, optval, optlen); + if (get_user(len, optlen)) return -EFAULT; switch (optname) { diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index aae6cedf1709..088b80b4ce74 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -53,6 +53,7 @@ #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) #include #endif +#include #include #include @@ -1135,7 +1136,11 @@ static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) } default: +#ifdef CONFIG_IPV6_MROUTE + return ip6mr_ioctl(sk, cmd, (void __user *)arg); +#else return -ENOIOCTLCMD; +#endif } } @@ -1143,7 +1148,7 @@ static void rawv6_close(struct sock *sk, long timeout) { if (inet_sk(sk)->num == IPPROTO_RAW) ip6_ra_control(sk, -1, NULL); - + ip6mr_sk_done(sk); sk_common_release(sk); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index cd82b6db35ff..3c314d5f46c6 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -2106,7 +2107,7 @@ static inline size_t rt6_nlmsg_size(void) static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, struct in6_addr *dst, struct in6_addr *src, int iif, int type, u32 pid, u32 seq, - int prefix, unsigned int flags) + int prefix, int nowait, unsigned int flags) { struct rtmsg *rtm; struct nlmsghdr *nlh; @@ -2166,9 +2167,24 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, } else if (rtm->rtm_src_len) NLA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr); #endif - if (iif) - NLA_PUT_U32(skb, RTA_IIF, iif); - else if (dst) { + if (iif) { +#ifdef CONFIG_IPV6_MROUTE + if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) { + int err = ip6mr_get_route(skb, rtm, nowait); + if (err <= 0) { + if (!nowait) { + if (err == 0) + return 0; + goto nla_put_failure; + } else { + if (err == -EMSGSIZE) + goto nla_put_failure; + } + } + } else +#endif + NLA_PUT_U32(skb, RTA_IIF, iif); + } else if (dst) { struct in6_addr saddr_buf; if (ipv6_dev_get_saddr(ip6_dst_idev(&rt->u.dst)->dev, dst, 0, &saddr_buf) == 0) @@ -2211,7 +2227,7 @@ int rt6_dump_route(struct rt6_info *rt, void *p_arg) return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq, - prefix, NLM_F_MULTI); + prefix, 0, NLM_F_MULTI); } static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) @@ -2277,7 +2293,7 @@ static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, RTM_NEWROUTE, NETLINK_CB(in_skb).pid, - nlh->nlmsg_seq, 0, 0); + nlh->nlmsg_seq, 0, 0, 0); if (err < 0) { kfree_skb(skb); goto errout; @@ -2303,7 +2319,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) goto errout; err = rt6_fill_node(skb, rt, NULL, NULL, 0, - event, info->pid, seq, 0, 0); + event, info->pid, seq, 0, 0, 0); if (err < 0) { /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ WARN_ON(err == -EMSGSIZE); -- cgit v1.2.3-59-g8ed1b From 14fb64e1f449ef6666f1c3a3fa4e13aec669b98d Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 3 Apr 2008 09:22:54 +0900 Subject: [IPV6] MROUTE: Support PIM-SM (SSM). Based on ancient patch by Mickael Hoerdt , which is available at . Signed-off-by: YOSHIFUJI Hideaki --- include/linux/mroute6.h | 4 + net/ipv6/Kconfig | 7 ++ net/ipv6/ip6mr.c | 275 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 285 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h index b92190304e0b..f6469fb90840 100644 --- a/include/linux/mroute6.h +++ b/include/linux/mroute6.h @@ -23,6 +23,8 @@ #define MRT6_ADD_MFC (MRT6_BASE+4) /* Add a multicast forwarding entry */ #define MRT6_DEL_MFC (MRT6_BASE+5) /* Delete a multicast forwarding entry */ #define MRT6_VERSION (MRT6_BASE+6) /* Get the kernel multicast version */ +#define MRT6_ASSERT (MRT6_BASE+7) /* Activate PIM assert mode */ +#define MRT6_PIM (MRT6_BASE+8) /* enable PIM code */ #define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */ #define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1) @@ -217,6 +219,8 @@ static inline int ip6mr_sk_done(struct sock *sk) { return 0; } struct mrt6msg { #define MRT6MSG_NOCACHE 1 +#define MRT6MSG_WRONGMIF 2 +#define MRT6MSG_WHOLEPKT 3 /* used for use level encap */ __u8 im6_mbz; /* must be zero */ __u8 im6_msgtype; /* what type of message */ __u16 im6_mif; /* mif rec'd on */ diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 9a2ea81e499f..82f987b4ef84 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -216,3 +216,10 @@ config IPV6_MROUTE Experimental support for IPv6 multicast forwarding. If unsure, say N. +config IPV6_PIMSM_V2 + bool "IPv6: PIM-SM version 2 support (EXPERIMENTAL)" + depends on IPV6_MROUTE + ---help--- + Support for IPv6 PIM multicast routing protocol PIM-SMv2. + If unsure, say N. + diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 1bdf3c177d58..2b70774be61f 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include @@ -75,6 +76,13 @@ static int maxvif; #define MIF_EXISTS(idx) (vif6_table[idx].dev != NULL) +static int mroute_do_assert; /* Set in PIM assert */ +#ifdef CONFIG_IPV6_PIMSM_V2 +static int mroute_do_pim; +#else +#define mroute_do_pim 0 +#endif + static struct mfc6_cache *mfc6_cache_array[MFC_LINES]; /* Forwarding cache */ static struct mfc6_cache *mfc_unres_queue; /* Queue of unresolved entries */ @@ -97,6 +105,10 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache); static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert); static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm); +#ifdef CONFIG_IPV6_PIMSM_V2 +static struct inet6_protocol pim6_protocol; +#endif + static struct timer_list ipmr_expire_timer; @@ -339,6 +351,132 @@ static struct file_operations ip6mr_mfc_fops = { }; #endif +#ifdef CONFIG_IPV6_PIMSM_V2 +static int reg_vif_num = -1; + +static int pim6_rcv(struct sk_buff *skb) +{ + struct pimreghdr *pim; + struct ipv6hdr *encap; + struct net_device *reg_dev = NULL; + + if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap))) + goto drop; + + pim = (struct pimreghdr *)skb_transport_header(skb); + if (pim->type != ((PIM_VERSION << 4) | PIM_REGISTER) || + (pim->flags & PIM_NULL_REGISTER) || + (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 && + (u16)csum_fold(skb_checksum(skb, 0, skb->len, 0)))) + goto drop; + + /* check if the inner packet is destined to mcast group */ + encap = (struct ipv6hdr *)(skb_transport_header(skb) + + sizeof(*pim)); + + if (!ipv6_addr_is_multicast(&encap->daddr) || + encap->payload_len == 0 || + ntohs(encap->payload_len) + sizeof(*pim) > skb->len) + goto drop; + + read_lock(&mrt_lock); + if (reg_vif_num >= 0) + reg_dev = vif6_table[reg_vif_num].dev; + if (reg_dev) + dev_hold(reg_dev); + read_unlock(&mrt_lock); + + if (reg_dev == NULL) + goto drop; + + skb->mac_header = skb->network_header; + skb_pull(skb, (u8 *)encap - skb->data); + skb_reset_network_header(skb); + skb->dev = reg_dev; + skb->protocol = htons(ETH_P_IP); + skb->ip_summed = 0; + skb->pkt_type = PACKET_HOST; + dst_release(skb->dst); + ((struct net_device_stats *)netdev_priv(reg_dev))->rx_bytes += skb->len; + ((struct net_device_stats *)netdev_priv(reg_dev))->rx_packets++; + skb->dst = NULL; + nf_reset(skb); + netif_rx(skb); + dev_put(reg_dev); + return 0; + drop: + kfree_skb(skb); + return 0; +} + +static struct inet6_protocol pim6_protocol = { + .handler = pim6_rcv, +}; + +/* Service routines creating virtual interfaces: PIMREG */ + +static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) +{ + read_lock(&mrt_lock); + ((struct net_device_stats *)netdev_priv(dev))->tx_bytes += skb->len; + ((struct net_device_stats *)netdev_priv(dev))->tx_packets++; + ip6mr_cache_report(skb, reg_vif_num, MRT6MSG_WHOLEPKT); + read_unlock(&mrt_lock); + kfree_skb(skb); + return 0; +} + +static struct net_device_stats *reg_vif_get_stats(struct net_device *dev) +{ + return (struct net_device_stats *)netdev_priv(dev); +} + +static void reg_vif_setup(struct net_device *dev) +{ + dev->type = ARPHRD_PIMREG; + dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8; + dev->flags = IFF_NOARP; + dev->hard_start_xmit = reg_vif_xmit; + dev->get_stats = reg_vif_get_stats; + dev->destructor = free_netdev; +} + +static struct net_device *ip6mr_reg_vif(void) +{ + struct net_device *dev; + struct inet6_dev *in_dev; + + dev = alloc_netdev(sizeof(struct net_device_stats), "pim6reg", + reg_vif_setup); + + if (dev == NULL) + return NULL; + + if (register_netdevice(dev)) { + free_netdev(dev); + return NULL; + } + dev->iflink = 0; + + in_dev = ipv6_find_idev(dev); + if (!in_dev) + goto failure; + + if (dev_open(dev)) + goto failure; + + return dev; + +failure: + /* allow the register to be completed before unregistering. */ + rtnl_unlock(); + rtnl_lock(); + + unregister_netdevice(dev); + return NULL; +} +#endif + /* * Delete a VIF entry */ @@ -361,6 +499,11 @@ static int mif6_delete(int vifi) return -EADDRNOTAVAIL; } +#ifdef CONFIG_IPV6_PIMSM_V2 + if (vifi == reg_vif_num) + reg_vif_num = -1; +#endif + if (vifi + 1 == maxvif) { int tmp; for (tmp = vifi - 1; tmp >= 0; tmp--) { @@ -480,6 +623,19 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock) return -EADDRINUSE; switch (vifc->mif6c_flags) { +#ifdef CONFIG_IPV6_PIMSM_V2 + case MIFF_REGISTER: + /* + * Special Purpose VIF in PIM + * All the packets will be sent to the daemon + */ + if (reg_vif_num >= 0) + return -EADDRINUSE; + dev = ip6mr_reg_vif(); + if (!dev) + return -ENOBUFS; + break; +#endif case 0: dev = dev_get_by_index(&init_net, vifc->mif6c_pifi); if (!dev) @@ -512,6 +668,10 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock) write_lock_bh(&mrt_lock); dev_hold(dev); v->dev = dev; +#ifdef CONFIG_IPV6_PIMSM_V2 + if (v->flags & MIFF_REGISTER) + reg_vif_num = vifi; +#endif if (vifi + 1 > maxvif) maxvif = vifi + 1; write_unlock_bh(&mrt_lock); @@ -599,7 +759,13 @@ static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) struct mrt6msg *msg; int ret; - skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC); +#ifdef CONFIG_IPV6_PIMSM_V2 + if (assert == MRT6MSG_WHOLEPKT) + skb = skb_realloc_headroom(pkt, -skb_network_offset(pkt) + +sizeof(*msg)); + else +#endif + skb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(*msg), GFP_ATOMIC); if (!skb) return -ENOBUFS; @@ -609,6 +775,29 @@ static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) skb->ip_summed = CHECKSUM_UNNECESSARY; +#ifdef CONFIG_IPV6_PIMSM_V2 + if (assert == MRT6MSG_WHOLEPKT) { + /* Ugly, but we have no choice with this interface. + Duplicate old header, fix length etc. + And all this only to mangle msg->im6_msgtype and + to set msg->im6_mbz to "mbz" :-) + */ + skb_push(skb, -skb_network_offset(pkt)); + + skb_push(skb, sizeof(*msg)); + skb_reset_transport_header(skb); + msg = (struct mrt6msg *)skb_transport_header(skb); + msg->im6_mbz = 0; + msg->im6_msgtype = MRT6MSG_WHOLEPKT; + msg->im6_mif = reg_vif_num; + msg->im6_pad = 0; + ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr); + ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr); + + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else +#endif + { /* * Copy the IP header */ @@ -635,6 +824,7 @@ static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) skb->ip_summed = CHECKSUM_UNNECESSARY; skb_pull(skb, sizeof(struct ipv6hdr)); + } if (mroute6_socket == NULL) { kfree_skb(skb); @@ -1033,6 +1223,44 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int rtnl_unlock(); return ret; + /* + * Control PIM assert (to activate pim will activate assert) + */ + case MRT6_ASSERT: + { + int v; + if (get_user(v, (int __user *)optval)) + return -EFAULT; + mroute_do_assert = !!v; + return 0; + } + +#ifdef CONFIG_IPV6_PIMSM_V2 + case MRT6_PIM: + { + int v, ret; + if (get_user(v, (int __user *)optval)) + return -EFAULT; + v = !!v; + rtnl_lock(); + ret = 0; + if (v != mroute_do_pim) { + mroute_do_pim = v; + mroute_do_assert = v; + if (mroute_do_pim) + ret = inet6_add_protocol(&pim6_protocol, + IPPROTO_PIM); + else + ret = inet6_del_protocol(&pim6_protocol, + IPPROTO_PIM); + if (ret < 0) + ret = -EAGAIN; + } + rtnl_unlock(); + return ret; + } + +#endif /* * Spurious command, or MRT_VERSION which you cannot * set. @@ -1056,6 +1284,14 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, case MRT6_VERSION: val = 0x0305; break; +#ifdef CONFIG_IPV6_PIMSM_V2 + case MRT6_PIM: + val = mroute_do_pim; + break; +#endif + case MRT6_ASSERT: + val = mroute_do_assert; + break; default: return -ENOPROTOOPT; } @@ -1151,6 +1387,18 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi) if (vif->dev == NULL) goto out_free; +#ifdef CONFIG_IPV6_PIMSM_V2 + if (vif->flags & MIFF_REGISTER) { + vif->pkt_out++; + vif->bytes_out += skb->len; + ((struct net_device_stats *)netdev_priv(vif->dev))->tx_bytes += skb->len; + ((struct net_device_stats *)netdev_priv(vif->dev))->tx_packets++; + ip6mr_cache_report(skb, vifi, MRT6MSG_WHOLEPKT); + kfree_skb(skb); + return 0; + } +#endif + ipv6h = ipv6_hdr(skb); fl = (struct flowi) { @@ -1220,6 +1468,30 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache) cache->mfc_un.res.pkt++; cache->mfc_un.res.bytes += skb->len; + /* + * Wrong interface: drop packet and (maybe) send PIM assert. + */ + if (vif6_table[vif].dev != skb->dev) { + int true_vifi; + + cache->mfc_un.res.wrong_if++; + true_vifi = ip6mr_find_vif(skb->dev); + + if (true_vifi >= 0 && mroute_do_assert && + /* pimsm uses asserts, when switching from RPT to SPT, + so that we cannot check that packet arrived on an oif. + It is bad, but otherwise we would need to move pretty + large chunk of pimd to kernel. Ough... --ANK + */ + (mroute_do_pim || cache->mfc_un.res.ttls[true_vifi] < 255) && + time_after(jiffies, + cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) { + cache->mfc_un.res.last_assert = jiffies; + ip6mr_cache_report(skb, true_vifi, MRT6MSG_WRONGMIF); + } + goto dont_forward; + } + vif6_table[vif].pkt_in++; vif6_table[vif].bytes_in += skb->len; @@ -1241,6 +1513,7 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache) return 0; } +dont_forward: kfree_skb(skb); return 0; } -- cgit v1.2.3-59-g8ed1b From 549e028d012fab01e5726943d4afecd0c33d64e6 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sat, 5 Apr 2008 22:17:39 +0900 Subject: [IPV6] MROUTE: Use skb_tail_pointer(skb) instead of skb->tail. This bug resulted in compilation error on 64bit machines. Pointed out by Rami Rosen . Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/ip6mr.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 2b70774be61f..da673ef75e12 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -733,7 +733,7 @@ static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c) struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct ipv6hdr)); if (ip6mr_fill_mroute(skb, c, NLMSG_DATA(nlh)) > 0) { - nlh->nlmsg_len = skb->tail - (u8 *)nlh; + nlh->nlmsg_len = skb_tail_pointer(skb) - (u8 *)nlh; } else { nlh->nlmsg_type = NLMSG_ERROR; nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); @@ -1562,7 +1562,7 @@ ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm) int ct; struct rtnexthop *nhp; struct net_device *dev = vif6_table[c->mf6c_parent].dev; - u8 *b = skb->tail; + u8 *b = skb_tail_pointer(skb); struct rtattr *mp_head; if (dev) @@ -1582,7 +1582,7 @@ ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm) } } mp_head->rta_type = RTA_MULTIPATH; - mp_head->rta_len = skb->tail - (u8 *)mp_head; + mp_head->rta_len = skb_tail_pointer(skb) - (u8 *)mp_head; rtm->rtm_type = RTN_MULTICAST; return 1; -- cgit v1.2.3-59-g8ed1b From 247367016305637fb981db020679520e354c80c4 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 8 Apr 2008 14:15:46 -0400 Subject: Revert "mac80211: use a struct for bss->mesh_config" This reverts commit 6c4711b4697d93424e4b1f76a9929ba844d714a5. That patch breaks mesh config comparison between beacons/probe reponses, so every beacon from a mesh network would be added as a new bss. Since the comparison has to be performed for every received beacon I believe it is best to save the mesh config in a format easy to compare, rather than do a bunch of unaligned accesses to compare field by field. Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 13 ++----------- net/mac80211/ieee80211_sta.c | 32 ++++++++++++-------------------- net/mac80211/mesh.c | 4 ++++ net/mac80211/mesh.h | 10 ---------- 4 files changed, 18 insertions(+), 41 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6c62dd42f915..0997a0f96203 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -69,14 +69,6 @@ struct ieee80211_fragment_entry { u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ }; -struct bss_mesh_config { - u32 path_proto_id; - u32 path_metric_id; - u32 cong_control_id; - u32 channel_precedence; - u8 mesh_version; -}; - struct ieee80211_sta_bss { struct list_head list; @@ -102,7 +94,7 @@ struct ieee80211_sta_bss { #ifdef CONFIG_MAC80211_MESH u8 *mesh_id; size_t mesh_id_len; - struct bss_mesh_config *mesh_cfg; + u8 *mesh_cfg; #endif #define IEEE80211_MAX_SUPP_RATES 32 u8 supp_rates[IEEE80211_MAX_SUPP_RATES]; @@ -121,8 +113,7 @@ struct ieee80211_sta_bss { u8 erp_value; }; -static inline -struct bss_mesh_config *bss_mesh_cfg(struct ieee80211_sta_bss *bss) +static inline u8 *bss_mesh_cfg(struct ieee80211_sta_bss *bss) { #ifdef CONFIG_MAC80211_MESH return bss->mesh_cfg; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index c20ef89acad6..1ee07f0b02e2 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include "ieee80211_i.h" @@ -2123,11 +2122,6 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, } #ifdef CONFIG_MAC80211_MESH -static inline u32 bss_mesh_cfg_get(u8 *mesh_cfg, u8 offset) -{ - return be32_to_cpu(get_unaligned((__be32 *) (mesh_cfg + offset))); -} - static struct ieee80211_sta_bss * ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len, u8 *mesh_cfg, int freq) @@ -2167,7 +2161,7 @@ ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len, if (!bss) return NULL; - bss->mesh_cfg = kmalloc(sizeof(struct bss_mesh_config), GFP_ATOMIC); + bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC); if (!bss->mesh_cfg) { kfree(bss); return NULL; @@ -2185,12 +2179,7 @@ ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len, atomic_inc(&bss->users); atomic_inc(&bss->users); - bss->mesh_cfg->mesh_version = mesh_cfg[0]; - bss->mesh_cfg->path_proto_id = bss_mesh_cfg_get(mesh_cfg, PP_OFFSET); - bss->mesh_cfg->path_metric_id = bss_mesh_cfg_get(mesh_cfg, PM_OFFSET); - bss->mesh_cfg->cong_control_id = bss_mesh_cfg_get(mesh_cfg, CC_OFFSET); - bss->mesh_cfg->channel_precedence = bss_mesh_cfg_get(mesh_cfg, - CP_OFFSET); + memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN); bss->mesh_id_len = mesh_id_len; bss->freq = freq; spin_lock_bh(&local->sta_bss_lock); @@ -4067,33 +4056,36 @@ ieee80211_sta_scan_result(struct net_device *dev, if (bss_mesh_cfg(bss)) { char *buf; - struct bss_mesh_config *cfg = bss_mesh_cfg(bss); + u8 *cfg = bss_mesh_cfg(bss); buf = kmalloc(50, GFP_ATOMIC); if (buf) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = IWEVCUSTOM; - sprintf(buf, "Mesh network (version %d)", - cfg->mesh_version); + sprintf(buf, "Mesh network (version %d)", cfg[0]); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); sprintf(buf, "Path Selection Protocol ID: " - "0x%08X", cfg->path_proto_id); + "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], + cfg[4]); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); sprintf(buf, "Path Selection Metric ID: " - "0x%08X", cfg->path_metric_id); + "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], + cfg[8]); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); sprintf(buf, "Congestion Control Mode ID: " - "0x%08X", cfg->cong_control_id); + "0x%02X%02X%02X%02X", cfg[9], cfg[10], + cfg[11], cfg[12]); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); sprintf(buf, "Channel Precedence: " - "0x%08X", cfg->channel_precedence); + "0x%02X%02X%02X%02X", cfg[13], cfg[14], + cfg[15], cfg[16]); iwe.u.data.length = strlen(buf); current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, buf); diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index b10f1e543a94..594a3356a508 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -11,6 +11,10 @@ #include "ieee80211_i.h" #include "mesh.h" +#define PP_OFFSET 1 /* Path Selection Protocol */ +#define PM_OFFSET 5 /* Path Selection Metric */ +#define CC_OFFSET 9 /* Congestion Control Mode */ +#define CAPAB_OFFSET 17 #define ACCEPT_PLINKS 0x80 int mesh_allocated; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 8ff46ea0f1d7..742003d3a841 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -157,16 +157,6 @@ struct mesh_rmc { */ #define MESH_CFG_CMP_LEN 17 -/* - * Components offset within the mesh configuration IE - */ -#define PP_OFFSET 1 /* Path Selection Protocol */ -#define PM_OFFSET 5 /* Path Selection Metric */ -#define CC_OFFSET 9 /* Congestion Control Mode */ -#define CP_OFFSET 13 /* Channel Precedence */ -#define CAPAB_OFFSET 17 /* Mesh Capabilities */ - - /* Default values, timeouts in ms */ #define MESH_TTL 5 #define MESH_MAX_RETR 3 -- cgit v1.2.3-59-g8ed1b From 38668c059f5202f5fd9612391f9aa1b38a97241b Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 28 Mar 2008 16:33:32 -0700 Subject: mac80211: eliminate conf_ht This patch eliminates the use of conf_ht, replacing it with bss_info_changed. Signed-off-by: Tomas Winkler Signed-off-by: Ron Rindjunsky Signed-off-by: John W. Linville --- include/net/mac80211.h | 10 +++++- net/mac80211/ieee80211.c | 73 ++++++++++++++++++++++++++------------------ net/mac80211/ieee80211_i.h | 6 ++-- net/mac80211/ieee80211_sta.c | 33 +++++++++++--------- 4 files changed, 75 insertions(+), 47 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 48428a6b9109..5174eaa89500 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -178,11 +178,13 @@ struct ieee80211_low_level_stats { * also implies a change in the AID. * @BSS_CHANGED_ERP_CTS_PROT: CTS protection changed * @BSS_CHANGED_ERP_PREAMBLE: preamble changed + * @BSS_CHANGED_HT: 802.11n parameters changed */ enum ieee80211_bss_change { BSS_CHANGED_ASSOC = 1<<0, BSS_CHANGED_ERP_CTS_PROT = 1<<1, BSS_CHANGED_ERP_PREAMBLE = 1<<2, + BSS_CHANGED_HT = 1<<4, }; /** @@ -195,6 +197,9 @@ enum ieee80211_bss_change { * @aid: association ID number, valid only when @assoc is true * @use_cts_prot: use CTS protection * @use_short_preamble: use 802.11b short preamble + * @assoc_ht: association in HT mode + * @ht_conf: ht capabilities + * @ht_bss_conf: ht extended capabilities */ struct ieee80211_bss_conf { /* association related data */ @@ -203,6 +208,10 @@ struct ieee80211_bss_conf { /* erp related data */ bool use_cts_prot; bool use_short_preamble; + /* ht related data */ + bool assoc_ht; + struct ieee80211_ht_info *ht_conf; + struct ieee80211_ht_bss_info *ht_bss_conf; }; /** @@ -1132,7 +1141,6 @@ struct ieee80211_ops { struct sk_buff *skb, struct ieee80211_tx_control *control); int (*tx_last_beacon)(struct ieee80211_hw *hw); - int (*conf_ht)(struct ieee80211_hw *hw, struct ieee80211_conf *conf); int (*ampdu_action)(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, const u8 *addr, u16 tid, u16 *ssn); diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index aaa5480e204a..5d30dd463f22 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -1046,54 +1046,69 @@ int ieee80211_hw_config(struct ieee80211_local *local) } /** - * ieee80211_hw_config_ht should be used only after legacy configuration - * has been determined, as ht configuration depends upon the hardware's - * HT abilities for a _specific_ band. + * ieee80211_handle_ht should be used only after legacy configuration + * has been determined namely band, as ht configuration depends upon + * the hardware's HT abilities for a _specific_ band. */ -int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, +u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, struct ieee80211_ht_info *req_ht_cap, struct ieee80211_ht_bss_info *req_bss_cap) { struct ieee80211_conf *conf = &local->hw.conf; struct ieee80211_supported_band *sband; + struct ieee80211_ht_info ht_conf; + struct ieee80211_ht_bss_info ht_bss_conf; int i; + u32 changed = 0; sband = local->hw.wiphy->bands[conf->channel->band]; /* HT is not supported */ if (!sband->ht_info.ht_supported) { conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; - return -EOPNOTSUPP; + return 0; } - /* disable HT */ - if (!enable_ht) { - conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; - } else { + memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info)); + memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); + + if (enable_ht) { + if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) + changed |= BSS_CHANGED_HT; + conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; - conf->ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; - conf->ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); - conf->ht_conf.cap |= - sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; - conf->ht_bss_conf.primary_channel = - req_bss_cap->primary_channel; - conf->ht_bss_conf.bss_cap = req_bss_cap->bss_cap; - conf->ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; + ht_conf.ht_supported = 1; + + ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; + ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); + ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; + for (i = 0; i < SUPP_MCS_SET_LEN; i++) - conf->ht_conf.supp_mcs_set[i] = - sband->ht_info.supp_mcs_set[i] & - req_ht_cap->supp_mcs_set[i]; - - /* In STA mode, this gives us indication - * to the AP's mode of operation */ - conf->ht_conf.ht_supported = 1; - conf->ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; - conf->ht_conf.ampdu_density = req_ht_cap->ampdu_density; + ht_conf.supp_mcs_set[i] = + sband->ht_info.supp_mcs_set[i] & + req_ht_cap->supp_mcs_set[i]; + + ht_bss_conf.primary_channel = req_bss_cap->primary_channel; + ht_bss_conf.bss_cap = req_bss_cap->bss_cap; + ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; + + ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; + ht_conf.ampdu_density = req_ht_cap->ampdu_density; + + /* if bss configuration changed store the new one */ + if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) || + memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { + changed |= BSS_CHANGED_HT; + memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf)); + memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); + } + } else { + if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) + changed |= BSS_CHANGED_HT; + conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; } - local->ops->conf_ht(local_to_hw(local), &local->hw.conf); - - return 0; + return changed; } void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 0997a0f96203..377c448a0556 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -865,9 +865,9 @@ int ieee80211_if_config(struct net_device *dev); int ieee80211_if_config_beacon(struct net_device *dev); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); void ieee80211_if_setup(struct net_device *dev); -int ieee80211_hw_config_ht(struct ieee80211_local *local, int enable_ht, - struct ieee80211_ht_info *req_ht_cap, - struct ieee80211_ht_bss_info *req_bss_cap); +u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, + struct ieee80211_ht_info *req_ht_cap, + struct ieee80211_ht_bss_info *req_bss_cap); /* ieee80211_ioctl.c */ extern const struct iw_handler_def ieee80211_iw_handler_def; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 1ee07f0b02e2..0e936233dac5 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -493,6 +493,7 @@ static void ieee80211_set_associated(struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; + struct ieee80211_conf *conf = &local_to_hw(local)->conf; union iwreq_data wrqu; u32 changed = BSS_CHANGED_ASSOC; @@ -505,7 +506,7 @@ static void ieee80211_set_associated(struct net_device *dev, return; bss = ieee80211_rx_bss_get(dev, ifsta->bssid, - local->hw.conf.channel->center_freq, + conf->channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (bss) { if (bss->has_erp_value) @@ -514,6 +515,13 @@ static void ieee80211_set_associated(struct net_device *dev, ieee80211_rx_bss_put(dev, bss); } + if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { + changed |= BSS_CHANGED_HT; + sdata->bss_conf.assoc_ht = 1; + sdata->bss_conf.ht_conf = &conf->ht_conf; + sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf; + } + netif_carrier_on(dev); ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); @@ -524,6 +532,11 @@ static void ieee80211_set_associated(struct net_device *dev, ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; netif_carrier_off(dev); ieee80211_reset_erp_info(dev); + + sdata->bss_conf.assoc_ht = 0; + sdata->bss_conf.ht_conf = NULL; + sdata->bss_conf.ht_bss_conf = NULL; + memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); } wrqu.ap_addr.sa_family = ARPHRD_ETHER; @@ -1999,17 +2012,15 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, else sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; - if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && - local->ops->conf_ht) { + if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) { struct ieee80211_ht_bss_info bss_info; - ieee80211_ht_cap_ie_to_ht_info( (struct ieee80211_ht_cap *) elems.ht_cap_elem, &sta->ht_info); ieee80211_ht_addt_info_ie_to_ht_bss_info( (struct ieee80211_ht_addt_info *) elems.ht_info_elem, &bss_info); - ieee80211_hw_config_ht(local, 1, &sta->ht_info, &bss_info); + ieee80211_handle_ht(local, 1, &sta->ht_info, &bss_info); } rate_control_rate_init(sta, local); @@ -2760,20 +2771,14 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]); if (elems.ht_cap_elem && elems.ht_info_elem && - elems.wmm_param && local->ops->conf_ht && - conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { + elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { struct ieee80211_ht_bss_info bss_info; ieee80211_ht_addt_info_ie_to_ht_bss_info( (struct ieee80211_ht_addt_info *) elems.ht_info_elem, &bss_info); - /* check if AP changed bss inforamation */ - if ((conf->ht_bss_conf.primary_channel != - bss_info.primary_channel) || - (conf->ht_bss_conf.bss_cap != bss_info.bss_cap) || - (conf->ht_bss_conf.bss_op_mode != bss_info.bss_op_mode)) - ieee80211_hw_config_ht(local, 1, &conf->ht_conf, - &bss_info); + changed |= ieee80211_handle_ht(local, 1, &conf->ht_conf, + &bss_info); } if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { -- cgit v1.2.3-59-g8ed1b From 21c0cbe760ca6b5d4c6927c3ec1352a843a8c11c Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Fri, 28 Mar 2008 16:33:34 -0700 Subject: mac80211: add association capabilty and timing info into bss_conf This patch adds assocation capability, timestamp (tsf) and beacon interval to bss_conf. This is required for successful assocation of iwlwifi drivers Signed-off-by: Tomas Winkler Signed-off-by: Gregory Greenman Signed-off-by: John W. Linville --- include/net/mac80211.h | 6 ++++++ net/mac80211/ieee80211_sta.c | 9 ++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 5174eaa89500..01b32152b89e 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -197,6 +197,9 @@ enum ieee80211_bss_change { * @aid: association ID number, valid only when @assoc is true * @use_cts_prot: use CTS protection * @use_short_preamble: use 802.11b short preamble + * @timestamp: beacon timestamp + * @beacon_int: beacon interval + * @assoc_capability: capabbilities taken from assoc resp * @assoc_ht: association in HT mode * @ht_conf: ht capabilities * @ht_bss_conf: ht extended capabilities @@ -208,6 +211,9 @@ struct ieee80211_bss_conf { /* erp related data */ bool use_cts_prot; bool use_short_preamble; + u16 beacon_int; + u16 assoc_capability; + u64 timestamp; /* ht related data */ bool assoc_ht; struct ieee80211_ht_info *ht_conf; diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 0e936233dac5..cb119d3b6353 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -509,9 +509,14 @@ static void ieee80211_set_associated(struct net_device *dev, conf->channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (bss) { + /* set timing information */ + sdata->bss_conf.beacon_int = bss->beacon_int; + sdata->bss_conf.timestamp = bss->timestamp; + if (bss->has_erp_value) changed |= ieee80211_handle_erp_ie( sdata, bss->erp_value); + ieee80211_rx_bss_put(dev, bss); } @@ -2033,8 +2038,10 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, } else rcu_read_unlock(); - /* set AID, ieee80211_set_associated() will tell the driver */ + /* set AID and assoc capability, + * ieee80211_set_associated() will tell the driver */ bss_conf->aid = aid; + bss_conf->assoc_capability = capab_info; ieee80211_set_associated(dev, ifsta, 1); ieee80211_associated(dev, ifsta); -- cgit v1.2.3-59-g8ed1b From fff7710937f755099209357e5b5740d42a2c9f97 Mon Sep 17 00:00:00 2001 From: Chr Date: Tue, 1 Apr 2008 21:45:18 +0200 Subject: mac80211: add station aid into ieee80211_tx_control This patch is necessary for the upcoming Accesspoint patch for p54. Signed-off-by: Christian Lamparter Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 1 + net/mac80211/tx.c | 1 + 2 files changed, 2 insertions(+) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 01b32152b89e..999f970da6ba 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -302,6 +302,7 @@ struct ieee80211_tx_control { u8 iv_len; /* length of the IV field in octets */ u8 queue; /* hardware queue to use for this frame; * 0 = highest, hw->queues-1 = lowest */ + u16 aid; /* Station AID */ int type; /* internal */ }; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 80f4343a3007..ea3fa0f91906 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -741,6 +741,7 @@ ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) } if (tx->sta) { + control->aid = tx->sta->aid; tx->sta->tx_packets++; tx->sta->tx_fragments++; tx->sta->tx_bytes += tx->skb->len; -- cgit v1.2.3-59-g8ed1b From 49ec6fa22028054f292c9c290415b88281f7b783 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 3 Apr 2008 14:31:05 +0200 Subject: mac80211: fix possible sta-debugfs work lockup Because we queue the sta-debugfs-adding work on our mac80211 workqueue (which needs to be flushed under RTNL) and that work needs the RTNL, it can currently deadlock, thanks to Reinette Chatre for pointing out the lockdep warning about this. This patch fixes it by moving this work to the common kernel workqueue (using schedule_work) and canceling it as appropriate. It also fixes a related problem: When a STA is pinned by the debugfs adding work and sta_info_flush() runs concurrently it is not guaranteed that all STAs are removed from the driver before the corresponding interface is removed which may lead to bugs. Signed-off-by: Johannes Berg Cc: Reinette Chatre Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 7e1e87257647..bfdaf5c82f9d 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -351,7 +351,7 @@ int sta_info_insert(struct sta_info *sta) * NOTE: due to auto-freeing semantics this may only be done * if the insertion is successful! */ - queue_work(local->hw.workqueue, &local->sta_debugfs_add); + schedule_work(&local->sta_debugfs_add); #endif if (ieee80211_vif_is_mesh(&sdata->vif)) @@ -476,16 +476,23 @@ void __sta_info_unlink(struct sta_info **sta) * * The rules are not trivial, but not too complex either: * (1) pin_status is only modified under the sta_lock - * (2) sta_info_debugfs_add_work() will set the status + * (2) STAs may only be pinned under the RTNL so that + * sta_info_flush() is guaranteed to actually destroy + * all STAs that are active for a given interface, this + * is required for correctness because otherwise we + * could notify a driver that an interface is going + * away and only after that (!) notify it about a STA + * on that interface going away. + * (3) sta_info_debugfs_add_work() will set the status * to PINNED when it found an item that needs a new * debugfs directory created. In that case, that item * must not be freed although all *RCU* users are done * with it. Hence, we tell the caller of _unlink() * that the item is already gone (as can happen when * two tasks try to unlink/destroy at the same time) - * (3) We set the pin_status to DESTROY here when we + * (4) We set the pin_status to DESTROY here when we * find such an item. - * (4) sta_info_debugfs_add_work() will reset the pin_status + * (5) sta_info_debugfs_add_work() will reset the pin_status * from PINNED to NORMAL when it is done with the item, * but will check for DESTROY before resetting it in * which case it will free the item. @@ -617,6 +624,8 @@ static void sta_info_debugfs_add_work(struct work_struct *work) struct sta_info *sta, *tmp; unsigned long flags; + /* We need to keep the RTNL across the whole pinned status. */ + rtnl_lock(); while (1) { sta = NULL; @@ -637,10 +646,9 @@ static void sta_info_debugfs_add_work(struct work_struct *work) rate_control_add_sta_debugfs(sta); sta = __sta_info_unpin(sta); - rtnl_lock(); sta_info_destroy(sta); - rtnl_unlock(); } + rtnl_unlock(); } #endif @@ -700,6 +708,15 @@ void sta_info_stop(struct ieee80211_local *local) { del_timer(&local->sta_cleanup); cancel_work_sync(&local->sta_flush_work); +#ifdef CONFIG_MAC80211_DEBUGFS + /* + * Make sure the debugfs adding work isn't pending after this + * because we're about to be destroyed. It doesn't matter + * whether it ran or not since we're going to flush all STAs + * anyway. + */ + cancel_work_sync(&local->sta_debugfs_add); +#endif rtnl_lock(); sta_info_flush(local, NULL); -- cgit v1.2.3-59-g8ed1b From 9cfb0009dab6d6b4c5a15c5d74ab60d7a7a7371b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 3 Apr 2008 15:17:31 +0200 Subject: mac80211: clean up IEEE80211_FC use Really doesn't need to be defined four times. Also, while at it, remove a useless macro (IEEE80211_ALIGN32_PAD) and a function prototype for a function we don't actually have (ieee80211_set_compression.) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 7 ++----- net/mac80211/ieee80211_sta.c | 2 -- net/mac80211/mesh_hwmp.c | 2 -- net/mac80211/mesh_plink.c | 1 - 4 files changed, 2 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 377c448a0556..8614c35544bb 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -35,9 +35,9 @@ #define WLAN_FC_DATA_PRESENT(fc) (((fc) & 0x4c) == 0x08) -struct ieee80211_local; +#define IEEE80211_FC(type, subtype) cpu_to_le16(type | subtype) -#define IEEE80211_ALIGN32_PAD(a) ((4 - ((a) & 3)) & 3) +struct ieee80211_local; /* Maximum number of broadcast/multicast frames to buffer when some of the * associated stations are using power saving. */ @@ -893,11 +893,8 @@ extern const struct iw_handler_def ieee80211_iw_handler_def; /* ieee80211_ioctl.c */ -int ieee80211_set_compression(struct ieee80211_local *local, - struct net_device *dev, struct sta_info *sta); int ieee80211_set_freq(struct ieee80211_local *local, int freq); /* ieee80211_sta.c */ -#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype) void ieee80211_sta_timer(unsigned long data); void ieee80211_sta_work(struct work_struct *work); void ieee80211_sta_scan_work(struct work_struct *work); diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index cb119d3b6353..0f2fc9c4703a 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -57,8 +57,6 @@ #define IEEE80211_IBSS_MAX_STA_ENTRIES 128 -#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype) - #define ERP_INFO_USE_PROTECTION BIT(1) /* mgmt header + 1 byte action code */ diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 576a6e55323e..02de8f1522a3 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -10,8 +10,6 @@ #include #include "mesh.h" -#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype) - #define TEST_FRAME_LEN 8192 #define MAX_METRIC 0xffffffff #define ARITH_SHIFT 8 diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 56c54e321b38..67271baa5b61 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -18,7 +18,6 @@ #define mpl_dbg(fmt, args...) do { (void)(0); } while (0) #endif -#define IEEE80211_FC(type, stype) cpu_to_le16(type | stype) #define PLINK_GET_FRAME_SUBTYPE(p) (p) #define PLINK_GET_LLID(p) (p + 1) #define PLINK_GET_PLID(p) (p + 3) -- cgit v1.2.3-59-g8ed1b From 253898c4170c7f426d1bc32860fee04f27de3ade Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Thu, 3 Apr 2008 15:32:54 -0400 Subject: cfg80211: default to regulatory max power for channel If the driver does not specify a maximum power output, default to the regulatory max. Signed-off-by: John W. Linville --- net/wireless/reg.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 8cc6037eb2ae..185488da2466 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -136,7 +136,10 @@ static void handle_channel(struct ieee80211_channel *chan, chan->flags = flags; chan->max_antenna_gain = min(chan->orig_mag, rg->max_antenna_gain); - chan->max_power = min(chan->orig_mpwr, rg->max_power); + if (chan->orig_mpwr) + chan->max_power = min(chan->orig_mpwr, rg->max_power); + else + chan->max_power = rg->max_power; } static void handle_band(struct ieee80211_supported_band *sband, -- cgit v1.2.3-59-g8ed1b From 41a7be4858b886f83522e62d409263fcdb82653b Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Thu, 3 Apr 2008 16:08:49 -0700 Subject: mac80211: notify upper layers after lower When drivers receive change notification they may do work that will enable the changes to take effect. For example, if new association the device needs to be programmed with this information. Give the driver chance to make the changes before notifying the upper layer - thus preventing race condition where upper layer attempts to utilize state that may not be configured yet. Signed-off-by: Reinette Chatre Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_sta.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 0f2fc9c4703a..9e30333aa81e 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -542,13 +542,13 @@ static void ieee80211_set_associated(struct net_device *dev, memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); } - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); ifsta->last_probe = jiffies; ieee80211_led_assoc(local, assoc); sdata->bss_conf.assoc = assoc; ieee80211_bss_info_change_notify(sdata, changed); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); } static void ieee80211_set_disassoc(struct net_device *dev, -- cgit v1.2.3-59-g8ed1b From bebb8a5e2cd30adcc5e9a14c3366a231da728aee Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 4 Apr 2008 23:33:37 +0200 Subject: mac80211: make debugfs files root-only Unfortunately, debugfs can be made to access invalid memory by open()ing a file and then waiting until the corresponding debugfs file has been removed (and, probably, the underlying object.) That could be exploited by any user if the user is able to open debugfs files and can cause networking devices, STA entries or similar to disappear which is quite easy to do. Hence, all debugfs files should be root-only. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs.c | 4 ++-- net/mac80211/debugfs_netdev.c | 6 +++--- net/mac80211/debugfs_sta.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 4736c64937b4..f4bb08b62d1a 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -37,7 +37,7 @@ static const struct file_operations name## _ops = { \ }; #define DEBUGFS_ADD(name) \ - local->debugfs.name = debugfs_create_file(#name, 0444, phyd, \ + local->debugfs.name = debugfs_create_file(#name, 0400, phyd, \ local, &name## _ops); #define DEBUGFS_DEL(name) \ @@ -130,7 +130,7 @@ static const struct file_operations stats_ ##name## _ops = { \ }; #define DEBUGFS_STATS_ADD(name) \ - local->debugfs.stats.name = debugfs_create_file(#name, 0444, statsd,\ + local->debugfs.stats.name = debugfs_create_file(#name, 0400, statsd,\ local, &stats_ ##name## _ops); #define DEBUGFS_STATS_DEL(name) \ diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 3e19d42e61cb..55cd6fc3f2e0 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -243,7 +243,7 @@ IEEE80211_IF_WFILE(min_discovery_timeout, #define DEBUGFS_ADD(name, type)\ - sdata->debugfs.type.name = debugfs_create_file(#name, 0444,\ + sdata->debugfs.type.name = debugfs_create_file(#name, 0400,\ sdata->debugfsdir, sdata, &name##_ops); static void add_sta_files(struct ieee80211_sub_if_data *sdata) @@ -298,7 +298,7 @@ static void add_monitor_files(struct ieee80211_sub_if_data *sdata) #ifdef CONFIG_MAC80211_MESH #define MESHSTATS_ADD(name)\ - sdata->mesh_stats.name = debugfs_create_file(#name, 0444,\ + sdata->mesh_stats.name = debugfs_create_file(#name, 0400,\ sdata->mesh_stats_dir, sdata, &name##_ops); static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) @@ -312,7 +312,7 @@ static void add_mesh_stats(struct ieee80211_sub_if_data *sdata) } #define MESHPARAMS_ADD(name)\ - sdata->mesh_config.name = debugfs_create_file(#name, 0644,\ + sdata->mesh_config.name = debugfs_create_file(#name, 0600,\ sdata->mesh_config_dir, sdata, &name##_ops); static void add_mesh_config(struct ieee80211_sub_if_data *sdata) diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 256ea880d28b..6d47a1d31b37 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -266,7 +266,7 @@ static ssize_t sta_agg_status_write(struct file *file, STA_OPS_WR(agg_status); #define DEBUGFS_ADD(name) \ - sta->debugfs.name = debugfs_create_file(#name, 0444, \ + sta->debugfs.name = debugfs_create_file(#name, 0400, \ sta->debugfs.dir, sta, &sta_ ##name## _ops); #define DEBUGFS_DEL(name) \ -- cgit v1.2.3-59-g8ed1b From 380a942b9177dcae1429fdd0f3639f92d9ab139d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 4 Apr 2008 23:40:35 +0200 Subject: mac80211: fix ieee80211_ioctl_giwrate The ieee80211_ioctl_giwrate() ioctl handler doesn't rcu_read_lock() its access to the sta table, fix it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_ioctl.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index b047eebb6330..41130b303170 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -586,19 +586,25 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->vif.type == IEEE80211_IF_TYPE_STA) - sta = sta_info_get(local, sdata->u.sta.bssid); - else + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) return -EOPNOTSUPP; - if (!sta) - return -ENODEV; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - if (sta->txrate_idx < sband->n_bitrates) + rcu_read_lock(); + + sta = sta_info_get(local, sdata->u.sta.bssid); + + if (sta && sta->txrate_idx < sband->n_bitrates) rate->value = sband->bitrates[sta->txrate_idx].bitrate; else rate->value = 0; + + rcu_read_unlock(); + + if (!sta) + return -ENODEV; + rate->value *= 100000; return 0; -- cgit v1.2.3-59-g8ed1b From 84363e6e07f17f8cc580065260907ee3f0520485 Mon Sep 17 00:00:00 2001 From: Mohamed Abbas Date: Fri, 4 Apr 2008 16:59:58 -0700 Subject: mac80211: notify mac from low level driver (iwlwifi) Add new API to MAC80211 to allow low level driver to notify MAC with driver status. Signed-off-by: Mohamed Abbas Signed-off-by: Reinette Chatre Acked-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl3945-base.c | 1 + drivers/net/wireless/iwlwifi/iwl4965-base.c | 1 + include/net/mac80211.h | 19 +++++++++++++++++++ net/mac80211/ieee80211_sta.c | 23 +++++++++++++++++++++++ 4 files changed, 44 insertions(+) (limited to 'net') diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5e51cfcda39f..29a9ecdcbf35 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -5886,6 +5886,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) if (priv->error_recovering) iwl3945_error_recovery(priv); + ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC); return; restart: diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index b043871d53f1..06e44dad5f02 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -5714,6 +5714,7 @@ static void iwl4965_alive_start(struct iwl_priv *priv) iwl4965_error_recovery(priv); iwlcore_low_level_notify(priv, IWLCORE_START_EVT); + ieee80211_notify_mac(priv->hw, IEEE80211_NOTIFY_RE_ASSOC); return; restart: diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 999f970da6ba..079e7bd86c90 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -73,6 +73,14 @@ * not do so then mac80211 may add this under certain circumstances. */ +/** + * enum ieee80211_notification_type - Low level driver notification + * @IEEE80211_NOTIFY_RE_ASSOC: start the re-association sequence + */ +enum ieee80211_notification_types { + IEEE80211_NOTIFY_RE_ASSOC, +}; + /** * struct ieee80211_ht_bss_info - describing BSS's HT characteristics * @@ -1678,4 +1686,15 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid); void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, const u8 *ra, u16 tid); +/** + * ieee80211_notify_mac - low level driver notification + * @hw: pointer as obtained from ieee80211_alloc_hw(). + * @notification_types: enum ieee80211_notification_types + * + * This function must be called by low level driver to inform mac80211 of + * low level driver status change or force mac80211 to re-assoc for low + * level driver internal error that require re-assoc. + */ +void ieee80211_notify_mac(struct ieee80211_hw *hw, + enum ieee80211_notification_types notif_type); #endif /* MAC80211_H */ diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 9e30333aa81e..89481c919cb6 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -4225,3 +4225,26 @@ int ieee80211_sta_disassociate(struct net_device *dev, u16 reason) ieee80211_set_disassoc(dev, ifsta, 0); return 0; } + +void ieee80211_notify_mac(struct ieee80211_hw *hw, + enum ieee80211_notification_types notif_type) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata; + + switch (notif_type) { + case IEEE80211_NOTIFY_RE_ASSOC: + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + + if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { + ieee80211_sta_req_auth(sdata->dev, + &sdata->u.sta); + } + + } + rcu_read_unlock(); + break; + } +} +EXPORT_SYMBOL(ieee80211_notify_mac); -- cgit v1.2.3-59-g8ed1b From 513a1025fd91008316a8e9b4803d1bfcbb2bf256 Mon Sep 17 00:00:00 2001 From: Ron Rindjunsky Date: Mon, 7 Apr 2008 10:16:56 -0700 Subject: mac80211: BA session debug prints changes This patch contains next issues: 1 - prevents "stop BA session" multiple warnings 2 - adds debug print to stop Rx BA session flow 3 - adds EOL in one debug print Signed-off-by: Ron Rindjunsky Signed-off-by: Reinette Chatre Acked-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211.c | 18 ++++++++---------- net/mac80211/ieee80211_sta.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 5d30dd463f22..b3cf69edeed9 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -700,11 +700,6 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, if (tid >= STA_TID_NUM) return -EINVAL; -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Stop a BA session requested for %s tid %u\n", - print_mac(mac, ra), tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - rcu_read_lock(); sta = sta_info_get(local, ra); if (!sta) { @@ -717,14 +712,15 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); if (*state != HT_AGG_STATE_OPERATIONAL) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Try to stop Tx aggregation on" - " non active TID\n"); -#endif /* CONFIG_MAC80211_HT_DEBUG */ ret = -ENOENT; goto stop_BA_exit; } +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Tx BA session stop requested for %s tid %u\n", + print_mac(mac, ra), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); *state = HT_AGG_STATE_REQ_STOP_BA_MSK | @@ -809,8 +805,10 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) return; } - printk(KERN_DEBUG "Stop a BA session requested on DA %s tid %d\n", +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Stopping Tx BA session for %s tid %d\n", print_mac(mac, ra), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ rcu_read_lock(); sta = sta_info_get(local, ra); diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 89481c919cb6..2a3f8a8e9a43 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -1278,7 +1278,7 @@ static void ieee80211_sta_process_addba_request(struct net_device *dev, ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, sta->addr, tid, &start_seq_num); #ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Rx A-MPDU on tid %d result %d", tid, ret); + printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); #endif /* CONFIG_MAC80211_HT_DEBUG */ if (ret) { @@ -1433,6 +1433,7 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, struct ieee80211_hw *hw = &local->hw; struct sta_info *sta; int ret, i; + DECLARE_MAC_BUF(mac); rcu_read_lock(); @@ -1453,12 +1454,17 @@ void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); /* stop HW Rx aggregation. ampdu_action existence * already verified in session init so we add the BUG_ON */ BUG_ON(!local->ops->ampdu_action); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Rx BA session stop requested for %s tid %u\n", + print_mac(mac, ra), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, ra, tid, NULL); if (ret) -- cgit v1.2.3-59-g8ed1b From 4d6141c30a2567a85d869d55f579438b3365d719 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 7 Apr 2008 21:53:49 +0200 Subject: mac80211: fix defined but not used These two symbols are used only in ifdeffed function. Move them to that section too. net/mac80211/sta_info.c:387: warning: `__sta_info_pin' defined but not used net/mac80211/sta_info.c:397: warning: `__sta_info_unpin' defined but not used Signed-off-by: Jiri Slaby Cc: Michael Wu Cc: Johannes Berg Cc: Jiri Benc Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 60 ++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index bfdaf5c82f9d..130aad2de108 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -424,36 +424,6 @@ void sta_info_clear_tim_bit(struct sta_info *sta) spin_unlock_irqrestore(&sta->local->sta_lock, flags); } -/* - * See comment in __sta_info_unlink, - * caller must hold local->sta_lock. - */ -static void __sta_info_pin(struct sta_info *sta) -{ - WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_NORMAL); - sta->pin_status = STA_INFO_PIN_STAT_PINNED; -} - -/* - * See comment in __sta_info_unlink, returns sta if it - * needs to be destroyed. - */ -static struct sta_info *__sta_info_unpin(struct sta_info *sta) -{ - struct sta_info *ret = NULL; - unsigned long flags; - - spin_lock_irqsave(&sta->local->sta_lock, flags); - WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_DESTROY && - sta->pin_status != STA_INFO_PIN_STAT_PINNED); - if (sta->pin_status == STA_INFO_PIN_STAT_DESTROY) - ret = sta; - sta->pin_status = STA_INFO_PIN_STAT_NORMAL; - spin_unlock_irqrestore(&sta->local->sta_lock, flags); - - return ret; -} - void __sta_info_unlink(struct sta_info **sta) { struct ieee80211_local *local = (*sta)->local; @@ -617,6 +587,36 @@ static void sta_info_cleanup(unsigned long data) } #ifdef CONFIG_MAC80211_DEBUGFS +/* + * See comment in __sta_info_unlink, + * caller must hold local->sta_lock. + */ +static void __sta_info_pin(struct sta_info *sta) +{ + WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_NORMAL); + sta->pin_status = STA_INFO_PIN_STAT_PINNED; +} + +/* + * See comment in __sta_info_unlink, returns sta if it + * needs to be destroyed. + */ +static struct sta_info *__sta_info_unpin(struct sta_info *sta) +{ + struct sta_info *ret = NULL; + unsigned long flags; + + spin_lock_irqsave(&sta->local->sta_lock, flags); + WARN_ON(sta->pin_status != STA_INFO_PIN_STAT_DESTROY && + sta->pin_status != STA_INFO_PIN_STAT_PINNED); + if (sta->pin_status == STA_INFO_PIN_STAT_DESTROY) + ret = sta; + sta->pin_status = STA_INFO_PIN_STAT_NORMAL; + spin_unlock_irqrestore(&sta->local->sta_lock, flags); + + return ret; +} + static void sta_info_debugfs_add_work(struct work_struct *work) { struct ieee80211_local *local = -- cgit v1.2.3-59-g8ed1b From 7d1559f1737d5ca27b267b0392015f42b3bbe2fa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 8 Apr 2008 13:08:20 +0200 Subject: mac80211: fix sta-info pinning When a STA is supposed to be unlinked but is pinned, it still needs to be unlinked from all structures. Only at the end of the unlink process should we check for pin status and invalidate the callers reference if it is pinned. Move the pin status check down. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/sta_info.c | 64 ++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'net') diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 130aad2de108..cedd73a0c875 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -439,8 +439,39 @@ void __sta_info_unlink(struct sta_info **sta) return; } + list_del(&(*sta)->list); + + if ((*sta)->flags & WLAN_STA_PS) { + (*sta)->flags &= ~WLAN_STA_PS; + if (sdata->bss) + atomic_dec(&sdata->bss->num_sta_ps); + __sta_info_clear_tim_bit(sdata->bss, *sta); + } + + local->num_sta--; + + if (local->ops->sta_notify) { + if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) + sdata = sdata->u.vlan.ap; + + local->ops->sta_notify(local_to_hw(local), &sdata->vif, + STA_NOTIFY_REMOVE, (*sta)->addr); + } + + if (ieee80211_vif_is_mesh(&sdata->vif)) { + mesh_accept_plinks_update(sdata); +#ifdef CONFIG_MAC80211_MESH + del_timer(&(*sta)->plink_timer); +#endif + } + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: Removed STA %s\n", + wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->addr)); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + /* - * Also pull caller's reference if the STA is pinned by the + * Finally, pull caller's reference if the STA is pinned by the * task that is adding the debugfs entries. In that case, we * leave the STA "to be freed". * @@ -472,37 +503,6 @@ void __sta_info_unlink(struct sta_info **sta) *sta = NULL; return; } - - list_del(&(*sta)->list); - - if ((*sta)->flags & WLAN_STA_PS) { - (*sta)->flags &= ~WLAN_STA_PS; - if (sdata->bss) - atomic_dec(&sdata->bss->num_sta_ps); - __sta_info_clear_tim_bit(sdata->bss, *sta); - } - - local->num_sta--; - - if (local->ops->sta_notify) { - if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) - sdata = sdata->u.vlan.ap; - - local->ops->sta_notify(local_to_hw(local), &sdata->vif, - STA_NOTIFY_REMOVE, (*sta)->addr); - } - - if (ieee80211_vif_is_mesh(&sdata->vif)) { - mesh_accept_plinks_update(sdata); -#ifdef CONFIG_MAC80211_MESH - del_timer(&(*sta)->plink_timer); -#endif - } - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Removed STA %s\n", - wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->addr)); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ } void sta_info_unlink(struct sta_info **sta) -- cgit v1.2.3-59-g8ed1b From 3b96766f0e643f52ae19e134664df6730c737e87 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 8 Apr 2008 17:56:52 +0200 Subject: mac80211: fix key vs. sta locking problems Up to now, key manipulation is supposed to run under RTNL to avoid concurrent manipulations and also allow the set_key() hardware callback to sleep. This is not feasible because STA structs are rcu-protected and thus a lot of operations there cannot take the RTNL. Also, key references are rcu-protected so we cannot do things atomically. This patch changes key locking completely: * key operations are now atomic * hardware crypto offload is enabled and disabled from a workqueue, due to that key freeing is also delayed * debugfs code is also run from a workqueue * keys reference STAs (and vice versa!) so during STA unlink the STAs key reference is removed but not the keys STA reference, to avoid races key todo work is run before STA destruction. * fewer STA operations now need the RTNL which was required due to key operations This fixes the locking problems lockdep pointed out and also makes things more light-weight because the rtnl isn't required as much. Note that the key todo lock/key mutex are global locks, this is not required, of course, they could be per-hardware instead. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 44 ++++- net/mac80211/debugfs_key.c | 37 ++-- net/mac80211/debugfs_key.h | 11 +- net/mac80211/ieee80211.c | 6 + net/mac80211/ieee80211_i.h | 4 +- net/mac80211/ieee80211_ioctl.c | 26 ++- net/mac80211/ieee80211_key.h | 20 +- net/mac80211/ieee80211_sta.c | 9 +- net/mac80211/key.c | 408 ++++++++++++++++++++++++++--------------- net/mac80211/sta_info.c | 48 +++-- net/mac80211/sta_info.h | 1 - 11 files changed, 385 insertions(+), 229 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5f8db5cab65d..fe05a7b85dc6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -135,6 +135,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, struct sta_info *sta = NULL; enum ieee80211_key_alg alg; struct ieee80211_key *key; + int err; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -157,17 +158,24 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, if (!key) return -ENOMEM; + rcu_read_lock(); + if (mac_addr) { sta = sta_info_get(sdata->local, mac_addr); if (!sta) { ieee80211_key_free(key); - return -ENOENT; + err = -ENOENT; + goto out_unlock; } } ieee80211_key_link(key, sdata, sta); - return 0; + err = 0; + out_unlock: + rcu_read_unlock(); + + return err; } static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, @@ -179,28 +187,37 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, sdata = IEEE80211_DEV_TO_SUB_IF(dev); + rcu_read_lock(); + if (mac_addr) { + ret = -ENOENT; + sta = sta_info_get(sdata->local, mac_addr); if (!sta) - return -ENOENT; + goto out_unlock; - ret = 0; if (sta->key) { ieee80211_key_free(sta->key); WARN_ON(sta->key); - } else - ret = -ENOENT; + ret = 0; + } - return ret; + goto out_unlock; } - if (!sdata->keys[key_idx]) - return -ENOENT; + if (!sdata->keys[key_idx]) { + ret = -ENOENT; + goto out_unlock; + } ieee80211_key_free(sdata->keys[key_idx]); WARN_ON(sdata->keys[key_idx]); - return 0; + ret = 0; + out_unlock: + rcu_read_unlock(); + + return ret; } static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, @@ -217,6 +234,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, u16 iv16; int err = -ENOENT; + rcu_read_lock(); + if (mac_addr) { sta = sta_info_get(sdata->local, mac_addr); if (!sta) @@ -280,6 +299,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, err = 0; out: + rcu_read_unlock(); return err; } @@ -289,9 +309,13 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, { struct ieee80211_sub_if_data *sdata; + rcu_read_lock(); + sdata = IEEE80211_DEV_TO_SUB_IF(dev); ieee80211_set_default_key(sdata, key_idx); + rcu_read_unlock(); + return 0; } diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index c881524c8725..459f0767fae5 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -184,23 +184,35 @@ KEY_OPS(key); key->debugfs.name = debugfs_create_file(#name, 0400,\ key->debugfs.dir, key, &key_##name##_ops); -void ieee80211_debugfs_key_add(struct ieee80211_local *local, - struct ieee80211_key *key) -{ +void ieee80211_debugfs_key_add(struct ieee80211_key *key) + { static int keycount; - char buf[20]; + char buf[50]; + DECLARE_MAC_BUF(mac); + struct sta_info *sta; - if (!local->debugfs.keys) + if (!key->local->debugfs.keys) return; sprintf(buf, "%d", keycount); keycount++; key->debugfs.dir = debugfs_create_dir(buf, - local->debugfs.keys); + key->local->debugfs.keys); if (!key->debugfs.dir) return; + rcu_read_lock(); + sta = rcu_dereference(key->sta); + if (sta) + sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr)); + rcu_read_unlock(); + + /* using sta as a boolean is fine outside RCU lock */ + if (sta) + key->debugfs.stalink = + debugfs_create_symlink("station", key->debugfs.dir, buf); + DEBUGFS_ADD(keylen); DEBUGFS_ADD(flags); DEBUGFS_ADD(keyidx); @@ -258,19 +270,6 @@ void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata) debugfs_remove(sdata->debugfs.default_key); sdata->debugfs.default_key = NULL; } -void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, - struct sta_info *sta) -{ - char buf[50]; - DECLARE_MAC_BUF(mac); - - if (!key->debugfs.dir) - return; - - sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr)); - key->debugfs.stalink = - debugfs_create_symlink("station", key->debugfs.dir, buf); -} void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, struct sta_info *sta) diff --git a/net/mac80211/debugfs_key.h b/net/mac80211/debugfs_key.h index aecfce395da6..b1a3754ee240 100644 --- a/net/mac80211/debugfs_key.h +++ b/net/mac80211/debugfs_key.h @@ -2,18 +2,14 @@ #define __MAC80211_DEBUGFS_KEY_H #ifdef CONFIG_MAC80211_DEBUGFS -void ieee80211_debugfs_key_add(struct ieee80211_local *local, - struct ieee80211_key *key); +void ieee80211_debugfs_key_add(struct ieee80211_key *key); void ieee80211_debugfs_key_remove(struct ieee80211_key *key); void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata); void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata); -void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, - struct sta_info *sta); void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, struct sta_info *sta); #else -static inline void ieee80211_debugfs_key_add(struct ieee80211_local *local, - struct ieee80211_key *key) +static inline void ieee80211_debugfs_key_add(struct ieee80211_key *key) {} static inline void ieee80211_debugfs_key_remove(struct ieee80211_key *key) {} @@ -23,9 +19,6 @@ static inline void ieee80211_debugfs_key_add_default( static inline void ieee80211_debugfs_key_remove_default( struct ieee80211_sub_if_data *sdata) {} -static inline void ieee80211_debugfs_key_sta_link( - struct ieee80211_key *key, struct sta_info *sta) -{} static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, struct sta_info *sta) {} diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index b3cf69edeed9..dbe993af8034 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -1868,6 +1868,12 @@ static void __exit ieee80211_exit(void) { rc80211_pid_exit(); + /* + * For key todo, it'll be empty by now but the work + * might still be scheduled. + */ + flush_scheduled_work(); + if (mesh_allocated) ieee80211s_stop(); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8614c35544bb..7f4e7f93ee47 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -600,8 +600,8 @@ struct ieee80211_local { /* * The lock only protects the list, hash, timer and counter * against manipulation, reads are done in RCU. Additionally, - * the lock protects each BSS's TIM bitmap and a few items - * in a STA info structure. + * the lock protects each BSS's TIM bitmap, a few items in + * STA info structures and various key pointers. */ spinlock_t sta_lock; unsigned long num_sta; diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 41130b303170..a611c8bc76bd 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -36,6 +36,7 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, struct sta_info *sta; struct ieee80211_key *key; struct ieee80211_sub_if_data *sdata; + int err; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -46,23 +47,31 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, } if (remove) { + rcu_read_lock(); + + err = 0; + if (is_broadcast_ether_addr(sta_addr)) { key = sdata->keys[idx]; } else { sta = sta_info_get(local, sta_addr); - if (!sta) - return -ENOENT; + if (!sta) { + err = -ENOENT; + goto out_unlock; + } key = sta->key; } ieee80211_key_free(key); - return 0; } else { key = ieee80211_key_alloc(alg, idx, key_len, _key); if (!key) return -ENOMEM; sta = NULL; + err = 0; + + rcu_read_lock(); if (!is_broadcast_ether_addr(sta_addr)) { set_tx_key = 0; @@ -74,13 +83,15 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, */ if (idx != 0 && alg != ALG_WEP) { ieee80211_key_free(key); - return -EINVAL; + err = -EINVAL; + goto out_unlock; } sta = sta_info_get(local, sta_addr); if (!sta) { ieee80211_key_free(key); - return -ENOENT; + err = -ENOENT; + goto out_unlock; } } @@ -90,7 +101,10 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, ieee80211_set_default_key(sdata, idx); } - return 0; + out_unlock: + rcu_read_unlock(); + + return err; } static int ieee80211_ioctl_siwgenie(struct net_device *dev, diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h index d670e6dbfa39..467890c6fe81 100644 --- a/net/mac80211/ieee80211_key.h +++ b/net/mac80211/ieee80211_key.h @@ -51,13 +51,19 @@ struct sta_info; * * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present * in the hardware for TX crypto hardware acceleration. - * @KEY_FLAG_REMOVE_FROM_HARDWARE: Indicates to the key code that this - * key is present in the hardware (but it cannot be used for - * hardware acceleration any more!) + * @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an + * RCU grace period, no longer be reachable other than from the + * todo list. + * @KEY_FLAG_TODO_HWACCEL: Key needs to be added to hardware acceleration. + * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated. + * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs. */ enum ieee80211_internal_key_flags { KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), - KEY_FLAG_REMOVE_FROM_HARDWARE = BIT(1), + KEY_FLAG_TODO_DELETE = BIT(1), + KEY_FLAG_TODO_HWACCEL = BIT(2), + KEY_FLAG_TODO_DEFKEY = BIT(3), + KEY_FLAG_TODO_ADD_DEBUGFS = BIT(4), }; struct ieee80211_key { @@ -65,8 +71,12 @@ struct ieee80211_key { struct ieee80211_sub_if_data *sdata; struct sta_info *sta; + /* for sdata list */ struct list_head list; + /* for todo list */ + struct list_head todo; + /* protected by todo lock! */ unsigned int flags; union { @@ -142,4 +152,6 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); +void ieee80211_key_todo(void); + #endif /* IEEE80211_KEY_H */ diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 2a3f8a8e9a43..3584a2bf0186 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -952,11 +952,8 @@ static void ieee80211_associated(struct net_device *dev, rcu_read_unlock(); - if (disassoc && sta) { - rtnl_lock(); + if (disassoc && sta) sta_info_destroy(sta); - rtnl_unlock(); - } if (disassoc) { ifsta->state = IEEE80211_DISABLED; @@ -3104,12 +3101,8 @@ static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time) } spin_unlock_irqrestore(&local->sta_lock, flags); - synchronize_rcu(); - - rtnl_lock(); list_for_each_entry_safe(sta, tmp, &tmp_list, list) sta_info_destroy(sta); - rtnl_unlock(); } diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 5df9e0cc009f..711e36e54ff8 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -2,7 +2,7 @@ * Copyright 2002-2005, Instant802 Networks, Inc. * Copyright 2005-2006, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc - * Copyright 2007 Johannes Berg + * Copyright 2007-2008 Johannes Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -33,17 +33,78 @@ * There is currently no way of knowing this except by looking into * debugfs. * - * All operations here are called under RTNL so no extra locking is - * required. + * All key operations are protected internally so you can call them at + * any time. * - * NOTE: This code requires that sta info *destruction* is done under - * RTNL, otherwise it can try to access already freed STA structs - * when a STA key is being freed. + * Within mac80211, key references are, just as STA structure references, + * protected by RCU. Note, however, that some things are unprotected, + * namely the key->sta dereferences within the hardware acceleration + * functions. This means that sta_info_destroy() must flush the key todo + * list. + * + * All the direct key list manipulation functions must not sleep because + * they can operate on STA info structs that are protected by RCU. */ static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; static const u8 zero_addr[ETH_ALEN]; +/* key mutex: used to synchronise todo runners */ +static DEFINE_MUTEX(key_mutex); +static DEFINE_SPINLOCK(todo_lock); +static LIST_HEAD(todo_list); + +static void key_todo(struct work_struct *work) +{ + ieee80211_key_todo(); +} + +static DECLARE_WORK(todo_work, key_todo); + +/** + * add_todo - add todo item for a key + * + * @key: key to add to do item for + * @flag: todo flag(s) + */ +static void add_todo(struct ieee80211_key *key, u32 flag) +{ + if (!key) + return; + + spin_lock(&todo_lock); + key->flags |= flag; + /* only add if not already added */ + if (list_empty(&key->todo)) + list_add(&key->todo, &todo_list); + schedule_work(&todo_work); + spin_unlock(&todo_lock); +} + +/** + * ieee80211_key_lock - lock the mac80211 key operation lock + * + * This locks the (global) mac80211 key operation lock, all + * key operations must be done under this lock. + */ +static void ieee80211_key_lock(void) +{ + mutex_lock(&key_mutex); +} + +/** + * ieee80211_key_unlock - unlock the mac80211 key operation lock + */ +static void ieee80211_key_unlock(void) +{ + mutex_unlock(&key_mutex); +} + +static void assert_key_lock(void) +{ + WARN_ON(!mutex_is_locked(&key_mutex)); +} + static const u8 *get_mac_for_key(struct ieee80211_key *key) { const u8 *addr = bcast_addr; @@ -70,26 +131,23 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) int ret; DECLARE_MAC_BUF(mac); + assert_key_lock(); + might_sleep(); + if (!key->local->ops->set_key) return; - /* - * This makes sure that all pending flushes have - * actually completed prior to uploading new key - * material to the hardware. That is necessary to - * avoid races between flushing STAs and adding - * new keys for them. - */ - __ieee80211_run_pending_flush(key->local); - addr = get_mac_for_key(key); ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, key->sdata->dev->dev_addr, addr, &key->conf); - if (!ret) + if (!ret) { + spin_lock(&todo_lock); key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; + spin_unlock(&todo_lock); + } if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) printk(KERN_ERR "mac80211-%s: failed to set key " @@ -98,26 +156,24 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) key->conf.keyidx, print_mac(mac, addr), ret); } -static void ieee80211_key_mark_hw_accel_off(struct ieee80211_key *key) -{ - if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { - key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; - key->flags |= KEY_FLAG_REMOVE_FROM_HARDWARE; - } -} - static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) { const u8 *addr; int ret; DECLARE_MAC_BUF(mac); + assert_key_lock(); + might_sleep(); + if (!key || !key->local->ops->set_key) return; - if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && - !(key->flags & KEY_FLAG_REMOVE_FROM_HARDWARE)) + spin_lock(&todo_lock); + if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { + spin_unlock(&todo_lock); return; + } + spin_unlock(&todo_lock); addr = get_mac_for_key(key); @@ -131,8 +187,72 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) wiphy_name(key->local->hw.wiphy), key->conf.keyidx, print_mac(mac, addr), ret); - key->flags &= ~(KEY_FLAG_UPLOADED_TO_HARDWARE | - KEY_FLAG_REMOVE_FROM_HARDWARE); + spin_lock(&todo_lock); + key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; + spin_unlock(&todo_lock); +} + +static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, + int idx) +{ + struct ieee80211_key *key = NULL; + + if (idx >= 0 && idx < NUM_DEFAULT_KEYS) + key = sdata->keys[idx]; + + rcu_assign_pointer(sdata->default_key, key); + + if (key) + add_todo(key, KEY_FLAG_TODO_DEFKEY); +} + +void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) +{ + unsigned long flags; + + spin_lock_irqsave(&sdata->local->sta_lock, flags); + __ieee80211_set_default_key(sdata, idx); + spin_unlock_irqrestore(&sdata->local->sta_lock, flags); +} + + +static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, + struct ieee80211_key *old, + struct ieee80211_key *new) +{ + int idx, defkey; + + if (new) + list_add(&new->list, &sdata->key_list); + + if (sta) { + rcu_assign_pointer(sta->key, new); + } else { + WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); + + if (old) + idx = old->conf.keyidx; + else + idx = new->conf.keyidx; + + defkey = old && sdata->default_key == old; + + if (defkey && !new) + __ieee80211_set_default_key(sdata, -1); + + rcu_assign_pointer(sdata->keys[idx], new); + if (defkey && new) + __ieee80211_set_default_key(sdata, new->conf.keyidx); + } + + if (old) { + /* + * We'll use an empty list to indicate that the key + * has already been removed. + */ + list_del_init(&old->list); + } } struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, @@ -160,6 +280,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, key->conf.keylen = key_len; memcpy(key->conf.key, key_data, key_len); INIT_LIST_HEAD(&key->list); + INIT_LIST_HEAD(&key->todo); if (alg == ALG_CCMP) { /* @@ -168,7 +289,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, */ key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data); if (!key->u.ccmp.tfm) { - ieee80211_key_free(key); + kfree(key); return NULL; } } @@ -176,56 +297,14 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, return key; } -static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta, - struct ieee80211_key *key, - struct ieee80211_key *new) -{ - int idx, defkey; - - if (new) - list_add(&new->list, &sdata->key_list); - - if (sta) { - rcu_assign_pointer(sta->key, new); - } else { - WARN_ON(new && key && new->conf.keyidx != key->conf.keyidx); - - if (key) - idx = key->conf.keyidx; - else - idx = new->conf.keyidx; - - defkey = key && sdata->default_key == key; - - if (defkey && !new) - ieee80211_set_default_key(sdata, -1); - - rcu_assign_pointer(sdata->keys[idx], new); - if (defkey && new) - ieee80211_set_default_key(sdata, new->conf.keyidx); - } - - if (key) { - ieee80211_key_mark_hw_accel_off(key); - /* - * We'll use an empty list to indicate that the key - * has already been removed. - */ - list_del_init(&key->list); - } -} - void ieee80211_key_link(struct ieee80211_key *key, struct ieee80211_sub_if_data *sdata, struct sta_info *sta) { struct ieee80211_key *old_key; + unsigned long flags; int idx; - ASSERT_RTNL(); - might_sleep(); - BUG_ON(!sdata); BUG_ON(!key); @@ -234,11 +313,7 @@ void ieee80211_key_link(struct ieee80211_key *key, key->sdata = sdata; key->sta = sta; - ieee80211_debugfs_key_add(key->local, key); - if (sta) { - ieee80211_debugfs_key_sta_link(key, sta); - /* * some hardware cannot handle TKIP with QoS, so * we indicate whether QoS could be in use. @@ -249,7 +324,10 @@ void ieee80211_key_link(struct ieee80211_key *key, if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { struct sta_info *ap; - rcu_read_lock(); + /* + * We're getting a sta pointer in, + * so must be under RCU read lock. + */ /* same here, the AP could be using QoS */ ap = sta_info_get(key->local, key->sdata->u.sta.bssid); @@ -258,11 +336,11 @@ void ieee80211_key_link(struct ieee80211_key *key, key->conf.flags |= IEEE80211_KEY_FLAG_WMM_STA; } - - rcu_read_unlock(); } } + spin_lock_irqsave(&sdata->local->sta_lock, flags); + if (sta) old_key = sta->key; else @@ -270,108 +348,150 @@ void ieee80211_key_link(struct ieee80211_key *key, __ieee80211_key_replace(sdata, sta, old_key, key); - if (old_key) { - synchronize_rcu(); - ieee80211_key_free(old_key); - } + spin_unlock_irqrestore(&sdata->local->sta_lock, flags); + + /* free old key later */ + add_todo(old_key, KEY_FLAG_TODO_DELETE); + add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); if (netif_running(sdata->dev)) - ieee80211_key_enable_hw_accel(key); + add_todo(key, KEY_FLAG_TODO_HWACCEL); } void ieee80211_key_free(struct ieee80211_key *key) { - ASSERT_RTNL(); - might_sleep(); + unsigned long flags; if (!key) return; + /* + * Replace key with nothingness if it was ever used. + */ if (key->sdata) { - /* - * Replace key with nothingness. - * - * Because other code may have key reference (RCU protected) - * right now, we then wait for a grace period before freeing - * it. - * An empty list indicates it was never added to the key list - * or has been removed already. It may, however, still be in - * hardware for acceleration. - */ - if (!list_empty(&key->list)) - __ieee80211_key_replace(key->sdata, key->sta, - key, NULL); + spin_lock_irqsave(&key->sdata->local->sta_lock, flags); + __ieee80211_key_replace(key->sdata, key->sta, + key, NULL); + spin_unlock_irqrestore(&key->sdata->local->sta_lock, flags); + } - /* - * Do NOT remove this without looking at sta_info_destroy() - */ - synchronize_rcu(); + add_todo(key, KEY_FLAG_TODO_DELETE); +} - /* - * Remove from hwaccel if appropriate, this will - * only happen when the key is actually unlinked, - * it will already be done when the key was replaced. - */ - ieee80211_key_disable_hw_accel(key); - } +void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_key *key; - if (key->conf.alg == ALG_CCMP) - ieee80211_aes_key_free(key->u.ccmp.tfm); - ieee80211_debugfs_key_remove(key); + might_sleep(); - kfree(key); + if (WARN_ON(!netif_running(sdata->dev))) + return; + + ieee80211_key_lock(); + + list_for_each_entry(key, &sdata->key_list, list) + ieee80211_key_enable_hw_accel(key); + + ieee80211_key_unlock(); } -void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) +void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) { - struct ieee80211_key *key = NULL; + struct ieee80211_key *key; - if (idx >= 0 && idx < NUM_DEFAULT_KEYS) - key = sdata->keys[idx]; + might_sleep(); - if (sdata->default_key != key) { - ieee80211_debugfs_key_remove_default(sdata); + ieee80211_key_lock(); - rcu_assign_pointer(sdata->default_key, key); + list_for_each_entry(key, &sdata->key_list, list) + ieee80211_key_disable_hw_accel(key); - if (sdata->default_key) - ieee80211_debugfs_key_add_default(sdata); - } + ieee80211_key_unlock(); } -void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) +static void __ieee80211_key_free(struct ieee80211_key *key) { - struct ieee80211_key *key, *tmp; - LIST_HEAD(tmp_list); + if (!key) + return; - ASSERT_RTNL(); - might_sleep(); + ieee80211_key_disable_hw_accel(key); - list_for_each_entry_safe(key, tmp, &sdata->key_list, list) - ieee80211_key_free(key); + if (key->conf.alg == ALG_CCMP) + ieee80211_aes_key_free(key->u.ccmp.tfm); + ieee80211_debugfs_key_remove(key); + + kfree(key); } -void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) +static void __ieee80211_key_todo(void) { struct ieee80211_key *key; + bool work_done; + u32 todoflags; - ASSERT_RTNL(); - might_sleep(); + /* + * NB: sta_info_destroy relies on this! + */ + synchronize_rcu(); + + spin_lock(&todo_lock); + while (!list_empty(&todo_list)) { + key = list_first_entry(&todo_list, struct ieee80211_key, todo); + list_del_init(&key->todo); + todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS | + KEY_FLAG_TODO_DEFKEY | + KEY_FLAG_TODO_HWACCEL | + KEY_FLAG_TODO_DELETE); + key->flags &= ~todoflags; + spin_unlock(&todo_lock); + + work_done = false; + + if (todoflags & KEY_FLAG_TODO_ADD_DEBUGFS) { + ieee80211_debugfs_key_add(key); + work_done = true; + } + if (todoflags & KEY_FLAG_TODO_DEFKEY) { + ieee80211_debugfs_key_remove_default(key->sdata); + ieee80211_debugfs_key_add_default(key->sdata); + work_done = true; + } + if (todoflags & KEY_FLAG_TODO_HWACCEL) { + ieee80211_key_enable_hw_accel(key); + work_done = true; + } + if (todoflags & KEY_FLAG_TODO_DELETE) { + __ieee80211_key_free(key); + work_done = true; + } - if (WARN_ON(!netif_running(sdata->dev))) - return; + WARN_ON(!work_done); - list_for_each_entry(key, &sdata->key_list, list) - ieee80211_key_enable_hw_accel(key); + spin_lock(&todo_lock); + } + spin_unlock(&todo_lock); } -void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) +void ieee80211_key_todo(void) { - struct ieee80211_key *key; + ieee80211_key_lock(); + __ieee80211_key_todo(); + ieee80211_key_unlock(); +} - ASSERT_RTNL(); - might_sleep(); +void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_key *key, *tmp; + LIST_HEAD(tmp_list); - list_for_each_entry(key, &sdata->key_list, list) - ieee80211_key_disable_hw_accel(key); + ieee80211_key_lock(); + + ieee80211_debugfs_key_remove_default(sdata); + + list_for_each_entry_safe(key, tmp, &sdata->key_list, list) + ieee80211_key_free(key); + + __ieee80211_key_todo(); + + ieee80211_key_unlock(); } diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index cedd73a0c875..5540cbf7c445 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -51,17 +51,15 @@ * * In order to remove a STA info structure, the caller needs to first * unlink it (sta_info_unlink()) from the list and hash tables and - * then destroy it while holding the RTNL; sta_info_destroy() will wait - * for an RCU grace period to elapse before actually freeing it. Due to - * the pinning and the possibility of multiple callers trying to remove - * the same STA info at the same time, sta_info_unlink() can clear the - * STA info pointer it is passed to indicate that the STA info is owned - * by somebody else now. + * then destroy it; sta_info_destroy() will wait for an RCU grace period + * to elapse before actually freeing it. Due to the pinning and the + * possibility of multiple callers trying to remove the same STA info at + * the same time, sta_info_unlink() can clear the STA info pointer it is + * passed to indicate that the STA info is owned by somebody else now. * * If sta_info_unlink() did not clear the pointer then the caller owns * the STA info structure now and is responsible of destroying it with - * a call to sta_info_destroy(), not before RCU synchronisation, of - * course. Note that sta_info_destroy() must be protected by the RTNL. + * a call to sta_info_destroy(). * * In all other cases, there is no concept of ownership on a STA entry, * each structure is owned by the global hash table/list until it is @@ -164,7 +162,6 @@ void sta_info_destroy(struct sta_info *sta) struct sk_buff *skb; int i; - ASSERT_RTNL(); might_sleep(); if (!sta) @@ -180,22 +177,16 @@ void sta_info_destroy(struct sta_info *sta) mesh_plink_deactivate(sta); #endif - if (sta->key) { - /* - * NOTE: This will call synchronize_rcu() internally to - * make sure no key references can be in use. We rely on - * that when we take this branch to make sure nobody can - * reference this STA struct any longer! - */ - ieee80211_key_free(sta->key); - WARN_ON(sta->key); - } else { - /* - * Make sure that nobody can reference this STA struct - * any longer. - */ - synchronize_rcu(); - } + /* + * We have only unlinked the key, and actually destroying it + * may mean it is removed from hardware which requires that + * the key->sta pointer is still valid, so flush the key todo + * list here. + * + * ieee80211_key_todo() will synchronize_rcu() so after this + * nothing can reference this sta struct any more. + */ + ieee80211_key_todo(); #ifdef CONFIG_MAC80211_MESH if (ieee80211_vif_is_mesh(&sta->sdata->vif)) @@ -439,6 +430,11 @@ void __sta_info_unlink(struct sta_info **sta) return; } + if ((*sta)->key) { + ieee80211_key_free((*sta)->key); + WARN_ON((*sta)->key); + } + list_del(&(*sta)->list); if ((*sta)->flags & WLAN_STA_PS) { @@ -652,7 +648,7 @@ static void sta_info_debugfs_add_work(struct work_struct *work) } #endif -void __ieee80211_run_pending_flush(struct ieee80211_local *local) +static void __ieee80211_run_pending_flush(struct ieee80211_local *local) { struct sta_info *sta; unsigned long flags; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index ebb7b2b4d0b9..30fd328e9991 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -359,6 +359,5 @@ void sta_info_stop(struct ieee80211_local *local); int sta_info_flush(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata); void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata); -void __ieee80211_run_pending_flush(struct ieee80211_local *local); #endif /* STA_INFO_H */ -- cgit v1.2.3-59-g8ed1b From 2c8dccc77420fb7433da5674818959d3499d35be Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 8 Apr 2008 15:14:40 -0400 Subject: mac80211: rename files This patch renames all mac80211 files (except ieee80211_i.h) to get rid of the useless ieee80211_ prefix. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- drivers/net/wireless/iwlwifi/iwl-3945-rs.c | 2 +- drivers/net/wireless/iwlwifi/iwl-4965-rs.c | 2 +- net/mac80211/Makefile | 12 +- net/mac80211/aes_ccm.c | 2 +- net/mac80211/cfg.c | 2 +- net/mac80211/debugfs.c | 2 +- net/mac80211/debugfs_key.c | 2 +- net/mac80211/debugfs_netdev.c | 2 +- net/mac80211/ieee80211.c | 1889 ------------- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/ieee80211_iface.c | 314 -- net/mac80211/ieee80211_ioctl.c | 1144 -------- net/mac80211/ieee80211_key.h | 157 - net/mac80211/ieee80211_led.c | 161 -- net/mac80211/ieee80211_led.h | 44 - net/mac80211/ieee80211_rate.c | 249 -- net/mac80211/ieee80211_rate.h | 189 -- net/mac80211/ieee80211_sta.c | 4249 ---------------------------- net/mac80211/iface.c | 314 ++ net/mac80211/key.h | 157 + net/mac80211/led.c | 161 ++ net/mac80211/led.h | 44 + net/mac80211/main.c | 1889 +++++++++++++ net/mac80211/mesh_plink.c | 2 +- net/mac80211/mlme.c | 4249 ++++++++++++++++++++++++++++ net/mac80211/rate.c | 249 ++ net/mac80211/rate.h | 189 ++ net/mac80211/rc80211_pid_algo.c | 2 +- net/mac80211/rc80211_pid_debugfs.c | 2 +- net/mac80211/rx.c | 2 +- net/mac80211/sta_info.c | 2 +- net/mac80211/sta_info.h | 2 +- net/mac80211/tkip.c | 2 +- net/mac80211/tkip.h | 2 +- net/mac80211/tx.c | 4 +- net/mac80211/util.c | 2 +- net/mac80211/wep.h | 2 +- net/mac80211/wext.c | 1144 ++++++++ 38 files changed, 8422 insertions(+), 8422 deletions(-) delete mode 100644 net/mac80211/ieee80211.c delete mode 100644 net/mac80211/ieee80211_iface.c delete mode 100644 net/mac80211/ieee80211_ioctl.c delete mode 100644 net/mac80211/ieee80211_key.h delete mode 100644 net/mac80211/ieee80211_led.c delete mode 100644 net/mac80211/ieee80211_led.h delete mode 100644 net/mac80211/ieee80211_rate.c delete mode 100644 net/mac80211/ieee80211_rate.h delete mode 100644 net/mac80211/ieee80211_sta.c create mode 100644 net/mac80211/iface.c create mode 100644 net/mac80211/key.h create mode 100644 net/mac80211/led.c create mode 100644 net/mac80211/led.h create mode 100644 net/mac80211/main.c create mode 100644 net/mac80211/mlme.c create mode 100644 net/mac80211/rate.c create mode 100644 net/mac80211/rate.h create mode 100644 net/mac80211/wext.c (limited to 'net') diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 8559f252a55f..85c22641542d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -37,7 +37,7 @@ #include -#include "../net/mac80211/ieee80211_rate.h" +#include "../net/mac80211/rate.h" #include "iwl-3945.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c index 32eb414899d6..315b0433801e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965-rs.c @@ -36,7 +36,7 @@ #include -#include "../net/mac80211/ieee80211_rate.h" +#include "../net/mac80211/rate.h" #include "iwl-4965.h" #include "iwl-core.h" diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 70f4b26c2d87..4e5847fd316c 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -10,14 +10,14 @@ rc-pid-m := rc80211_pid.o # mac80211 objects mac80211-y := \ - ieee80211.o \ - ieee80211_ioctl.o \ + main.o \ + wext.o \ sta_info.o \ wep.o \ wpa.o \ - ieee80211_sta.o \ - ieee80211_iface.o \ - ieee80211_rate.o \ + mlme.o \ + iface.o \ + rate.o \ michael.o \ tkip.o \ aes_ccm.o \ @@ -28,7 +28,7 @@ mac80211-y := \ util.o \ event.o -mac80211-$(CONFIG_MAC80211_LEDS) += ieee80211_led.o +mac80211-$(CONFIG_MAC80211_LEDS) += led.o mac80211-$(CONFIG_NET_SCHED) += wme.o mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ debugfs.o \ diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c index e62fe55944b8..59f1691f62c8 100644 --- a/net/mac80211/aes_ccm.c +++ b/net/mac80211/aes_ccm.c @@ -13,7 +13,7 @@ #include #include -#include "ieee80211_key.h" +#include "key.h" #include "aes_ccm.h" diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index fe05a7b85dc6..8af576c1d2f1 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -14,7 +14,7 @@ #include #include "ieee80211_i.h" #include "cfg.h" -#include "ieee80211_rate.h" +#include "rate.h" #include "mesh.h" static enum ieee80211_if_types diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index f4bb08b62d1a..1cccbfd781f6 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -10,7 +10,7 @@ #include #include #include "ieee80211_i.h" -#include "ieee80211_rate.h" +#include "rate.h" #include "debugfs.h" int mac80211_open_file_generic(struct inode *inode, struct file *file) diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 459f0767fae5..bf7027e9ce9f 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -10,7 +10,7 @@ #include #include "ieee80211_i.h" -#include "ieee80211_key.h" +#include "key.h" #include "debugfs.h" #include "debugfs_key.h" diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 55cd6fc3f2e0..e3326d046944 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -17,7 +17,7 @@ #include #include #include "ieee80211_i.h" -#include "ieee80211_rate.h" +#include "rate.h" #include "debugfs.h" #include "debugfs_netdev.h" diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c deleted file mode 100644 index dbe993af8034..000000000000 --- a/net/mac80211/ieee80211.c +++ /dev/null @@ -1,1889 +0,0 @@ -/* - * Copyright 2002-2005, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * Copyright 2006-2007 Jiri Benc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ieee80211_i.h" -#include "ieee80211_rate.h" -#include "mesh.h" -#include "wep.h" -#include "wme.h" -#include "aes_ccm.h" -#include "ieee80211_led.h" -#include "cfg.h" -#include "debugfs.h" -#include "debugfs_netdev.h" - -#define SUPP_MCS_SET_LEN 16 - -/* - * For seeing transmitted packets on monitor interfaces - * we have a radiotap header too. - */ -struct ieee80211_tx_status_rtap_hdr { - struct ieee80211_radiotap_header hdr; - __le16 tx_flags; - u8 data_retries; -} __attribute__ ((packed)); - -/* common interface routines */ - -static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) -{ - memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ - return ETH_ALEN; -} - -/* must be called under mdev tx lock */ -static void ieee80211_configure_filter(struct ieee80211_local *local) -{ - unsigned int changed_flags; - unsigned int new_flags = 0; - - if (atomic_read(&local->iff_promiscs)) - new_flags |= FIF_PROMISC_IN_BSS; - - if (atomic_read(&local->iff_allmultis)) - new_flags |= FIF_ALLMULTI; - - if (local->monitors) - new_flags |= FIF_BCN_PRBRESP_PROMISC; - - if (local->fif_fcsfail) - new_flags |= FIF_FCSFAIL; - - if (local->fif_plcpfail) - new_flags |= FIF_PLCPFAIL; - - if (local->fif_control) - new_flags |= FIF_CONTROL; - - if (local->fif_other_bss) - new_flags |= FIF_OTHER_BSS; - - changed_flags = local->filter_flags ^ new_flags; - - /* be a bit nasty */ - new_flags |= (1<<31); - - local->ops->configure_filter(local_to_hw(local), - changed_flags, &new_flags, - local->mdev->mc_count, - local->mdev->mc_list); - - WARN_ON(new_flags & (1<<31)); - - local->filter_flags = new_flags & ~(1<<31); -} - -/* master interface */ - -static int ieee80211_master_open(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; - int res = -EOPNOTSUPP; - - /* we hold the RTNL here so can safely walk the list */ - list_for_each_entry(sdata, &local->interfaces, list) { - if (sdata->dev != dev && netif_running(sdata->dev)) { - res = 0; - break; - } - } - return res; -} - -static int ieee80211_master_stop(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; - - /* we hold the RTNL here so can safely walk the list */ - list_for_each_entry(sdata, &local->interfaces, list) - if (sdata->dev != dev && netif_running(sdata->dev)) - dev_close(sdata->dev); - - return 0; -} - -static void ieee80211_master_set_multicast_list(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - ieee80211_configure_filter(local); -} - -/* regular interfaces */ - -static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) -{ - int meshhdrlen; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - meshhdrlen = (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) ? 5 : 0; - - /* FIX: what would be proper limits for MTU? - * This interface uses 802.3 frames. */ - if (new_mtu < 256 || - new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) { - printk(KERN_WARNING "%s: invalid MTU %d\n", - dev->name, new_mtu); - return -EINVAL; - } - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ - dev->mtu = new_mtu; - return 0; -} - -static inline int identical_mac_addr_allowed(int type1, int type2) -{ - return (type1 == IEEE80211_IF_TYPE_MNTR || - type2 == IEEE80211_IF_TYPE_MNTR || - (type1 == IEEE80211_IF_TYPE_AP && - type2 == IEEE80211_IF_TYPE_WDS) || - (type1 == IEEE80211_IF_TYPE_WDS && - (type2 == IEEE80211_IF_TYPE_WDS || - type2 == IEEE80211_IF_TYPE_AP)) || - (type1 == IEEE80211_IF_TYPE_AP && - type2 == IEEE80211_IF_TYPE_VLAN) || - (type1 == IEEE80211_IF_TYPE_VLAN && - (type2 == IEEE80211_IF_TYPE_AP || - type2 == IEEE80211_IF_TYPE_VLAN))); -} - -static int ieee80211_open(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata, *nsdata; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_if_init_conf conf; - int res; - bool need_hw_reconfig = 0; - struct sta_info *sta; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - /* we hold the RTNL here so can safely walk the list */ - list_for_each_entry(nsdata, &local->interfaces, list) { - struct net_device *ndev = nsdata->dev; - - if (ndev != dev && ndev != local->mdev && netif_running(ndev)) { - /* - * Allow only a single IBSS interface to be up at any - * time. This is restricted because beacon distribution - * cannot work properly if both are in the same IBSS. - * - * To remove this restriction we'd have to disallow them - * from setting the same SSID on different IBSS interfaces - * belonging to the same hardware. Then, however, we're - * faced with having to adopt two different TSF timers... - */ - if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && - nsdata->vif.type == IEEE80211_IF_TYPE_IBSS) - return -EBUSY; - - /* - * Disallow multiple IBSS/STA mode interfaces. - * - * This is a technical restriction, it is possible although - * most likely not IEEE 802.11 compliant to have multiple - * STAs with just a single hardware (the TSF timer will not - * be adjusted properly.) - * - * However, because mac80211 uses the master device's BSS - * information for each STA/IBSS interface, doing this will - * currently corrupt that BSS information completely, unless, - * a not very useful case, both STAs are associated to the - * same BSS. - * - * To remove this restriction, the BSS information needs to - * be embedded in the STA/IBSS mode sdata instead of using - * the master device's BSS structure. - */ - if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) && - (nsdata->vif.type == IEEE80211_IF_TYPE_STA || - nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)) - return -EBUSY; - - /* - * The remaining checks are only performed for interfaces - * with the same MAC address. - */ - if (compare_ether_addr(dev->dev_addr, ndev->dev_addr)) - continue; - - /* - * check whether it may have the same address - */ - if (!identical_mac_addr_allowed(sdata->vif.type, - nsdata->vif.type)) - return -ENOTUNIQ; - - /* - * can only add VLANs to enabled APs - */ - if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN && - nsdata->vif.type == IEEE80211_IF_TYPE_AP) - sdata->u.vlan.ap = nsdata; - } - } - - switch (sdata->vif.type) { - case IEEE80211_IF_TYPE_WDS: - if (is_zero_ether_addr(sdata->u.wds.remote_addr)) - return -ENOLINK; - - /* Create STA entry for the WDS peer */ - sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, - GFP_KERNEL); - if (!sta) - return -ENOMEM; - - sta->flags |= WLAN_STA_AUTHORIZED; - - res = sta_info_insert(sta); - if (res) { - /* STA has been freed */ - return res; - } - break; - case IEEE80211_IF_TYPE_VLAN: - if (!sdata->u.vlan.ap) - return -ENOLINK; - break; - case IEEE80211_IF_TYPE_AP: - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_MNTR: - case IEEE80211_IF_TYPE_IBSS: - case IEEE80211_IF_TYPE_MESH_POINT: - /* no special treatment */ - break; - case IEEE80211_IF_TYPE_INVALID: - /* cannot happen */ - WARN_ON(1); - break; - } - - if (local->open_count == 0) { - res = 0; - if (local->ops->start) - res = local->ops->start(local_to_hw(local)); - if (res) - return res; - need_hw_reconfig = 1; - ieee80211_led_radio(local, local->hw.conf.radio_enabled); - } - - switch (sdata->vif.type) { - case IEEE80211_IF_TYPE_VLAN: - list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans); - /* no need to tell driver */ - break; - case IEEE80211_IF_TYPE_MNTR: - if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { - local->cooked_mntrs++; - break; - } - - /* must be before the call to ieee80211_configure_filter */ - local->monitors++; - if (local->monitors == 1) - local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; - - if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) - local->fif_fcsfail++; - if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) - local->fif_plcpfail++; - if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) - local->fif_control++; - if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) - local->fif_other_bss++; - - netif_tx_lock_bh(local->mdev); - ieee80211_configure_filter(local); - netif_tx_unlock_bh(local->mdev); - break; - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: - sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; - /* fall through */ - default: - conf.vif = &sdata->vif; - conf.type = sdata->vif.type; - conf.mac_addr = dev->dev_addr; - res = local->ops->add_interface(local_to_hw(local), &conf); - if (res && !local->open_count && local->ops->stop) - local->ops->stop(local_to_hw(local)); - if (res) - return res; - - ieee80211_if_config(dev); - ieee80211_reset_erp_info(dev); - ieee80211_enable_keys(sdata); - - if (sdata->vif.type == IEEE80211_IF_TYPE_STA && - !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) - netif_carrier_off(dev); - else - netif_carrier_on(dev); - } - - if (local->open_count == 0) { - res = dev_open(local->mdev); - WARN_ON(res); - tasklet_enable(&local->tx_pending_tasklet); - tasklet_enable(&local->tasklet); - } - - /* - * set_multicast_list will be invoked by the networking core - * which will check whether any increments here were done in - * error and sync them down to the hardware as filter flags. - */ - if (sdata->flags & IEEE80211_SDATA_ALLMULTI) - atomic_inc(&local->iff_allmultis); - - if (sdata->flags & IEEE80211_SDATA_PROMISC) - atomic_inc(&local->iff_promiscs); - - local->open_count++; - if (need_hw_reconfig) - ieee80211_hw_config(local); - - /* - * ieee80211_sta_work is disabled while network interface - * is down. Therefore, some configuration changes may not - * yet be effective. Trigger execution of ieee80211_sta_work - * to fix this. - */ - if(sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { - struct ieee80211_if_sta *ifsta = &sdata->u.sta; - queue_work(local->hw.workqueue, &ifsta->work); - } - - netif_start_queue(dev); - - return 0; -} - -static int ieee80211_stop(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; - struct ieee80211_if_init_conf conf; - struct sta_info *sta; - - /* - * Stop TX on this interface first. - */ - netif_stop_queue(dev); - - /* - * Now delete all active aggregation sessions. - */ - rcu_read_lock(); - - list_for_each_entry_rcu(sta, &local->sta_list, list) { - if (sta->sdata == sdata) - ieee80211_sta_tear_down_BA_sessions(dev, sta->addr); - } - - rcu_read_unlock(); - - /* - * Remove all stations associated with this interface. - * - * This must be done before calling ops->remove_interface() - * because otherwise we can later invoke ops->sta_notify() - * whenever the STAs are removed, and that invalidates driver - * assumptions about always getting a vif pointer that is valid - * (because if we remove a STA after ops->remove_interface() - * the driver will have removed the vif info already!) - * - * We could relax this and only unlink the stations from the - * hash table and list but keep them on a per-sdata list that - * will be inserted back again when the interface is brought - * up again, but I don't currently see a use case for that, - * except with WDS which gets a STA entry created when it is - * brought up. - */ - sta_info_flush(local, sdata); - - /* - * Don't count this interface for promisc/allmulti while it - * is down. dev_mc_unsync() will invoke set_multicast_list - * on the master interface which will sync these down to the - * hardware as filter flags. - */ - if (sdata->flags & IEEE80211_SDATA_ALLMULTI) - atomic_dec(&local->iff_allmultis); - - if (sdata->flags & IEEE80211_SDATA_PROMISC) - atomic_dec(&local->iff_promiscs); - - dev_mc_unsync(local->mdev, dev); - - /* APs need special treatment */ - if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { - struct ieee80211_sub_if_data *vlan, *tmp; - struct beacon_data *old_beacon = sdata->u.ap.beacon; - - /* remove beacon */ - rcu_assign_pointer(sdata->u.ap.beacon, NULL); - synchronize_rcu(); - kfree(old_beacon); - - /* down all dependent devices, that is VLANs */ - list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans, - u.vlan.list) - dev_close(vlan->dev); - WARN_ON(!list_empty(&sdata->u.ap.vlans)); - } - - local->open_count--; - - switch (sdata->vif.type) { - case IEEE80211_IF_TYPE_VLAN: - list_del(&sdata->u.vlan.list); - sdata->u.vlan.ap = NULL; - /* no need to tell driver */ - break; - case IEEE80211_IF_TYPE_MNTR: - if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { - local->cooked_mntrs--; - break; - } - - local->monitors--; - if (local->monitors == 0) - local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; - - if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) - local->fif_fcsfail--; - if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) - local->fif_plcpfail--; - if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) - local->fif_control--; - if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) - local->fif_other_bss--; - - netif_tx_lock_bh(local->mdev); - ieee80211_configure_filter(local); - netif_tx_unlock_bh(local->mdev); - break; - case IEEE80211_IF_TYPE_MESH_POINT: - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: - sdata->u.sta.state = IEEE80211_DISABLED; - del_timer_sync(&sdata->u.sta.timer); - /* - * When we get here, the interface is marked down. - * Call synchronize_rcu() to wait for the RX path - * should it be using the interface and enqueuing - * frames at this very time on another CPU. - */ - synchronize_rcu(); - skb_queue_purge(&sdata->u.sta.skb_queue); - - if (local->scan_dev == sdata->dev) { - if (!local->ops->hw_scan) { - local->sta_sw_scanning = 0; - cancel_delayed_work(&local->scan_work); - } else - local->sta_hw_scanning = 0; - } - - flush_workqueue(local->hw.workqueue); - - sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; - kfree(sdata->u.sta.extra_ie); - sdata->u.sta.extra_ie = NULL; - sdata->u.sta.extra_ie_len = 0; - /* fall through */ - default: - conf.vif = &sdata->vif; - conf.type = sdata->vif.type; - conf.mac_addr = dev->dev_addr; - /* disable all keys for as long as this netdev is down */ - ieee80211_disable_keys(sdata); - local->ops->remove_interface(local_to_hw(local), &conf); - } - - if (local->open_count == 0) { - if (netif_running(local->mdev)) - dev_close(local->mdev); - - if (local->ops->stop) - local->ops->stop(local_to_hw(local)); - - ieee80211_led_radio(local, 0); - - tasklet_disable(&local->tx_pending_tasklet); - tasklet_disable(&local->tasklet); - } - - return 0; -} - -int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct sta_info *sta; - struct ieee80211_sub_if_data *sdata; - u16 start_seq_num = 0; - u8 *state; - int ret; - DECLARE_MAC_BUF(mac); - - if (tid >= STA_TID_NUM) - return -EINVAL; - -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Open BA session requested for %s tid %u\n", - print_mac(mac, ra), tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - - rcu_read_lock(); - - sta = sta_info_get(local, ra); - if (!sta) { - printk(KERN_DEBUG "Could not find the station\n"); - rcu_read_unlock(); - return -ENOENT; - } - - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); - - /* we have tried too many times, receiver does not want A-MPDU */ - if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { - ret = -EBUSY; - goto start_ba_exit; - } - - state = &sta->ampdu_mlme.tid_state_tx[tid]; - /* check if the TID is not in aggregation flow already */ - if (*state != HT_AGG_STATE_IDLE) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "BA request denied - session is not " - "idle on tid %u\n", tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - ret = -EAGAIN; - goto start_ba_exit; - } - - /* prepare A-MPDU MLME for Tx aggregation */ - sta->ampdu_mlme.tid_tx[tid] = - kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); - if (!sta->ampdu_mlme.tid_tx[tid]) { - if (net_ratelimit()) - printk(KERN_ERR "allocate tx mlme to tid %d failed\n", - tid); - ret = -ENOMEM; - goto start_ba_exit; - } - /* Tx timer */ - sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = - sta_addba_resp_timer_expired; - sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data = - (unsigned long)&sta->timer_to_tid[tid]; - init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); - - /* ensure that TX flow won't interrupt us - * until the end of the call to requeue function */ - spin_lock_bh(&local->mdev->queue_lock); - - /* create a new queue for this aggregation */ - ret = ieee80211_ht_agg_queue_add(local, sta, tid); - - /* case no queue is available to aggregation - * don't switch to aggregation */ - if (ret) { -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "BA request denied - queue unavailable for" - " tid %d\n", tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - goto start_ba_err; - } - sdata = sta->sdata; - - /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the - * call back right away, it must see that the flow has begun */ - *state |= HT_ADDBA_REQUESTED_MSK; - - if (local->ops->ampdu_action) - ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, - ra, tid, &start_seq_num); - - if (ret) { - /* No need to requeue the packets in the agg queue, since we - * held the tx lock: no packet could be enqueued to the newly - * allocated queue */ - ieee80211_ht_agg_queue_remove(local, sta, tid, 0); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "BA request denied - HW unavailable for" - " tid %d\n", tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - *state = HT_AGG_STATE_IDLE; - goto start_ba_err; - } - - /* Will put all the packets in the new SW queue */ - ieee80211_requeue(local, ieee802_1d_to_ac[tid]); - spin_unlock_bh(&local->mdev->queue_lock); - - /* send an addBA request */ - sta->ampdu_mlme.dialog_token_allocator++; - sta->ampdu_mlme.tid_tx[tid]->dialog_token = - sta->ampdu_mlme.dialog_token_allocator; - sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; - - ieee80211_send_addba_request(sta->sdata->dev, ra, tid, - sta->ampdu_mlme.tid_tx[tid]->dialog_token, - sta->ampdu_mlme.tid_tx[tid]->ssn, - 0x40, 5000); - - /* activate the timer for the recipient's addBA response */ - sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = - jiffies + ADDBA_RESP_INTERVAL; - add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); - printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); - goto start_ba_exit; - -start_ba_err: - kfree(sta->ampdu_mlme.tid_tx[tid]); - sta->ampdu_mlme.tid_tx[tid] = NULL; - spin_unlock_bh(&local->mdev->queue_lock); - ret = -EBUSY; -start_ba_exit: - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - rcu_read_unlock(); - return ret; -} -EXPORT_SYMBOL(ieee80211_start_tx_ba_session); - -int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, - u8 *ra, u16 tid, - enum ieee80211_back_parties initiator) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct sta_info *sta; - u8 *state; - int ret = 0; - DECLARE_MAC_BUF(mac); - - if (tid >= STA_TID_NUM) - return -EINVAL; - - rcu_read_lock(); - sta = sta_info_get(local, ra); - if (!sta) { - rcu_read_unlock(); - return -ENOENT; - } - - /* check if the TID is in aggregation */ - state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); - - if (*state != HT_AGG_STATE_OPERATIONAL) { - ret = -ENOENT; - goto stop_BA_exit; - } - -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Tx BA session stop requested for %s tid %u\n", - print_mac(mac, ra), tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - - ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); - - *state = HT_AGG_STATE_REQ_STOP_BA_MSK | - (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - - if (local->ops->ampdu_action) - ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP, - ra, tid, NULL); - - /* case HW denied going back to legacy */ - if (ret) { - WARN_ON(ret != -EBUSY); - *state = HT_AGG_STATE_OPERATIONAL; - ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); - goto stop_BA_exit; - } - -stop_BA_exit: - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - rcu_read_unlock(); - return ret; -} -EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); - -void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct sta_info *sta; - u8 *state; - DECLARE_MAC_BUF(mac); - - if (tid >= STA_TID_NUM) { - printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", - tid, STA_TID_NUM); - return; - } - - rcu_read_lock(); - sta = sta_info_get(local, ra); - if (!sta) { - rcu_read_unlock(); - printk(KERN_DEBUG "Could not find station: %s\n", - print_mac(mac, ra)); - return; - } - - state = &sta->ampdu_mlme.tid_state_tx[tid]; - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); - - if (!(*state & HT_ADDBA_REQUESTED_MSK)) { - printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", - *state); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - rcu_read_unlock(); - return; - } - - WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); - - *state |= HT_ADDBA_DRV_READY_MSK; - - if (*state == HT_AGG_STATE_OPERATIONAL) { - printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); - ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); - } - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - rcu_read_unlock(); -} -EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); - -void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct sta_info *sta; - u8 *state; - int agg_queue; - DECLARE_MAC_BUF(mac); - - if (tid >= STA_TID_NUM) { - printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", - tid, STA_TID_NUM); - return; - } - -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Stopping Tx BA session for %s tid %d\n", - print_mac(mac, ra), tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - - rcu_read_lock(); - sta = sta_info_get(local, ra); - if (!sta) { - printk(KERN_DEBUG "Could not find station: %s\n", - print_mac(mac, ra)); - rcu_read_unlock(); - return; - } - state = &sta->ampdu_mlme.tid_state_tx[tid]; - - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); - if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { - printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - rcu_read_unlock(); - return; - } - - if (*state & HT_AGG_STATE_INITIATOR_MSK) - ieee80211_send_delba(sta->sdata->dev, ra, tid, - WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); - - agg_queue = sta->tid_to_tx_q[tid]; - - /* avoid ordering issues: we are the only one that can modify - * the content of the qdiscs */ - spin_lock_bh(&local->mdev->queue_lock); - /* remove the queue for this aggregation */ - ieee80211_ht_agg_queue_remove(local, sta, tid, 1); - spin_unlock_bh(&local->mdev->queue_lock); - - /* we just requeued the all the frames that were in the removed - * queue, and since we might miss a softirq we do netif_schedule. - * ieee80211_wake_queue is not used here as this queue is not - * necessarily stopped */ - netif_schedule(local->mdev); - *state = HT_AGG_STATE_IDLE; - sta->ampdu_mlme.addba_req_num[tid] = 0; - kfree(sta->ampdu_mlme.tid_tx[tid]); - sta->ampdu_mlme.tid_tx[tid] = NULL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - - rcu_read_unlock(); -} -EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); - -void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, - const u8 *ra, u16 tid) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_ra_tid *ra_tid; - struct sk_buff *skb = dev_alloc_skb(0); - - if (unlikely(!skb)) { - if (net_ratelimit()) - printk(KERN_WARNING "%s: Not enough memory, " - "dropping start BA session", skb->dev->name); - return; - } - ra_tid = (struct ieee80211_ra_tid *) &skb->cb; - memcpy(&ra_tid->ra, ra, ETH_ALEN); - ra_tid->tid = tid; - - skb->pkt_type = IEEE80211_ADDBA_MSG; - skb_queue_tail(&local->skb_queue, skb); - tasklet_schedule(&local->tasklet); -} -EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); - -void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, - const u8 *ra, u16 tid) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_ra_tid *ra_tid; - struct sk_buff *skb = dev_alloc_skb(0); - - if (unlikely(!skb)) { - if (net_ratelimit()) - printk(KERN_WARNING "%s: Not enough memory, " - "dropping stop BA session", skb->dev->name); - return; - } - ra_tid = (struct ieee80211_ra_tid *) &skb->cb; - memcpy(&ra_tid->ra, ra, ETH_ALEN); - ra_tid->tid = tid; - - skb->pkt_type = IEEE80211_DELBA_MSG; - skb_queue_tail(&local->skb_queue, skb); - tasklet_schedule(&local->tasklet); -} -EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); - -static void ieee80211_set_multicast_list(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int allmulti, promisc, sdata_allmulti, sdata_promisc; - - allmulti = !!(dev->flags & IFF_ALLMULTI); - promisc = !!(dev->flags & IFF_PROMISC); - sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI); - sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC); - - if (allmulti != sdata_allmulti) { - if (dev->flags & IFF_ALLMULTI) - atomic_inc(&local->iff_allmultis); - else - atomic_dec(&local->iff_allmultis); - sdata->flags ^= IEEE80211_SDATA_ALLMULTI; - } - - if (promisc != sdata_promisc) { - if (dev->flags & IFF_PROMISC) - atomic_inc(&local->iff_promiscs); - else - atomic_dec(&local->iff_promiscs); - sdata->flags ^= IEEE80211_SDATA_PROMISC; - } - - dev_mc_sync(local->mdev, dev); -} - -static const struct header_ops ieee80211_header_ops = { - .create = eth_header, - .parse = header_parse_80211, - .rebuild = eth_rebuild_header, - .cache = eth_header_cache, - .cache_update = eth_header_cache_update, -}; - -/* Must not be called for mdev */ -void ieee80211_if_setup(struct net_device *dev) -{ - ether_setup(dev); - dev->hard_start_xmit = ieee80211_subif_start_xmit; - dev->wireless_handlers = &ieee80211_iw_handler_def; - dev->set_multicast_list = ieee80211_set_multicast_list; - dev->change_mtu = ieee80211_change_mtu; - dev->open = ieee80211_open; - dev->stop = ieee80211_stop; - dev->destructor = ieee80211_if_free; -} - -/* everything else */ - -static int __ieee80211_if_config(struct net_device *dev, - struct sk_buff *beacon, - struct ieee80211_tx_control *control) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_if_conf conf; - - if (!local->ops->config_interface || !netif_running(dev)) - return 0; - - memset(&conf, 0, sizeof(conf)); - conf.type = sdata->vif.type; - if (sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { - conf.bssid = sdata->u.sta.bssid; - conf.ssid = sdata->u.sta.ssid; - conf.ssid_len = sdata->u.sta.ssid_len; - } else if (ieee80211_vif_is_mesh(&sdata->vif)) { - conf.beacon = beacon; - ieee80211_start_mesh(dev); - } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { - conf.ssid = sdata->u.ap.ssid; - conf.ssid_len = sdata->u.ap.ssid_len; - conf.beacon = beacon; - conf.beacon_control = control; - } - return local->ops->config_interface(local_to_hw(local), - &sdata->vif, &conf); -} - -int ieee80211_if_config(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && - (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) - return ieee80211_if_config_beacon(dev); - return __ieee80211_if_config(dev, NULL, NULL); -} - -int ieee80211_if_config_beacon(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_control control; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct sk_buff *skb; - - if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) - return 0; - skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif, - &control); - if (!skb) - return -ENOMEM; - return __ieee80211_if_config(dev, skb, &control); -} - -int ieee80211_hw_config(struct ieee80211_local *local) -{ - struct ieee80211_channel *chan; - int ret = 0; - - if (local->sta_sw_scanning) - chan = local->scan_channel; - else - chan = local->oper_channel; - - local->hw.conf.channel = chan; - - if (!local->hw.conf.power_level) - local->hw.conf.power_level = chan->max_power; - else - local->hw.conf.power_level = min(chan->max_power, - local->hw.conf.power_level); - - local->hw.conf.max_antenna_gain = chan->max_antenna_gain; - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n", - wiphy_name(local->hw.wiphy), chan->center_freq); -#endif - - if (local->open_count) - ret = local->ops->config(local_to_hw(local), &local->hw.conf); - - return ret; -} - -/** - * ieee80211_handle_ht should be used only after legacy configuration - * has been determined namely band, as ht configuration depends upon - * the hardware's HT abilities for a _specific_ band. - */ -u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, - struct ieee80211_ht_info *req_ht_cap, - struct ieee80211_ht_bss_info *req_bss_cap) -{ - struct ieee80211_conf *conf = &local->hw.conf; - struct ieee80211_supported_band *sband; - struct ieee80211_ht_info ht_conf; - struct ieee80211_ht_bss_info ht_bss_conf; - int i; - u32 changed = 0; - - sband = local->hw.wiphy->bands[conf->channel->band]; - - /* HT is not supported */ - if (!sband->ht_info.ht_supported) { - conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; - return 0; - } - - memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info)); - memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); - - if (enable_ht) { - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) - changed |= BSS_CHANGED_HT; - - conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; - ht_conf.ht_supported = 1; - - ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; - ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); - ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; - - for (i = 0; i < SUPP_MCS_SET_LEN; i++) - ht_conf.supp_mcs_set[i] = - sband->ht_info.supp_mcs_set[i] & - req_ht_cap->supp_mcs_set[i]; - - ht_bss_conf.primary_channel = req_bss_cap->primary_channel; - ht_bss_conf.bss_cap = req_bss_cap->bss_cap; - ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; - - ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; - ht_conf.ampdu_density = req_ht_cap->ampdu_density; - - /* if bss configuration changed store the new one */ - if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) || - memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { - changed |= BSS_CHANGED_HT; - memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf)); - memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); - } - } else { - if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) - changed |= BSS_CHANGED_HT; - conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; - } - - return changed; -} - -void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, - u32 changed) -{ - struct ieee80211_local *local = sdata->local; - - if (!changed) - return; - - if (local->ops->bss_info_changed) - local->ops->bss_info_changed(local_to_hw(local), - &sdata->vif, - &sdata->bss_conf, - changed); -} - -void ieee80211_reset_erp_info(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - sdata->bss_conf.use_cts_prot = 0; - sdata->bss_conf.use_short_preamble = 0; - ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_ERP_CTS_PROT | - BSS_CHANGED_ERP_PREAMBLE); -} - -void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, - struct sk_buff *skb, - struct ieee80211_tx_status *status) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_tx_status *saved; - int tmp; - - skb->dev = local->mdev; - saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC); - if (unlikely(!saved)) { - if (net_ratelimit()) - printk(KERN_WARNING "%s: Not enough memory, " - "dropping tx status", skb->dev->name); - /* should be dev_kfree_skb_irq, but due to this function being - * named _irqsafe instead of just _irq we can't be sure that - * people won't call it from non-irq contexts */ - dev_kfree_skb_any(skb); - return; - } - memcpy(saved, status, sizeof(struct ieee80211_tx_status)); - /* copy pointer to saved status into skb->cb for use by tasklet */ - memcpy(skb->cb, &saved, sizeof(saved)); - - skb->pkt_type = IEEE80211_TX_STATUS_MSG; - skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ? - &local->skb_queue : &local->skb_queue_unreliable, skb); - tmp = skb_queue_len(&local->skb_queue) + - skb_queue_len(&local->skb_queue_unreliable); - while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT && - (skb = skb_dequeue(&local->skb_queue_unreliable))) { - memcpy(&saved, skb->cb, sizeof(saved)); - kfree(saved); - dev_kfree_skb_irq(skb); - tmp--; - I802_DEBUG_INC(local->tx_status_drop); - } - tasklet_schedule(&local->tasklet); -} -EXPORT_SYMBOL(ieee80211_tx_status_irqsafe); - -static void ieee80211_tasklet_handler(unsigned long data) -{ - struct ieee80211_local *local = (struct ieee80211_local *) data; - struct sk_buff *skb; - struct ieee80211_rx_status rx_status; - struct ieee80211_tx_status *tx_status; - struct ieee80211_ra_tid *ra_tid; - - while ((skb = skb_dequeue(&local->skb_queue)) || - (skb = skb_dequeue(&local->skb_queue_unreliable))) { - switch (skb->pkt_type) { - case IEEE80211_RX_MSG: - /* status is in skb->cb */ - memcpy(&rx_status, skb->cb, sizeof(rx_status)); - /* Clear skb->pkt_type in order to not confuse kernel - * netstack. */ - skb->pkt_type = 0; - __ieee80211_rx(local_to_hw(local), skb, &rx_status); - break; - case IEEE80211_TX_STATUS_MSG: - /* get pointer to saved status out of skb->cb */ - memcpy(&tx_status, skb->cb, sizeof(tx_status)); - skb->pkt_type = 0; - ieee80211_tx_status(local_to_hw(local), - skb, tx_status); - kfree(tx_status); - break; - case IEEE80211_DELBA_MSG: - ra_tid = (struct ieee80211_ra_tid *) &skb->cb; - ieee80211_stop_tx_ba_cb(local_to_hw(local), - ra_tid->ra, ra_tid->tid); - dev_kfree_skb(skb); - break; - case IEEE80211_ADDBA_MSG: - ra_tid = (struct ieee80211_ra_tid *) &skb->cb; - ieee80211_start_tx_ba_cb(local_to_hw(local), - ra_tid->ra, ra_tid->tid); - dev_kfree_skb(skb); - break ; - default: /* should never get here! */ - printk(KERN_ERR "%s: Unknown message type (%d)\n", - wiphy_name(local->hw.wiphy), skb->pkt_type); - dev_kfree_skb(skb); - break; - } - } -} - -/* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to - * make a prepared TX frame (one that has been given to hw) to look like brand - * new IEEE 802.11 frame that is ready to go through TX processing again. - * Also, tx_packet_data in cb is restored from tx_control. */ -static void ieee80211_remove_tx_extra(struct ieee80211_local *local, - struct ieee80211_key *key, - struct sk_buff *skb, - struct ieee80211_tx_control *control) -{ - int hdrlen, iv_len, mic_len; - struct ieee80211_tx_packet_data *pkt_data; - - pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; - pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex; - pkt_data->flags = 0; - if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS) - pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; - if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT) - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; - if (control->flags & IEEE80211_TXCTL_REQUEUE) - pkt_data->flags |= IEEE80211_TXPD_REQUEUE; - if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME) - pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; - pkt_data->queue = control->queue; - - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - - if (!key) - goto no_key; - - switch (key->conf.alg) { - case ALG_WEP: - iv_len = WEP_IV_LEN; - mic_len = WEP_ICV_LEN; - break; - case ALG_TKIP: - iv_len = TKIP_IV_LEN; - mic_len = TKIP_ICV_LEN; - break; - case ALG_CCMP: - iv_len = CCMP_HDR_LEN; - mic_len = CCMP_MIC_LEN; - break; - default: - goto no_key; - } - - if (skb->len >= mic_len && - !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) - skb_trim(skb, skb->len - mic_len); - if (skb->len >= iv_len && skb->len > hdrlen) { - memmove(skb->data + iv_len, skb->data, hdrlen); - skb_pull(skb, iv_len); - } - -no_key: - { - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - u16 fc = le16_to_cpu(hdr->frame_control); - if ((fc & 0x8C) == 0x88) /* QoS Control Field */ { - fc &= ~IEEE80211_STYPE_QOS_DATA; - hdr->frame_control = cpu_to_le16(fc); - memmove(skb->data + 2, skb->data, hdrlen - 2); - skb_pull(skb, 2); - } - } -} - -static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, - struct sta_info *sta, - struct sk_buff *skb, - struct ieee80211_tx_status *status) -{ - sta->tx_filtered_count++; - - /* - * Clear the TX filter mask for this STA when sending the next - * packet. If the STA went to power save mode, this will happen - * happen when it wakes up for the next time. - */ - sta->flags |= WLAN_STA_CLEAR_PS_FILT; - - /* - * This code races in the following way: - * - * (1) STA sends frame indicating it will go to sleep and does so - * (2) hardware/firmware adds STA to filter list, passes frame up - * (3) hardware/firmware processes TX fifo and suppresses a frame - * (4) we get TX status before having processed the frame and - * knowing that the STA has gone to sleep. - * - * This is actually quite unlikely even when both those events are - * processed from interrupts coming in quickly after one another or - * even at the same time because we queue both TX status events and - * RX frames to be processed by a tasklet and process them in the - * same order that they were received or TX status last. Hence, there - * is no race as long as the frame RX is processed before the next TX - * status, which drivers can ensure, see below. - * - * Note that this can only happen if the hardware or firmware can - * actually add STAs to the filter list, if this is done by the - * driver in response to set_tim() (which will only reduce the race - * this whole filtering tries to solve, not completely solve it) - * this situation cannot happen. - * - * To completely solve this race drivers need to make sure that they - * (a) don't mix the irq-safe/not irq-safe TX status/RX processing - * functions and - * (b) always process RX events before TX status events if ordering - * can be unknown, for example with different interrupt status - * bits. - */ - if (sta->flags & WLAN_STA_PS && - skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { - ieee80211_remove_tx_extra(local, sta->key, skb, - &status->control); - skb_queue_tail(&sta->tx_filtered, skb); - return; - } - - if (!(sta->flags & WLAN_STA_PS) && - !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) { - /* Software retry the packet once */ - status->control.flags |= IEEE80211_TXCTL_REQUEUE; - ieee80211_remove_tx_extra(local, sta->key, skb, - &status->control); - dev_queue_xmit(skb); - return; - } - - if (net_ratelimit()) - printk(KERN_DEBUG "%s: dropped TX filtered frame, " - "queue_len=%d PS=%d @%lu\n", - wiphy_name(local->hw.wiphy), - skb_queue_len(&sta->tx_filtered), - !!(sta->flags & WLAN_STA_PS), jiffies); - dev_kfree_skb(skb); -} - -void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, - struct ieee80211_tx_status *status) -{ - struct sk_buff *skb2; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct ieee80211_local *local = hw_to_local(hw); - u16 frag, type; - struct ieee80211_tx_status_rtap_hdr *rthdr; - struct ieee80211_sub_if_data *sdata; - struct net_device *prev_dev = NULL; - - if (!status) { - printk(KERN_ERR - "%s: ieee80211_tx_status called with NULL status\n", - wiphy_name(local->hw.wiphy)); - dev_kfree_skb(skb); - return; - } - - rcu_read_lock(); - - if (status->excessive_retries) { - struct sta_info *sta; - sta = sta_info_get(local, hdr->addr1); - if (sta) { - if (sta->flags & WLAN_STA_PS) { - /* - * The STA is in power save mode, so assume - * that this TX packet failed because of that. - */ - status->excessive_retries = 0; - status->flags |= IEEE80211_TX_STATUS_TX_FILTERED; - ieee80211_handle_filtered_frame(local, sta, - skb, status); - rcu_read_unlock(); - return; - } - } - } - - if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) { - struct sta_info *sta; - sta = sta_info_get(local, hdr->addr1); - if (sta) { - ieee80211_handle_filtered_frame(local, sta, skb, - status); - rcu_read_unlock(); - return; - } - } else - rate_control_tx_status(local->mdev, skb, status); - - rcu_read_unlock(); - - ieee80211_led_tx(local, 0); - - /* SNMP counters - * Fragments are passed to low-level drivers as separate skbs, so these - * are actually fragments, not frames. Update frame counters only for - * the first fragment of the frame. */ - - frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; - type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; - - if (status->flags & IEEE80211_TX_STATUS_ACK) { - if (frag == 0) { - local->dot11TransmittedFrameCount++; - if (is_multicast_ether_addr(hdr->addr1)) - local->dot11MulticastTransmittedFrameCount++; - if (status->retry_count > 0) - local->dot11RetryCount++; - if (status->retry_count > 1) - local->dot11MultipleRetryCount++; - } - - /* This counter shall be incremented for an acknowledged MPDU - * with an individual address in the address 1 field or an MPDU - * with a multicast address in the address 1 field of type Data - * or Management. */ - if (!is_multicast_ether_addr(hdr->addr1) || - type == IEEE80211_FTYPE_DATA || - type == IEEE80211_FTYPE_MGMT) - local->dot11TransmittedFragmentCount++; - } else { - if (frag == 0) - local->dot11FailedCount++; - } - - /* this was a transmitted frame, but now we want to reuse it */ - skb_orphan(skb); - - /* - * This is a bit racy but we can avoid a lot of work - * with this test... - */ - if (!local->monitors && !local->cooked_mntrs) { - dev_kfree_skb(skb); - return; - } - - /* send frame to monitor interfaces now */ - - if (skb_headroom(skb) < sizeof(*rthdr)) { - printk(KERN_ERR "ieee80211_tx_status: headroom too small\n"); - dev_kfree_skb(skb); - return; - } - - rthdr = (struct ieee80211_tx_status_rtap_hdr*) - skb_push(skb, sizeof(*rthdr)); - - memset(rthdr, 0, sizeof(*rthdr)); - rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); - rthdr->hdr.it_present = - cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | - (1 << IEEE80211_RADIOTAP_DATA_RETRIES)); - - if (!(status->flags & IEEE80211_TX_STATUS_ACK) && - !is_multicast_ether_addr(hdr->addr1)) - rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); - - if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) && - (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) - rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); - else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) - rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); - - rthdr->data_retries = status->retry_count; - - /* XXX: is this sufficient for BPF? */ - skb_set_mac_header(skb, 0); - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->pkt_type = PACKET_OTHERHOST; - skb->protocol = htons(ETH_P_802_2); - memset(skb->cb, 0, sizeof(skb->cb)); - - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) { - if (!netif_running(sdata->dev)) - continue; - - if (prev_dev) { - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2) { - skb2->dev = prev_dev; - netif_rx(skb2); - } - } - - prev_dev = sdata->dev; - } - } - if (prev_dev) { - skb->dev = prev_dev; - netif_rx(skb); - skb = NULL; - } - rcu_read_unlock(); - dev_kfree_skb(skb); -} -EXPORT_SYMBOL(ieee80211_tx_status); - -struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, - const struct ieee80211_ops *ops) -{ - struct ieee80211_local *local; - int priv_size; - struct wiphy *wiphy; - - /* Ensure 32-byte alignment of our private data and hw private data. - * We use the wiphy priv data for both our ieee80211_local and for - * the driver's private data - * - * In memory it'll be like this: - * - * +-------------------------+ - * | struct wiphy | - * +-------------------------+ - * | struct ieee80211_local | - * +-------------------------+ - * | driver's private data | - * +-------------------------+ - * - */ - priv_size = ((sizeof(struct ieee80211_local) + - NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) + - priv_data_len; - - wiphy = wiphy_new(&mac80211_config_ops, priv_size); - - if (!wiphy) - return NULL; - - wiphy->privid = mac80211_wiphy_privid; - - local = wiphy_priv(wiphy); - local->hw.wiphy = wiphy; - - local->hw.priv = (char *)local + - ((sizeof(struct ieee80211_local) + - NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); - - BUG_ON(!ops->tx); - BUG_ON(!ops->start); - BUG_ON(!ops->stop); - BUG_ON(!ops->config); - BUG_ON(!ops->add_interface); - BUG_ON(!ops->remove_interface); - BUG_ON(!ops->configure_filter); - local->ops = ops; - - local->hw.queues = 1; /* default */ - - local->bridge_packets = 1; - - local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; - local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; - local->short_retry_limit = 7; - local->long_retry_limit = 4; - local->hw.conf.radio_enabled = 1; - - INIT_LIST_HEAD(&local->interfaces); - - INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); - - sta_info_init(local); - - tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, - (unsigned long)local); - tasklet_disable(&local->tx_pending_tasklet); - - tasklet_init(&local->tasklet, - ieee80211_tasklet_handler, - (unsigned long) local); - tasklet_disable(&local->tasklet); - - skb_queue_head_init(&local->skb_queue); - skb_queue_head_init(&local->skb_queue_unreliable); - - return local_to_hw(local); -} -EXPORT_SYMBOL(ieee80211_alloc_hw); - -int ieee80211_register_hw(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - const char *name; - int result; - enum ieee80211_band band; - struct net_device *mdev; - struct ieee80211_sub_if_data *sdata; - - /* - * generic code guarantees at least one band, - * set this very early because much code assumes - * that hw.conf.channel is assigned - */ - for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - struct ieee80211_supported_band *sband; - - sband = local->hw.wiphy->bands[band]; - if (sband) { - /* init channel we're on */ - local->hw.conf.channel = - local->oper_channel = - local->scan_channel = &sband->channels[0]; - break; - } - } - - result = wiphy_register(local->hw.wiphy); - if (result < 0) - return result; - - /* for now, mdev needs sub_if_data :/ */ - mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), - "wmaster%d", ether_setup); - if (!mdev) - goto fail_mdev_alloc; - - sdata = IEEE80211_DEV_TO_SUB_IF(mdev); - mdev->ieee80211_ptr = &sdata->wdev; - sdata->wdev.wiphy = local->hw.wiphy; - - local->mdev = mdev; - - ieee80211_rx_bss_list_init(mdev); - - mdev->hard_start_xmit = ieee80211_master_start_xmit; - mdev->open = ieee80211_master_open; - mdev->stop = ieee80211_master_stop; - mdev->type = ARPHRD_IEEE80211; - mdev->header_ops = &ieee80211_header_ops; - mdev->set_multicast_list = ieee80211_master_set_multicast_list; - - sdata->vif.type = IEEE80211_IF_TYPE_AP; - sdata->dev = mdev; - sdata->local = local; - sdata->u.ap.force_unicast_rateidx = -1; - sdata->u.ap.max_ratectrl_rateidx = -1; - ieee80211_if_sdata_init(sdata); - - /* no RCU needed since we're still during init phase */ - list_add_tail(&sdata->list, &local->interfaces); - - name = wiphy_dev(local->hw.wiphy)->driver->name; - local->hw.workqueue = create_singlethread_workqueue(name); - if (!local->hw.workqueue) { - result = -ENOMEM; - goto fail_workqueue; - } - - /* - * The hardware needs headroom for sending the frame, - * and we need some headroom for passing the frame to monitor - * interfaces, but never both at the same time. - */ - local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, - sizeof(struct ieee80211_tx_status_rtap_hdr)); - - debugfs_hw_add(local); - - local->hw.conf.beacon_int = 1000; - - local->wstats_flags |= local->hw.max_rssi ? - IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID; - local->wstats_flags |= local->hw.max_signal ? - IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; - local->wstats_flags |= local->hw.max_noise ? - IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; - if (local->hw.max_rssi < 0 || local->hw.max_noise < 0) - local->wstats_flags |= IW_QUAL_DBM; - - result = sta_info_start(local); - if (result < 0) - goto fail_sta_info; - - rtnl_lock(); - result = dev_alloc_name(local->mdev, local->mdev->name); - if (result < 0) - goto fail_dev; - - memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); - SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); - - result = register_netdevice(local->mdev); - if (result < 0) - goto fail_dev; - - ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); - ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP); - - result = ieee80211_init_rate_ctrl_alg(local, - hw->rate_control_algorithm); - if (result < 0) { - printk(KERN_DEBUG "%s: Failed to initialize rate control " - "algorithm\n", wiphy_name(local->hw.wiphy)); - goto fail_rate; - } - - result = ieee80211_wep_init(local); - - if (result < 0) { - printk(KERN_DEBUG "%s: Failed to initialize wep\n", - wiphy_name(local->hw.wiphy)); - goto fail_wep; - } - - ieee80211_install_qdisc(local->mdev); - - /* add one default STA interface */ - result = ieee80211_if_add(local->mdev, "wlan%d", NULL, - IEEE80211_IF_TYPE_STA, NULL); - if (result) - printk(KERN_WARNING "%s: Failed to add default virtual iface\n", - wiphy_name(local->hw.wiphy)); - - local->reg_state = IEEE80211_DEV_REGISTERED; - rtnl_unlock(); - - ieee80211_led_init(local); - - return 0; - -fail_wep: - rate_control_deinitialize(local); -fail_rate: - ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); - unregister_netdevice(local->mdev); -fail_dev: - rtnl_unlock(); - sta_info_stop(local); -fail_sta_info: - debugfs_hw_del(local); - destroy_workqueue(local->hw.workqueue); -fail_workqueue: - ieee80211_if_free(local->mdev); - local->mdev = NULL; -fail_mdev_alloc: - wiphy_unregister(local->hw.wiphy); - return result; -} -EXPORT_SYMBOL(ieee80211_register_hw); - -void ieee80211_unregister_hw(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_sub_if_data *sdata, *tmp; - - tasklet_kill(&local->tx_pending_tasklet); - tasklet_kill(&local->tasklet); - - rtnl_lock(); - - BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED); - - local->reg_state = IEEE80211_DEV_UNREGISTERED; - - /* - * At this point, interface list manipulations are fine - * because the driver cannot be handing us frames any - * more and the tasklet is killed. - */ - - /* - * First, we remove all non-master interfaces. Do this because they - * may have bss pointer dependency on the master, and when we free - * the master these would be freed as well, breaking our list - * iteration completely. - */ - list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { - if (sdata->dev == local->mdev) - continue; - list_del(&sdata->list); - __ieee80211_if_del(local, sdata); - } - - /* then, finally, remove the master interface */ - __ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev)); - - rtnl_unlock(); - - ieee80211_rx_bss_list_deinit(local->mdev); - ieee80211_clear_tx_pending(local); - sta_info_stop(local); - rate_control_deinitialize(local); - debugfs_hw_del(local); - - if (skb_queue_len(&local->skb_queue) - || skb_queue_len(&local->skb_queue_unreliable)) - printk(KERN_WARNING "%s: skb_queue not empty\n", - wiphy_name(local->hw.wiphy)); - skb_queue_purge(&local->skb_queue); - skb_queue_purge(&local->skb_queue_unreliable); - - destroy_workqueue(local->hw.workqueue); - wiphy_unregister(local->hw.wiphy); - ieee80211_wep_free(local); - ieee80211_led_exit(local); - ieee80211_if_free(local->mdev); - local->mdev = NULL; -} -EXPORT_SYMBOL(ieee80211_unregister_hw); - -void ieee80211_free_hw(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - - wiphy_free(local->hw.wiphy); -} -EXPORT_SYMBOL(ieee80211_free_hw); - -static int __init ieee80211_init(void) -{ - struct sk_buff *skb; - int ret; - - BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb)); - - ret = rc80211_pid_init(); - if (ret) - goto out; - - ret = ieee80211_wme_register(); - if (ret) { - printk(KERN_DEBUG "ieee80211_init: failed to " - "initialize WME (err=%d)\n", ret); - goto out_cleanup_pid; - } - - ieee80211_debugfs_netdev_init(); - - return 0; - - out_cleanup_pid: - rc80211_pid_exit(); - out: - return ret; -} - -static void __exit ieee80211_exit(void) -{ - rc80211_pid_exit(); - - /* - * For key todo, it'll be empty by now but the work - * might still be scheduled. - */ - flush_scheduled_work(); - - if (mesh_allocated) - ieee80211s_stop(); - - ieee80211_wme_unregister(); - ieee80211_debugfs_netdev_exit(); -} - - -subsys_initcall(ieee80211_init); -module_exit(ieee80211_exit); - -MODULE_DESCRIPTION("IEEE 802.11 subsystem"); -MODULE_LICENSE("GPL"); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7f4e7f93ee47..c642538e8282 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -23,7 +23,7 @@ #include #include #include -#include "ieee80211_key.h" +#include "key.h" #include "sta_info.h" /* ieee80211.o internal definitions, etc. These are not included into diff --git a/net/mac80211/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c deleted file mode 100644 index 80954a512185..000000000000 --- a/net/mac80211/ieee80211_iface.c +++ /dev/null @@ -1,314 +0,0 @@ -/* - * Copyright 2002-2005, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * Copyright (c) 2006 Jiri Benc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include "ieee80211_i.h" -#include "sta_info.h" -#include "debugfs_netdev.h" -#include "mesh.h" - -void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) -{ - int i; - - /* Default values for sub-interface parameters */ - sdata->drop_unencrypted = 0; - for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) - skb_queue_head_init(&sdata->fragments[i].skb_list); - - INIT_LIST_HEAD(&sdata->key_list); -} - -static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) -{ - int i; - - for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { - __skb_queue_purge(&sdata->fragments[i].skb_list); - } -} - -/* Must be called with rtnl lock held. */ -int ieee80211_if_add(struct net_device *dev, const char *name, - struct net_device **new_dev, int type, - struct vif_params *params) -{ - struct net_device *ndev; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = NULL; - int ret; - - ASSERT_RTNL(); - ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, - name, ieee80211_if_setup); - if (!ndev) - return -ENOMEM; - - ret = dev_alloc_name(ndev, ndev->name); - if (ret < 0) - goto fail; - - memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); - ndev->base_addr = dev->base_addr; - ndev->irq = dev->irq; - ndev->mem_start = dev->mem_start; - ndev->mem_end = dev->mem_end; - SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); - - sdata = IEEE80211_DEV_TO_SUB_IF(ndev); - ndev->ieee80211_ptr = &sdata->wdev; - sdata->wdev.wiphy = local->hw.wiphy; - sdata->vif.type = IEEE80211_IF_TYPE_AP; - sdata->dev = ndev; - sdata->local = local; - ieee80211_if_sdata_init(sdata); - - ret = register_netdevice(ndev); - if (ret) - goto fail; - - ieee80211_debugfs_add_netdev(sdata); - ieee80211_if_set_type(ndev, type); - - if (ieee80211_vif_is_mesh(&sdata->vif) && - params && params->mesh_id_len) - ieee80211_if_sta_set_mesh_id(&sdata->u.sta, - params->mesh_id_len, - params->mesh_id); - - /* we're under RTNL so all this is fine */ - if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) { - __ieee80211_if_del(local, sdata); - return -ENODEV; - } - list_add_tail_rcu(&sdata->list, &local->interfaces); - - if (new_dev) - *new_dev = ndev; - - return 0; - -fail: - free_netdev(ndev); - return ret; -} - -void ieee80211_if_set_type(struct net_device *dev, int type) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int oldtype = sdata->vif.type; - - /* - * We need to call this function on the master interface - * which already has a hard_start_xmit routine assigned - * which must not be changed. - */ - if (dev != sdata->local->mdev) - dev->hard_start_xmit = ieee80211_subif_start_xmit; - - /* - * Called even when register_netdevice fails, it would - * oops if assigned before initialising the rest. - */ - dev->uninit = ieee80211_if_reinit; - - /* most have no BSS pointer */ - sdata->bss = NULL; - sdata->vif.type = type; - - sdata->basic_rates = 0; - - switch (type) { - case IEEE80211_IF_TYPE_WDS: - /* nothing special */ - break; - case IEEE80211_IF_TYPE_VLAN: - sdata->u.vlan.ap = NULL; - break; - case IEEE80211_IF_TYPE_AP: - sdata->u.ap.force_unicast_rateidx = -1; - sdata->u.ap.max_ratectrl_rateidx = -1; - skb_queue_head_init(&sdata->u.ap.ps_bc_buf); - sdata->bss = &sdata->u.ap; - INIT_LIST_HEAD(&sdata->u.ap.vlans); - break; - case IEEE80211_IF_TYPE_MESH_POINT: - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: { - struct ieee80211_sub_if_data *msdata; - struct ieee80211_if_sta *ifsta; - - ifsta = &sdata->u.sta; - INIT_WORK(&ifsta->work, ieee80211_sta_work); - setup_timer(&ifsta->timer, ieee80211_sta_timer, - (unsigned long) sdata); - skb_queue_head_init(&ifsta->skb_queue); - - ifsta->capab = WLAN_CAPABILITY_ESS; - ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN | - IEEE80211_AUTH_ALG_SHARED_KEY; - ifsta->flags |= IEEE80211_STA_CREATE_IBSS | - IEEE80211_STA_WMM_ENABLED | - IEEE80211_STA_AUTO_BSSID_SEL | - IEEE80211_STA_AUTO_CHANNEL_SEL; - - msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); - sdata->bss = &msdata->u.ap; - - if (ieee80211_vif_is_mesh(&sdata->vif)) - ieee80211_mesh_init_sdata(sdata); - break; - } - case IEEE80211_IF_TYPE_MNTR: - dev->type = ARPHRD_IEEE80211_RADIOTAP; - dev->hard_start_xmit = ieee80211_monitor_start_xmit; - sdata->u.mntr_flags = MONITOR_FLAG_CONTROL | - MONITOR_FLAG_OTHER_BSS; - break; - default: - printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x", - dev->name, __func__, type); - } - ieee80211_debugfs_change_if_type(sdata, oldtype); -} - -/* Must be called with rtnl lock held. */ -void ieee80211_if_reinit(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct sk_buff *skb; - int flushed; - - ASSERT_RTNL(); - - ieee80211_free_keys(sdata); - - ieee80211_if_sdata_deinit(sdata); - - /* Need to handle mesh specially to allow eliding the function call */ - if (ieee80211_vif_is_mesh(&sdata->vif)) - mesh_rmc_free(dev); - - switch (sdata->vif.type) { - case IEEE80211_IF_TYPE_INVALID: - /* cannot happen */ - WARN_ON(1); - break; - case IEEE80211_IF_TYPE_AP: { - /* Remove all virtual interfaces that use this BSS - * as their sdata->bss */ - struct ieee80211_sub_if_data *tsdata, *n; - struct beacon_data *beacon; - - list_for_each_entry_safe(tsdata, n, &local->interfaces, list) { - if (tsdata != sdata && tsdata->bss == &sdata->u.ap) { - printk(KERN_DEBUG "%s: removing virtual " - "interface %s because its BSS interface" - " is being removed\n", - sdata->dev->name, tsdata->dev->name); - list_del_rcu(&tsdata->list); - /* - * We have lots of time and can afford - * to sync for each interface - */ - synchronize_rcu(); - __ieee80211_if_del(local, tsdata); - } - } - - beacon = sdata->u.ap.beacon; - rcu_assign_pointer(sdata->u.ap.beacon, NULL); - synchronize_rcu(); - kfree(beacon); - - while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { - local->total_ps_buffered--; - dev_kfree_skb(skb); - } - - break; - } - case IEEE80211_IF_TYPE_WDS: - /* nothing to do */ - break; - case IEEE80211_IF_TYPE_MESH_POINT: - case IEEE80211_IF_TYPE_STA: - case IEEE80211_IF_TYPE_IBSS: - kfree(sdata->u.sta.extra_ie); - sdata->u.sta.extra_ie = NULL; - kfree(sdata->u.sta.assocreq_ies); - sdata->u.sta.assocreq_ies = NULL; - kfree(sdata->u.sta.assocresp_ies); - sdata->u.sta.assocresp_ies = NULL; - if (sdata->u.sta.probe_resp) { - dev_kfree_skb(sdata->u.sta.probe_resp); - sdata->u.sta.probe_resp = NULL; - } - - break; - case IEEE80211_IF_TYPE_MNTR: - dev->type = ARPHRD_ETHER; - break; - case IEEE80211_IF_TYPE_VLAN: - sdata->u.vlan.ap = NULL; - break; - } - - flushed = sta_info_flush(local, sdata); - WARN_ON(flushed); - - memset(&sdata->u, 0, sizeof(sdata->u)); - ieee80211_if_sdata_init(sdata); -} - -/* Must be called with rtnl lock held. */ -void __ieee80211_if_del(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata) -{ - struct net_device *dev = sdata->dev; - - ieee80211_debugfs_remove_netdev(sdata); - unregister_netdevice(dev); - /* Except master interface, the net_device will be freed by - * net_device->destructor (i. e. ieee80211_if_free). */ -} - -/* Must be called with rtnl lock held. */ -int ieee80211_if_remove(struct net_device *dev, const char *name, int id) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata, *n; - - ASSERT_RTNL(); - - list_for_each_entry_safe(sdata, n, &local->interfaces, list) { - if ((sdata->vif.type == id || id == -1) && - strcmp(name, sdata->dev->name) == 0 && - sdata->dev != local->mdev) { - list_del_rcu(&sdata->list); - synchronize_rcu(); - __ieee80211_if_del(local, sdata); - return 0; - } - } - return -ENODEV; -} - -void ieee80211_if_free(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - ieee80211_if_sdata_deinit(sdata); - free_netdev(dev); -} diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c deleted file mode 100644 index a611c8bc76bd..000000000000 --- a/net/mac80211/ieee80211_ioctl.c +++ /dev/null @@ -1,1144 +0,0 @@ -/* - * Copyright 2002-2005, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "ieee80211_i.h" -#include "ieee80211_led.h" -#include "ieee80211_rate.h" -#include "wpa.h" -#include "aes_ccm.h" - - -static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, - int idx, int alg, int remove, - int set_tx_key, const u8 *_key, - size_t key_len) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; - struct ieee80211_key *key; - struct ieee80211_sub_if_data *sdata; - int err; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (idx < 0 || idx >= NUM_DEFAULT_KEYS) { - printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n", - dev->name, idx); - return -EINVAL; - } - - if (remove) { - rcu_read_lock(); - - err = 0; - - if (is_broadcast_ether_addr(sta_addr)) { - key = sdata->keys[idx]; - } else { - sta = sta_info_get(local, sta_addr); - if (!sta) { - err = -ENOENT; - goto out_unlock; - } - key = sta->key; - } - - ieee80211_key_free(key); - } else { - key = ieee80211_key_alloc(alg, idx, key_len, _key); - if (!key) - return -ENOMEM; - - sta = NULL; - err = 0; - - rcu_read_lock(); - - if (!is_broadcast_ether_addr(sta_addr)) { - set_tx_key = 0; - /* - * According to the standard, the key index of a - * pairwise key must be zero. However, some AP are - * broken when it comes to WEP key indices, so we - * work around this. - */ - if (idx != 0 && alg != ALG_WEP) { - ieee80211_key_free(key); - err = -EINVAL; - goto out_unlock; - } - - sta = sta_info_get(local, sta_addr); - if (!sta) { - ieee80211_key_free(key); - err = -ENOENT; - goto out_unlock; - } - } - - ieee80211_key_link(key, sdata, sta); - - if (set_tx_key || (!sta && !sdata->default_key && key)) - ieee80211_set_default_key(sdata, idx); - } - - out_unlock: - rcu_read_unlock(); - - return err; -} - -static int ieee80211_ioctl_siwgenie(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) - return -EOPNOTSUPP; - - if (sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { - int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length); - if (ret) - return ret; - sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; - ieee80211_sta_req_auth(dev, &sdata->u.sta); - return 0; - } - - return -EOPNOTSUPP; -} - -static int ieee80211_ioctl_giwname(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ - strcpy(name, "IEEE 802.11"); - - return 0; -} - - -static int ieee80211_ioctl_giwrange(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct iw_range *range = (struct iw_range *) extra; - enum ieee80211_band band; - int c = 0; - - data->length = sizeof(struct iw_range); - memset(range, 0, sizeof(struct iw_range)); - - range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 21; - range->retry_capa = IW_RETRY_LIMIT; - range->retry_flags = IW_RETRY_LIMIT; - range->min_retry = 0; - range->max_retry = 255; - range->min_rts = 0; - range->max_rts = 2347; - range->min_frag = 256; - range->max_frag = 2346; - - range->encoding_size[0] = 5; - range->encoding_size[1] = 13; - range->num_encoding_sizes = 2; - range->max_encoding_tokens = NUM_DEFAULT_KEYS; - - range->max_qual.qual = local->hw.max_signal; - range->max_qual.level = local->hw.max_rssi; - range->max_qual.noise = local->hw.max_noise; - range->max_qual.updated = local->wstats_flags; - - range->avg_qual.qual = local->hw.max_signal/2; - range->avg_qual.level = 0; - range->avg_qual.noise = 0; - range->avg_qual.updated = local->wstats_flags; - - range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | - IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - - - for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { - int i; - struct ieee80211_supported_band *sband; - - sband = local->hw.wiphy->bands[band]; - - if (!sband) - continue; - - for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { - struct ieee80211_channel *chan = &sband->channels[i]; - - if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { - range->freq[c].i = - ieee80211_frequency_to_channel( - chan->center_freq); - range->freq[c].m = chan->center_freq; - range->freq[c].e = 6; - c++; - } - } - } - range->num_channels = c; - range->num_frequency = c; - - IW_EVENT_CAPA_SET_KERNEL(range->event_capa); - IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY); - IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); - IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); - - range->scan_capa |= IW_SCAN_CAPA_ESSID; - - return 0; -} - - -static int ieee80211_ioctl_siwmode(struct net_device *dev, - struct iw_request_info *info, - __u32 *mode, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int type; - - if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) - return -EOPNOTSUPP; - - switch (*mode) { - case IW_MODE_INFRA: - type = IEEE80211_IF_TYPE_STA; - break; - case IW_MODE_ADHOC: - type = IEEE80211_IF_TYPE_IBSS; - break; - case IW_MODE_MONITOR: - type = IEEE80211_IF_TYPE_MNTR; - break; - default: - return -EINVAL; - } - - if (type == sdata->vif.type) - return 0; - if (netif_running(dev)) - return -EBUSY; - - ieee80211_if_reinit(dev); - ieee80211_if_set_type(dev, type); - - return 0; -} - - -static int ieee80211_ioctl_giwmode(struct net_device *dev, - struct iw_request_info *info, - __u32 *mode, char *extra) -{ - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - switch (sdata->vif.type) { - case IEEE80211_IF_TYPE_AP: - *mode = IW_MODE_MASTER; - break; - case IEEE80211_IF_TYPE_STA: - *mode = IW_MODE_INFRA; - break; - case IEEE80211_IF_TYPE_IBSS: - *mode = IW_MODE_ADHOC; - break; - case IEEE80211_IF_TYPE_MNTR: - *mode = IW_MODE_MONITOR; - break; - case IEEE80211_IF_TYPE_WDS: - *mode = IW_MODE_REPEAT; - break; - case IEEE80211_IF_TYPE_VLAN: - *mode = IW_MODE_SECOND; /* FIXME */ - break; - default: - *mode = IW_MODE_AUTO; - break; - } - return 0; -} - -int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz) -{ - int ret = -EINVAL; - struct ieee80211_channel *chan; - - chan = ieee80211_get_channel(local->hw.wiphy, freqMHz); - - if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { - local->oper_channel = chan; - - if (local->sta_sw_scanning || local->sta_hw_scanning) - ret = 0; - else - ret = ieee80211_hw_config(local); - - rate_control_clear(local); - } - - return ret; -} - -static int ieee80211_ioctl_siwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type == IEEE80211_IF_TYPE_STA) - sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; - - /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ - if (freq->e == 0) { - if (freq->m < 0) { - if (sdata->vif.type == IEEE80211_IF_TYPE_STA) - sdata->u.sta.flags |= - IEEE80211_STA_AUTO_CHANNEL_SEL; - return 0; - } else - return ieee80211_set_freq(local, - ieee80211_channel_to_frequency(freq->m)); - } else { - int i, div = 1000000; - for (i = 0; i < freq->e; i++) - div /= 10; - if (div > 0) - return ieee80211_set_freq(local, freq->m / div); - else - return -EINVAL; - } -} - - -static int ieee80211_ioctl_giwfreq(struct net_device *dev, - struct iw_request_info *info, - struct iw_freq *freq, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - freq->m = local->hw.conf.channel->center_freq; - freq->e = 6; - - return 0; -} - - -static int ieee80211_ioctl_siwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - struct ieee80211_sub_if_data *sdata; - size_t len = data->length; - - /* iwconfig uses nul termination in SSID.. */ - if (len > 0 && ssid[len - 1] == '\0') - len--; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { - int ret; - if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { - if (len > IEEE80211_MAX_SSID_LEN) - return -EINVAL; - memcpy(sdata->u.sta.ssid, ssid, len); - sdata->u.sta.ssid_len = len; - return 0; - } - if (data->flags) - sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; - else - sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL; - ret = ieee80211_sta_set_ssid(dev, ssid, len); - if (ret) - return ret; - ieee80211_sta_req_auth(dev, &sdata->u.sta); - return 0; - } - - if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { - memcpy(sdata->u.ap.ssid, ssid, len); - memset(sdata->u.ap.ssid + len, 0, - IEEE80211_MAX_SSID_LEN - len); - sdata->u.ap.ssid_len = len; - return ieee80211_if_config(dev); - } - return -EOPNOTSUPP; -} - - -static int ieee80211_ioctl_giwessid(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *ssid) -{ - size_t len; - - struct ieee80211_sub_if_data *sdata; - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { - int res = ieee80211_sta_get_ssid(dev, ssid, &len); - if (res == 0) { - data->length = len; - data->flags = 1; - } else - data->flags = 0; - return res; - } - - if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { - len = sdata->u.ap.ssid_len; - if (len > IW_ESSID_MAX_SIZE) - len = IW_ESSID_MAX_SIZE; - memcpy(ssid, sdata->u.ap.ssid, len); - data->length = len; - data->flags = 1; - return 0; - } - return -EOPNOTSUPP; -} - - -static int ieee80211_ioctl_siwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { - int ret; - if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { - memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data, - ETH_ALEN); - return 0; - } - if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) - sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL | - IEEE80211_STA_AUTO_CHANNEL_SEL; - else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) - sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL; - else - sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; - ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data); - if (ret) - return ret; - ieee80211_sta_req_auth(dev, &sdata->u.sta); - return 0; - } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) { - /* - * If it is necessary to update the WDS peer address - * while the interface is running, then we need to do - * more work here, namely if it is running we need to - * add a new and remove the old STA entry, this is - * normally handled by _open() and _stop(). - */ - if (netif_running(dev)) - return -EBUSY; - - memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, - ETH_ALEN); - - return 0; - } - - return -EOPNOTSUPP; -} - - -static int ieee80211_ioctl_giwap(struct net_device *dev, - struct iw_request_info *info, - struct sockaddr *ap_addr, char *extra) -{ - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN); - return 0; - } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) { - ap_addr->sa_family = ARPHRD_ETHER; - memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); - return 0; - } - - return -EOPNOTSUPP; -} - - -static int ieee80211_ioctl_siwscan(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *wrqu, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct iw_scan_req *req = NULL; - u8 *ssid = NULL; - size_t ssid_len = 0; - - if (!netif_running(dev)) - return -ENETDOWN; - - if (sdata->vif.type != IEEE80211_IF_TYPE_STA && - sdata->vif.type != IEEE80211_IF_TYPE_IBSS && - sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT && - sdata->vif.type != IEEE80211_IF_TYPE_AP) - return -EOPNOTSUPP; - - /* if SSID was specified explicitly then use that */ - if (wrqu->data.length == sizeof(struct iw_scan_req) && - wrqu->data.flags & IW_SCAN_THIS_ESSID) { - req = (struct iw_scan_req *)extra; - ssid = req->essid; - ssid_len = req->essid_len; - } - - return ieee80211_sta_req_scan(dev, ssid, ssid_len); -} - - -static int ieee80211_ioctl_giwscan(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - int res; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (local->sta_sw_scanning || local->sta_hw_scanning) - return -EAGAIN; - - res = ieee80211_sta_scan_results(dev, extra, data->length); - if (res >= 0) { - data->length = res; - return 0; - } - data->length = 0; - return res; -} - - -static int ieee80211_ioctl_siwrate(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rate, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int i, err = -EINVAL; - u32 target_rate = rate->value / 100000; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_supported_band *sband; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (!sdata->bss) - return -ENODEV; - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates - * target_rate = X, rate->fixed = 1 means only rate X - * target_rate = X, rate->fixed = 0 means all rates <= X */ - sdata->bss->max_ratectrl_rateidx = -1; - sdata->bss->force_unicast_rateidx = -1; - if (rate->value < 0) - return 0; - - for (i=0; i< sband->n_bitrates; i++) { - struct ieee80211_rate *brate = &sband->bitrates[i]; - int this_rate = brate->bitrate; - - if (target_rate == this_rate) { - sdata->bss->max_ratectrl_rateidx = i; - if (rate->fixed) - sdata->bss->force_unicast_rateidx = i; - err = 0; - break; - } - } - return err; -} - -static int ieee80211_ioctl_giwrate(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rate, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_supported_band *sband; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type != IEEE80211_IF_TYPE_STA) - return -EOPNOTSUPP; - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - rcu_read_lock(); - - sta = sta_info_get(local, sdata->u.sta.bssid); - - if (sta && sta->txrate_idx < sband->n_bitrates) - rate->value = sband->bitrates[sta->txrate_idx].bitrate; - else - rate->value = 0; - - rcu_read_unlock(); - - if (!sta) - return -ENODEV; - - rate->value *= 100000; - - return 0; -} - -static int ieee80211_ioctl_siwtxpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *data, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - bool need_reconfig = 0; - int new_power_level; - - if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) - return -EINVAL; - if (data->txpower.flags & IW_TXPOW_RANGE) - return -EINVAL; - - if (data->txpower.fixed) { - new_power_level = data->txpower.value; - } else { - /* - * Automatic power level. Use maximum power for the current - * channel. Should be part of rate control. - */ - struct ieee80211_channel* chan = local->hw.conf.channel; - if (!chan) - return -EINVAL; - - new_power_level = chan->max_power; - } - - if (local->hw.conf.power_level != new_power_level) { - local->hw.conf.power_level = new_power_level; - need_reconfig = 1; - } - - if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { - local->hw.conf.radio_enabled = !(data->txpower.disabled); - need_reconfig = 1; - ieee80211_led_radio(local, local->hw.conf.radio_enabled); - } - - if (need_reconfig) { - ieee80211_hw_config(local); - /* The return value of hw_config is not of big interest here, - * as it doesn't say that it failed because of _this_ config - * change or something else. Ignore it. */ - } - - return 0; -} - -static int ieee80211_ioctl_giwtxpower(struct net_device *dev, - struct iw_request_info *info, - union iwreq_data *data, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - data->txpower.fixed = 1; - data->txpower.disabled = !(local->hw.conf.radio_enabled); - data->txpower.value = local->hw.conf.power_level; - data->txpower.flags = IW_TXPOW_DBM; - - return 0; -} - -static int ieee80211_ioctl_siwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (rts->disabled) - local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; - else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD) - return -EINVAL; - else - local->rts_threshold = rts->value; - - /* If the wlan card performs RTS/CTS in hardware/firmware, - * configure it here */ - - if (local->ops->set_rts_threshold) - local->ops->set_rts_threshold(local_to_hw(local), - local->rts_threshold); - - return 0; -} - -static int ieee80211_ioctl_giwrts(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *rts, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - rts->value = local->rts_threshold; - rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD); - rts->fixed = 1; - - return 0; -} - - -static int ieee80211_ioctl_siwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (frag->disabled) - local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; - else if (frag->value < 256 || - frag->value > IEEE80211_MAX_FRAG_THRESHOLD) - return -EINVAL; - else { - /* Fragment length must be even, so strip LSB. */ - local->fragmentation_threshold = frag->value & ~0x1; - } - - /* If the wlan card performs fragmentation in hardware/firmware, - * configure it here */ - - if (local->ops->set_frag_threshold) - local->ops->set_frag_threshold( - local_to_hw(local), - local->fragmentation_threshold); - - return 0; -} - -static int ieee80211_ioctl_giwfrag(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *frag, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - frag->value = local->fragmentation_threshold; - frag->disabled = (frag->value >= IEEE80211_MAX_RTS_THRESHOLD); - frag->fixed = 1; - - return 0; -} - - -static int ieee80211_ioctl_siwretry(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *retry, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (retry->disabled || - (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) - return -EINVAL; - - if (retry->flags & IW_RETRY_MAX) - local->long_retry_limit = retry->value; - else if (retry->flags & IW_RETRY_MIN) - local->short_retry_limit = retry->value; - else { - local->long_retry_limit = retry->value; - local->short_retry_limit = retry->value; - } - - if (local->ops->set_retry_limit) { - return local->ops->set_retry_limit( - local_to_hw(local), - local->short_retry_limit, - local->long_retry_limit); - } - - return 0; -} - - -static int ieee80211_ioctl_giwretry(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *retry, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - retry->disabled = 0; - if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) { - /* first return min value, iwconfig will ask max value - * later if needed */ - retry->flags |= IW_RETRY_LIMIT; - retry->value = local->short_retry_limit; - if (local->long_retry_limit != local->short_retry_limit) - retry->flags |= IW_RETRY_MIN; - return 0; - } - if (retry->flags & IW_RETRY_MAX) { - retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - retry->value = local->long_retry_limit; - } - - return 0; -} - -static int ieee80211_ioctl_siwmlme(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *data, char *extra) -{ - struct ieee80211_sub_if_data *sdata; - struct iw_mlme *mlme = (struct iw_mlme *) extra; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->vif.type != IEEE80211_IF_TYPE_STA && - sdata->vif.type != IEEE80211_IF_TYPE_IBSS) - return -EINVAL; - - switch (mlme->cmd) { - case IW_MLME_DEAUTH: - /* TODO: mlme->addr.sa_data */ - return ieee80211_sta_deauthenticate(dev, mlme->reason_code); - case IW_MLME_DISASSOC: - /* TODO: mlme->addr.sa_data */ - return ieee80211_sta_disassociate(dev, mlme->reason_code); - default: - return -EOPNOTSUPP; - } -} - - -static int ieee80211_ioctl_siwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *keybuf) -{ - struct ieee80211_sub_if_data *sdata; - int idx, i, alg = ALG_WEP; - u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - int remove = 0; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - idx = erq->flags & IW_ENCODE_INDEX; - if (idx == 0) { - if (sdata->default_key) - for (i = 0; i < NUM_DEFAULT_KEYS; i++) { - if (sdata->default_key == sdata->keys[i]) { - idx = i; - break; - } - } - } else if (idx < 1 || idx > 4) - return -EINVAL; - else - idx--; - - if (erq->flags & IW_ENCODE_DISABLED) - remove = 1; - else if (erq->length == 0) { - /* No key data - just set the default TX key index */ - ieee80211_set_default_key(sdata, idx); - return 0; - } - - return ieee80211_set_encryption( - dev, bcaddr, - idx, alg, remove, - !sdata->default_key, - keybuf, erq->length); -} - - -static int ieee80211_ioctl_giwencode(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *key) -{ - struct ieee80211_sub_if_data *sdata; - int idx, i; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - idx = erq->flags & IW_ENCODE_INDEX; - if (idx < 1 || idx > 4) { - idx = -1; - if (!sdata->default_key) - idx = 0; - else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { - if (sdata->default_key == sdata->keys[i]) { - idx = i; - break; - } - } - if (idx < 0) - return -EINVAL; - } else - idx--; - - erq->flags = idx + 1; - - if (!sdata->keys[idx]) { - erq->length = 0; - erq->flags |= IW_ENCODE_DISABLED; - return 0; - } - - memcpy(key, sdata->keys[idx]->conf.key, - min_t(int, erq->length, sdata->keys[idx]->conf.keylen)); - erq->length = sdata->keys[idx]->conf.keylen; - erq->flags |= IW_ENCODE_ENABLED; - - return 0; -} - -static int ieee80211_ioctl_siwauth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int ret = 0; - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_WPA_VERSION: - case IW_AUTH_CIPHER_PAIRWISE: - case IW_AUTH_CIPHER_GROUP: - case IW_AUTH_WPA_ENABLED: - case IW_AUTH_RX_UNENCRYPTED_EAPOL: - case IW_AUTH_KEY_MGMT: - break; - case IW_AUTH_DROP_UNENCRYPTED: - sdata->drop_unencrypted = !!data->value; - break; - case IW_AUTH_PRIVACY_INVOKED: - if (sdata->vif.type != IEEE80211_IF_TYPE_STA) - ret = -EINVAL; - else { - sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; - /* - * Privacy invoked by wpa_supplicant, store the - * value and allow associating to a protected - * network without having a key up front. - */ - if (data->value) - sdata->u.sta.flags |= - IEEE80211_STA_PRIVACY_INVOKED; - } - break; - case IW_AUTH_80211_AUTH_ALG: - if (sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) - sdata->u.sta.auth_algs = data->value; - else - ret = -EOPNOTSUPP; - break; - default: - ret = -EOPNOTSUPP; - break; - } - return ret; -} - -/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ -static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct iw_statistics *wstats = &local->wstats; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct sta_info *sta = NULL; - - if (sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) - sta = sta_info_get(local, sdata->u.sta.bssid); - if (!sta) { - wstats->discard.fragment = 0; - wstats->discard.misc = 0; - wstats->qual.qual = 0; - wstats->qual.level = 0; - wstats->qual.noise = 0; - wstats->qual.updated = IW_QUAL_ALL_INVALID; - } else { - wstats->qual.level = sta->last_rssi; - wstats->qual.qual = sta->last_signal; - wstats->qual.noise = sta->last_noise; - wstats->qual.updated = local->wstats_flags; - } - return wstats; -} - -static int ieee80211_ioctl_giwauth(struct net_device *dev, - struct iw_request_info *info, - struct iw_param *data, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int ret = 0; - - switch (data->flags & IW_AUTH_INDEX) { - case IW_AUTH_80211_AUTH_ALG: - if (sdata->vif.type == IEEE80211_IF_TYPE_STA || - sdata->vif.type == IEEE80211_IF_TYPE_IBSS) - data->value = sdata->u.sta.auth_algs; - else - ret = -EOPNOTSUPP; - break; - default: - ret = -EOPNOTSUPP; - break; - } - return ret; -} - - -static int ieee80211_ioctl_siwencodeext(struct net_device *dev, - struct iw_request_info *info, - struct iw_point *erq, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; - int uninitialized_var(alg), idx, i, remove = 0; - - switch (ext->alg) { - case IW_ENCODE_ALG_NONE: - remove = 1; - break; - case IW_ENCODE_ALG_WEP: - alg = ALG_WEP; - break; - case IW_ENCODE_ALG_TKIP: - alg = ALG_TKIP; - break; - case IW_ENCODE_ALG_CCMP: - alg = ALG_CCMP; - break; - default: - return -EOPNOTSUPP; - } - - if (erq->flags & IW_ENCODE_DISABLED) - remove = 1; - - idx = erq->flags & IW_ENCODE_INDEX; - if (idx < 1 || idx > 4) { - idx = -1; - if (!sdata->default_key) - idx = 0; - else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { - if (sdata->default_key == sdata->keys[i]) { - idx = i; - break; - } - } - if (idx < 0) - return -EINVAL; - } else - idx--; - - return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg, - remove, - ext->ext_flags & - IW_ENCODE_EXT_SET_TX_KEY, - ext->key, ext->key_len); -} - - -/* Structures to export the Wireless Handlers */ - -static const iw_handler ieee80211_handler[] = -{ - (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) ieee80211_ioctl_giwname, /* SIOCGIWNAME */ - (iw_handler) NULL, /* SIOCSIWNWID */ - (iw_handler) NULL, /* SIOCGIWNWID */ - (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */ - (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */ - (iw_handler) ieee80211_ioctl_siwmode, /* SIOCSIWMODE */ - (iw_handler) ieee80211_ioctl_giwmode, /* SIOCGIWMODE */ - (iw_handler) NULL, /* SIOCSIWSENS */ - (iw_handler) NULL, /* SIOCGIWSENS */ - (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ - (iw_handler) ieee80211_ioctl_giwrange, /* SIOCGIWRANGE */ - (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ - (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ - (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ - (iw_handler) NULL, /* SIOCSIWSPY */ - (iw_handler) NULL, /* SIOCGIWSPY */ - (iw_handler) NULL, /* SIOCSIWTHRSPY */ - (iw_handler) NULL, /* SIOCGIWTHRSPY */ - (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */ - (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ - (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */ - (iw_handler) NULL, /* SIOCGIWAPLIST */ - (iw_handler) ieee80211_ioctl_siwscan, /* SIOCSIWSCAN */ - (iw_handler) ieee80211_ioctl_giwscan, /* SIOCGIWSCAN */ - (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */ - (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */ - (iw_handler) NULL, /* SIOCSIWNICKN */ - (iw_handler) NULL, /* SIOCGIWNICKN */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */ - (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */ - (iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */ - (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */ - (iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */ - (iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */ - (iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */ - (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ - (iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */ - (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */ - (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */ - (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */ - (iw_handler) NULL, /* SIOCSIWPOWER */ - (iw_handler) NULL, /* SIOCGIWPOWER */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) NULL, /* -- hole -- */ - (iw_handler) ieee80211_ioctl_siwgenie, /* SIOCSIWGENIE */ - (iw_handler) NULL, /* SIOCGIWGENIE */ - (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */ - (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */ - (iw_handler) ieee80211_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ - (iw_handler) NULL, /* SIOCGIWENCODEEXT */ - (iw_handler) NULL, /* SIOCSIWPMKSA */ - (iw_handler) NULL, /* -- hole -- */ -}; - -const struct iw_handler_def ieee80211_iw_handler_def = -{ - .num_standard = ARRAY_SIZE(ieee80211_handler), - .standard = (iw_handler *) ieee80211_handler, - .get_wireless_stats = ieee80211_get_wireless_stats, -}; diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h deleted file mode 100644 index 467890c6fe81..000000000000 --- a/net/mac80211/ieee80211_key.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2002-2004, Instant802 Networks, Inc. - * Copyright 2005, Devicescape Software, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef IEEE80211_KEY_H -#define IEEE80211_KEY_H - -#include -#include -#include -#include -#include - -/* ALG_TKIP - * struct ieee80211_key::key is encoded as a 256-bit (32 byte) data block: - * Temporal Encryption Key (128 bits) - * Temporal Authenticator Tx MIC Key (64 bits) - * Temporal Authenticator Rx MIC Key (64 bits) - */ - -#define WEP_IV_LEN 4 -#define WEP_ICV_LEN 4 - -#define ALG_TKIP_KEY_LEN 32 -/* Starting offsets for each key */ -#define ALG_TKIP_TEMP_ENCR_KEY 0 -#define ALG_TKIP_TEMP_AUTH_TX_MIC_KEY 16 -#define ALG_TKIP_TEMP_AUTH_RX_MIC_KEY 24 -#define TKIP_IV_LEN 8 -#define TKIP_ICV_LEN 4 - -#define ALG_CCMP_KEY_LEN 16 -#define CCMP_HDR_LEN 8 -#define CCMP_MIC_LEN 8 -#define CCMP_TK_LEN 16 -#define CCMP_PN_LEN 6 - -#define NUM_RX_DATA_QUEUES 17 - -struct ieee80211_local; -struct ieee80211_sub_if_data; -struct sta_info; - -/** - * enum ieee80211_internal_key_flags - internal key flags - * - * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present - * in the hardware for TX crypto hardware acceleration. - * @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an - * RCU grace period, no longer be reachable other than from the - * todo list. - * @KEY_FLAG_TODO_HWACCEL: Key needs to be added to hardware acceleration. - * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated. - * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs. - */ -enum ieee80211_internal_key_flags { - KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), - KEY_FLAG_TODO_DELETE = BIT(1), - KEY_FLAG_TODO_HWACCEL = BIT(2), - KEY_FLAG_TODO_DEFKEY = BIT(3), - KEY_FLAG_TODO_ADD_DEBUGFS = BIT(4), -}; - -struct ieee80211_key { - struct ieee80211_local *local; - struct ieee80211_sub_if_data *sdata; - struct sta_info *sta; - - /* for sdata list */ - struct list_head list; - /* for todo list */ - struct list_head todo; - - /* protected by todo lock! */ - unsigned int flags; - - union { - struct { - /* last used TSC */ - u32 iv32; - u16 iv16; - u16 p1k[5]; - int tx_initialized; - - /* last received RSC */ - u32 iv32_rx[NUM_RX_DATA_QUEUES]; - u16 iv16_rx[NUM_RX_DATA_QUEUES]; - u16 p1k_rx[NUM_RX_DATA_QUEUES][5]; - int rx_initialized[NUM_RX_DATA_QUEUES]; - } tkip; - struct { - u8 tx_pn[6]; - u8 rx_pn[NUM_RX_DATA_QUEUES][6]; - struct crypto_cipher *tfm; - u32 replays; /* dot11RSNAStatsCCMPReplays */ - /* scratch buffers for virt_to_page() (crypto API) */ -#ifndef AES_BLOCK_LEN -#define AES_BLOCK_LEN 16 -#endif - u8 tx_crypto_buf[6 * AES_BLOCK_LEN]; - u8 rx_crypto_buf[6 * AES_BLOCK_LEN]; - } ccmp; - } u; - - /* number of times this key has been used */ - int tx_rx_count; - -#ifdef CONFIG_MAC80211_DEBUGFS - struct { - struct dentry *stalink; - struct dentry *dir; - struct dentry *keylen; - struct dentry *flags; - struct dentry *keyidx; - struct dentry *hw_key_idx; - struct dentry *tx_rx_count; - struct dentry *algorithm; - struct dentry *tx_spec; - struct dentry *rx_spec; - struct dentry *replays; - struct dentry *key; - struct dentry *ifindex; - } debugfs; -#endif - - /* - * key config, must be last because it contains key - * material as variable length member - */ - struct ieee80211_key_conf conf; -}; - -struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, - int idx, - size_t key_len, - const u8 *key_data); -/* - * Insert a key into data structures (sdata, sta if necessary) - * to make it used, free old key. - */ -void ieee80211_key_link(struct ieee80211_key *key, - struct ieee80211_sub_if_data *sdata, - struct sta_info *sta); -void ieee80211_key_free(struct ieee80211_key *key); -void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); -void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); -void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); -void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); - -void ieee80211_key_todo(void); - -#endif /* IEEE80211_KEY_H */ diff --git a/net/mac80211/ieee80211_led.c b/net/mac80211/ieee80211_led.c deleted file mode 100644 index f401484ab6d7..000000000000 --- a/net/mac80211/ieee80211_led.c +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2006, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* just for IFNAMSIZ */ -#include -#include "ieee80211_led.h" - -void ieee80211_led_rx(struct ieee80211_local *local) -{ - if (unlikely(!local->rx_led)) - return; - if (local->rx_led_counter++ % 2 == 0) - led_trigger_event(local->rx_led, LED_OFF); - else - led_trigger_event(local->rx_led, LED_FULL); -} - -/* q is 1 if a packet was enqueued, 0 if it has been transmitted */ -void ieee80211_led_tx(struct ieee80211_local *local, int q) -{ - if (unlikely(!local->tx_led)) - return; - /* not sure how this is supposed to work ... */ - local->tx_led_counter += 2*q-1; - if (local->tx_led_counter % 2 == 0) - led_trigger_event(local->tx_led, LED_OFF); - else - led_trigger_event(local->tx_led, LED_FULL); -} - -void ieee80211_led_assoc(struct ieee80211_local *local, bool associated) -{ - if (unlikely(!local->assoc_led)) - return; - if (associated) - led_trigger_event(local->assoc_led, LED_FULL); - else - led_trigger_event(local->assoc_led, LED_OFF); -} - -void ieee80211_led_radio(struct ieee80211_local *local, bool enabled) -{ - if (unlikely(!local->radio_led)) - return; - if (enabled) - led_trigger_event(local->radio_led, LED_FULL); - else - led_trigger_event(local->radio_led, LED_OFF); -} - -void ieee80211_led_init(struct ieee80211_local *local) -{ - local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); - if (local->rx_led) { - snprintf(local->rx_led_name, sizeof(local->rx_led_name), - "%srx", wiphy_name(local->hw.wiphy)); - local->rx_led->name = local->rx_led_name; - if (led_trigger_register(local->rx_led)) { - kfree(local->rx_led); - local->rx_led = NULL; - } - } - - local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); - if (local->tx_led) { - snprintf(local->tx_led_name, sizeof(local->tx_led_name), - "%stx", wiphy_name(local->hw.wiphy)); - local->tx_led->name = local->tx_led_name; - if (led_trigger_register(local->tx_led)) { - kfree(local->tx_led); - local->tx_led = NULL; - } - } - - local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); - if (local->assoc_led) { - snprintf(local->assoc_led_name, sizeof(local->assoc_led_name), - "%sassoc", wiphy_name(local->hw.wiphy)); - local->assoc_led->name = local->assoc_led_name; - if (led_trigger_register(local->assoc_led)) { - kfree(local->assoc_led); - local->assoc_led = NULL; - } - } - - local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); - if (local->radio_led) { - snprintf(local->radio_led_name, sizeof(local->radio_led_name), - "%sradio", wiphy_name(local->hw.wiphy)); - local->radio_led->name = local->radio_led_name; - if (led_trigger_register(local->radio_led)) { - kfree(local->radio_led); - local->radio_led = NULL; - } - } -} - -void ieee80211_led_exit(struct ieee80211_local *local) -{ - if (local->radio_led) { - led_trigger_unregister(local->radio_led); - kfree(local->radio_led); - } - if (local->assoc_led) { - led_trigger_unregister(local->assoc_led); - kfree(local->assoc_led); - } - if (local->tx_led) { - led_trigger_unregister(local->tx_led); - kfree(local->tx_led); - } - if (local->rx_led) { - led_trigger_unregister(local->rx_led); - kfree(local->rx_led); - } -} - -char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - - if (local->radio_led) - return local->radio_led_name; - return NULL; -} -EXPORT_SYMBOL(__ieee80211_get_radio_led_name); - -char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - - if (local->assoc_led) - return local->assoc_led_name; - return NULL; -} -EXPORT_SYMBOL(__ieee80211_get_assoc_led_name); - -char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - - if (local->tx_led) - return local->tx_led_name; - return NULL; -} -EXPORT_SYMBOL(__ieee80211_get_tx_led_name); - -char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - - if (local->rx_led) - return local->rx_led_name; - return NULL; -} -EXPORT_SYMBOL(__ieee80211_get_rx_led_name); diff --git a/net/mac80211/ieee80211_led.h b/net/mac80211/ieee80211_led.h deleted file mode 100644 index 77b1e1ba6039..000000000000 --- a/net/mac80211/ieee80211_led.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2006, Johannes Berg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include "ieee80211_i.h" - -#ifdef CONFIG_MAC80211_LEDS -extern void ieee80211_led_rx(struct ieee80211_local *local); -extern void ieee80211_led_tx(struct ieee80211_local *local, int q); -extern void ieee80211_led_assoc(struct ieee80211_local *local, - bool associated); -extern void ieee80211_led_radio(struct ieee80211_local *local, - bool enabled); -extern void ieee80211_led_init(struct ieee80211_local *local); -extern void ieee80211_led_exit(struct ieee80211_local *local); -#else -static inline void ieee80211_led_rx(struct ieee80211_local *local) -{ -} -static inline void ieee80211_led_tx(struct ieee80211_local *local, int q) -{ -} -static inline void ieee80211_led_assoc(struct ieee80211_local *local, - bool associated) -{ -} -static inline void ieee80211_led_radio(struct ieee80211_local *local, - bool enabled) -{ -} -static inline void ieee80211_led_init(struct ieee80211_local *local) -{ -} -static inline void ieee80211_led_exit(struct ieee80211_local *local) -{ -} -#endif diff --git a/net/mac80211/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c deleted file mode 100644 index 4de06f128d90..000000000000 --- a/net/mac80211/ieee80211_rate.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2002-2005, Instant802 Networks, Inc. - * Copyright 2005-2006, Devicescape Software, Inc. - * Copyright (c) 2006 Jiri Benc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include "ieee80211_rate.h" -#include "ieee80211_i.h" - -struct rate_control_alg { - struct list_head list; - struct rate_control_ops *ops; -}; - -static LIST_HEAD(rate_ctrl_algs); -static DEFINE_MUTEX(rate_ctrl_mutex); - -static char *ieee80211_default_rc_algo = CONFIG_MAC80211_RC_DEFAULT; -module_param(ieee80211_default_rc_algo, charp, 0644); -MODULE_PARM_DESC(ieee80211_default_rc_algo, - "Default rate control algorithm for mac80211 to use"); - -int ieee80211_rate_control_register(struct rate_control_ops *ops) -{ - struct rate_control_alg *alg; - - if (!ops->name) - return -EINVAL; - - mutex_lock(&rate_ctrl_mutex); - list_for_each_entry(alg, &rate_ctrl_algs, list) { - if (!strcmp(alg->ops->name, ops->name)) { - /* don't register an algorithm twice */ - WARN_ON(1); - mutex_unlock(&rate_ctrl_mutex); - return -EALREADY; - } - } - - alg = kzalloc(sizeof(*alg), GFP_KERNEL); - if (alg == NULL) { - mutex_unlock(&rate_ctrl_mutex); - return -ENOMEM; - } - alg->ops = ops; - - list_add_tail(&alg->list, &rate_ctrl_algs); - mutex_unlock(&rate_ctrl_mutex); - - return 0; -} -EXPORT_SYMBOL(ieee80211_rate_control_register); - -void ieee80211_rate_control_unregister(struct rate_control_ops *ops) -{ - struct rate_control_alg *alg; - - mutex_lock(&rate_ctrl_mutex); - list_for_each_entry(alg, &rate_ctrl_algs, list) { - if (alg->ops == ops) { - list_del(&alg->list); - kfree(alg); - break; - } - } - mutex_unlock(&rate_ctrl_mutex); -} -EXPORT_SYMBOL(ieee80211_rate_control_unregister); - -static struct rate_control_ops * -ieee80211_try_rate_control_ops_get(const char *name) -{ - struct rate_control_alg *alg; - struct rate_control_ops *ops = NULL; - - if (!name) - return NULL; - - mutex_lock(&rate_ctrl_mutex); - list_for_each_entry(alg, &rate_ctrl_algs, list) { - if (!strcmp(alg->ops->name, name)) - if (try_module_get(alg->ops->module)) { - ops = alg->ops; - break; - } - } - mutex_unlock(&rate_ctrl_mutex); - return ops; -} - -/* Get the rate control algorithm. */ -static struct rate_control_ops * -ieee80211_rate_control_ops_get(const char *name) -{ - struct rate_control_ops *ops; - const char *alg_name; - - if (!name) - alg_name = ieee80211_default_rc_algo; - else - alg_name = name; - - ops = ieee80211_try_rate_control_ops_get(alg_name); - if (!ops) { - request_module("rc80211_%s", alg_name); - ops = ieee80211_try_rate_control_ops_get(alg_name); - } - if (!ops && name) - /* try default if specific alg requested but not found */ - ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo); - - /* try built-in one if specific alg requested but not found */ - if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT)) - ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT); - - return ops; -} - -static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops) -{ - module_put(ops->module); -} - -struct rate_control_ref *rate_control_alloc(const char *name, - struct ieee80211_local *local) -{ - struct rate_control_ref *ref; - - ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL); - if (!ref) - goto fail_ref; - kref_init(&ref->kref); - ref->ops = ieee80211_rate_control_ops_get(name); - if (!ref->ops) - goto fail_ops; - ref->priv = ref->ops->alloc(local); - if (!ref->priv) - goto fail_priv; - return ref; - -fail_priv: - ieee80211_rate_control_ops_put(ref->ops); -fail_ops: - kfree(ref); -fail_ref: - return NULL; -} - -static void rate_control_release(struct kref *kref) -{ - struct rate_control_ref *ctrl_ref; - - ctrl_ref = container_of(kref, struct rate_control_ref, kref); - ctrl_ref->ops->free(ctrl_ref->priv); - ieee80211_rate_control_ops_put(ctrl_ref->ops); - kfree(ctrl_ref); -} - -void rate_control_get_rate(struct net_device *dev, - struct ieee80211_supported_band *sband, - struct sk_buff *skb, - struct rate_selection *sel) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct rate_control_ref *ref = local->rate_ctrl; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct sta_info *sta; - int i; - - rcu_read_lock(); - sta = sta_info_get(local, hdr->addr1); - - memset(sel, 0, sizeof(struct rate_selection)); - - ref->ops->get_rate(ref->priv, dev, sband, skb, sel); - - /* Select a non-ERP backup rate. */ - if (!sel->nonerp) { - for (i = 0; i < sband->n_bitrates; i++) { - struct ieee80211_rate *rate = &sband->bitrates[i]; - if (sel->rate->bitrate < rate->bitrate) - break; - - if (rate_supported(sta, sband->band, i) && - !(rate->flags & IEEE80211_RATE_ERP_G)) - sel->nonerp = rate; - } - } - - rcu_read_unlock(); -} - -struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) -{ - kref_get(&ref->kref); - return ref; -} - -void rate_control_put(struct rate_control_ref *ref) -{ - kref_put(&ref->kref, rate_control_release); -} - -int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, - const char *name) -{ - struct rate_control_ref *ref, *old; - - ASSERT_RTNL(); - if (local->open_count || netif_running(local->mdev)) - return -EBUSY; - - ref = rate_control_alloc(name, local); - if (!ref) { - printk(KERN_WARNING "%s: Failed to select rate control " - "algorithm\n", wiphy_name(local->hw.wiphy)); - return -ENOENT; - } - - old = local->rate_ctrl; - local->rate_ctrl = ref; - if (old) { - rate_control_put(old); - sta_info_flush(local, NULL); - } - - printk(KERN_DEBUG "%s: Selected rate control " - "algorithm '%s'\n", wiphy_name(local->hw.wiphy), - ref->ops->name); - - - return 0; -} - -void rate_control_deinitialize(struct ieee80211_local *local) -{ - struct rate_control_ref *ref; - - ref = local->rate_ctrl; - local->rate_ctrl = NULL; - rate_control_put(ref); -} - diff --git a/net/mac80211/ieee80211_rate.h b/net/mac80211/ieee80211_rate.h deleted file mode 100644 index 5b45f33cb766..000000000000 --- a/net/mac80211/ieee80211_rate.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2002-2005, Instant802 Networks, Inc. - * Copyright 2005, Devicescape Software, Inc. - * Copyright (c) 2006 Jiri Benc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef IEEE80211_RATE_H -#define IEEE80211_RATE_H - -#include -#include -#include -#include -#include -#include "ieee80211_i.h" -#include "sta_info.h" - -/* TODO: kdoc */ -struct rate_selection { - /* Selected transmission rate */ - struct ieee80211_rate *rate; - /* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */ - struct ieee80211_rate *nonerp; - /* probe with this rate, or NULL for no probing */ - struct ieee80211_rate *probe; -}; - -struct rate_control_ops { - struct module *module; - const char *name; - void (*tx_status)(void *priv, struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *status); - void (*get_rate)(void *priv, struct net_device *dev, - struct ieee80211_supported_band *band, - struct sk_buff *skb, - struct rate_selection *sel); - void (*rate_init)(void *priv, void *priv_sta, - struct ieee80211_local *local, struct sta_info *sta); - void (*clear)(void *priv); - - void *(*alloc)(struct ieee80211_local *local); - void (*free)(void *priv); - void *(*alloc_sta)(void *priv, gfp_t gfp); - void (*free_sta)(void *priv, void *priv_sta); - - int (*add_attrs)(void *priv, struct kobject *kobj); - void (*remove_attrs)(void *priv, struct kobject *kobj); - void (*add_sta_debugfs)(void *priv, void *priv_sta, - struct dentry *dir); - void (*remove_sta_debugfs)(void *priv, void *priv_sta); -}; - -struct rate_control_ref { - struct rate_control_ops *ops; - void *priv; - struct kref kref; -}; - -int ieee80211_rate_control_register(struct rate_control_ops *ops); -void ieee80211_rate_control_unregister(struct rate_control_ops *ops); - -/* Get a reference to the rate control algorithm. If `name' is NULL, get the - * first available algorithm. */ -struct rate_control_ref *rate_control_alloc(const char *name, - struct ieee80211_local *local); -void rate_control_get_rate(struct net_device *dev, - struct ieee80211_supported_band *sband, - struct sk_buff *skb, - struct rate_selection *sel); -struct rate_control_ref *rate_control_get(struct rate_control_ref *ref); -void rate_control_put(struct rate_control_ref *ref); - -static inline void rate_control_tx_status(struct net_device *dev, - struct sk_buff *skb, - struct ieee80211_tx_status *status) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct rate_control_ref *ref = local->rate_ctrl; - - ref->ops->tx_status(ref->priv, dev, skb, status); -} - - -static inline void rate_control_rate_init(struct sta_info *sta, - struct ieee80211_local *local) -{ - struct rate_control_ref *ref = sta->rate_ctrl; - ref->ops->rate_init(ref->priv, sta->rate_ctrl_priv, local, sta); -} - - -static inline void rate_control_clear(struct ieee80211_local *local) -{ - struct rate_control_ref *ref = local->rate_ctrl; - ref->ops->clear(ref->priv); -} - -static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, - gfp_t gfp) -{ - return ref->ops->alloc_sta(ref->priv, gfp); -} - -static inline void rate_control_free_sta(struct rate_control_ref *ref, - void *priv) -{ - ref->ops->free_sta(ref->priv, priv); -} - -static inline void rate_control_add_sta_debugfs(struct sta_info *sta) -{ -#ifdef CONFIG_MAC80211_DEBUGFS - struct rate_control_ref *ref = sta->rate_ctrl; - if (sta->debugfs.dir && ref->ops->add_sta_debugfs) - ref->ops->add_sta_debugfs(ref->priv, sta->rate_ctrl_priv, - sta->debugfs.dir); -#endif -} - -static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) -{ -#ifdef CONFIG_MAC80211_DEBUGFS - struct rate_control_ref *ref = sta->rate_ctrl; - if (ref->ops->remove_sta_debugfs) - ref->ops->remove_sta_debugfs(ref->priv, sta->rate_ctrl_priv); -#endif -} - -static inline int rate_supported(struct sta_info *sta, - enum ieee80211_band band, - int index) -{ - return (sta == NULL || sta->supp_rates[band] & BIT(index)); -} - -static inline int -rate_lowest_index(struct ieee80211_local *local, - struct ieee80211_supported_band *sband, - struct sta_info *sta) -{ - int i; - - for (i = 0; i < sband->n_bitrates; i++) - if (rate_supported(sta, sband->band, i)) - return i; - - /* warn when we cannot find a rate. */ - WARN_ON(1); - - return 0; -} - -static inline struct ieee80211_rate * -rate_lowest(struct ieee80211_local *local, - struct ieee80211_supported_band *sband, - struct sta_info *sta) -{ - return &sband->bitrates[rate_lowest_index(local, sband, sta)]; -} - - -/* functions for rate control related to a device */ -int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, - const char *name); -void rate_control_deinitialize(struct ieee80211_local *local); - - -/* Rate control algorithms */ -#if defined(RC80211_PID_COMPILE) || \ - (defined(CONFIG_MAC80211_RC_PID) && \ - !defined(CONFIG_MAC80211_RC_PID_MODULE)) -extern int rc80211_pid_init(void); -extern void rc80211_pid_exit(void); -#else -static inline int rc80211_pid_init(void) -{ - return 0; -} -static inline void rc80211_pid_exit(void) -{ -} -#endif - -#endif /* IEEE80211_RATE_H */ diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c deleted file mode 100644 index 3584a2bf0186..000000000000 --- a/net/mac80211/ieee80211_sta.c +++ /dev/null @@ -1,4249 +0,0 @@ -/* - * BSS client mode implementation - * Copyright 2003, Jouni Malinen - * Copyright 2004, Instant802 Networks, Inc. - * Copyright 2005, Devicescape Software, Inc. - * Copyright 2006-2007 Jiri Benc - * Copyright 2007, Michael Wu - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* TODO: - * order BSS list by RSSI(?) ("quality of AP") - * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, - * SSID) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "ieee80211_i.h" -#include "ieee80211_rate.h" -#include "ieee80211_led.h" -#include "mesh.h" - -#define IEEE80211_AUTH_TIMEOUT (HZ / 5) -#define IEEE80211_AUTH_MAX_TRIES 3 -#define IEEE80211_ASSOC_TIMEOUT (HZ / 5) -#define IEEE80211_ASSOC_MAX_TRIES 3 -#define IEEE80211_MONITORING_INTERVAL (2 * HZ) -#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) -#define IEEE80211_PROBE_INTERVAL (60 * HZ) -#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) -#define IEEE80211_SCAN_INTERVAL (2 * HZ) -#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) -#define IEEE80211_IBSS_JOIN_TIMEOUT (20 * HZ) - -#define IEEE80211_PROBE_DELAY (HZ / 33) -#define IEEE80211_CHANNEL_TIME (HZ / 33) -#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5) -#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) -#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) -#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) -#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) - -#define IEEE80211_IBSS_MAX_STA_ENTRIES 128 - - -#define ERP_INFO_USE_PROTECTION BIT(1) - -/* mgmt header + 1 byte action code */ -#define IEEE80211_MIN_ACTION_SIZE (24 + 1) - -#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 -#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C -#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0 -#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000 -#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800 - -/* next values represent the buffer size for A-MPDU frame. - * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) */ -#define IEEE80211_MIN_AMPDU_BUF 0x8 -#define IEEE80211_MAX_AMPDU_BUF 0x40 - -static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, - u8 *ssid, size_t ssid_len); -static struct ieee80211_sta_bss * -ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, - u8 *ssid, u8 ssid_len); -static void ieee80211_rx_bss_put(struct net_device *dev, - struct ieee80211_sta_bss *bss); -static int ieee80211_sta_find_ibss(struct net_device *dev, - struct ieee80211_if_sta *ifsta); -static int ieee80211_sta_wep_configured(struct net_device *dev); -static int ieee80211_sta_start_scan(struct net_device *dev, - u8 *ssid, size_t ssid_len); -static int ieee80211_sta_config_auth(struct net_device *dev, - struct ieee80211_if_sta *ifsta); - - -void ieee802_11_parse_elems(u8 *start, size_t len, - struct ieee802_11_elems *elems) -{ - size_t left = len; - u8 *pos = start; - - memset(elems, 0, sizeof(*elems)); - - while (left >= 2) { - u8 id, elen; - - id = *pos++; - elen = *pos++; - left -= 2; - - if (elen > left) - return; - - switch (id) { - case WLAN_EID_SSID: - elems->ssid = pos; - elems->ssid_len = elen; - break; - case WLAN_EID_SUPP_RATES: - elems->supp_rates = pos; - elems->supp_rates_len = elen; - break; - case WLAN_EID_FH_PARAMS: - elems->fh_params = pos; - elems->fh_params_len = elen; - break; - case WLAN_EID_DS_PARAMS: - elems->ds_params = pos; - elems->ds_params_len = elen; - break; - case WLAN_EID_CF_PARAMS: - elems->cf_params = pos; - elems->cf_params_len = elen; - break; - case WLAN_EID_TIM: - elems->tim = pos; - elems->tim_len = elen; - break; - case WLAN_EID_IBSS_PARAMS: - elems->ibss_params = pos; - elems->ibss_params_len = elen; - break; - case WLAN_EID_CHALLENGE: - elems->challenge = pos; - elems->challenge_len = elen; - break; - case WLAN_EID_WPA: - if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && - pos[2] == 0xf2) { - /* Microsoft OUI (00:50:F2) */ - if (pos[3] == 1) { - /* OUI Type 1 - WPA IE */ - elems->wpa = pos; - elems->wpa_len = elen; - } else if (elen >= 5 && pos[3] == 2) { - if (pos[4] == 0) { - elems->wmm_info = pos; - elems->wmm_info_len = elen; - } else if (pos[4] == 1) { - elems->wmm_param = pos; - elems->wmm_param_len = elen; - } - } - } - break; - case WLAN_EID_RSN: - elems->rsn = pos; - elems->rsn_len = elen; - break; - case WLAN_EID_ERP_INFO: - elems->erp_info = pos; - elems->erp_info_len = elen; - break; - case WLAN_EID_EXT_SUPP_RATES: - elems->ext_supp_rates = pos; - elems->ext_supp_rates_len = elen; - break; - case WLAN_EID_HT_CAPABILITY: - elems->ht_cap_elem = pos; - elems->ht_cap_elem_len = elen; - break; - case WLAN_EID_HT_EXTRA_INFO: - elems->ht_info_elem = pos; - elems->ht_info_elem_len = elen; - break; - case WLAN_EID_MESH_ID: - elems->mesh_id = pos; - elems->mesh_id_len = elen; - break; - case WLAN_EID_MESH_CONFIG: - elems->mesh_config = pos; - elems->mesh_config_len = elen; - break; - case WLAN_EID_PEER_LINK: - elems->peer_link = pos; - elems->peer_link_len = elen; - break; - case WLAN_EID_PREQ: - elems->preq = pos; - elems->preq_len = elen; - break; - case WLAN_EID_PREP: - elems->prep = pos; - elems->prep_len = elen; - break; - case WLAN_EID_PERR: - elems->perr = pos; - elems->perr_len = elen; - break; - default: - break; - } - - left -= elen; - pos += elen; - } -} - - -static int ecw2cw(int ecw) -{ - return (1 << ecw) - 1; -} - - -static void ieee80211_sta_def_wmm_params(struct net_device *dev, - struct ieee80211_sta_bss *bss, - int ibss) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; - int i, have_higher_than_11mbit = 0; - - - /* cf. IEEE 802.11 9.2.12 */ - for (i = 0; i < bss->supp_rates_len; i++) - if ((bss->supp_rates[i] & 0x7f) * 5 > 110) - have_higher_than_11mbit = 1; - - if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && - have_higher_than_11mbit) - sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; - else - sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; - - - if (local->ops->conf_tx) { - struct ieee80211_tx_queue_params qparam; - - memset(&qparam, 0, sizeof(qparam)); - - qparam.aifs = 2; - - if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && - !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) - qparam.cw_min = 31; - else - qparam.cw_min = 15; - - qparam.cw_max = 1023; - qparam.txop = 0; - - for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) - local->ops->conf_tx(local_to_hw(local), - i + IEEE80211_TX_QUEUE_DATA0, - &qparam); - - if (ibss) { - /* IBSS uses different parameters for Beacon sending */ - qparam.cw_min++; - qparam.cw_min *= 2; - qparam.cw_min--; - local->ops->conf_tx(local_to_hw(local), - IEEE80211_TX_QUEUE_BEACON, &qparam); - } - } -} - -static void ieee80211_sta_wmm_params(struct net_device *dev, - struct ieee80211_if_sta *ifsta, - u8 *wmm_param, size_t wmm_param_len) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_tx_queue_params params; - size_t left; - int count; - u8 *pos; - - if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) - return; - count = wmm_param[6] & 0x0f; - if (count == ifsta->wmm_last_param_set) - return; - ifsta->wmm_last_param_set = count; - - pos = wmm_param + 8; - left = wmm_param_len - 8; - - memset(¶ms, 0, sizeof(params)); - - if (!local->ops->conf_tx) - return; - - local->wmm_acm = 0; - for (; left >= 4; left -= 4, pos += 4) { - int aci = (pos[0] >> 5) & 0x03; - int acm = (pos[0] >> 4) & 0x01; - int queue; - - switch (aci) { - case 1: - queue = IEEE80211_TX_QUEUE_DATA3; - if (acm) { - local->wmm_acm |= BIT(0) | BIT(3); - } - break; - case 2: - queue = IEEE80211_TX_QUEUE_DATA1; - if (acm) { - local->wmm_acm |= BIT(4) | BIT(5); - } - break; - case 3: - queue = IEEE80211_TX_QUEUE_DATA0; - if (acm) { - local->wmm_acm |= BIT(6) | BIT(7); - } - break; - case 0: - default: - queue = IEEE80211_TX_QUEUE_DATA2; - if (acm) { - local->wmm_acm |= BIT(1) | BIT(2); - } - break; - } - - params.aifs = pos[0] & 0x0f; - params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); - params.cw_min = ecw2cw(pos[1] & 0x0f); - params.txop = pos[2] | (pos[3] << 8); -#ifdef CONFIG_MAC80211_DEBUG - printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " - "cWmin=%d cWmax=%d txop=%d\n", - dev->name, queue, aci, acm, params.aifs, params.cw_min, - params.cw_max, params.txop); -#endif - /* TODO: handle ACM (block TX, fallback to next lowest allowed - * AC for now) */ - if (local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) { - printk(KERN_DEBUG "%s: failed to set TX queue " - "parameters for queue %d\n", dev->name, queue); - } - } -} - - -static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata, - u8 erp_value) -{ - struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; - struct ieee80211_if_sta *ifsta = &sdata->u.sta; - bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; - bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0; - DECLARE_MAC_BUF(mac); - u32 changed = 0; - - if (use_protection != bss_conf->use_cts_prot) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: CTS protection %s (BSSID=" - "%s)\n", - sdata->dev->name, - use_protection ? "enabled" : "disabled", - print_mac(mac, ifsta->bssid)); - } - bss_conf->use_cts_prot = use_protection; - changed |= BSS_CHANGED_ERP_CTS_PROT; - } - - if (use_short_preamble != bss_conf->use_short_preamble) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: switched to %s barker preamble" - " (BSSID=%s)\n", - sdata->dev->name, - use_short_preamble ? "short" : "long", - print_mac(mac, ifsta->bssid)); - } - bss_conf->use_short_preamble = use_short_preamble; - changed |= BSS_CHANGED_ERP_PREAMBLE; - } - - return changed; -} - -int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, - struct ieee80211_ht_info *ht_info) -{ - - if (ht_info == NULL) - return -EINVAL; - - memset(ht_info, 0, sizeof(*ht_info)); - - if (ht_cap_ie) { - u8 ampdu_info = ht_cap_ie->ampdu_params_info; - - ht_info->ht_supported = 1; - ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info); - ht_info->ampdu_factor = - ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR; - ht_info->ampdu_density = - (ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2; - memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16); - } else - ht_info->ht_supported = 0; - - return 0; -} - -int ieee80211_ht_addt_info_ie_to_ht_bss_info( - struct ieee80211_ht_addt_info *ht_add_info_ie, - struct ieee80211_ht_bss_info *bss_info) -{ - if (bss_info == NULL) - return -EINVAL; - - memset(bss_info, 0, sizeof(*bss_info)); - - if (ht_add_info_ie) { - u16 op_mode; - op_mode = le16_to_cpu(ht_add_info_ie->operation_mode); - - bss_info->primary_channel = ht_add_info_ie->control_chan; - bss_info->bss_cap = ht_add_info_ie->ht_param; - bss_info->bss_op_mode = (u8)(op_mode & 0xff); - } - - return 0; -} - -static void ieee80211_sta_send_associnfo(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - char *buf; - size_t len; - int i; - union iwreq_data wrqu; - - if (!ifsta->assocreq_ies && !ifsta->assocresp_ies) - return; - - buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len + - ifsta->assocresp_ies_len), GFP_KERNEL); - if (!buf) - return; - - len = sprintf(buf, "ASSOCINFO("); - if (ifsta->assocreq_ies) { - len += sprintf(buf + len, "ReqIEs="); - for (i = 0; i < ifsta->assocreq_ies_len; i++) { - len += sprintf(buf + len, "%02x", - ifsta->assocreq_ies[i]); - } - } - if (ifsta->assocresp_ies) { - if (ifsta->assocreq_ies) - len += sprintf(buf + len, " "); - len += sprintf(buf + len, "RespIEs="); - for (i = 0; i < ifsta->assocresp_ies_len; i++) { - len += sprintf(buf + len, "%02x", - ifsta->assocresp_ies[i]); - } - } - len += sprintf(buf + len, ")"); - - if (len > IW_CUSTOM_MAX) { - len = sprintf(buf, "ASSOCRESPIE="); - for (i = 0; i < ifsta->assocresp_ies_len; i++) { - len += sprintf(buf + len, "%02x", - ifsta->assocresp_ies[i]); - } - } - - memset(&wrqu, 0, sizeof(wrqu)); - wrqu.data.length = len; - wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); - - kfree(buf); -} - - -static void ieee80211_set_associated(struct net_device *dev, - struct ieee80211_if_sta *ifsta, - bool assoc) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; - struct ieee80211_conf *conf = &local_to_hw(local)->conf; - union iwreq_data wrqu; - u32 changed = BSS_CHANGED_ASSOC; - - if (assoc) { - struct ieee80211_sta_bss *bss; - - ifsta->flags |= IEEE80211_STA_ASSOCIATED; - - if (sdata->vif.type != IEEE80211_IF_TYPE_STA) - return; - - bss = ieee80211_rx_bss_get(dev, ifsta->bssid, - conf->channel->center_freq, - ifsta->ssid, ifsta->ssid_len); - if (bss) { - /* set timing information */ - sdata->bss_conf.beacon_int = bss->beacon_int; - sdata->bss_conf.timestamp = bss->timestamp; - - if (bss->has_erp_value) - changed |= ieee80211_handle_erp_ie( - sdata, bss->erp_value); - - ieee80211_rx_bss_put(dev, bss); - } - - if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { - changed |= BSS_CHANGED_HT; - sdata->bss_conf.assoc_ht = 1; - sdata->bss_conf.ht_conf = &conf->ht_conf; - sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf; - } - - netif_carrier_on(dev); - ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; - memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); - memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN); - ieee80211_sta_send_associnfo(dev, ifsta); - } else { - ieee80211_sta_tear_down_BA_sessions(dev, ifsta->bssid); - ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; - netif_carrier_off(dev); - ieee80211_reset_erp_info(dev); - - sdata->bss_conf.assoc_ht = 0; - sdata->bss_conf.ht_conf = NULL; - sdata->bss_conf.ht_bss_conf = NULL; - - memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); - } - ifsta->last_probe = jiffies; - ieee80211_led_assoc(local, assoc); - - sdata->bss_conf.assoc = assoc; - ieee80211_bss_info_change_notify(sdata, changed); - wrqu.ap_addr.sa_family = ARPHRD_ETHER; - wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); -} - -static void ieee80211_set_disassoc(struct net_device *dev, - struct ieee80211_if_sta *ifsta, int deauth) -{ - if (deauth) - ifsta->auth_tries = 0; - ifsta->assoc_tries = 0; - ieee80211_set_associated(dev, ifsta, 0); -} - -void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, - int encrypt) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_tx_packet_data *pkt_data; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - skb->dev = sdata->local->mdev; - skb_set_mac_header(skb, 0); - skb_set_network_header(skb, 0); - skb_set_transport_header(skb, 0); - - pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; - memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); - pkt_data->ifindex = sdata->dev->ifindex; - if (!encrypt) - pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; - - dev_queue_xmit(skb); -} - - -static void ieee80211_send_auth(struct net_device *dev, - struct ieee80211_if_sta *ifsta, - int transaction, u8 *extra, size_t extra_len, - int encrypt) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + - sizeof(*mgmt) + 6 + extra_len); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for auth " - "frame\n", dev->name); - return; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); - memset(mgmt, 0, 24 + 6); - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_AUTH); - if (encrypt) - mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); - mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg); - mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); - ifsta->auth_transaction = transaction + 1; - mgmt->u.auth.status_code = cpu_to_le16(0); - if (extra) - memcpy(skb_put(skb, extra_len), extra, extra_len); - - ieee80211_sta_tx(dev, skb, encrypt); -} - - -static void ieee80211_authenticate(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - DECLARE_MAC_BUF(mac); - - ifsta->auth_tries++; - if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: authentication with AP %s" - " timed out\n", - dev->name, print_mac(mac, ifsta->bssid)); - ifsta->state = IEEE80211_DISABLED; - return; - } - - ifsta->state = IEEE80211_AUTHENTICATE; - printk(KERN_DEBUG "%s: authenticate with AP %s\n", - dev->name, print_mac(mac, ifsta->bssid)); - - ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0); - - mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); -} - - -static void ieee80211_send_assoc(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - u8 *pos, *ies; - int i, len; - u16 capab; - struct ieee80211_sta_bss *bss; - int wmm = 0; - struct ieee80211_supported_band *sband; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + - sizeof(*mgmt) + 200 + ifsta->extra_ie_len + - ifsta->ssid_len); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " - "frame\n", dev->name); - return; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - capab = ifsta->capab; - - if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { - if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) - capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; - if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) - capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; - } - - bss = ieee80211_rx_bss_get(dev, ifsta->bssid, - local->hw.conf.channel->center_freq, - ifsta->ssid, ifsta->ssid_len); - if (bss) { - if (bss->capability & WLAN_CAPABILITY_PRIVACY) - capab |= WLAN_CAPABILITY_PRIVACY; - if (bss->wmm_ie) { - wmm = 1; - } - ieee80211_rx_bss_put(dev, bss); - } - - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); - memset(mgmt, 0, 24); - memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); - - if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { - skb_put(skb, 10); - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_REASSOC_REQ); - mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); - mgmt->u.reassoc_req.listen_interval = cpu_to_le16(1); - memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid, - ETH_ALEN); - } else { - skb_put(skb, 4); - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_ASSOC_REQ); - mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); - mgmt->u.assoc_req.listen_interval = cpu_to_le16(1); - } - - /* SSID */ - ies = pos = skb_put(skb, 2 + ifsta->ssid_len); - *pos++ = WLAN_EID_SSID; - *pos++ = ifsta->ssid_len; - memcpy(pos, ifsta->ssid, ifsta->ssid_len); - - len = sband->n_bitrates; - if (len > 8) - len = 8; - pos = skb_put(skb, len + 2); - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = len; - for (i = 0; i < len; i++) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - } - - if (sband->n_bitrates > len) { - pos = skb_put(skb, sband->n_bitrates - len + 2); - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = sband->n_bitrates - len; - for (i = len; i < sband->n_bitrates; i++) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - } - } - - if (ifsta->extra_ie) { - pos = skb_put(skb, ifsta->extra_ie_len); - memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); - } - - if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { - pos = skb_put(skb, 9); - *pos++ = WLAN_EID_VENDOR_SPECIFIC; - *pos++ = 7; /* len */ - *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ - *pos++ = 0x50; - *pos++ = 0xf2; - *pos++ = 2; /* WME */ - *pos++ = 0; /* WME info */ - *pos++ = 1; /* WME ver */ - *pos++ = 0; - } - /* wmm support is a must to HT */ - if (wmm && sband->ht_info.ht_supported) { - __le16 tmp = cpu_to_le16(sband->ht_info.cap); - pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); - *pos++ = WLAN_EID_HT_CAPABILITY; - *pos++ = sizeof(struct ieee80211_ht_cap); - memset(pos, 0, sizeof(struct ieee80211_ht_cap)); - memcpy(pos, &tmp, sizeof(u16)); - pos += sizeof(u16); - /* TODO: needs a define here for << 2 */ - *pos++ = sband->ht_info.ampdu_factor | - (sband->ht_info.ampdu_density << 2); - memcpy(pos, sband->ht_info.supp_mcs_set, 16); - } - - kfree(ifsta->assocreq_ies); - ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; - ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); - if (ifsta->assocreq_ies) - memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len); - - ieee80211_sta_tx(dev, skb, 0); -} - - -static void ieee80211_send_deauth(struct net_device *dev, - struct ieee80211_if_sta *ifsta, u16 reason) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for deauth " - "frame\n", dev->name); - return; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); - memset(mgmt, 0, 24); - memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_DEAUTH); - skb_put(skb, 2); - mgmt->u.deauth.reason_code = cpu_to_le16(reason); - - ieee80211_sta_tx(dev, skb, 0); -} - - -static void ieee80211_send_disassoc(struct net_device *dev, - struct ieee80211_if_sta *ifsta, u16 reason) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for disassoc " - "frame\n", dev->name); - return; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); - memset(mgmt, 0, 24); - memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_DISASSOC); - skb_put(skb, 2); - mgmt->u.disassoc.reason_code = cpu_to_le16(reason); - - ieee80211_sta_tx(dev, skb, 0); -} - - -static int ieee80211_privacy_mismatch(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sta_bss *bss; - int bss_privacy; - int wep_privacy; - int privacy_invoked; - - if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL)) - return 0; - - bss = ieee80211_rx_bss_get(dev, ifsta->bssid, - local->hw.conf.channel->center_freq, - ifsta->ssid, ifsta->ssid_len); - if (!bss) - return 0; - - bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY); - wep_privacy = !!ieee80211_sta_wep_configured(dev); - privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED); - - ieee80211_rx_bss_put(dev, bss); - - if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked)) - return 0; - - return 1; -} - - -static void ieee80211_associate(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - DECLARE_MAC_BUF(mac); - - ifsta->assoc_tries++; - if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { - printk(KERN_DEBUG "%s: association with AP %s" - " timed out\n", - dev->name, print_mac(mac, ifsta->bssid)); - ifsta->state = IEEE80211_DISABLED; - return; - } - - ifsta->state = IEEE80211_ASSOCIATE; - printk(KERN_DEBUG "%s: associate with AP %s\n", - dev->name, print_mac(mac, ifsta->bssid)); - if (ieee80211_privacy_mismatch(dev, ifsta)) { - printk(KERN_DEBUG "%s: mismatch in privacy configuration and " - "mixed-cell disabled - abort association\n", dev->name); - ifsta->state = IEEE80211_DISABLED; - return; - } - - ieee80211_send_assoc(dev, ifsta); - - mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); -} - - -static void ieee80211_associated(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; - int disassoc; - DECLARE_MAC_BUF(mac); - - /* TODO: start monitoring current AP signal quality and number of - * missed beacons. Scan other channels every now and then and search - * for better APs. */ - /* TODO: remove expired BSSes */ - - ifsta->state = IEEE80211_ASSOCIATED; - - rcu_read_lock(); - - sta = sta_info_get(local, ifsta->bssid); - if (!sta) { - printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", - dev->name, print_mac(mac, ifsta->bssid)); - disassoc = 1; - } else { - disassoc = 0; - if (time_after(jiffies, - sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { - if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) { - printk(KERN_DEBUG "%s: No ProbeResp from " - "current AP %s - assume out of " - "range\n", - dev->name, print_mac(mac, ifsta->bssid)); - disassoc = 1; - sta_info_unlink(&sta); - } else - ieee80211_send_probe_req(dev, ifsta->bssid, - local->scan_ssid, - local->scan_ssid_len); - ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL; - } else { - ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL; - if (time_after(jiffies, ifsta->last_probe + - IEEE80211_PROBE_INTERVAL)) { - ifsta->last_probe = jiffies; - ieee80211_send_probe_req(dev, ifsta->bssid, - ifsta->ssid, - ifsta->ssid_len); - } - } - } - - rcu_read_unlock(); - - if (disassoc && sta) - sta_info_destroy(sta); - - if (disassoc) { - ifsta->state = IEEE80211_DISABLED; - ieee80211_set_associated(dev, ifsta, 0); - } else { - mod_timer(&ifsta->timer, jiffies + - IEEE80211_MONITORING_INTERVAL); - } -} - - -static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, - u8 *ssid, size_t ssid_len) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_supported_band *sband; - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - u8 *pos, *supp_rates, *esupp_rates = NULL; - int i; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for probe " - "request\n", dev->name); - return; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); - memset(mgmt, 0, 24); - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_PROBE_REQ); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - if (dst) { - memcpy(mgmt->da, dst, ETH_ALEN); - memcpy(mgmt->bssid, dst, ETH_ALEN); - } else { - memset(mgmt->da, 0xff, ETH_ALEN); - memset(mgmt->bssid, 0xff, ETH_ALEN); - } - pos = skb_put(skb, 2 + ssid_len); - *pos++ = WLAN_EID_SSID; - *pos++ = ssid_len; - memcpy(pos, ssid, ssid_len); - - supp_rates = skb_put(skb, 2); - supp_rates[0] = WLAN_EID_SUPP_RATES; - supp_rates[1] = 0; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - for (i = 0; i < sband->n_bitrates; i++) { - struct ieee80211_rate *rate = &sband->bitrates[i]; - if (esupp_rates) { - pos = skb_put(skb, 1); - esupp_rates[1]++; - } else if (supp_rates[1] == 8) { - esupp_rates = skb_put(skb, 3); - esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; - esupp_rates[1] = 1; - pos = &esupp_rates[2]; - } else { - pos = skb_put(skb, 1); - supp_rates[1]++; - } - *pos = rate->bitrate / 5; - } - - ieee80211_sta_tx(dev, skb, 0); -} - - -static int ieee80211_sta_wep_configured(struct net_device *dev) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (!sdata || !sdata->default_key || - sdata->default_key->conf.alg != ALG_WEP) - return 0; - return 1; -} - - -static void ieee80211_auth_completed(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - printk(KERN_DEBUG "%s: authenticated\n", dev->name); - ifsta->flags |= IEEE80211_STA_AUTHENTICATED; - ieee80211_associate(dev, ifsta); -} - - -static void ieee80211_auth_challenge(struct net_device *dev, - struct ieee80211_if_sta *ifsta, - struct ieee80211_mgmt *mgmt, - size_t len) -{ - u8 *pos; - struct ieee802_11_elems elems; - - printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name); - pos = mgmt->u.auth.variable; - ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); - if (!elems.challenge) { - printk(KERN_DEBUG "%s: no challenge IE in shared key auth " - "frame\n", dev->name); - return; - } - ieee80211_send_auth(dev, ifsta, 3, elems.challenge - 2, - elems.challenge_len + 2, 1); -} - -static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid, - u8 dialog_token, u16 status, u16 policy, - u16 buf_size, u16 timeout) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_if_sta *ifsta = &sdata->u.sta; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - u16 capab; - - skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + - sizeof(mgmt->u.action.u.addba_resp)); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer " - "for addba resp frame\n", dev->name); - return; - } - - skb_reserve(skb, local->hw.extra_tx_headroom); - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); - memset(mgmt, 0, 24); - memcpy(mgmt->da, da, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - if (sdata->vif.type == IEEE80211_IF_TYPE_AP) - memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN); - else - memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_ACTION); - - skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp)); - mgmt->u.action.category = WLAN_CATEGORY_BACK; - mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; - mgmt->u.action.u.addba_resp.dialog_token = dialog_token; - - capab = (u16)(policy << 1); /* bit 1 aggregation policy */ - capab |= (u16)(tid << 2); /* bit 5:2 TID number */ - capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ - - mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab); - mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); - mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); - - ieee80211_sta_tx(dev, skb, 0); - - return; -} - -void ieee80211_send_addba_request(struct net_device *dev, const u8 *da, - u16 tid, u8 dialog_token, u16 start_seq_num, - u16 agg_size, u16 timeout) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_if_sta *ifsta = &sdata->u.sta; - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - u16 capab; - - skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + - sizeof(mgmt->u.action.u.addba_req)); - - - if (!skb) { - printk(KERN_ERR "%s: failed to allocate buffer " - "for addba request frame\n", dev->name); - return; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); - memset(mgmt, 0, 24); - memcpy(mgmt->da, da, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - if (sdata->vif.type == IEEE80211_IF_TYPE_AP) - memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN); - else - memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); - - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_ACTION); - - skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req)); - - mgmt->u.action.category = WLAN_CATEGORY_BACK; - mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; - - mgmt->u.action.u.addba_req.dialog_token = dialog_token; - capab = (u16)(1 << 1); /* bit 1 aggregation policy */ - capab |= (u16)(tid << 2); /* bit 5:2 TID number */ - capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */ - - mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); - - mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout); - mgmt->u.action.u.addba_req.start_seq_num = - cpu_to_le16(start_seq_num << 4); - - ieee80211_sta_tx(dev, skb, 0); -} - -static void ieee80211_sta_process_addba_request(struct net_device *dev, - struct ieee80211_mgmt *mgmt, - size_t len) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw *hw = &local->hw; - struct ieee80211_conf *conf = &hw->conf; - struct sta_info *sta; - struct tid_ampdu_rx *tid_agg_rx; - u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; - u8 dialog_token; - int ret = -EOPNOTSUPP; - DECLARE_MAC_BUF(mac); - - rcu_read_lock(); - - sta = sta_info_get(local, mgmt->sa); - if (!sta) { - rcu_read_unlock(); - return; - } - - /* extract session parameters from addba request frame */ - dialog_token = mgmt->u.action.u.addba_req.dialog_token; - timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); - start_seq_num = - le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; - - capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); - ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; - tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; - buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; - - status = WLAN_STATUS_REQUEST_DECLINED; - - /* sanity check for incoming parameters: - * check if configuration can support the BA policy - * and if buffer size does not exceeds max value */ - if (((ba_policy != 1) - && (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA))) - || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { - status = WLAN_STATUS_INVALID_QOS_PARAM; -#ifdef CONFIG_MAC80211_HT_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "AddBA Req with bad params from " - "%s on tid %u. policy %d, buffer size %d\n", - print_mac(mac, mgmt->sa), tid, ba_policy, - buf_size); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - goto end_no_lock; - } - /* determine default buffer size */ - if (buf_size == 0) { - struct ieee80211_supported_band *sband; - - sband = local->hw.wiphy->bands[conf->channel->band]; - buf_size = IEEE80211_MIN_AMPDU_BUF; - buf_size = buf_size << sband->ht_info.ampdu_factor; - } - - - /* examine state machine */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); - - if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { -#ifdef CONFIG_MAC80211_HT_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "unexpected AddBA Req from " - "%s on tid %u\n", - print_mac(mac, mgmt->sa), tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - goto end; - } - - /* prepare A-MPDU MLME for Rx aggregation */ - sta->ampdu_mlme.tid_rx[tid] = - kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); - if (!sta->ampdu_mlme.tid_rx[tid]) { - if (net_ratelimit()) - printk(KERN_ERR "allocate rx mlme to tid %d failed\n", - tid); - goto end; - } - /* rx timer */ - sta->ampdu_mlme.tid_rx[tid]->session_timer.function = - sta_rx_agg_session_timer_expired; - sta->ampdu_mlme.tid_rx[tid]->session_timer.data = - (unsigned long)&sta->timer_to_tid[tid]; - init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer); - - tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; - - /* prepare reordering buffer */ - tid_agg_rx->reorder_buf = - kmalloc(buf_size * sizeof(struct sk_buf *), GFP_ATOMIC); - if (!tid_agg_rx->reorder_buf) { - if (net_ratelimit()) - printk(KERN_ERR "can not allocate reordering buffer " - "to tid %d\n", tid); - kfree(sta->ampdu_mlme.tid_rx[tid]); - goto end; - } - memset(tid_agg_rx->reorder_buf, 0, - buf_size * sizeof(struct sk_buf *)); - - if (local->ops->ampdu_action) - ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, - sta->addr, tid, &start_seq_num); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - - if (ret) { - kfree(tid_agg_rx->reorder_buf); - kfree(tid_agg_rx); - sta->ampdu_mlme.tid_rx[tid] = NULL; - goto end; - } - - /* change state and send addba resp */ - sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL; - tid_agg_rx->dialog_token = dialog_token; - tid_agg_rx->ssn = start_seq_num; - tid_agg_rx->head_seq_num = start_seq_num; - tid_agg_rx->buf_size = buf_size; - tid_agg_rx->timeout = timeout; - tid_agg_rx->stored_mpdu_num = 0; - status = WLAN_STATUS_SUCCESS; -end: - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); - -end_no_lock: - ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid, - dialog_token, status, 1, buf_size, timeout); - rcu_read_unlock(); -} - -static void ieee80211_sta_process_addba_resp(struct net_device *dev, - struct ieee80211_mgmt *mgmt, - size_t len) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw *hw = &local->hw; - struct sta_info *sta; - u16 capab; - u16 tid; - u8 *state; - - rcu_read_lock(); - - sta = sta_info_get(local, mgmt->sa); - if (!sta) { - rcu_read_unlock(); - return; - } - - capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); - tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; - - state = &sta->ampdu_mlme.tid_state_tx[tid]; - - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); - - if (!(*state & HT_ADDBA_REQUESTED_MSK)) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" - "%d\n", *state); - goto addba_resp_exit; - } - - if (mgmt->u.action.u.addba_resp.dialog_token != - sta->ampdu_mlme.tid_tx[tid]->dialog_token) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - goto addba_resp_exit; - } - - del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) - == WLAN_STATUS_SUCCESS) { - if (*state & HT_ADDBA_RECEIVED_MSK) - printk(KERN_DEBUG "double addBA response\n"); - - *state |= HT_ADDBA_RECEIVED_MSK; - sta->ampdu_mlme.addba_req_num[tid] = 0; - - if (*state == HT_AGG_STATE_OPERATIONAL) { - printk(KERN_DEBUG "Aggregation on for tid %d \n", tid); - ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); - } - - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid); - } else { - printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid); - - sta->ampdu_mlme.addba_req_num[tid]++; - /* this will allow the state check in stop_BA_session */ - *state = HT_AGG_STATE_OPERATIONAL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - ieee80211_stop_tx_ba_session(hw, sta->addr, tid, - WLAN_BACK_INITIATOR); - } - -addba_resp_exit: - rcu_read_unlock(); -} - -void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, - u16 initiator, u16 reason_code) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_if_sta *ifsta = &sdata->u.sta; - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - u16 params; - - skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + - sizeof(mgmt->u.action.u.delba)); - - if (!skb) { - printk(KERN_ERR "%s: failed to allocate buffer " - "for delba frame\n", dev->name); - return; - } - - skb_reserve(skb, local->hw.extra_tx_headroom); - mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); - memset(mgmt, 0, 24); - memcpy(mgmt->da, da, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - if (sdata->vif.type == IEEE80211_IF_TYPE_AP) - memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN); - else - memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_ACTION); - - skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba)); - - mgmt->u.action.category = WLAN_CATEGORY_BACK; - mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA; - params = (u16)(initiator << 11); /* bit 11 initiator */ - params |= (u16)(tid << 12); /* bit 15:12 TID number */ - - mgmt->u.action.u.delba.params = cpu_to_le16(params); - mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); - - ieee80211_sta_tx(dev, skb, 0); -} - -void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, - u16 initiator, u16 reason) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_hw *hw = &local->hw; - struct sta_info *sta; - int ret, i; - DECLARE_MAC_BUF(mac); - - rcu_read_lock(); - - sta = sta_info_get(local, ra); - if (!sta) { - rcu_read_unlock(); - return; - } - - /* check if TID is in operational state */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); - if (sta->ampdu_mlme.tid_state_rx[tid] - != HT_AGG_STATE_OPERATIONAL) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); - rcu_read_unlock(); - return; - } - sta->ampdu_mlme.tid_state_rx[tid] = - HT_AGG_STATE_REQ_STOP_BA_MSK | - (initiator << HT_AGG_STATE_INITIATOR_SHIFT); - spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); - - /* stop HW Rx aggregation. ampdu_action existence - * already verified in session init so we add the BUG_ON */ - BUG_ON(!local->ops->ampdu_action); - -#ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Rx BA session stop requested for %s tid %u\n", - print_mac(mac, ra), tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - - ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, - ra, tid, NULL); - if (ret) - printk(KERN_DEBUG "HW problem - can not stop rx " - "aggergation for tid %d\n", tid); - - /* shutdown timer has not expired */ - if (initiator != WLAN_BACK_TIMER) - del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer); - - /* check if this is a self generated aggregation halt */ - if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER) - ieee80211_send_delba(dev, ra, tid, 0, reason); - - /* free the reordering buffer */ - for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) { - if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) { - /* release the reordered frames */ - dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]); - sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--; - sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL; - } - } - /* free resources */ - kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); - kfree(sta->ampdu_mlme.tid_rx[tid]); - sta->ampdu_mlme.tid_rx[tid] = NULL; - sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE; - - rcu_read_unlock(); -} - - -static void ieee80211_sta_process_delba(struct net_device *dev, - struct ieee80211_mgmt *mgmt, size_t len) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; - u16 tid, params; - u16 initiator; - DECLARE_MAC_BUF(mac); - - rcu_read_lock(); - - sta = sta_info_get(local, mgmt->sa); - if (!sta) { - rcu_read_unlock(); - return; - } - - params = le16_to_cpu(mgmt->u.action.u.delba.params); - tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; - initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11; - -#ifdef CONFIG_MAC80211_HT_DEBUG - if (net_ratelimit()) - printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n", - print_mac(mac, mgmt->sa), - initiator ? "initiator" : "recipient", tid, - mgmt->u.action.u.delba.reason_code); -#endif /* CONFIG_MAC80211_HT_DEBUG */ - - if (initiator == WLAN_BACK_INITIATOR) - ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid, - WLAN_BACK_INITIATOR, 0); - else { /* WLAN_BACK_RECIPIENT */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); - sta->ampdu_mlme.tid_state_tx[tid] = - HT_AGG_STATE_OPERATIONAL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, - WLAN_BACK_RECIPIENT); - } - rcu_read_unlock(); -} - -/* - * After sending add Block Ack request we activated a timer until - * add Block Ack response will arrive from the recipient. - * If this timer expires sta_addba_resp_timer_expired will be executed. - */ -void sta_addba_resp_timer_expired(unsigned long data) -{ - /* not an elegant detour, but there is no choice as the timer passes - * only one argument, and both sta_info and TID are needed, so init - * flow in sta_info_create gives the TID as data, while the timer_to_id - * array gives the sta through container_of */ - u16 tid = *(int *)data; - struct sta_info *temp_sta = container_of((void *)data, - struct sta_info, timer_to_tid[tid]); - - struct ieee80211_local *local = temp_sta->local; - struct ieee80211_hw *hw = &local->hw; - struct sta_info *sta; - u8 *state; - - rcu_read_lock(); - - sta = sta_info_get(local, temp_sta->addr); - if (!sta) { - rcu_read_unlock(); - return; - } - - state = &sta->ampdu_mlme.tid_state_tx[tid]; - /* check if the TID waits for addBA response */ - spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); - if (!(*state & HT_ADDBA_REQUESTED_MSK)) { - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - *state = HT_AGG_STATE_IDLE; - printk(KERN_DEBUG "timer expired on tid %d but we are not " - "expecting addBA response there", tid); - goto timer_expired_exit; - } - - printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); - - /* go through the state check in stop_BA_session */ - *state = HT_AGG_STATE_OPERATIONAL; - spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); - ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid, - WLAN_BACK_INITIATOR); - -timer_expired_exit: - rcu_read_unlock(); -} - -/* - * After accepting the AddBA Request we activated a timer, - * resetting it after each frame that arrives from the originator. - * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. - */ -void sta_rx_agg_session_timer_expired(unsigned long data) -{ - /* not an elegant detour, but there is no choice as the timer passes - * only one argument, and verious sta_info are needed here, so init - * flow in sta_info_create gives the TID as data, while the timer_to_id - * array gives the sta through container_of */ - u8 *ptid = (u8 *)data; - u8 *timer_to_id = ptid - *ptid; - struct sta_info *sta = container_of(timer_to_id, struct sta_info, - timer_to_tid[0]); - - printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); - ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr, - (u16)*ptid, WLAN_BACK_TIMER, - WLAN_REASON_QSTA_TIMEOUT); -} - -void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int i; - - for (i = 0; i < STA_TID_NUM; i++) { - ieee80211_stop_tx_ba_session(&local->hw, addr, i, - WLAN_BACK_INITIATOR); - ieee80211_sta_stop_rx_ba_session(dev, addr, i, - WLAN_BACK_RECIPIENT, - WLAN_REASON_QSTA_LEAVE_QBSS); - } -} - -static void ieee80211_rx_mgmt_auth(struct net_device *dev, - struct ieee80211_if_sta *ifsta, - struct ieee80211_mgmt *mgmt, - size_t len) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - u16 auth_alg, auth_transaction, status_code; - DECLARE_MAC_BUF(mac); - - if (ifsta->state != IEEE80211_AUTHENTICATE && - sdata->vif.type != IEEE80211_IF_TYPE_IBSS) { - printk(KERN_DEBUG "%s: authentication frame received from " - "%s, but not in authenticate state - ignored\n", - dev->name, print_mac(mac, mgmt->sa)); - return; - } - - if (len < 24 + 6) { - printk(KERN_DEBUG "%s: too short (%zd) authentication frame " - "received from %s - ignored\n", - dev->name, len, print_mac(mac, mgmt->sa)); - return; - } - - if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && - memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { - printk(KERN_DEBUG "%s: authentication frame received from " - "unknown AP (SA=%s BSSID=%s) - " - "ignored\n", dev->name, print_mac(mac, mgmt->sa), - print_mac(mac, mgmt->bssid)); - return; - } - - if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && - memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) { - printk(KERN_DEBUG "%s: authentication frame received from " - "unknown BSSID (SA=%s BSSID=%s) - " - "ignored\n", dev->name, print_mac(mac, mgmt->sa), - print_mac(mac, mgmt->bssid)); - return; - } - - auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); - auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); - status_code = le16_to_cpu(mgmt->u.auth.status_code); - - printk(KERN_DEBUG "%s: RX authentication from %s (alg=%d " - "transaction=%d status=%d)\n", - dev->name, print_mac(mac, mgmt->sa), auth_alg, - auth_transaction, status_code); - - if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { - /* IEEE 802.11 standard does not require authentication in IBSS - * networks and most implementations do not seem to use it. - * However, try to reply to authentication attempts if someone - * has actually implemented this. - * TODO: Could implement shared key authentication. */ - if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) { - printk(KERN_DEBUG "%s: unexpected IBSS authentication " - "frame (alg=%d transaction=%d)\n", - dev->name, auth_alg, auth_transaction); - return; - } - ieee80211_send_auth(dev, ifsta, 2, NULL, 0, 0); - } - - if (auth_alg != ifsta->auth_alg || - auth_transaction != ifsta->auth_transaction) { - printk(KERN_DEBUG "%s: unexpected authentication frame " - "(alg=%d transaction=%d)\n", - dev->name, auth_alg, auth_transaction); - return; - } - - if (status_code != WLAN_STATUS_SUCCESS) { - printk(KERN_DEBUG "%s: AP denied authentication (auth_alg=%d " - "code=%d)\n", dev->name, ifsta->auth_alg, status_code); - if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { - u8 algs[3]; - const int num_algs = ARRAY_SIZE(algs); - int i, pos; - algs[0] = algs[1] = algs[2] = 0xff; - if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) - algs[0] = WLAN_AUTH_OPEN; - if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) - algs[1] = WLAN_AUTH_SHARED_KEY; - if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) - algs[2] = WLAN_AUTH_LEAP; - if (ifsta->auth_alg == WLAN_AUTH_OPEN) - pos = 0; - else if (ifsta->auth_alg == WLAN_AUTH_SHARED_KEY) - pos = 1; - else - pos = 2; - for (i = 0; i < num_algs; i++) { - pos++; - if (pos >= num_algs) - pos = 0; - if (algs[pos] == ifsta->auth_alg || - algs[pos] == 0xff) - continue; - if (algs[pos] == WLAN_AUTH_SHARED_KEY && - !ieee80211_sta_wep_configured(dev)) - continue; - ifsta->auth_alg = algs[pos]; - printk(KERN_DEBUG "%s: set auth_alg=%d for " - "next try\n", - dev->name, ifsta->auth_alg); - break; - } - } - return; - } - - switch (ifsta->auth_alg) { - case WLAN_AUTH_OPEN: - case WLAN_AUTH_LEAP: - ieee80211_auth_completed(dev, ifsta); - break; - case WLAN_AUTH_SHARED_KEY: - if (ifsta->auth_transaction == 4) - ieee80211_auth_completed(dev, ifsta); - else - ieee80211_auth_challenge(dev, ifsta, mgmt, len); - break; - } -} - - -static void ieee80211_rx_mgmt_deauth(struct net_device *dev, - struct ieee80211_if_sta *ifsta, - struct ieee80211_mgmt *mgmt, - size_t len) -{ - u16 reason_code; - DECLARE_MAC_BUF(mac); - - if (len < 24 + 2) { - printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame " - "received from %s - ignored\n", - dev->name, len, print_mac(mac, mgmt->sa)); - return; - } - - if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { - printk(KERN_DEBUG "%s: deauthentication frame received from " - "unknown AP (SA=%s BSSID=%s) - " - "ignored\n", dev->name, print_mac(mac, mgmt->sa), - print_mac(mac, mgmt->bssid)); - return; - } - - reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); - - printk(KERN_DEBUG "%s: RX deauthentication from %s" - " (reason=%d)\n", - dev->name, print_mac(mac, mgmt->sa), reason_code); - - if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) { - printk(KERN_DEBUG "%s: deauthenticated\n", dev->name); - } - - if (ifsta->state == IEEE80211_AUTHENTICATE || - ifsta->state == IEEE80211_ASSOCIATE || - ifsta->state == IEEE80211_ASSOCIATED) { - ifsta->state = IEEE80211_AUTHENTICATE; - mod_timer(&ifsta->timer, jiffies + - IEEE80211_RETRY_AUTH_INTERVAL); - } - - ieee80211_set_disassoc(dev, ifsta, 1); - ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED; -} - - -static void ieee80211_rx_mgmt_disassoc(struct net_device *dev, - struct ieee80211_if_sta *ifsta, - struct ieee80211_mgmt *mgmt, - size_t len) -{ - u16 reason_code; - DECLARE_MAC_BUF(mac); - - if (len < 24 + 2) { - printk(KERN_DEBUG "%s: too short (%zd) disassociation frame " - "received from %s - ignored\n", - dev->name, len, print_mac(mac, mgmt->sa)); - return; - } - - if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { - printk(KERN_DEBUG "%s: disassociation frame received from " - "unknown AP (SA=%s BSSID=%s) - " - "ignored\n", dev->name, print_mac(mac, mgmt->sa), - print_mac(mac, mgmt->bssid)); - return; - } - - reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - - printk(KERN_DEBUG "%s: RX disassociation from %s" - " (reason=%d)\n", - dev->name, print_mac(mac, mgmt->sa), reason_code); - - if (ifsta->flags & IEEE80211_STA_ASSOCIATED) - printk(KERN_DEBUG "%s: disassociated\n", dev->name); - - if (ifsta->state == IEEE80211_ASSOCIATED) { - ifsta->state = IEEE80211_ASSOCIATE; - mod_timer(&ifsta->timer, jiffies + - IEEE80211_RETRY_AUTH_INTERVAL); - } - - ieee80211_set_disassoc(dev, ifsta, 0); -} - - -static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, - struct ieee80211_if_sta *ifsta, - struct ieee80211_mgmt *mgmt, - size_t len, - int reassoc) -{ - struct ieee80211_local *local = sdata->local; - struct net_device *dev = sdata->dev; - struct ieee80211_supported_band *sband; - struct sta_info *sta; - u64 rates, basic_rates; - u16 capab_info, status_code, aid; - struct ieee802_11_elems elems; - struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; - u8 *pos; - int i, j; - DECLARE_MAC_BUF(mac); - bool have_higher_than_11mbit = false; - - /* AssocResp and ReassocResp have identical structure, so process both - * of them in this function. */ - - if (ifsta->state != IEEE80211_ASSOCIATE) { - printk(KERN_DEBUG "%s: association frame received from " - "%s, but not in associate state - ignored\n", - dev->name, print_mac(mac, mgmt->sa)); - return; - } - - if (len < 24 + 6) { - printk(KERN_DEBUG "%s: too short (%zd) association frame " - "received from %s - ignored\n", - dev->name, len, print_mac(mac, mgmt->sa)); - return; - } - - if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { - printk(KERN_DEBUG "%s: association frame received from " - "unknown AP (SA=%s BSSID=%s) - " - "ignored\n", dev->name, print_mac(mac, mgmt->sa), - print_mac(mac, mgmt->bssid)); - return; - } - - capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); - status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); - aid = le16_to_cpu(mgmt->u.assoc_resp.aid); - - printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x " - "status=%d aid=%d)\n", - dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa), - capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); - - if (status_code != WLAN_STATUS_SUCCESS) { - printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", - dev->name, status_code); - /* if this was a reassociation, ensure we try a "full" - * association next time. This works around some broken APs - * which do not correctly reject reassociation requests. */ - ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; - return; - } - - if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) - printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " - "set\n", dev->name, aid); - aid &= ~(BIT(15) | BIT(14)); - - pos = mgmt->u.assoc_resp.variable; - ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); - - if (!elems.supp_rates) { - printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", - dev->name); - return; - } - - printk(KERN_DEBUG "%s: associated\n", dev->name); - ifsta->aid = aid; - ifsta->ap_capab = capab_info; - - kfree(ifsta->assocresp_ies); - ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt); - ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_KERNEL); - if (ifsta->assocresp_ies) - memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); - - rcu_read_lock(); - - /* Add STA entry for the AP */ - sta = sta_info_get(local, ifsta->bssid); - if (!sta) { - struct ieee80211_sta_bss *bss; - int err; - - sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC); - if (!sta) { - printk(KERN_DEBUG "%s: failed to alloc STA entry for" - " the AP\n", dev->name); - rcu_read_unlock(); - return; - } - bss = ieee80211_rx_bss_get(dev, ifsta->bssid, - local->hw.conf.channel->center_freq, - ifsta->ssid, ifsta->ssid_len); - if (bss) { - sta->last_rssi = bss->rssi; - sta->last_signal = bss->signal; - sta->last_noise = bss->noise; - ieee80211_rx_bss_put(dev, bss); - } - - err = sta_info_insert(sta); - if (err) { - printk(KERN_DEBUG "%s: failed to insert STA entry for" - " the AP (error %d)\n", dev->name, err); - rcu_read_unlock(); - return; - } - } - - /* - * FIXME: Do we really need to update the sta_info's information here? - * We already know about the AP (we found it in our list) so it - * should already be filled with the right info, no? - * As is stands, all this is racy because typically we assume - * the information that is filled in here (except flags) doesn't - * change while a STA structure is alive. As such, it should move - * to between the sta_info_alloc() and sta_info_insert() above. - */ - - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | - WLAN_STA_AUTHORIZED; - - rates = 0; - basic_rates = 0; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - for (i = 0; i < elems.supp_rates_len; i++) { - int rate = (elems.supp_rates[i] & 0x7f) * 5; - - if (rate > 110) - have_higher_than_11mbit = true; - - for (j = 0; j < sband->n_bitrates; j++) { - if (sband->bitrates[j].bitrate == rate) - rates |= BIT(j); - if (elems.supp_rates[i] & 0x80) - basic_rates |= BIT(j); - } - } - - for (i = 0; i < elems.ext_supp_rates_len; i++) { - int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; - - if (rate > 110) - have_higher_than_11mbit = true; - - for (j = 0; j < sband->n_bitrates; j++) { - if (sband->bitrates[j].bitrate == rate) - rates |= BIT(j); - if (elems.ext_supp_rates[i] & 0x80) - basic_rates |= BIT(j); - } - } - - sta->supp_rates[local->hw.conf.channel->band] = rates; - sdata->basic_rates = basic_rates; - - /* cf. IEEE 802.11 9.2.12 */ - if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && - have_higher_than_11mbit) - sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; - else - sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; - - if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) { - struct ieee80211_ht_bss_info bss_info; - ieee80211_ht_cap_ie_to_ht_info( - (struct ieee80211_ht_cap *) - elems.ht_cap_elem, &sta->ht_info); - ieee80211_ht_addt_info_ie_to_ht_bss_info( - (struct ieee80211_ht_addt_info *) - elems.ht_info_elem, &bss_info); - ieee80211_handle_ht(local, 1, &sta->ht_info, &bss_info); - } - - rate_control_rate_init(sta, local); - - if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { - sta->flags |= WLAN_STA_WME; - rcu_read_unlock(); - ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, - elems.wmm_param_len); - } else - rcu_read_unlock(); - - /* set AID and assoc capability, - * ieee80211_set_associated() will tell the driver */ - bss_conf->aid = aid; - bss_conf->assoc_capability = capab_info; - ieee80211_set_associated(dev, ifsta, 1); - - ieee80211_associated(dev, ifsta); -} - - -/* Caller must hold local->sta_bss_lock */ -static void __ieee80211_rx_bss_hash_add(struct net_device *dev, - struct ieee80211_sta_bss *bss) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - u8 hash_idx; - - if (bss_mesh_cfg(bss)) - hash_idx = mesh_id_hash(bss_mesh_id(bss), - bss_mesh_id_len(bss)); - else - hash_idx = STA_HASH(bss->bssid); - - bss->hnext = local->sta_bss_hash[hash_idx]; - local->sta_bss_hash[hash_idx] = bss; -} - - -/* Caller must hold local->sta_bss_lock */ -static void __ieee80211_rx_bss_hash_del(struct net_device *dev, - struct ieee80211_sta_bss *bss) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sta_bss *b, *prev = NULL; - b = local->sta_bss_hash[STA_HASH(bss->bssid)]; - while (b) { - if (b == bss) { - if (!prev) - local->sta_bss_hash[STA_HASH(bss->bssid)] = - bss->hnext; - else - prev->hnext = bss->hnext; - break; - } - prev = b; - b = b->hnext; - } -} - - -static struct ieee80211_sta_bss * -ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int freq, - u8 *ssid, u8 ssid_len) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sta_bss *bss; - - bss = kzalloc(sizeof(*bss), GFP_ATOMIC); - if (!bss) - return NULL; - atomic_inc(&bss->users); - atomic_inc(&bss->users); - memcpy(bss->bssid, bssid, ETH_ALEN); - bss->freq = freq; - if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) { - memcpy(bss->ssid, ssid, ssid_len); - bss->ssid_len = ssid_len; - } - - spin_lock_bh(&local->sta_bss_lock); - /* TODO: order by RSSI? */ - list_add_tail(&bss->list, &local->sta_bss_list); - __ieee80211_rx_bss_hash_add(dev, bss); - spin_unlock_bh(&local->sta_bss_lock); - return bss; -} - -static struct ieee80211_sta_bss * -ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, - u8 *ssid, u8 ssid_len) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sta_bss *bss; - - spin_lock_bh(&local->sta_bss_lock); - bss = local->sta_bss_hash[STA_HASH(bssid)]; - while (bss) { - if (!bss_mesh_cfg(bss) && - !memcmp(bss->bssid, bssid, ETH_ALEN) && - bss->freq == freq && - bss->ssid_len == ssid_len && - (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { - atomic_inc(&bss->users); - break; - } - bss = bss->hnext; - } - spin_unlock_bh(&local->sta_bss_lock); - return bss; -} - -#ifdef CONFIG_MAC80211_MESH -static struct ieee80211_sta_bss * -ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len, - u8 *mesh_cfg, int freq) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sta_bss *bss; - - spin_lock_bh(&local->sta_bss_lock); - bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)]; - while (bss) { - if (bss_mesh_cfg(bss) && - !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) && - bss->freq == freq && - mesh_id_len == bss->mesh_id_len && - (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id, - mesh_id_len))) { - atomic_inc(&bss->users); - break; - } - bss = bss->hnext; - } - spin_unlock_bh(&local->sta_bss_lock); - return bss; -} - -static struct ieee80211_sta_bss * -ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len, - u8 *mesh_cfg, int mesh_config_len, int freq) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sta_bss *bss; - - if (mesh_config_len != MESH_CFG_LEN) - return NULL; - - bss = kzalloc(sizeof(*bss), GFP_ATOMIC); - if (!bss) - return NULL; - - bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC); - if (!bss->mesh_cfg) { - kfree(bss); - return NULL; - } - - if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) { - bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC); - if (!bss->mesh_id) { - kfree(bss->mesh_cfg); - kfree(bss); - return NULL; - } - memcpy(bss->mesh_id, mesh_id, mesh_id_len); - } - - atomic_inc(&bss->users); - atomic_inc(&bss->users); - memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN); - bss->mesh_id_len = mesh_id_len; - bss->freq = freq; - spin_lock_bh(&local->sta_bss_lock); - /* TODO: order by RSSI? */ - list_add_tail(&bss->list, &local->sta_bss_list); - __ieee80211_rx_bss_hash_add(dev, bss); - spin_unlock_bh(&local->sta_bss_lock); - return bss; -} -#endif - -static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) -{ - kfree(bss->wpa_ie); - kfree(bss->rsn_ie); - kfree(bss->wmm_ie); - kfree(bss->ht_ie); - kfree(bss_mesh_id(bss)); - kfree(bss_mesh_cfg(bss)); - kfree(bss); -} - - -static void ieee80211_rx_bss_put(struct net_device *dev, - struct ieee80211_sta_bss *bss) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - if (!atomic_dec_and_test(&bss->users)) - return; - - spin_lock_bh(&local->sta_bss_lock); - __ieee80211_rx_bss_hash_del(dev, bss); - list_del(&bss->list); - spin_unlock_bh(&local->sta_bss_lock); - ieee80211_rx_bss_free(bss); -} - - -void ieee80211_rx_bss_list_init(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - spin_lock_init(&local->sta_bss_lock); - INIT_LIST_HEAD(&local->sta_bss_list); -} - - -void ieee80211_rx_bss_list_deinit(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sta_bss *bss, *tmp; - - list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list) - ieee80211_rx_bss_put(dev, bss); -} - - -static int ieee80211_sta_join_ibss(struct net_device *dev, - struct ieee80211_if_sta *ifsta, - struct ieee80211_sta_bss *bss) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int res, rates, i, j; - struct sk_buff *skb; - struct ieee80211_mgmt *mgmt; - struct ieee80211_tx_control control; - struct rate_selection ratesel; - u8 *pos; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_supported_band *sband; - - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - /* Remove possible STA entries from other IBSS networks. */ - sta_info_flush_delayed(sdata); - - if (local->ops->reset_tsf) { - /* Reset own TSF to allow time synchronization work. */ - local->ops->reset_tsf(local_to_hw(local)); - } - memcpy(ifsta->bssid, bss->bssid, ETH_ALEN); - res = ieee80211_if_config(dev); - if (res) - return res; - - local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; - - sdata->drop_unencrypted = bss->capability & - WLAN_CAPABILITY_PRIVACY ? 1 : 0; - - res = ieee80211_set_freq(local, bss->freq); - - if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) { - printk(KERN_DEBUG "%s: IBSS not allowed on frequency " - "%d MHz\n", dev->name, local->oper_channel->center_freq); - return -1; - } - - /* Set beacon template */ - skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); - do { - if (!skb) - break; - - skb_reserve(skb, local->hw.extra_tx_headroom); - - mgmt = (struct ieee80211_mgmt *) - skb_put(skb, 24 + sizeof(mgmt->u.beacon)); - memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); - mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_BEACON); - memset(mgmt->da, 0xff, ETH_ALEN); - memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); - memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); - mgmt->u.beacon.beacon_int = - cpu_to_le16(local->hw.conf.beacon_int); - mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability); - - pos = skb_put(skb, 2 + ifsta->ssid_len); - *pos++ = WLAN_EID_SSID; - *pos++ = ifsta->ssid_len; - memcpy(pos, ifsta->ssid, ifsta->ssid_len); - - rates = bss->supp_rates_len; - if (rates > 8) - rates = 8; - pos = skb_put(skb, 2 + rates); - *pos++ = WLAN_EID_SUPP_RATES; - *pos++ = rates; - memcpy(pos, bss->supp_rates, rates); - - if (bss->band == IEEE80211_BAND_2GHZ) { - pos = skb_put(skb, 2 + 1); - *pos++ = WLAN_EID_DS_PARAMS; - *pos++ = 1; - *pos++ = ieee80211_frequency_to_channel(bss->freq); - } - - pos = skb_put(skb, 2 + 2); - *pos++ = WLAN_EID_IBSS_PARAMS; - *pos++ = 2; - /* FIX: set ATIM window based on scan results */ - *pos++ = 0; - *pos++ = 0; - - if (bss->supp_rates_len > 8) { - rates = bss->supp_rates_len - 8; - pos = skb_put(skb, 2 + rates); - *pos++ = WLAN_EID_EXT_SUPP_RATES; - *pos++ = rates; - memcpy(pos, &bss->supp_rates[8], rates); - } - - memset(&control, 0, sizeof(control)); - rate_control_get_rate(dev, sband, skb, &ratesel); - if (!ratesel.rate) { - printk(KERN_DEBUG "%s: Failed to determine TX rate " - "for IBSS beacon\n", dev->name); - break; - } - control.vif = &sdata->vif; - control.tx_rate = ratesel.rate; - if (sdata->bss_conf.use_short_preamble && - ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) - control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; - control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; - control.flags |= IEEE80211_TXCTL_NO_ACK; - control.retry_limit = 1; - - ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC); - if (ifsta->probe_resp) { - mgmt = (struct ieee80211_mgmt *) - ifsta->probe_resp->data; - mgmt->frame_control = - IEEE80211_FC(IEEE80211_FTYPE_MGMT, - IEEE80211_STYPE_PROBE_RESP); - } else { - printk(KERN_DEBUG "%s: Could not allocate ProbeResp " - "template for IBSS\n", dev->name); - } - - if (local->ops->beacon_update && - local->ops->beacon_update(local_to_hw(local), - skb, &control) == 0) { - printk(KERN_DEBUG "%s: Configured IBSS beacon " - "template\n", dev->name); - skb = NULL; - } - - rates = 0; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - for (i = 0; i < bss->supp_rates_len; i++) { - int bitrate = (bss->supp_rates[i] & 0x7f) * 5; - for (j = 0; j < sband->n_bitrates; j++) - if (sband->bitrates[j].bitrate == bitrate) - rates |= BIT(j); - } - ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; - - ieee80211_sta_def_wmm_params(dev, bss, 1); - } while (0); - - if (skb) { - printk(KERN_DEBUG "%s: Failed to configure IBSS beacon " - "template\n", dev->name); - dev_kfree_skb(skb); - } - - ifsta->state = IEEE80211_IBSS_JOINED; - mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); - - ieee80211_rx_bss_put(dev, bss); - - return res; -} - -u64 ieee80211_sta_get_rates(struct ieee80211_local *local, - struct ieee802_11_elems *elems, - enum ieee80211_band band) -{ - struct ieee80211_supported_band *sband; - struct ieee80211_rate *bitrates; - size_t num_rates; - u64 supp_rates; - int i, j; - sband = local->hw.wiphy->bands[band]; - - if (!sband) { - WARN_ON(1); - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - } - - bitrates = sband->bitrates; - num_rates = sband->n_bitrates; - supp_rates = 0; - for (i = 0; i < elems->supp_rates_len + - elems->ext_supp_rates_len; i++) { - u8 rate = 0; - int own_rate; - if (i < elems->supp_rates_len) - rate = elems->supp_rates[i]; - else if (elems->ext_supp_rates) - rate = elems->ext_supp_rates - [i - elems->supp_rates_len]; - own_rate = 5 * (rate & 0x7f); - for (j = 0; j < num_rates; j++) - if (bitrates[j].bitrate == own_rate) - supp_rates |= BIT(j); - } - return supp_rates; -} - - -static void ieee80211_rx_bss_info(struct net_device *dev, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status, - int beacon) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee802_11_elems elems; - size_t baselen; - int freq, clen; - struct ieee80211_sta_bss *bss; - struct sta_info *sta; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - u64 beacon_timestamp, rx_timestamp; - struct ieee80211_channel *channel; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - - if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN)) - return; /* ignore ProbeResp to foreign address */ - -#if 0 - printk(KERN_DEBUG "%s: RX %s from %s to %s\n", - dev->name, beacon ? "Beacon" : "Probe Response", - print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da)); -#endif - - baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; - if (baselen > len) - return; - - beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); - ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); - - if (ieee80211_vif_is_mesh(&sdata->vif) && elems.mesh_id && - elems.mesh_config && mesh_matches_local(&elems, dev)) { - u64 rates = ieee80211_sta_get_rates(local, &elems, - rx_status->band); - - mesh_neighbour_update(mgmt->sa, rates, dev, - mesh_peer_accepts_plinks(&elems, dev)); - } - - rcu_read_lock(); - - if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && - memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && - (sta = sta_info_get(local, mgmt->sa))) { - u64 prev_rates; - u64 supp_rates = ieee80211_sta_get_rates(local, &elems, - rx_status->band); - - prev_rates = sta->supp_rates[rx_status->band]; - sta->supp_rates[rx_status->band] &= supp_rates; - if (sta->supp_rates[rx_status->band] == 0) { - /* No matching rates - this should not really happen. - * Make sure that at least one rate is marked - * supported to avoid issues with TX rate ctrl. */ - sta->supp_rates[rx_status->band] = - sdata->u.sta.supp_rates_bits[rx_status->band]; - } - if (sta->supp_rates[rx_status->band] != prev_rates) { - printk(KERN_DEBUG "%s: updated supp_rates set for " - "%s based on beacon info (0x%llx & 0x%llx -> " - "0x%llx)\n", - dev->name, print_mac(mac, sta->addr), - (unsigned long long) prev_rates, - (unsigned long long) supp_rates, - (unsigned long long) sta->supp_rates[rx_status->band]); - } - } - - rcu_read_unlock(); - - if (elems.ds_params && elems.ds_params_len == 1) - freq = ieee80211_channel_to_frequency(elems.ds_params[0]); - else - freq = rx_status->freq; - - channel = ieee80211_get_channel(local->hw.wiphy, freq); - - if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) - return; - -#ifdef CONFIG_MAC80211_MESH - if (elems.mesh_config) - bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id, - elems.mesh_id_len, elems.mesh_config, freq); - else -#endif - bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq, - elems.ssid, elems.ssid_len); - if (!bss) { -#ifdef CONFIG_MAC80211_MESH - if (elems.mesh_config) - bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id, - elems.mesh_id_len, elems.mesh_config, - elems.mesh_config_len, freq); - else -#endif - bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, - elems.ssid, elems.ssid_len); - if (!bss) - return; - } else { -#if 0 - /* TODO: order by RSSI? */ - spin_lock_bh(&local->sta_bss_lock); - list_move_tail(&bss->list, &local->sta_bss_list); - spin_unlock_bh(&local->sta_bss_lock); -#endif - } - - bss->band = rx_status->band; - - if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && - bss->probe_resp && beacon) { - /* STA mode: - * Do not allow beacon to override data from Probe Response. */ - ieee80211_rx_bss_put(dev, bss); - return; - } - - /* save the ERP value so that it is available at association time */ - if (elems.erp_info && elems.erp_info_len >= 1) { - bss->erp_value = elems.erp_info[0]; - bss->has_erp_value = 1; - } - - bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); - bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); - - bss->supp_rates_len = 0; - if (elems.supp_rates) { - clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; - if (clen > elems.supp_rates_len) - clen = elems.supp_rates_len; - memcpy(&bss->supp_rates[bss->supp_rates_len], elems.supp_rates, - clen); - bss->supp_rates_len += clen; - } - if (elems.ext_supp_rates) { - clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; - if (clen > elems.ext_supp_rates_len) - clen = elems.ext_supp_rates_len; - memcpy(&bss->supp_rates[bss->supp_rates_len], - elems.ext_supp_rates, clen); - bss->supp_rates_len += clen; - } - - if (elems.wpa && - (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len || - memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) { - kfree(bss->wpa_ie); - bss->wpa_ie = kmalloc(elems.wpa_len + 2, GFP_ATOMIC); - if (bss->wpa_ie) { - memcpy(bss->wpa_ie, elems.wpa - 2, elems.wpa_len + 2); - bss->wpa_ie_len = elems.wpa_len + 2; - } else - bss->wpa_ie_len = 0; - } else if (!elems.wpa && bss->wpa_ie) { - kfree(bss->wpa_ie); - bss->wpa_ie = NULL; - bss->wpa_ie_len = 0; - } - - if (elems.rsn && - (!bss->rsn_ie || bss->rsn_ie_len != elems.rsn_len || - memcmp(bss->rsn_ie, elems.rsn, elems.rsn_len))) { - kfree(bss->rsn_ie); - bss->rsn_ie = kmalloc(elems.rsn_len + 2, GFP_ATOMIC); - if (bss->rsn_ie) { - memcpy(bss->rsn_ie, elems.rsn - 2, elems.rsn_len + 2); - bss->rsn_ie_len = elems.rsn_len + 2; - } else - bss->rsn_ie_len = 0; - } else if (!elems.rsn && bss->rsn_ie) { - kfree(bss->rsn_ie); - bss->rsn_ie = NULL; - bss->rsn_ie_len = 0; - } - - if (elems.wmm_param && - (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len || - memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) { - kfree(bss->wmm_ie); - bss->wmm_ie = kmalloc(elems.wmm_param_len + 2, GFP_ATOMIC); - if (bss->wmm_ie) { - memcpy(bss->wmm_ie, elems.wmm_param - 2, - elems.wmm_param_len + 2); - bss->wmm_ie_len = elems.wmm_param_len + 2; - } else - bss->wmm_ie_len = 0; - } else if (!elems.wmm_param && bss->wmm_ie) { - kfree(bss->wmm_ie); - bss->wmm_ie = NULL; - bss->wmm_ie_len = 0; - } - if (elems.ht_cap_elem && - (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len || - memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) { - kfree(bss->ht_ie); - bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC); - if (bss->ht_ie) { - memcpy(bss->ht_ie, elems.ht_cap_elem - 2, - elems.ht_cap_elem_len + 2); - bss->ht_ie_len = elems.ht_cap_elem_len + 2; - } else - bss->ht_ie_len = 0; - } else if (!elems.ht_cap_elem && bss->ht_ie) { - kfree(bss->ht_ie); - bss->ht_ie = NULL; - bss->ht_ie_len = 0; - } - - bss->timestamp = beacon_timestamp; - bss->last_update = jiffies; - bss->rssi = rx_status->ssi; - bss->signal = rx_status->signal; - bss->noise = rx_status->noise; - if (!beacon) - bss->probe_resp++; - - /* check if we need to merge IBSS */ - if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && - !local->sta_sw_scanning && !local->sta_hw_scanning && - bss->capability & WLAN_CAPABILITY_IBSS && - bss->freq == local->oper_channel->center_freq && - elems.ssid_len == sdata->u.sta.ssid_len && - memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) { - if (rx_status->flag & RX_FLAG_TSFT) { - /* in order for correct IBSS merging we need mactime - * - * since mactime is defined as the time the first data - * symbol of the frame hits the PHY, and the timestamp - * of the beacon is defined as "the time that the data - * symbol containing the first bit of the timestamp is - * transmitted to the PHY plus the transmitting STA’s - * delays through its local PHY from the MAC-PHY - * interface to its interface with the WM" - * (802.11 11.1.2) - equals the time this bit arrives at - * the receiver - we have to take into account the - * offset between the two. - * e.g: at 1 MBit that means mactime is 192 usec earlier - * (=24 bytes * 8 usecs/byte) than the beacon timestamp. - */ - int rate = local->hw.wiphy->bands[rx_status->band]-> - bitrates[rx_status->rate_idx].bitrate; - rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); - } else if (local && local->ops && local->ops->get_tsf) - /* second best option: get current TSF */ - rx_timestamp = local->ops->get_tsf(local_to_hw(local)); - else - /* can't merge without knowing the TSF */ - rx_timestamp = -1LLU; -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "RX beacon SA=%s BSSID=" - "%s TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", - print_mac(mac, mgmt->sa), - print_mac(mac2, mgmt->bssid), - (unsigned long long)rx_timestamp, - (unsigned long long)beacon_timestamp, - (unsigned long long)(rx_timestamp - beacon_timestamp), - jiffies); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ - if (beacon_timestamp > rx_timestamp) { -#ifndef CONFIG_MAC80211_IBSS_DEBUG - if (net_ratelimit()) -#endif - printk(KERN_DEBUG "%s: beacon TSF higher than " - "local TSF - IBSS merge with BSSID %s\n", - dev->name, print_mac(mac, mgmt->bssid)); - ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); - ieee80211_ibss_add_sta(dev, NULL, - mgmt->bssid, mgmt->sa); - } - } - - ieee80211_rx_bss_put(dev, bss); -} - - -static void ieee80211_rx_mgmt_probe_resp(struct net_device *dev, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status) -{ - ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 0); -} - - -static void ieee80211_rx_mgmt_beacon(struct net_device *dev, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_sta *ifsta; - size_t baselen; - struct ieee802_11_elems elems; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_conf *conf = &local->hw.conf; - u32 changed = 0; - - ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1); - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->vif.type != IEEE80211_IF_TYPE_STA) - return; - ifsta = &sdata->u.sta; - - if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED) || - memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) - return; - - /* Process beacon from the current BSS */ - baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; - if (baselen > len) - return; - - ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); - - if (elems.erp_info && elems.erp_info_len >= 1) - changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]); - - if (elems.ht_cap_elem && elems.ht_info_elem && - elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { - struct ieee80211_ht_bss_info bss_info; - - ieee80211_ht_addt_info_ie_to_ht_bss_info( - (struct ieee80211_ht_addt_info *) - elems.ht_info_elem, &bss_info); - changed |= ieee80211_handle_ht(local, 1, &conf->ht_conf, - &bss_info); - } - - if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { - ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, - elems.wmm_param_len); - } - - ieee80211_bss_info_change_notify(sdata, changed); -} - - -static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, - struct ieee80211_if_sta *ifsta, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - int tx_last_beacon; - struct sk_buff *skb; - struct ieee80211_mgmt *resp; - u8 *pos, *end; - DECLARE_MAC_BUF(mac); -#ifdef CONFIG_MAC80211_IBSS_DEBUG - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); -#endif - - if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS || - ifsta->state != IEEE80211_IBSS_JOINED || - len < 24 + 2 || !ifsta->probe_resp) - return; - - if (local->ops->tx_last_beacon) - tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local)); - else - tx_last_beacon = 1; - -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: RX ProbeReq SA=%s DA=%s BSSID=" - "%s (tx_last_beacon=%d)\n", - dev->name, print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da), - print_mac(mac3, mgmt->bssid), tx_last_beacon); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ - - if (!tx_last_beacon) - return; - - if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0 && - memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) - return; - - end = ((u8 *) mgmt) + len; - pos = mgmt->u.probe_req.variable; - if (pos[0] != WLAN_EID_SSID || - pos + 2 + pos[1] > end) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " - "from %s\n", - dev->name, print_mac(mac, mgmt->sa)); - } - return; - } - if (pos[1] != 0 && - (pos[1] != ifsta->ssid_len || - memcmp(pos + 2, ifsta->ssid, ifsta->ssid_len) != 0)) { - /* Ignore ProbeReq for foreign SSID */ - return; - } - - /* Reply with ProbeResp */ - skb = skb_copy(ifsta->probe_resp, GFP_KERNEL); - if (!skb) - return; - - resp = (struct ieee80211_mgmt *) skb->data; - memcpy(resp->da, mgmt->sa, ETH_ALEN); -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n", - dev->name, print_mac(mac, resp->da)); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ - ieee80211_sta_tx(dev, skb, 0); -} - -static void ieee80211_rx_mgmt_action(struct net_device *dev, - struct ieee80211_if_sta *ifsta, - struct ieee80211_mgmt *mgmt, - size_t len, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (len < IEEE80211_MIN_ACTION_SIZE) - return; - - switch (mgmt->u.action.category) { - case WLAN_CATEGORY_BACK: - switch (mgmt->u.action.u.addba_req.action_code) { - case WLAN_ACTION_ADDBA_REQ: - if (len < (IEEE80211_MIN_ACTION_SIZE + - sizeof(mgmt->u.action.u.addba_req))) - break; - ieee80211_sta_process_addba_request(dev, mgmt, len); - break; - case WLAN_ACTION_ADDBA_RESP: - if (len < (IEEE80211_MIN_ACTION_SIZE + - sizeof(mgmt->u.action.u.addba_resp))) - break; - ieee80211_sta_process_addba_resp(dev, mgmt, len); - break; - case WLAN_ACTION_DELBA: - if (len < (IEEE80211_MIN_ACTION_SIZE + - sizeof(mgmt->u.action.u.delba))) - break; - ieee80211_sta_process_delba(dev, mgmt, len); - break; - default: - if (net_ratelimit()) - printk(KERN_DEBUG "%s: Rx unknown A-MPDU action\n", - dev->name); - break; - } - break; - case PLINK_CATEGORY: - if (ieee80211_vif_is_mesh(&sdata->vif)) - mesh_rx_plink_frame(dev, mgmt, len, rx_status); - break; - case MESH_PATH_SEL_CATEGORY: - if (ieee80211_vif_is_mesh(&sdata->vif)) - mesh_rx_path_sel_frame(dev, mgmt, len); - break; - default: - if (net_ratelimit()) - printk(KERN_DEBUG "%s: Rx unknown action frame - " - "category=%d\n", dev->name, mgmt->u.action.category); - break; - } -} - -void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_sta *ifsta; - struct ieee80211_mgmt *mgmt; - u16 fc; - - if (skb->len < 24) - goto fail; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - ifsta = &sdata->u.sta; - - mgmt = (struct ieee80211_mgmt *) skb->data; - fc = le16_to_cpu(mgmt->frame_control); - - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PROBE_REQ: - case IEEE80211_STYPE_PROBE_RESP: - case IEEE80211_STYPE_BEACON: - case IEEE80211_STYPE_ACTION: - memcpy(skb->cb, rx_status, sizeof(*rx_status)); - case IEEE80211_STYPE_AUTH: - case IEEE80211_STYPE_ASSOC_RESP: - case IEEE80211_STYPE_REASSOC_RESP: - case IEEE80211_STYPE_DEAUTH: - case IEEE80211_STYPE_DISASSOC: - skb_queue_tail(&ifsta->skb_queue, skb); - queue_work(local->hw.workqueue, &ifsta->work); - return; - default: - printk(KERN_DEBUG "%s: received unknown management frame - " - "stype=%d\n", dev->name, - (fc & IEEE80211_FCTL_STYPE) >> 4); - break; - } - - fail: - kfree_skb(skb); -} - - -static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev, - struct sk_buff *skb) -{ - struct ieee80211_rx_status *rx_status; - struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_sta *ifsta; - struct ieee80211_mgmt *mgmt; - u16 fc; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - ifsta = &sdata->u.sta; - - rx_status = (struct ieee80211_rx_status *) skb->cb; - mgmt = (struct ieee80211_mgmt *) skb->data; - fc = le16_to_cpu(mgmt->frame_control); - - switch (fc & IEEE80211_FCTL_STYPE) { - case IEEE80211_STYPE_PROBE_REQ: - ieee80211_rx_mgmt_probe_req(dev, ifsta, mgmt, skb->len, - rx_status); - break; - case IEEE80211_STYPE_PROBE_RESP: - ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status); - break; - case IEEE80211_STYPE_BEACON: - ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status); - break; - case IEEE80211_STYPE_AUTH: - ieee80211_rx_mgmt_auth(dev, ifsta, mgmt, skb->len); - break; - case IEEE80211_STYPE_ASSOC_RESP: - ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0); - break; - case IEEE80211_STYPE_REASSOC_RESP: - ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1); - break; - case IEEE80211_STYPE_DEAUTH: - ieee80211_rx_mgmt_deauth(dev, ifsta, mgmt, skb->len); - break; - case IEEE80211_STYPE_DISASSOC: - ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len); - break; - case IEEE80211_STYPE_ACTION: - ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len, rx_status); - break; - } - - kfree_skb(skb); -} - - -ieee80211_rx_result -ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_mgmt *mgmt; - u16 fc; - - if (skb->len < 2) - return RX_DROP_UNUSABLE; - - mgmt = (struct ieee80211_mgmt *) skb->data; - fc = le16_to_cpu(mgmt->frame_control); - - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) - return RX_CONTINUE; - - if (skb->len < 24) - return RX_DROP_MONITOR; - - if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { - if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) { - ieee80211_rx_mgmt_probe_resp(dev, mgmt, - skb->len, rx_status); - dev_kfree_skb(skb); - return RX_QUEUED; - } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) { - ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, - rx_status); - dev_kfree_skb(skb); - return RX_QUEUED; - } - } - return RX_CONTINUE; -} - - -static int ieee80211_sta_active_ibss(struct net_device *dev) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - int active = 0; - struct sta_info *sta; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - rcu_read_lock(); - - list_for_each_entry_rcu(sta, &local->sta_list, list) { - if (sta->sdata == sdata && - time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, - jiffies)) { - active++; - break; - } - } - - rcu_read_unlock(); - - return active; -} - - -static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta, *tmp; - LIST_HEAD(tmp_list); - DECLARE_MAC_BUF(mac); - unsigned long flags; - - spin_lock_irqsave(&local->sta_lock, flags); - list_for_each_entry_safe(sta, tmp, &local->sta_list, list) - if (time_after(jiffies, sta->last_rx + exp_time)) { - printk(KERN_DEBUG "%s: expiring inactive STA %s\n", - dev->name, print_mac(mac, sta->addr)); - __sta_info_unlink(&sta); - if (sta) - list_add(&sta->list, &tmp_list); - } - spin_unlock_irqrestore(&local->sta_lock, flags); - - list_for_each_entry_safe(sta, tmp, &tmp_list, list) - sta_info_destroy(sta); -} - - -static void ieee80211_sta_merge_ibss(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); - - ieee80211_sta_expire(dev, IEEE80211_IBSS_INACTIVITY_LIMIT); - if (ieee80211_sta_active_ibss(dev)) - return; - - printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " - "IBSS networks with same SSID (merge)\n", dev->name); - ieee80211_sta_req_scan(dev, ifsta->ssid, ifsta->ssid_len); -} - - -#ifdef CONFIG_MAC80211_MESH -static void ieee80211_mesh_housekeeping(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - bool free_plinks; - - ieee80211_sta_expire(dev, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); - mesh_path_expire(dev); - - free_plinks = mesh_plink_availables(sdata); - if (free_plinks != sdata->u.sta.accepting_plinks) - ieee80211_if_config_beacon(dev); - - mod_timer(&ifsta->timer, jiffies + - IEEE80211_MESH_HOUSEKEEPING_INTERVAL); -} - - -void ieee80211_start_mesh(struct net_device *dev) -{ - struct ieee80211_if_sta *ifsta; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - ifsta = &sdata->u.sta; - ifsta->state = IEEE80211_MESH_UP; - ieee80211_sta_timer((unsigned long)sdata); -} -#endif - - -void ieee80211_sta_timer(unsigned long data) -{ - struct ieee80211_sub_if_data *sdata = - (struct ieee80211_sub_if_data *) data; - struct ieee80211_if_sta *ifsta = &sdata->u.sta; - struct ieee80211_local *local = wdev_priv(&sdata->wdev); - - set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); - queue_work(local->hw.workqueue, &ifsta->work); -} - -void ieee80211_sta_work(struct work_struct *work) -{ - struct ieee80211_sub_if_data *sdata = - container_of(work, struct ieee80211_sub_if_data, u.sta.work); - struct net_device *dev = sdata->dev; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_if_sta *ifsta; - struct sk_buff *skb; - - if (!netif_running(dev)) - return; - - if (local->sta_sw_scanning || local->sta_hw_scanning) - return; - - if (sdata->vif.type != IEEE80211_IF_TYPE_STA && - sdata->vif.type != IEEE80211_IF_TYPE_IBSS && - sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) { - printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface " - "(type=%d)\n", dev->name, sdata->vif.type); - return; - } - ifsta = &sdata->u.sta; - - while ((skb = skb_dequeue(&ifsta->skb_queue))) - ieee80211_sta_rx_queued_mgmt(dev, skb); - -#ifdef CONFIG_MAC80211_MESH - if (ifsta->preq_queue_len && - time_after(jiffies, - ifsta->last_preq + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval))) - mesh_path_start_discovery(dev); -#endif - - if (ifsta->state != IEEE80211_AUTHENTICATE && - ifsta->state != IEEE80211_ASSOCIATE && - test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { - if (ifsta->scan_ssid_len) - ieee80211_sta_start_scan(dev, ifsta->scan_ssid, ifsta->scan_ssid_len); - else - ieee80211_sta_start_scan(dev, NULL, 0); - return; - } - - if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) { - if (ieee80211_sta_config_auth(dev, ifsta)) - return; - clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); - } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request)) - return; - - switch (ifsta->state) { - case IEEE80211_DISABLED: - break; - case IEEE80211_AUTHENTICATE: - ieee80211_authenticate(dev, ifsta); - break; - case IEEE80211_ASSOCIATE: - ieee80211_associate(dev, ifsta); - break; - case IEEE80211_ASSOCIATED: - ieee80211_associated(dev, ifsta); - break; - case IEEE80211_IBSS_SEARCH: - ieee80211_sta_find_ibss(dev, ifsta); - break; - case IEEE80211_IBSS_JOINED: - ieee80211_sta_merge_ibss(dev, ifsta); - break; -#ifdef CONFIG_MAC80211_MESH - case IEEE80211_MESH_UP: - ieee80211_mesh_housekeeping(dev, ifsta); - break; -#endif - default: - printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n", - ifsta->state); - break; - } - - if (ieee80211_privacy_mismatch(dev, ifsta)) { - printk(KERN_DEBUG "%s: privacy configuration mismatch and " - "mixed-cell disabled - disassociate\n", dev->name); - - ieee80211_send_disassoc(dev, ifsta, WLAN_REASON_UNSPECIFIED); - ieee80211_set_disassoc(dev, ifsta, 0); - } -} - - -static void ieee80211_sta_reset_auth(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (local->ops->reset_tsf) { - /* Reset own TSF to allow time synchronization work. */ - local->ops->reset_tsf(local_to_hw(local)); - } - - ifsta->wmm_last_param_set = -1; /* allow any WMM update */ - - - if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) - ifsta->auth_alg = WLAN_AUTH_OPEN; - else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) - ifsta->auth_alg = WLAN_AUTH_SHARED_KEY; - else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) - ifsta->auth_alg = WLAN_AUTH_LEAP; - else - ifsta->auth_alg = WLAN_AUTH_OPEN; - printk(KERN_DEBUG "%s: Initial auth_alg=%d\n", dev->name, - ifsta->auth_alg); - ifsta->auth_transaction = -1; - ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; - ifsta->auth_tries = ifsta->assoc_tries = 0; - netif_carrier_off(dev); -} - - -void ieee80211_sta_req_auth(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - - if (sdata->vif.type != IEEE80211_IF_TYPE_STA) - return; - - if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | - IEEE80211_STA_AUTO_BSSID_SEL)) && - (ifsta->flags & (IEEE80211_STA_SSID_SET | - IEEE80211_STA_AUTO_SSID_SEL))) { - set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); - queue_work(local->hw.workqueue, &ifsta->work); - } -} - -static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, - const char *ssid, int ssid_len) -{ - int tmp, hidden_ssid; - - if (ssid_len == ifsta->ssid_len && - !memcmp(ifsta->ssid, ssid, ssid_len)) - return 1; - - if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) - return 0; - - hidden_ssid = 1; - tmp = ssid_len; - while (tmp--) { - if (ssid[tmp] != '\0') { - hidden_ssid = 0; - break; - } - } - - if (hidden_ssid && ifsta->ssid_len == ssid_len) - return 1; - - if (ssid_len == 1 && ssid[0] == ' ') - return 1; - - return 0; -} - -static int ieee80211_sta_config_auth(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_sta_bss *bss, *selected = NULL; - int top_rssi = 0, freq; - - if (!(ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | - IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL))) { - ifsta->state = IEEE80211_AUTHENTICATE; - ieee80211_sta_reset_auth(dev, ifsta); - return 0; - } - - spin_lock_bh(&local->sta_bss_lock); - freq = local->oper_channel->center_freq; - list_for_each_entry(bss, &local->sta_bss_list, list) { - if (!(bss->capability & WLAN_CAPABILITY_ESS)) - continue; - - if (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^ - !!sdata->default_key) - continue; - - if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) && - bss->freq != freq) - continue; - - if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) && - memcmp(bss->bssid, ifsta->bssid, ETH_ALEN)) - continue; - - if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) && - !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) - continue; - - if (!selected || top_rssi < bss->rssi) { - selected = bss; - top_rssi = bss->rssi; - } - } - if (selected) - atomic_inc(&selected->users); - spin_unlock_bh(&local->sta_bss_lock); - - if (selected) { - ieee80211_set_freq(local, selected->freq); - if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) - ieee80211_sta_set_ssid(dev, selected->ssid, - selected->ssid_len); - ieee80211_sta_set_bssid(dev, selected->bssid); - ieee80211_sta_def_wmm_params(dev, selected, 0); - ieee80211_rx_bss_put(dev, selected); - ifsta->state = IEEE80211_AUTHENTICATE; - ieee80211_sta_reset_auth(dev, ifsta); - return 0; - } else { - if (ifsta->state != IEEE80211_AUTHENTICATE) { - if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) - ieee80211_sta_start_scan(dev, NULL, 0); - else - ieee80211_sta_start_scan(dev, ifsta->ssid, - ifsta->ssid_len); - ifsta->state = IEEE80211_AUTHENTICATE; - set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); - } else - ifsta->state = IEEE80211_DISABLED; - } - return -1; -} - - -static int ieee80211_sta_create_ibss(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sta_bss *bss; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_supported_band *sband; - u8 bssid[ETH_ALEN], *pos; - int i; - DECLARE_MAC_BUF(mac); - -#if 0 - /* Easier testing, use fixed BSSID. */ - memset(bssid, 0xfe, ETH_ALEN); -#else - /* Generate random, not broadcast, locally administered BSSID. Mix in - * own MAC address to make sure that devices that do not have proper - * random number generator get different BSSID. */ - get_random_bytes(bssid, ETH_ALEN); - for (i = 0; i < ETH_ALEN; i++) - bssid[i] ^= dev->dev_addr[i]; - bssid[0] &= ~0x01; - bssid[0] |= 0x02; -#endif - - printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", - dev->name, print_mac(mac, bssid)); - - bss = ieee80211_rx_bss_add(dev, bssid, - local->hw.conf.channel->center_freq, - sdata->u.sta.ssid, sdata->u.sta.ssid_len); - if (!bss) - return -ENOMEM; - - bss->band = local->hw.conf.channel->band; - sband = local->hw.wiphy->bands[bss->band]; - - if (local->hw.conf.beacon_int == 0) - local->hw.conf.beacon_int = 10000; - bss->beacon_int = local->hw.conf.beacon_int; - bss->last_update = jiffies; - bss->capability = WLAN_CAPABILITY_IBSS; - if (sdata->default_key) { - bss->capability |= WLAN_CAPABILITY_PRIVACY; - } else - sdata->drop_unencrypted = 0; - bss->supp_rates_len = sband->n_bitrates; - pos = bss->supp_rates; - for (i = 0; i < sband->n_bitrates; i++) { - int rate = sband->bitrates[i].bitrate; - *pos++ = (u8) (rate / 5); - } - - return ieee80211_sta_join_ibss(dev, ifsta, bss); -} - - -static int ieee80211_sta_find_ibss(struct net_device *dev, - struct ieee80211_if_sta *ifsta) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sta_bss *bss; - int found = 0; - u8 bssid[ETH_ALEN]; - int active_ibss; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - - if (ifsta->ssid_len == 0) - return -EINVAL; - - active_ibss = ieee80211_sta_active_ibss(dev); -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", - dev->name, active_ibss); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ - spin_lock_bh(&local->sta_bss_lock); - list_for_each_entry(bss, &local->sta_bss_list, list) { - if (ifsta->ssid_len != bss->ssid_len || - memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0 - || !(bss->capability & WLAN_CAPABILITY_IBSS)) - continue; -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " bssid=%s found\n", - print_mac(mac, bss->bssid)); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ - memcpy(bssid, bss->bssid, ETH_ALEN); - found = 1; - if (active_ibss || memcmp(bssid, ifsta->bssid, ETH_ALEN) != 0) - break; - } - spin_unlock_bh(&local->sta_bss_lock); - -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " sta_find_ibss: selected %s current " - "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid)); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ - if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && - (bss = ieee80211_rx_bss_get(dev, bssid, - local->hw.conf.channel->center_freq, - ifsta->ssid, ifsta->ssid_len))) { - printk(KERN_DEBUG "%s: Selected IBSS BSSID %s" - " based on configured SSID\n", - dev->name, print_mac(mac, bssid)); - return ieee80211_sta_join_ibss(dev, ifsta, bss); - } -#ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " did not try to join ibss\n"); -#endif /* CONFIG_MAC80211_IBSS_DEBUG */ - - /* Selected IBSS not found in current scan results - try to scan */ - if (ifsta->state == IEEE80211_IBSS_JOINED && - !ieee80211_sta_active_ibss(dev)) { - mod_timer(&ifsta->timer, jiffies + - IEEE80211_IBSS_MERGE_INTERVAL); - } else if (time_after(jiffies, local->last_scan_completed + - IEEE80211_SCAN_INTERVAL)) { - printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " - "join\n", dev->name); - return ieee80211_sta_req_scan(dev, ifsta->ssid, - ifsta->ssid_len); - } else if (ifsta->state != IEEE80211_IBSS_JOINED) { - int interval = IEEE80211_SCAN_INTERVAL; - - if (time_after(jiffies, ifsta->ibss_join_req + - IEEE80211_IBSS_JOIN_TIMEOUT)) { - if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) && - (!(local->oper_channel->flags & - IEEE80211_CHAN_NO_IBSS))) - return ieee80211_sta_create_ibss(dev, ifsta); - if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) { - printk(KERN_DEBUG "%s: IBSS not allowed on" - " %d MHz\n", dev->name, - local->hw.conf.channel->center_freq); - } - - /* No IBSS found - decrease scan interval and continue - * scanning. */ - interval = IEEE80211_SCAN_INTERVAL_SLOW; - } - - ifsta->state = IEEE80211_IBSS_SEARCH; - mod_timer(&ifsta->timer, jiffies + interval); - return 0; - } - - return 0; -} - - -int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_if_sta *ifsta; - - if (len > IEEE80211_MAX_SSID_LEN) - return -EINVAL; - - ifsta = &sdata->u.sta; - - if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) - ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; - memcpy(ifsta->ssid, ssid, len); - memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len); - ifsta->ssid_len = len; - - if (len) - ifsta->flags |= IEEE80211_STA_SSID_SET; - else - ifsta->flags &= ~IEEE80211_STA_SSID_SET; - if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && - !(ifsta->flags & IEEE80211_STA_BSSID_SET)) { - ifsta->ibss_join_req = jiffies; - ifsta->state = IEEE80211_IBSS_SEARCH; - return ieee80211_sta_find_ibss(dev, ifsta); - } - return 0; -} - - -int ieee80211_sta_get_ssid(struct net_device *dev, char *ssid, size_t *len) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_if_sta *ifsta = &sdata->u.sta; - memcpy(ssid, ifsta->ssid, ifsta->ssid_len); - *len = ifsta->ssid_len; - return 0; -} - - -int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid) -{ - struct ieee80211_sub_if_data *sdata; - struct ieee80211_if_sta *ifsta; - int res; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - ifsta = &sdata->u.sta; - - if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { - memcpy(ifsta->bssid, bssid, ETH_ALEN); - res = ieee80211_if_config(dev); - if (res) { - printk(KERN_DEBUG "%s: Failed to config new BSSID to " - "the low-level driver\n", dev->name); - return res; - } - } - - if (is_valid_ether_addr(bssid)) - ifsta->flags |= IEEE80211_STA_BSSID_SET; - else - ifsta->flags &= ~IEEE80211_STA_BSSID_SET; - - return 0; -} - - -static void ieee80211_send_nullfunc(struct ieee80211_local *local, - struct ieee80211_sub_if_data *sdata, - int powersave) -{ - struct sk_buff *skb; - struct ieee80211_hdr *nullfunc; - u16 fc; - - skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); - if (!skb) { - printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " - "frame\n", sdata->dev->name); - return; - } - skb_reserve(skb, local->hw.extra_tx_headroom); - - nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); - memset(nullfunc, 0, 24); - fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | - IEEE80211_FCTL_TODS; - if (powersave) - fc |= IEEE80211_FCTL_PM; - nullfunc->frame_control = cpu_to_le16(fc); - memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN); - memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); - memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN); - - ieee80211_sta_tx(sdata->dev, skb, 0); -} - - -static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) -{ - if (sdata->vif.type == IEEE80211_IF_TYPE_STA || - ieee80211_vif_is_mesh(&sdata->vif)) - ieee80211_sta_timer((unsigned long)sdata); -} - -void ieee80211_scan_completed(struct ieee80211_hw *hw) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct net_device *dev = local->scan_dev; - struct ieee80211_sub_if_data *sdata; - union iwreq_data wrqu; - - local->last_scan_completed = jiffies; - memset(&wrqu, 0, sizeof(wrqu)); - wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); - - if (local->sta_hw_scanning) { - local->sta_hw_scanning = 0; - if (ieee80211_hw_config(local)) - printk(KERN_DEBUG "%s: failed to restore operational " - "channel after scan\n", dev->name); - /* Restart STA timer for HW scan case */ - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) - ieee80211_restart_sta_timer(sdata); - rcu_read_unlock(); - - goto done; - } - - local->sta_sw_scanning = 0; - if (ieee80211_hw_config(local)) - printk(KERN_DEBUG "%s: failed to restore operational " - "channel after scan\n", dev->name); - - - netif_tx_lock_bh(local->mdev); - local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; - local->ops->configure_filter(local_to_hw(local), - FIF_BCN_PRBRESP_PROMISC, - &local->filter_flags, - local->mdev->mc_count, - local->mdev->mc_list); - - netif_tx_unlock_bh(local->mdev); - - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - - /* No need to wake the master device. */ - if (sdata->dev == local->mdev) - continue; - - /* Tell AP we're back */ - if (sdata->vif.type == IEEE80211_IF_TYPE_STA && - sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) - ieee80211_send_nullfunc(local, sdata, 0); - - ieee80211_restart_sta_timer(sdata); - - netif_wake_queue(sdata->dev); - } - rcu_read_unlock(); - -done: - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { - struct ieee80211_if_sta *ifsta = &sdata->u.sta; - if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) || - (!ifsta->state == IEEE80211_IBSS_JOINED && - !ieee80211_sta_active_ibss(dev))) - ieee80211_sta_find_ibss(dev, ifsta); - } -} -EXPORT_SYMBOL(ieee80211_scan_completed); - -void ieee80211_sta_scan_work(struct work_struct *work) -{ - struct ieee80211_local *local = - container_of(work, struct ieee80211_local, scan_work.work); - struct net_device *dev = local->scan_dev; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_supported_band *sband; - struct ieee80211_channel *chan; - int skip; - unsigned long next_delay = 0; - - if (!local->sta_sw_scanning) - return; - - switch (local->scan_state) { - case SCAN_SET_CHANNEL: - /* - * Get current scan band. scan_band may be IEEE80211_NUM_BANDS - * after we successfully scanned the last channel of the last - * band (and the last band is supported by the hw) - */ - if (local->scan_band < IEEE80211_NUM_BANDS) - sband = local->hw.wiphy->bands[local->scan_band]; - else - sband = NULL; - - /* - * If we are at an unsupported band and have more bands - * left to scan, advance to the next supported one. - */ - while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) { - local->scan_band++; - sband = local->hw.wiphy->bands[local->scan_band]; - local->scan_channel_idx = 0; - } - - /* if no more bands/channels left, complete scan */ - if (!sband || local->scan_channel_idx >= sband->n_channels) { - ieee80211_scan_completed(local_to_hw(local)); - return; - } - skip = 0; - chan = &sband->channels[local->scan_channel_idx]; - - if (chan->flags & IEEE80211_CHAN_DISABLED || - (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && - chan->flags & IEEE80211_CHAN_NO_IBSS)) - skip = 1; - - if (!skip) { - local->scan_channel = chan; - if (ieee80211_hw_config(local)) { - printk(KERN_DEBUG "%s: failed to set freq to " - "%d MHz for scan\n", dev->name, - chan->center_freq); - skip = 1; - } - } - - /* advance state machine to next channel/band */ - local->scan_channel_idx++; - if (local->scan_channel_idx >= sband->n_channels) { - /* - * scan_band may end up == IEEE80211_NUM_BANDS, but - * we'll catch that case above and complete the scan - * if that is the case. - */ - local->scan_band++; - local->scan_channel_idx = 0; - } - - if (skip) - break; - - next_delay = IEEE80211_PROBE_DELAY + - usecs_to_jiffies(local->hw.channel_change_time); - local->scan_state = SCAN_SEND_PROBE; - break; - case SCAN_SEND_PROBE: - next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; - local->scan_state = SCAN_SET_CHANNEL; - - if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN) - break; - ieee80211_send_probe_req(dev, NULL, local->scan_ssid, - local->scan_ssid_len); - next_delay = IEEE80211_CHANNEL_TIME; - break; - } - - if (local->sta_sw_scanning) - queue_delayed_work(local->hw.workqueue, &local->scan_work, - next_delay); -} - - -static int ieee80211_sta_start_scan(struct net_device *dev, - u8 *ssid, size_t ssid_len) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_sub_if_data *sdata; - - if (ssid_len > IEEE80211_MAX_SSID_LEN) - return -EINVAL; - - /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) - * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS - * BSSID: MACAddress - * SSID - * ScanType: ACTIVE, PASSIVE - * ProbeDelay: delay (in microseconds) to be used prior to transmitting - * a Probe frame during active scanning - * ChannelList - * MinChannelTime (>= ProbeDelay), in TU - * MaxChannelTime: (>= MinChannelTime), in TU - */ - - /* MLME-SCAN.confirm - * BSSDescriptionSet - * ResultCode: SUCCESS, INVALID_PARAMETERS - */ - - if (local->sta_sw_scanning || local->sta_hw_scanning) { - if (local->scan_dev == dev) - return 0; - return -EBUSY; - } - - if (local->ops->hw_scan) { - int rc = local->ops->hw_scan(local_to_hw(local), - ssid, ssid_len); - if (!rc) { - local->sta_hw_scanning = 1; - local->scan_dev = dev; - } - return rc; - } - - local->sta_sw_scanning = 1; - - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - - /* Don't stop the master interface, otherwise we can't transmit - * probes! */ - if (sdata->dev == local->mdev) - continue; - - netif_stop_queue(sdata->dev); - if (sdata->vif.type == IEEE80211_IF_TYPE_STA && - (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) - ieee80211_send_nullfunc(local, sdata, 1); - } - rcu_read_unlock(); - - if (ssid) { - local->scan_ssid_len = ssid_len; - memcpy(local->scan_ssid, ssid, ssid_len); - } else - local->scan_ssid_len = 0; - local->scan_state = SCAN_SET_CHANNEL; - local->scan_channel_idx = 0; - local->scan_band = IEEE80211_BAND_2GHZ; - local->scan_dev = dev; - - netif_tx_lock_bh(local->mdev); - local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; - local->ops->configure_filter(local_to_hw(local), - FIF_BCN_PRBRESP_PROMISC, - &local->filter_flags, - local->mdev->mc_count, - local->mdev->mc_list); - netif_tx_unlock_bh(local->mdev); - - /* TODO: start scan as soon as all nullfunc frames are ACKed */ - queue_delayed_work(local->hw.workqueue, &local->scan_work, - IEEE80211_CHANNEL_TIME); - - return 0; -} - - -int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_if_sta *ifsta = &sdata->u.sta; - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - - if (sdata->vif.type != IEEE80211_IF_TYPE_STA) - return ieee80211_sta_start_scan(dev, ssid, ssid_len); - - if (local->sta_sw_scanning || local->sta_hw_scanning) { - if (local->scan_dev == dev) - return 0; - return -EBUSY; - } - - ifsta->scan_ssid_len = ssid_len; - if (ssid_len) - memcpy(ifsta->scan_ssid, ssid, ssid_len); - set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request); - queue_work(local->hw.workqueue, &ifsta->work); - return 0; -} - -static char * -ieee80211_sta_scan_result(struct net_device *dev, - struct ieee80211_sta_bss *bss, - char *current_ev, char *end_buf) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct iw_event iwe; - - if (time_after(jiffies, - bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE)) - return current_ev; - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWAP; - iwe.u.ap_addr.sa_family = ARPHRD_ETHER; - memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, - IW_EV_ADDR_LEN); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWESSID; - if (bss_mesh_cfg(bss)) { - iwe.u.data.length = bss_mesh_id_len(bss); - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - bss_mesh_id(bss)); - } else { - iwe.u.data.length = bss->ssid_len; - iwe.u.data.flags = 1; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - bss->ssid); - } - - if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) - || bss_mesh_cfg(bss)) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWMODE; - if (bss_mesh_cfg(bss)) - iwe.u.mode = IW_MODE_MESH; - else if (bss->capability & WLAN_CAPABILITY_ESS) - iwe.u.mode = IW_MODE_MASTER; - else - iwe.u.mode = IW_MODE_ADHOC; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, - IW_EV_UINT_LEN); - } - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = bss->freq; - iwe.u.freq.e = 6; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, - IW_EV_FREQ_LEN); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWFREQ; - iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); - iwe.u.freq.e = 0; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, - IW_EV_FREQ_LEN); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVQUAL; - iwe.u.qual.qual = bss->signal; - iwe.u.qual.level = bss->rssi; - iwe.u.qual.noise = bss->noise; - iwe.u.qual.updated = local->wstats_flags; - current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, - IW_EV_QUAL_LEN); - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWENCODE; - if (bss->capability & WLAN_CAPABILITY_PRIVACY) - iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; - else - iwe.u.data.flags = IW_ENCODE_DISABLED; - iwe.u.data.length = 0; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); - - if (bss && bss->wpa_ie) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = bss->wpa_ie_len; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - bss->wpa_ie); - } - - if (bss && bss->rsn_ie) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVGENIE; - iwe.u.data.length = bss->rsn_ie_len; - current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, - bss->rsn_ie); - } - - if (bss && bss->supp_rates_len > 0) { - /* display all supported rates in readable format */ - char *p = current_ev + IW_EV_LCP_LEN; - int i; - - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = SIOCGIWRATE; - /* Those two flags are ignored... */ - iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; - - for (i = 0; i < bss->supp_rates_len; i++) { - iwe.u.bitrate.value = ((bss->supp_rates[i] & - 0x7f) * 500000); - p = iwe_stream_add_value(current_ev, p, - end_buf, &iwe, IW_EV_PARAM_LEN); - } - current_ev = p; - } - - if (bss) { - char *buf; - buf = kmalloc(30, GFP_ATOMIC); - if (buf) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp)); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, buf); - kfree(buf); - } - } - - if (bss_mesh_cfg(bss)) { - char *buf; - u8 *cfg = bss_mesh_cfg(bss); - buf = kmalloc(50, GFP_ATOMIC); - if (buf) { - memset(&iwe, 0, sizeof(iwe)); - iwe.cmd = IWEVCUSTOM; - sprintf(buf, "Mesh network (version %d)", cfg[0]); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, buf); - sprintf(buf, "Path Selection Protocol ID: " - "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], - cfg[4]); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, buf); - sprintf(buf, "Path Selection Metric ID: " - "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], - cfg[8]); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, buf); - sprintf(buf, "Congestion Control Mode ID: " - "0x%02X%02X%02X%02X", cfg[9], cfg[10], - cfg[11], cfg[12]); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, buf); - sprintf(buf, "Channel Precedence: " - "0x%02X%02X%02X%02X", cfg[13], cfg[14], - cfg[15], cfg[16]); - iwe.u.data.length = strlen(buf); - current_ev = iwe_stream_add_point(current_ev, end_buf, - &iwe, buf); - kfree(buf); - } - } - - return current_ev; -} - - -int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - char *current_ev = buf; - char *end_buf = buf + len; - struct ieee80211_sta_bss *bss; - - spin_lock_bh(&local->sta_bss_lock); - list_for_each_entry(bss, &local->sta_bss_list, list) { - if (buf + len - current_ev <= IW_EV_ADDR_LEN) { - spin_unlock_bh(&local->sta_bss_lock); - return -E2BIG; - } - current_ev = ieee80211_sta_scan_result(dev, bss, current_ev, - end_buf); - } - spin_unlock_bh(&local->sta_bss_lock); - return current_ev - buf; -} - - -int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_if_sta *ifsta = &sdata->u.sta; - kfree(ifsta->extra_ie); - if (len == 0) { - ifsta->extra_ie = NULL; - ifsta->extra_ie_len = 0; - return 0; - } - ifsta->extra_ie = kmalloc(len, GFP_KERNEL); - if (!ifsta->extra_ie) { - ifsta->extra_ie_len = 0; - return -ENOMEM; - } - memcpy(ifsta->extra_ie, ie, len); - ifsta->extra_ie_len = len; - return 0; -} - - -struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, - struct sk_buff *skb, u8 *bssid, - u8 *addr) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct sta_info *sta; - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - DECLARE_MAC_BUF(mac); - - /* TODO: Could consider removing the least recently used entry and - * allow new one to be added. */ - if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: No room for a new IBSS STA " - "entry %s\n", dev->name, print_mac(mac, addr)); - } - return NULL; - } - - printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", - wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); - - sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); - if (!sta) - return NULL; - - sta->flags |= WLAN_STA_AUTHORIZED; - - sta->supp_rates[local->hw.conf.channel->band] = - sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band]; - - rate_control_rate_init(sta, local); - - if (sta_info_insert(sta)) - return NULL; - - return sta; -} - - -int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_if_sta *ifsta = &sdata->u.sta; - - printk(KERN_DEBUG "%s: deauthenticate(reason=%d)\n", - dev->name, reason); - - if (sdata->vif.type != IEEE80211_IF_TYPE_STA && - sdata->vif.type != IEEE80211_IF_TYPE_IBSS) - return -EINVAL; - - ieee80211_send_deauth(dev, ifsta, reason); - ieee80211_set_disassoc(dev, ifsta, 1); - return 0; -} - - -int ieee80211_sta_disassociate(struct net_device *dev, u16 reason) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_if_sta *ifsta = &sdata->u.sta; - - printk(KERN_DEBUG "%s: disassociate(reason=%d)\n", - dev->name, reason); - - if (sdata->vif.type != IEEE80211_IF_TYPE_STA) - return -EINVAL; - - if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) - return -1; - - ieee80211_send_disassoc(dev, ifsta, reason); - ieee80211_set_disassoc(dev, ifsta, 0); - return 0; -} - -void ieee80211_notify_mac(struct ieee80211_hw *hw, - enum ieee80211_notification_types notif_type) -{ - struct ieee80211_local *local = hw_to_local(hw); - struct ieee80211_sub_if_data *sdata; - - switch (notif_type) { - case IEEE80211_NOTIFY_RE_ASSOC: - rcu_read_lock(); - list_for_each_entry_rcu(sdata, &local->interfaces, list) { - - if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { - ieee80211_sta_req_auth(sdata->dev, - &sdata->u.sta); - } - - } - rcu_read_unlock(); - break; - } -} -EXPORT_SYMBOL(ieee80211_notify_mac); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c new file mode 100644 index 000000000000..80954a512185 --- /dev/null +++ b/net/mac80211/iface.c @@ -0,0 +1,314 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright (c) 2006 Jiri Benc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include "ieee80211_i.h" +#include "sta_info.h" +#include "debugfs_netdev.h" +#include "mesh.h" + +void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata) +{ + int i; + + /* Default values for sub-interface parameters */ + sdata->drop_unencrypted = 0; + for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) + skb_queue_head_init(&sdata->fragments[i].skb_list); + + INIT_LIST_HEAD(&sdata->key_list); +} + +static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata) +{ + int i; + + for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) { + __skb_queue_purge(&sdata->fragments[i].skb_list); + } +} + +/* Must be called with rtnl lock held. */ +int ieee80211_if_add(struct net_device *dev, const char *name, + struct net_device **new_dev, int type, + struct vif_params *params) +{ + struct net_device *ndev; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = NULL; + int ret; + + ASSERT_RTNL(); + ndev = alloc_netdev(sizeof(*sdata) + local->hw.vif_data_size, + name, ieee80211_if_setup); + if (!ndev) + return -ENOMEM; + + ret = dev_alloc_name(ndev, ndev->name); + if (ret < 0) + goto fail; + + memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); + ndev->base_addr = dev->base_addr; + ndev->irq = dev->irq; + ndev->mem_start = dev->mem_start; + ndev->mem_end = dev->mem_end; + SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy)); + + sdata = IEEE80211_DEV_TO_SUB_IF(ndev); + ndev->ieee80211_ptr = &sdata->wdev; + sdata->wdev.wiphy = local->hw.wiphy; + sdata->vif.type = IEEE80211_IF_TYPE_AP; + sdata->dev = ndev; + sdata->local = local; + ieee80211_if_sdata_init(sdata); + + ret = register_netdevice(ndev); + if (ret) + goto fail; + + ieee80211_debugfs_add_netdev(sdata); + ieee80211_if_set_type(ndev, type); + + if (ieee80211_vif_is_mesh(&sdata->vif) && + params && params->mesh_id_len) + ieee80211_if_sta_set_mesh_id(&sdata->u.sta, + params->mesh_id_len, + params->mesh_id); + + /* we're under RTNL so all this is fine */ + if (unlikely(local->reg_state == IEEE80211_DEV_UNREGISTERED)) { + __ieee80211_if_del(local, sdata); + return -ENODEV; + } + list_add_tail_rcu(&sdata->list, &local->interfaces); + + if (new_dev) + *new_dev = ndev; + + return 0; + +fail: + free_netdev(ndev); + return ret; +} + +void ieee80211_if_set_type(struct net_device *dev, int type) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int oldtype = sdata->vif.type; + + /* + * We need to call this function on the master interface + * which already has a hard_start_xmit routine assigned + * which must not be changed. + */ + if (dev != sdata->local->mdev) + dev->hard_start_xmit = ieee80211_subif_start_xmit; + + /* + * Called even when register_netdevice fails, it would + * oops if assigned before initialising the rest. + */ + dev->uninit = ieee80211_if_reinit; + + /* most have no BSS pointer */ + sdata->bss = NULL; + sdata->vif.type = type; + + sdata->basic_rates = 0; + + switch (type) { + case IEEE80211_IF_TYPE_WDS: + /* nothing special */ + break; + case IEEE80211_IF_TYPE_VLAN: + sdata->u.vlan.ap = NULL; + break; + case IEEE80211_IF_TYPE_AP: + sdata->u.ap.force_unicast_rateidx = -1; + sdata->u.ap.max_ratectrl_rateidx = -1; + skb_queue_head_init(&sdata->u.ap.ps_bc_buf); + sdata->bss = &sdata->u.ap; + INIT_LIST_HEAD(&sdata->u.ap.vlans); + break; + case IEEE80211_IF_TYPE_MESH_POINT: + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: { + struct ieee80211_sub_if_data *msdata; + struct ieee80211_if_sta *ifsta; + + ifsta = &sdata->u.sta; + INIT_WORK(&ifsta->work, ieee80211_sta_work); + setup_timer(&ifsta->timer, ieee80211_sta_timer, + (unsigned long) sdata); + skb_queue_head_init(&ifsta->skb_queue); + + ifsta->capab = WLAN_CAPABILITY_ESS; + ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN | + IEEE80211_AUTH_ALG_SHARED_KEY; + ifsta->flags |= IEEE80211_STA_CREATE_IBSS | + IEEE80211_STA_WMM_ENABLED | + IEEE80211_STA_AUTO_BSSID_SEL | + IEEE80211_STA_AUTO_CHANNEL_SEL; + + msdata = IEEE80211_DEV_TO_SUB_IF(sdata->local->mdev); + sdata->bss = &msdata->u.ap; + + if (ieee80211_vif_is_mesh(&sdata->vif)) + ieee80211_mesh_init_sdata(sdata); + break; + } + case IEEE80211_IF_TYPE_MNTR: + dev->type = ARPHRD_IEEE80211_RADIOTAP; + dev->hard_start_xmit = ieee80211_monitor_start_xmit; + sdata->u.mntr_flags = MONITOR_FLAG_CONTROL | + MONITOR_FLAG_OTHER_BSS; + break; + default: + printk(KERN_WARNING "%s: %s: Unknown interface type 0x%x", + dev->name, __func__, type); + } + ieee80211_debugfs_change_if_type(sdata, oldtype); +} + +/* Must be called with rtnl lock held. */ +void ieee80211_if_reinit(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct sk_buff *skb; + int flushed; + + ASSERT_RTNL(); + + ieee80211_free_keys(sdata); + + ieee80211_if_sdata_deinit(sdata); + + /* Need to handle mesh specially to allow eliding the function call */ + if (ieee80211_vif_is_mesh(&sdata->vif)) + mesh_rmc_free(dev); + + switch (sdata->vif.type) { + case IEEE80211_IF_TYPE_INVALID: + /* cannot happen */ + WARN_ON(1); + break; + case IEEE80211_IF_TYPE_AP: { + /* Remove all virtual interfaces that use this BSS + * as their sdata->bss */ + struct ieee80211_sub_if_data *tsdata, *n; + struct beacon_data *beacon; + + list_for_each_entry_safe(tsdata, n, &local->interfaces, list) { + if (tsdata != sdata && tsdata->bss == &sdata->u.ap) { + printk(KERN_DEBUG "%s: removing virtual " + "interface %s because its BSS interface" + " is being removed\n", + sdata->dev->name, tsdata->dev->name); + list_del_rcu(&tsdata->list); + /* + * We have lots of time and can afford + * to sync for each interface + */ + synchronize_rcu(); + __ieee80211_if_del(local, tsdata); + } + } + + beacon = sdata->u.ap.beacon; + rcu_assign_pointer(sdata->u.ap.beacon, NULL); + synchronize_rcu(); + kfree(beacon); + + while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) { + local->total_ps_buffered--; + dev_kfree_skb(skb); + } + + break; + } + case IEEE80211_IF_TYPE_WDS: + /* nothing to do */ + break; + case IEEE80211_IF_TYPE_MESH_POINT: + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + kfree(sdata->u.sta.extra_ie); + sdata->u.sta.extra_ie = NULL; + kfree(sdata->u.sta.assocreq_ies); + sdata->u.sta.assocreq_ies = NULL; + kfree(sdata->u.sta.assocresp_ies); + sdata->u.sta.assocresp_ies = NULL; + if (sdata->u.sta.probe_resp) { + dev_kfree_skb(sdata->u.sta.probe_resp); + sdata->u.sta.probe_resp = NULL; + } + + break; + case IEEE80211_IF_TYPE_MNTR: + dev->type = ARPHRD_ETHER; + break; + case IEEE80211_IF_TYPE_VLAN: + sdata->u.vlan.ap = NULL; + break; + } + + flushed = sta_info_flush(local, sdata); + WARN_ON(flushed); + + memset(&sdata->u, 0, sizeof(sdata->u)); + ieee80211_if_sdata_init(sdata); +} + +/* Must be called with rtnl lock held. */ +void __ieee80211_if_del(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + struct net_device *dev = sdata->dev; + + ieee80211_debugfs_remove_netdev(sdata); + unregister_netdevice(dev); + /* Except master interface, the net_device will be freed by + * net_device->destructor (i. e. ieee80211_if_free). */ +} + +/* Must be called with rtnl lock held. */ +int ieee80211_if_remove(struct net_device *dev, const char *name, int id) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata, *n; + + ASSERT_RTNL(); + + list_for_each_entry_safe(sdata, n, &local->interfaces, list) { + if ((sdata->vif.type == id || id == -1) && + strcmp(name, sdata->dev->name) == 0 && + sdata->dev != local->mdev) { + list_del_rcu(&sdata->list); + synchronize_rcu(); + __ieee80211_if_del(local, sdata); + return 0; + } + } + return -ENODEV; +} + +void ieee80211_if_free(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + ieee80211_if_sdata_deinit(sdata); + free_netdev(dev); +} diff --git a/net/mac80211/key.h b/net/mac80211/key.h new file mode 100644 index 000000000000..467890c6fe81 --- /dev/null +++ b/net/mac80211/key.h @@ -0,0 +1,157 @@ +/* + * Copyright 2002-2004, Instant802 Networks, Inc. + * Copyright 2005, Devicescape Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef IEEE80211_KEY_H +#define IEEE80211_KEY_H + +#include +#include +#include +#include +#include + +/* ALG_TKIP + * struct ieee80211_key::key is encoded as a 256-bit (32 byte) data block: + * Temporal Encryption Key (128 bits) + * Temporal Authenticator Tx MIC Key (64 bits) + * Temporal Authenticator Rx MIC Key (64 bits) + */ + +#define WEP_IV_LEN 4 +#define WEP_ICV_LEN 4 + +#define ALG_TKIP_KEY_LEN 32 +/* Starting offsets for each key */ +#define ALG_TKIP_TEMP_ENCR_KEY 0 +#define ALG_TKIP_TEMP_AUTH_TX_MIC_KEY 16 +#define ALG_TKIP_TEMP_AUTH_RX_MIC_KEY 24 +#define TKIP_IV_LEN 8 +#define TKIP_ICV_LEN 4 + +#define ALG_CCMP_KEY_LEN 16 +#define CCMP_HDR_LEN 8 +#define CCMP_MIC_LEN 8 +#define CCMP_TK_LEN 16 +#define CCMP_PN_LEN 6 + +#define NUM_RX_DATA_QUEUES 17 + +struct ieee80211_local; +struct ieee80211_sub_if_data; +struct sta_info; + +/** + * enum ieee80211_internal_key_flags - internal key flags + * + * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present + * in the hardware for TX crypto hardware acceleration. + * @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an + * RCU grace period, no longer be reachable other than from the + * todo list. + * @KEY_FLAG_TODO_HWACCEL: Key needs to be added to hardware acceleration. + * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated. + * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs. + */ +enum ieee80211_internal_key_flags { + KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), + KEY_FLAG_TODO_DELETE = BIT(1), + KEY_FLAG_TODO_HWACCEL = BIT(2), + KEY_FLAG_TODO_DEFKEY = BIT(3), + KEY_FLAG_TODO_ADD_DEBUGFS = BIT(4), +}; + +struct ieee80211_key { + struct ieee80211_local *local; + struct ieee80211_sub_if_data *sdata; + struct sta_info *sta; + + /* for sdata list */ + struct list_head list; + /* for todo list */ + struct list_head todo; + + /* protected by todo lock! */ + unsigned int flags; + + union { + struct { + /* last used TSC */ + u32 iv32; + u16 iv16; + u16 p1k[5]; + int tx_initialized; + + /* last received RSC */ + u32 iv32_rx[NUM_RX_DATA_QUEUES]; + u16 iv16_rx[NUM_RX_DATA_QUEUES]; + u16 p1k_rx[NUM_RX_DATA_QUEUES][5]; + int rx_initialized[NUM_RX_DATA_QUEUES]; + } tkip; + struct { + u8 tx_pn[6]; + u8 rx_pn[NUM_RX_DATA_QUEUES][6]; + struct crypto_cipher *tfm; + u32 replays; /* dot11RSNAStatsCCMPReplays */ + /* scratch buffers for virt_to_page() (crypto API) */ +#ifndef AES_BLOCK_LEN +#define AES_BLOCK_LEN 16 +#endif + u8 tx_crypto_buf[6 * AES_BLOCK_LEN]; + u8 rx_crypto_buf[6 * AES_BLOCK_LEN]; + } ccmp; + } u; + + /* number of times this key has been used */ + int tx_rx_count; + +#ifdef CONFIG_MAC80211_DEBUGFS + struct { + struct dentry *stalink; + struct dentry *dir; + struct dentry *keylen; + struct dentry *flags; + struct dentry *keyidx; + struct dentry *hw_key_idx; + struct dentry *tx_rx_count; + struct dentry *algorithm; + struct dentry *tx_spec; + struct dentry *rx_spec; + struct dentry *replays; + struct dentry *key; + struct dentry *ifindex; + } debugfs; +#endif + + /* + * key config, must be last because it contains key + * material as variable length member + */ + struct ieee80211_key_conf conf; +}; + +struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, + int idx, + size_t key_len, + const u8 *key_data); +/* + * Insert a key into data structures (sdata, sta if necessary) + * to make it used, free old key. + */ +void ieee80211_key_link(struct ieee80211_key *key, + struct ieee80211_sub_if_data *sdata, + struct sta_info *sta); +void ieee80211_key_free(struct ieee80211_key *key); +void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx); +void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); +void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); +void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); + +void ieee80211_key_todo(void); + +#endif /* IEEE80211_KEY_H */ diff --git a/net/mac80211/led.c b/net/mac80211/led.c new file mode 100644 index 000000000000..162a643f16b6 --- /dev/null +++ b/net/mac80211/led.c @@ -0,0 +1,161 @@ +/* + * Copyright 2006, Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* just for IFNAMSIZ */ +#include +#include "led.h" + +void ieee80211_led_rx(struct ieee80211_local *local) +{ + if (unlikely(!local->rx_led)) + return; + if (local->rx_led_counter++ % 2 == 0) + led_trigger_event(local->rx_led, LED_OFF); + else + led_trigger_event(local->rx_led, LED_FULL); +} + +/* q is 1 if a packet was enqueued, 0 if it has been transmitted */ +void ieee80211_led_tx(struct ieee80211_local *local, int q) +{ + if (unlikely(!local->tx_led)) + return; + /* not sure how this is supposed to work ... */ + local->tx_led_counter += 2*q-1; + if (local->tx_led_counter % 2 == 0) + led_trigger_event(local->tx_led, LED_OFF); + else + led_trigger_event(local->tx_led, LED_FULL); +} + +void ieee80211_led_assoc(struct ieee80211_local *local, bool associated) +{ + if (unlikely(!local->assoc_led)) + return; + if (associated) + led_trigger_event(local->assoc_led, LED_FULL); + else + led_trigger_event(local->assoc_led, LED_OFF); +} + +void ieee80211_led_radio(struct ieee80211_local *local, bool enabled) +{ + if (unlikely(!local->radio_led)) + return; + if (enabled) + led_trigger_event(local->radio_led, LED_FULL); + else + led_trigger_event(local->radio_led, LED_OFF); +} + +void ieee80211_led_init(struct ieee80211_local *local) +{ + local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + if (local->rx_led) { + snprintf(local->rx_led_name, sizeof(local->rx_led_name), + "%srx", wiphy_name(local->hw.wiphy)); + local->rx_led->name = local->rx_led_name; + if (led_trigger_register(local->rx_led)) { + kfree(local->rx_led); + local->rx_led = NULL; + } + } + + local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + if (local->tx_led) { + snprintf(local->tx_led_name, sizeof(local->tx_led_name), + "%stx", wiphy_name(local->hw.wiphy)); + local->tx_led->name = local->tx_led_name; + if (led_trigger_register(local->tx_led)) { + kfree(local->tx_led); + local->tx_led = NULL; + } + } + + local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + if (local->assoc_led) { + snprintf(local->assoc_led_name, sizeof(local->assoc_led_name), + "%sassoc", wiphy_name(local->hw.wiphy)); + local->assoc_led->name = local->assoc_led_name; + if (led_trigger_register(local->assoc_led)) { + kfree(local->assoc_led); + local->assoc_led = NULL; + } + } + + local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); + if (local->radio_led) { + snprintf(local->radio_led_name, sizeof(local->radio_led_name), + "%sradio", wiphy_name(local->hw.wiphy)); + local->radio_led->name = local->radio_led_name; + if (led_trigger_register(local->radio_led)) { + kfree(local->radio_led); + local->radio_led = NULL; + } + } +} + +void ieee80211_led_exit(struct ieee80211_local *local) +{ + if (local->radio_led) { + led_trigger_unregister(local->radio_led); + kfree(local->radio_led); + } + if (local->assoc_led) { + led_trigger_unregister(local->assoc_led); + kfree(local->assoc_led); + } + if (local->tx_led) { + led_trigger_unregister(local->tx_led); + kfree(local->tx_led); + } + if (local->rx_led) { + led_trigger_unregister(local->rx_led); + kfree(local->rx_led); + } +} + +char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (local->radio_led) + return local->radio_led_name; + return NULL; +} +EXPORT_SYMBOL(__ieee80211_get_radio_led_name); + +char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (local->assoc_led) + return local->assoc_led_name; + return NULL; +} +EXPORT_SYMBOL(__ieee80211_get_assoc_led_name); + +char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (local->tx_led) + return local->tx_led_name; + return NULL; +} +EXPORT_SYMBOL(__ieee80211_get_tx_led_name); + +char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + + if (local->rx_led) + return local->rx_led_name; + return NULL; +} +EXPORT_SYMBOL(__ieee80211_get_rx_led_name); diff --git a/net/mac80211/led.h b/net/mac80211/led.h new file mode 100644 index 000000000000..77b1e1ba6039 --- /dev/null +++ b/net/mac80211/led.h @@ -0,0 +1,44 @@ +/* + * Copyright 2006, Johannes Berg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include "ieee80211_i.h" + +#ifdef CONFIG_MAC80211_LEDS +extern void ieee80211_led_rx(struct ieee80211_local *local); +extern void ieee80211_led_tx(struct ieee80211_local *local, int q); +extern void ieee80211_led_assoc(struct ieee80211_local *local, + bool associated); +extern void ieee80211_led_radio(struct ieee80211_local *local, + bool enabled); +extern void ieee80211_led_init(struct ieee80211_local *local); +extern void ieee80211_led_exit(struct ieee80211_local *local); +#else +static inline void ieee80211_led_rx(struct ieee80211_local *local) +{ +} +static inline void ieee80211_led_tx(struct ieee80211_local *local, int q) +{ +} +static inline void ieee80211_led_assoc(struct ieee80211_local *local, + bool associated) +{ +} +static inline void ieee80211_led_radio(struct ieee80211_local *local, + bool enabled) +{ +} +static inline void ieee80211_led_init(struct ieee80211_local *local) +{ +} +static inline void ieee80211_led_exit(struct ieee80211_local *local) +{ +} +#endif diff --git a/net/mac80211/main.c b/net/mac80211/main.c new file mode 100644 index 000000000000..bfcbcf5353ad --- /dev/null +++ b/net/mac80211/main.c @@ -0,0 +1,1889 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ieee80211_i.h" +#include "rate.h" +#include "mesh.h" +#include "wep.h" +#include "wme.h" +#include "aes_ccm.h" +#include "led.h" +#include "cfg.h" +#include "debugfs.h" +#include "debugfs_netdev.h" + +#define SUPP_MCS_SET_LEN 16 + +/* + * For seeing transmitted packets on monitor interfaces + * we have a radiotap header too. + */ +struct ieee80211_tx_status_rtap_hdr { + struct ieee80211_radiotap_header hdr; + __le16 tx_flags; + u8 data_retries; +} __attribute__ ((packed)); + +/* common interface routines */ + +static int header_parse_80211(const struct sk_buff *skb, unsigned char *haddr) +{ + memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); /* addr2 */ + return ETH_ALEN; +} + +/* must be called under mdev tx lock */ +static void ieee80211_configure_filter(struct ieee80211_local *local) +{ + unsigned int changed_flags; + unsigned int new_flags = 0; + + if (atomic_read(&local->iff_promiscs)) + new_flags |= FIF_PROMISC_IN_BSS; + + if (atomic_read(&local->iff_allmultis)) + new_flags |= FIF_ALLMULTI; + + if (local->monitors) + new_flags |= FIF_BCN_PRBRESP_PROMISC; + + if (local->fif_fcsfail) + new_flags |= FIF_FCSFAIL; + + if (local->fif_plcpfail) + new_flags |= FIF_PLCPFAIL; + + if (local->fif_control) + new_flags |= FIF_CONTROL; + + if (local->fif_other_bss) + new_flags |= FIF_OTHER_BSS; + + changed_flags = local->filter_flags ^ new_flags; + + /* be a bit nasty */ + new_flags |= (1<<31); + + local->ops->configure_filter(local_to_hw(local), + changed_flags, &new_flags, + local->mdev->mc_count, + local->mdev->mc_list); + + WARN_ON(new_flags & (1<<31)); + + local->filter_flags = new_flags & ~(1<<31); +} + +/* master interface */ + +static int ieee80211_master_open(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata; + int res = -EOPNOTSUPP; + + /* we hold the RTNL here so can safely walk the list */ + list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->dev != dev && netif_running(sdata->dev)) { + res = 0; + break; + } + } + return res; +} + +static int ieee80211_master_stop(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata; + + /* we hold the RTNL here so can safely walk the list */ + list_for_each_entry(sdata, &local->interfaces, list) + if (sdata->dev != dev && netif_running(sdata->dev)) + dev_close(sdata->dev); + + return 0; +} + +static void ieee80211_master_set_multicast_list(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + ieee80211_configure_filter(local); +} + +/* regular interfaces */ + +static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) +{ + int meshhdrlen; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + meshhdrlen = (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) ? 5 : 0; + + /* FIX: what would be proper limits for MTU? + * This interface uses 802.3 frames. */ + if (new_mtu < 256 || + new_mtu > IEEE80211_MAX_DATA_LEN - 24 - 6 - meshhdrlen) { + printk(KERN_WARNING "%s: invalid MTU %d\n", + dev->name, new_mtu); + return -EINVAL; + } + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: setting MTU %d\n", dev->name, new_mtu); +#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + dev->mtu = new_mtu; + return 0; +} + +static inline int identical_mac_addr_allowed(int type1, int type2) +{ + return (type1 == IEEE80211_IF_TYPE_MNTR || + type2 == IEEE80211_IF_TYPE_MNTR || + (type1 == IEEE80211_IF_TYPE_AP && + type2 == IEEE80211_IF_TYPE_WDS) || + (type1 == IEEE80211_IF_TYPE_WDS && + (type2 == IEEE80211_IF_TYPE_WDS || + type2 == IEEE80211_IF_TYPE_AP)) || + (type1 == IEEE80211_IF_TYPE_AP && + type2 == IEEE80211_IF_TYPE_VLAN) || + (type1 == IEEE80211_IF_TYPE_VLAN && + (type2 == IEEE80211_IF_TYPE_AP || + type2 == IEEE80211_IF_TYPE_VLAN))); +} + +static int ieee80211_open(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata, *nsdata; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_if_init_conf conf; + int res; + bool need_hw_reconfig = 0; + struct sta_info *sta; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + /* we hold the RTNL here so can safely walk the list */ + list_for_each_entry(nsdata, &local->interfaces, list) { + struct net_device *ndev = nsdata->dev; + + if (ndev != dev && ndev != local->mdev && netif_running(ndev)) { + /* + * Allow only a single IBSS interface to be up at any + * time. This is restricted because beacon distribution + * cannot work properly if both are in the same IBSS. + * + * To remove this restriction we'd have to disallow them + * from setting the same SSID on different IBSS interfaces + * belonging to the same hardware. Then, however, we're + * faced with having to adopt two different TSF timers... + */ + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && + nsdata->vif.type == IEEE80211_IF_TYPE_IBSS) + return -EBUSY; + + /* + * Disallow multiple IBSS/STA mode interfaces. + * + * This is a technical restriction, it is possible although + * most likely not IEEE 802.11 compliant to have multiple + * STAs with just a single hardware (the TSF timer will not + * be adjusted properly.) + * + * However, because mac80211 uses the master device's BSS + * information for each STA/IBSS interface, doing this will + * currently corrupt that BSS information completely, unless, + * a not very useful case, both STAs are associated to the + * same BSS. + * + * To remove this restriction, the BSS information needs to + * be embedded in the STA/IBSS mode sdata instead of using + * the master device's BSS structure. + */ + if ((sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) && + (nsdata->vif.type == IEEE80211_IF_TYPE_STA || + nsdata->vif.type == IEEE80211_IF_TYPE_IBSS)) + return -EBUSY; + + /* + * The remaining checks are only performed for interfaces + * with the same MAC address. + */ + if (compare_ether_addr(dev->dev_addr, ndev->dev_addr)) + continue; + + /* + * check whether it may have the same address + */ + if (!identical_mac_addr_allowed(sdata->vif.type, + nsdata->vif.type)) + return -ENOTUNIQ; + + /* + * can only add VLANs to enabled APs + */ + if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN && + nsdata->vif.type == IEEE80211_IF_TYPE_AP) + sdata->u.vlan.ap = nsdata; + } + } + + switch (sdata->vif.type) { + case IEEE80211_IF_TYPE_WDS: + if (is_zero_ether_addr(sdata->u.wds.remote_addr)) + return -ENOLINK; + + /* Create STA entry for the WDS peer */ + sta = sta_info_alloc(sdata, sdata->u.wds.remote_addr, + GFP_KERNEL); + if (!sta) + return -ENOMEM; + + sta->flags |= WLAN_STA_AUTHORIZED; + + res = sta_info_insert(sta); + if (res) { + /* STA has been freed */ + return res; + } + break; + case IEEE80211_IF_TYPE_VLAN: + if (!sdata->u.vlan.ap) + return -ENOLINK; + break; + case IEEE80211_IF_TYPE_AP: + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_MNTR: + case IEEE80211_IF_TYPE_IBSS: + case IEEE80211_IF_TYPE_MESH_POINT: + /* no special treatment */ + break; + case IEEE80211_IF_TYPE_INVALID: + /* cannot happen */ + WARN_ON(1); + break; + } + + if (local->open_count == 0) { + res = 0; + if (local->ops->start) + res = local->ops->start(local_to_hw(local)); + if (res) + return res; + need_hw_reconfig = 1; + ieee80211_led_radio(local, local->hw.conf.radio_enabled); + } + + switch (sdata->vif.type) { + case IEEE80211_IF_TYPE_VLAN: + list_add(&sdata->u.vlan.list, &sdata->u.vlan.ap->u.ap.vlans); + /* no need to tell driver */ + break; + case IEEE80211_IF_TYPE_MNTR: + if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { + local->cooked_mntrs++; + break; + } + + /* must be before the call to ieee80211_configure_filter */ + local->monitors++; + if (local->monitors == 1) + local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; + + if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) + local->fif_fcsfail++; + if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) + local->fif_plcpfail++; + if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) + local->fif_control++; + if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) + local->fif_other_bss++; + + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); + break; + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET; + /* fall through */ + default: + conf.vif = &sdata->vif; + conf.type = sdata->vif.type; + conf.mac_addr = dev->dev_addr; + res = local->ops->add_interface(local_to_hw(local), &conf); + if (res && !local->open_count && local->ops->stop) + local->ops->stop(local_to_hw(local)); + if (res) + return res; + + ieee80211_if_config(dev); + ieee80211_reset_erp_info(dev); + ieee80211_enable_keys(sdata); + + if (sdata->vif.type == IEEE80211_IF_TYPE_STA && + !(sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)) + netif_carrier_off(dev); + else + netif_carrier_on(dev); + } + + if (local->open_count == 0) { + res = dev_open(local->mdev); + WARN_ON(res); + tasklet_enable(&local->tx_pending_tasklet); + tasklet_enable(&local->tasklet); + } + + /* + * set_multicast_list will be invoked by the networking core + * which will check whether any increments here were done in + * error and sync them down to the hardware as filter flags. + */ + if (sdata->flags & IEEE80211_SDATA_ALLMULTI) + atomic_inc(&local->iff_allmultis); + + if (sdata->flags & IEEE80211_SDATA_PROMISC) + atomic_inc(&local->iff_promiscs); + + local->open_count++; + if (need_hw_reconfig) + ieee80211_hw_config(local); + + /* + * ieee80211_sta_work is disabled while network interface + * is down. Therefore, some configuration changes may not + * yet be effective. Trigger execution of ieee80211_sta_work + * to fix this. + */ + if(sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + queue_work(local->hw.workqueue, &ifsta->work); + } + + netif_start_queue(dev); + + return 0; +} + +static int ieee80211_stop(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + struct ieee80211_if_init_conf conf; + struct sta_info *sta; + + /* + * Stop TX on this interface first. + */ + netif_stop_queue(dev); + + /* + * Now delete all active aggregation sessions. + */ + rcu_read_lock(); + + list_for_each_entry_rcu(sta, &local->sta_list, list) { + if (sta->sdata == sdata) + ieee80211_sta_tear_down_BA_sessions(dev, sta->addr); + } + + rcu_read_unlock(); + + /* + * Remove all stations associated with this interface. + * + * This must be done before calling ops->remove_interface() + * because otherwise we can later invoke ops->sta_notify() + * whenever the STAs are removed, and that invalidates driver + * assumptions about always getting a vif pointer that is valid + * (because if we remove a STA after ops->remove_interface() + * the driver will have removed the vif info already!) + * + * We could relax this and only unlink the stations from the + * hash table and list but keep them on a per-sdata list that + * will be inserted back again when the interface is brought + * up again, but I don't currently see a use case for that, + * except with WDS which gets a STA entry created when it is + * brought up. + */ + sta_info_flush(local, sdata); + + /* + * Don't count this interface for promisc/allmulti while it + * is down. dev_mc_unsync() will invoke set_multicast_list + * on the master interface which will sync these down to the + * hardware as filter flags. + */ + if (sdata->flags & IEEE80211_SDATA_ALLMULTI) + atomic_dec(&local->iff_allmultis); + + if (sdata->flags & IEEE80211_SDATA_PROMISC) + atomic_dec(&local->iff_promiscs); + + dev_mc_unsync(local->mdev, dev); + + /* APs need special treatment */ + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { + struct ieee80211_sub_if_data *vlan, *tmp; + struct beacon_data *old_beacon = sdata->u.ap.beacon; + + /* remove beacon */ + rcu_assign_pointer(sdata->u.ap.beacon, NULL); + synchronize_rcu(); + kfree(old_beacon); + + /* down all dependent devices, that is VLANs */ + list_for_each_entry_safe(vlan, tmp, &sdata->u.ap.vlans, + u.vlan.list) + dev_close(vlan->dev); + WARN_ON(!list_empty(&sdata->u.ap.vlans)); + } + + local->open_count--; + + switch (sdata->vif.type) { + case IEEE80211_IF_TYPE_VLAN: + list_del(&sdata->u.vlan.list); + sdata->u.vlan.ap = NULL; + /* no need to tell driver */ + break; + case IEEE80211_IF_TYPE_MNTR: + if (sdata->u.mntr_flags & MONITOR_FLAG_COOK_FRAMES) { + local->cooked_mntrs--; + break; + } + + local->monitors--; + if (local->monitors == 0) + local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; + + if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) + local->fif_fcsfail--; + if (sdata->u.mntr_flags & MONITOR_FLAG_PLCPFAIL) + local->fif_plcpfail--; + if (sdata->u.mntr_flags & MONITOR_FLAG_CONTROL) + local->fif_control--; + if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) + local->fif_other_bss--; + + netif_tx_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_tx_unlock_bh(local->mdev); + break; + case IEEE80211_IF_TYPE_MESH_POINT: + case IEEE80211_IF_TYPE_STA: + case IEEE80211_IF_TYPE_IBSS: + sdata->u.sta.state = IEEE80211_DISABLED; + del_timer_sync(&sdata->u.sta.timer); + /* + * When we get here, the interface is marked down. + * Call synchronize_rcu() to wait for the RX path + * should it be using the interface and enqueuing + * frames at this very time on another CPU. + */ + synchronize_rcu(); + skb_queue_purge(&sdata->u.sta.skb_queue); + + if (local->scan_dev == sdata->dev) { + if (!local->ops->hw_scan) { + local->sta_sw_scanning = 0; + cancel_delayed_work(&local->scan_work); + } else + local->sta_hw_scanning = 0; + } + + flush_workqueue(local->hw.workqueue); + + sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; + kfree(sdata->u.sta.extra_ie); + sdata->u.sta.extra_ie = NULL; + sdata->u.sta.extra_ie_len = 0; + /* fall through */ + default: + conf.vif = &sdata->vif; + conf.type = sdata->vif.type; + conf.mac_addr = dev->dev_addr; + /* disable all keys for as long as this netdev is down */ + ieee80211_disable_keys(sdata); + local->ops->remove_interface(local_to_hw(local), &conf); + } + + if (local->open_count == 0) { + if (netif_running(local->mdev)) + dev_close(local->mdev); + + if (local->ops->stop) + local->ops->stop(local_to_hw(local)); + + ieee80211_led_radio(local, 0); + + tasklet_disable(&local->tx_pending_tasklet); + tasklet_disable(&local->tasklet); + } + + return 0; +} + +int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + struct ieee80211_sub_if_data *sdata; + u16 start_seq_num = 0; + u8 *state; + int ret; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) + return -EINVAL; + +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Open BA session requested for %s tid %u\n", + print_mac(mac, ra), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + rcu_read_lock(); + + sta = sta_info_get(local, ra); + if (!sta) { + printk(KERN_DEBUG "Could not find the station\n"); + rcu_read_unlock(); + return -ENOENT; + } + + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + /* we have tried too many times, receiver does not want A-MPDU */ + if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) { + ret = -EBUSY; + goto start_ba_exit; + } + + state = &sta->ampdu_mlme.tid_state_tx[tid]; + /* check if the TID is not in aggregation flow already */ + if (*state != HT_AGG_STATE_IDLE) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - session is not " + "idle on tid %u\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + ret = -EAGAIN; + goto start_ba_exit; + } + + /* prepare A-MPDU MLME for Tx aggregation */ + sta->ampdu_mlme.tid_tx[tid] = + kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC); + if (!sta->ampdu_mlme.tid_tx[tid]) { + if (net_ratelimit()) + printk(KERN_ERR "allocate tx mlme to tid %d failed\n", + tid); + ret = -ENOMEM; + goto start_ba_exit; + } + /* Tx timer */ + sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function = + sta_addba_resp_timer_expired; + sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.data = + (unsigned long)&sta->timer_to_tid[tid]; + init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); + + /* ensure that TX flow won't interrupt us + * until the end of the call to requeue function */ + spin_lock_bh(&local->mdev->queue_lock); + + /* create a new queue for this aggregation */ + ret = ieee80211_ht_agg_queue_add(local, sta, tid); + + /* case no queue is available to aggregation + * don't switch to aggregation */ + if (ret) { +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - queue unavailable for" + " tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + goto start_ba_err; + } + sdata = sta->sdata; + + /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the + * call back right away, it must see that the flow has begun */ + *state |= HT_ADDBA_REQUESTED_MSK; + + if (local->ops->ampdu_action) + ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START, + ra, tid, &start_seq_num); + + if (ret) { + /* No need to requeue the packets in the agg queue, since we + * held the tx lock: no packet could be enqueued to the newly + * allocated queue */ + ieee80211_ht_agg_queue_remove(local, sta, tid, 0); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "BA request denied - HW unavailable for" + " tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + *state = HT_AGG_STATE_IDLE; + goto start_ba_err; + } + + /* Will put all the packets in the new SW queue */ + ieee80211_requeue(local, ieee802_1d_to_ac[tid]); + spin_unlock_bh(&local->mdev->queue_lock); + + /* send an addBA request */ + sta->ampdu_mlme.dialog_token_allocator++; + sta->ampdu_mlme.tid_tx[tid]->dialog_token = + sta->ampdu_mlme.dialog_token_allocator; + sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num; + + ieee80211_send_addba_request(sta->sdata->dev, ra, tid, + sta->ampdu_mlme.tid_tx[tid]->dialog_token, + sta->ampdu_mlme.tid_tx[tid]->ssn, + 0x40, 5000); + + /* activate the timer for the recipient's addBA response */ + sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.expires = + jiffies + ADDBA_RESP_INTERVAL; + add_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); + printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid); + goto start_ba_exit; + +start_ba_err: + kfree(sta->ampdu_mlme.tid_tx[tid]); + sta->ampdu_mlme.tid_tx[tid] = NULL; + spin_unlock_bh(&local->mdev->queue_lock); + ret = -EBUSY; +start_ba_exit: + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + rcu_read_unlock(); + return ret; +} +EXPORT_SYMBOL(ieee80211_start_tx_ba_session); + +int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, + u8 *ra, u16 tid, + enum ieee80211_back_parties initiator) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + u8 *state; + int ret = 0; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) + return -EINVAL; + + rcu_read_lock(); + sta = sta_info_get(local, ra); + if (!sta) { + rcu_read_unlock(); + return -ENOENT; + } + + /* check if the TID is in aggregation */ + state = &sta->ampdu_mlme.tid_state_tx[tid]; + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + if (*state != HT_AGG_STATE_OPERATIONAL) { + ret = -ENOENT; + goto stop_BA_exit; + } + +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Tx BA session stop requested for %s tid %u\n", + print_mac(mac, ra), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); + + *state = HT_AGG_STATE_REQ_STOP_BA_MSK | + (initiator << HT_AGG_STATE_INITIATOR_SHIFT); + + if (local->ops->ampdu_action) + ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_STOP, + ra, tid, NULL); + + /* case HW denied going back to legacy */ + if (ret) { + WARN_ON(ret != -EBUSY); + *state = HT_AGG_STATE_OPERATIONAL; + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + goto stop_BA_exit; + } + +stop_BA_exit: + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + rcu_read_unlock(); + return ret; +} +EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); + +void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + u8 *state; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) { + printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", + tid, STA_TID_NUM); + return; + } + + rcu_read_lock(); + sta = sta_info_get(local, ra); + if (!sta) { + rcu_read_unlock(); + printk(KERN_DEBUG "Could not find station: %s\n", + print_mac(mac, ra)); + return; + } + + state = &sta->ampdu_mlme.tid_state_tx[tid]; + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + printk(KERN_DEBUG "addBA was not requested yet, state is %d\n", + *state); + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + rcu_read_unlock(); + return; + } + + WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK); + + *state |= HT_ADDBA_DRV_READY_MSK; + + if (*state == HT_AGG_STATE_OPERATIONAL) { + printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + } + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + rcu_read_unlock(); +} +EXPORT_SYMBOL(ieee80211_start_tx_ba_cb); + +void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct sta_info *sta; + u8 *state; + int agg_queue; + DECLARE_MAC_BUF(mac); + + if (tid >= STA_TID_NUM) { + printk(KERN_DEBUG "Bad TID value: tid = %d (>= %d)\n", + tid, STA_TID_NUM); + return; + } + +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Stopping Tx BA session for %s tid %d\n", + print_mac(mac, ra), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + rcu_read_lock(); + sta = sta_info_get(local, ra); + if (!sta) { + printk(KERN_DEBUG "Could not find station: %s\n", + print_mac(mac, ra)); + rcu_read_unlock(); + return; + } + state = &sta->ampdu_mlme.tid_state_tx[tid]; + + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + if ((*state & HT_AGG_STATE_REQ_STOP_BA_MSK) == 0) { + printk(KERN_DEBUG "unexpected callback to A-MPDU stop\n"); + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + rcu_read_unlock(); + return; + } + + if (*state & HT_AGG_STATE_INITIATOR_MSK) + ieee80211_send_delba(sta->sdata->dev, ra, tid, + WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); + + agg_queue = sta->tid_to_tx_q[tid]; + + /* avoid ordering issues: we are the only one that can modify + * the content of the qdiscs */ + spin_lock_bh(&local->mdev->queue_lock); + /* remove the queue for this aggregation */ + ieee80211_ht_agg_queue_remove(local, sta, tid, 1); + spin_unlock_bh(&local->mdev->queue_lock); + + /* we just requeued the all the frames that were in the removed + * queue, and since we might miss a softirq we do netif_schedule. + * ieee80211_wake_queue is not used here as this queue is not + * necessarily stopped */ + netif_schedule(local->mdev); + *state = HT_AGG_STATE_IDLE; + sta->ampdu_mlme.addba_req_num[tid] = 0; + kfree(sta->ampdu_mlme.tid_tx[tid]); + sta->ampdu_mlme.tid_tx[tid] = NULL; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + + rcu_read_unlock(); +} +EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb); + +void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, + const u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_ra_tid *ra_tid; + struct sk_buff *skb = dev_alloc_skb(0); + + if (unlikely(!skb)) { + if (net_ratelimit()) + printk(KERN_WARNING "%s: Not enough memory, " + "dropping start BA session", skb->dev->name); + return; + } + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + memcpy(&ra_tid->ra, ra, ETH_ALEN); + ra_tid->tid = tid; + + skb->pkt_type = IEEE80211_ADDBA_MSG; + skb_queue_tail(&local->skb_queue, skb); + tasklet_schedule(&local->tasklet); +} +EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); + +void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_hw *hw, + const u8 *ra, u16 tid) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_ra_tid *ra_tid; + struct sk_buff *skb = dev_alloc_skb(0); + + if (unlikely(!skb)) { + if (net_ratelimit()) + printk(KERN_WARNING "%s: Not enough memory, " + "dropping stop BA session", skb->dev->name); + return; + } + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + memcpy(&ra_tid->ra, ra, ETH_ALEN); + ra_tid->tid = tid; + + skb->pkt_type = IEEE80211_DELBA_MSG; + skb_queue_tail(&local->skb_queue, skb); + tasklet_schedule(&local->tasklet); +} +EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); + +static void ieee80211_set_multicast_list(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int allmulti, promisc, sdata_allmulti, sdata_promisc; + + allmulti = !!(dev->flags & IFF_ALLMULTI); + promisc = !!(dev->flags & IFF_PROMISC); + sdata_allmulti = !!(sdata->flags & IEEE80211_SDATA_ALLMULTI); + sdata_promisc = !!(sdata->flags & IEEE80211_SDATA_PROMISC); + + if (allmulti != sdata_allmulti) { + if (dev->flags & IFF_ALLMULTI) + atomic_inc(&local->iff_allmultis); + else + atomic_dec(&local->iff_allmultis); + sdata->flags ^= IEEE80211_SDATA_ALLMULTI; + } + + if (promisc != sdata_promisc) { + if (dev->flags & IFF_PROMISC) + atomic_inc(&local->iff_promiscs); + else + atomic_dec(&local->iff_promiscs); + sdata->flags ^= IEEE80211_SDATA_PROMISC; + } + + dev_mc_sync(local->mdev, dev); +} + +static const struct header_ops ieee80211_header_ops = { + .create = eth_header, + .parse = header_parse_80211, + .rebuild = eth_rebuild_header, + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, +}; + +/* Must not be called for mdev */ +void ieee80211_if_setup(struct net_device *dev) +{ + ether_setup(dev); + dev->hard_start_xmit = ieee80211_subif_start_xmit; + dev->wireless_handlers = &ieee80211_iw_handler_def; + dev->set_multicast_list = ieee80211_set_multicast_list; + dev->change_mtu = ieee80211_change_mtu; + dev->open = ieee80211_open; + dev->stop = ieee80211_stop; + dev->destructor = ieee80211_if_free; +} + +/* everything else */ + +static int __ieee80211_if_config(struct net_device *dev, + struct sk_buff *beacon, + struct ieee80211_tx_control *control) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_if_conf conf; + + if (!local->ops->config_interface || !netif_running(dev)) + return 0; + + memset(&conf, 0, sizeof(conf)); + conf.type = sdata->vif.type; + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + conf.bssid = sdata->u.sta.bssid; + conf.ssid = sdata->u.sta.ssid; + conf.ssid_len = sdata->u.sta.ssid_len; + } else if (ieee80211_vif_is_mesh(&sdata->vif)) { + conf.beacon = beacon; + ieee80211_start_mesh(dev); + } else if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { + conf.ssid = sdata->u.ap.ssid; + conf.ssid_len = sdata->u.ap.ssid_len; + conf.beacon = beacon; + conf.beacon_control = control; + } + return local->ops->config_interface(local_to_hw(local), + &sdata->vif, &conf); +} + +int ieee80211_if_config(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + if (sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT && + (local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) + return ieee80211_if_config_beacon(dev); + return __ieee80211_if_config(dev, NULL, NULL); +} + +int ieee80211_if_config_beacon(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_tx_control control; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct sk_buff *skb; + + if (!(local->hw.flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE)) + return 0; + skb = ieee80211_beacon_get(local_to_hw(local), &sdata->vif, + &control); + if (!skb) + return -ENOMEM; + return __ieee80211_if_config(dev, skb, &control); +} + +int ieee80211_hw_config(struct ieee80211_local *local) +{ + struct ieee80211_channel *chan; + int ret = 0; + + if (local->sta_sw_scanning) + chan = local->scan_channel; + else + chan = local->oper_channel; + + local->hw.conf.channel = chan; + + if (!local->hw.conf.power_level) + local->hw.conf.power_level = chan->max_power; + else + local->hw.conf.power_level = min(chan->max_power, + local->hw.conf.power_level); + + local->hw.conf.max_antenna_gain = chan->max_antenna_gain; + +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + printk(KERN_DEBUG "%s: HW CONFIG: freq=%d\n", + wiphy_name(local->hw.wiphy), chan->center_freq); +#endif + + if (local->open_count) + ret = local->ops->config(local_to_hw(local), &local->hw.conf); + + return ret; +} + +/** + * ieee80211_handle_ht should be used only after legacy configuration + * has been determined namely band, as ht configuration depends upon + * the hardware's HT abilities for a _specific_ band. + */ +u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, + struct ieee80211_ht_info *req_ht_cap, + struct ieee80211_ht_bss_info *req_bss_cap) +{ + struct ieee80211_conf *conf = &local->hw.conf; + struct ieee80211_supported_band *sband; + struct ieee80211_ht_info ht_conf; + struct ieee80211_ht_bss_info ht_bss_conf; + int i; + u32 changed = 0; + + sband = local->hw.wiphy->bands[conf->channel->band]; + + /* HT is not supported */ + if (!sband->ht_info.ht_supported) { + conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; + return 0; + } + + memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info)); + memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); + + if (enable_ht) { + if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) + changed |= BSS_CHANGED_HT; + + conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; + ht_conf.ht_supported = 1; + + ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; + ht_conf.cap &= ~(IEEE80211_HT_CAP_MIMO_PS); + ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_MIMO_PS; + + for (i = 0; i < SUPP_MCS_SET_LEN; i++) + ht_conf.supp_mcs_set[i] = + sband->ht_info.supp_mcs_set[i] & + req_ht_cap->supp_mcs_set[i]; + + ht_bss_conf.primary_channel = req_bss_cap->primary_channel; + ht_bss_conf.bss_cap = req_bss_cap->bss_cap; + ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; + + ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; + ht_conf.ampdu_density = req_ht_cap->ampdu_density; + + /* if bss configuration changed store the new one */ + if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) || + memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { + changed |= BSS_CHANGED_HT; + memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf)); + memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); + } + } else { + if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) + changed |= BSS_CHANGED_HT; + conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; + } + + return changed; +} + +void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, + u32 changed) +{ + struct ieee80211_local *local = sdata->local; + + if (!changed) + return; + + if (local->ops->bss_info_changed) + local->ops->bss_info_changed(local_to_hw(local), + &sdata->vif, + &sdata->bss_conf, + changed); +} + +void ieee80211_reset_erp_info(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + sdata->bss_conf.use_cts_prot = 0; + sdata->bss_conf.use_short_preamble = 0; + ieee80211_bss_info_change_notify(sdata, + BSS_CHANGED_ERP_CTS_PROT | + BSS_CHANGED_ERP_PREAMBLE); +} + +void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, + struct sk_buff *skb, + struct ieee80211_tx_status *status) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_tx_status *saved; + int tmp; + + skb->dev = local->mdev; + saved = kmalloc(sizeof(struct ieee80211_tx_status), GFP_ATOMIC); + if (unlikely(!saved)) { + if (net_ratelimit()) + printk(KERN_WARNING "%s: Not enough memory, " + "dropping tx status", skb->dev->name); + /* should be dev_kfree_skb_irq, but due to this function being + * named _irqsafe instead of just _irq we can't be sure that + * people won't call it from non-irq contexts */ + dev_kfree_skb_any(skb); + return; + } + memcpy(saved, status, sizeof(struct ieee80211_tx_status)); + /* copy pointer to saved status into skb->cb for use by tasklet */ + memcpy(skb->cb, &saved, sizeof(saved)); + + skb->pkt_type = IEEE80211_TX_STATUS_MSG; + skb_queue_tail(status->control.flags & IEEE80211_TXCTL_REQ_TX_STATUS ? + &local->skb_queue : &local->skb_queue_unreliable, skb); + tmp = skb_queue_len(&local->skb_queue) + + skb_queue_len(&local->skb_queue_unreliable); + while (tmp > IEEE80211_IRQSAFE_QUEUE_LIMIT && + (skb = skb_dequeue(&local->skb_queue_unreliable))) { + memcpy(&saved, skb->cb, sizeof(saved)); + kfree(saved); + dev_kfree_skb_irq(skb); + tmp--; + I802_DEBUG_INC(local->tx_status_drop); + } + tasklet_schedule(&local->tasklet); +} +EXPORT_SYMBOL(ieee80211_tx_status_irqsafe); + +static void ieee80211_tasklet_handler(unsigned long data) +{ + struct ieee80211_local *local = (struct ieee80211_local *) data; + struct sk_buff *skb; + struct ieee80211_rx_status rx_status; + struct ieee80211_tx_status *tx_status; + struct ieee80211_ra_tid *ra_tid; + + while ((skb = skb_dequeue(&local->skb_queue)) || + (skb = skb_dequeue(&local->skb_queue_unreliable))) { + switch (skb->pkt_type) { + case IEEE80211_RX_MSG: + /* status is in skb->cb */ + memcpy(&rx_status, skb->cb, sizeof(rx_status)); + /* Clear skb->pkt_type in order to not confuse kernel + * netstack. */ + skb->pkt_type = 0; + __ieee80211_rx(local_to_hw(local), skb, &rx_status); + break; + case IEEE80211_TX_STATUS_MSG: + /* get pointer to saved status out of skb->cb */ + memcpy(&tx_status, skb->cb, sizeof(tx_status)); + skb->pkt_type = 0; + ieee80211_tx_status(local_to_hw(local), + skb, tx_status); + kfree(tx_status); + break; + case IEEE80211_DELBA_MSG: + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + ieee80211_stop_tx_ba_cb(local_to_hw(local), + ra_tid->ra, ra_tid->tid); + dev_kfree_skb(skb); + break; + case IEEE80211_ADDBA_MSG: + ra_tid = (struct ieee80211_ra_tid *) &skb->cb; + ieee80211_start_tx_ba_cb(local_to_hw(local), + ra_tid->ra, ra_tid->tid); + dev_kfree_skb(skb); + break ; + default: /* should never get here! */ + printk(KERN_ERR "%s: Unknown message type (%d)\n", + wiphy_name(local->hw.wiphy), skb->pkt_type); + dev_kfree_skb(skb); + break; + } + } +} + +/* Remove added headers (e.g., QoS control), encryption header/MIC, etc. to + * make a prepared TX frame (one that has been given to hw) to look like brand + * new IEEE 802.11 frame that is ready to go through TX processing again. + * Also, tx_packet_data in cb is restored from tx_control. */ +static void ieee80211_remove_tx_extra(struct ieee80211_local *local, + struct ieee80211_key *key, + struct sk_buff *skb, + struct ieee80211_tx_control *control) +{ + int hdrlen, iv_len, mic_len; + struct ieee80211_tx_packet_data *pkt_data; + + pkt_data = (struct ieee80211_tx_packet_data *)skb->cb; + pkt_data->ifindex = vif_to_sdata(control->vif)->dev->ifindex; + pkt_data->flags = 0; + if (control->flags & IEEE80211_TXCTL_REQ_TX_STATUS) + pkt_data->flags |= IEEE80211_TXPD_REQ_TX_STATUS; + if (control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT) + pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; + if (control->flags & IEEE80211_TXCTL_REQUEUE) + pkt_data->flags |= IEEE80211_TXPD_REQUEUE; + if (control->flags & IEEE80211_TXCTL_EAPOL_FRAME) + pkt_data->flags |= IEEE80211_TXPD_EAPOL_FRAME; + pkt_data->queue = control->queue; + + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + + if (!key) + goto no_key; + + switch (key->conf.alg) { + case ALG_WEP: + iv_len = WEP_IV_LEN; + mic_len = WEP_ICV_LEN; + break; + case ALG_TKIP: + iv_len = TKIP_IV_LEN; + mic_len = TKIP_ICV_LEN; + break; + case ALG_CCMP: + iv_len = CCMP_HDR_LEN; + mic_len = CCMP_MIC_LEN; + break; + default: + goto no_key; + } + + if (skb->len >= mic_len && + !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) + skb_trim(skb, skb->len - mic_len); + if (skb->len >= iv_len && skb->len > hdrlen) { + memmove(skb->data + iv_len, skb->data, hdrlen); + skb_pull(skb, iv_len); + } + +no_key: + { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u16 fc = le16_to_cpu(hdr->frame_control); + if ((fc & 0x8C) == 0x88) /* QoS Control Field */ { + fc &= ~IEEE80211_STYPE_QOS_DATA; + hdr->frame_control = cpu_to_le16(fc); + memmove(skb->data + 2, skb->data, hdrlen - 2); + skb_pull(skb, 2); + } + } +} + +static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, + struct sta_info *sta, + struct sk_buff *skb, + struct ieee80211_tx_status *status) +{ + sta->tx_filtered_count++; + + /* + * Clear the TX filter mask for this STA when sending the next + * packet. If the STA went to power save mode, this will happen + * happen when it wakes up for the next time. + */ + sta->flags |= WLAN_STA_CLEAR_PS_FILT; + + /* + * This code races in the following way: + * + * (1) STA sends frame indicating it will go to sleep and does so + * (2) hardware/firmware adds STA to filter list, passes frame up + * (3) hardware/firmware processes TX fifo and suppresses a frame + * (4) we get TX status before having processed the frame and + * knowing that the STA has gone to sleep. + * + * This is actually quite unlikely even when both those events are + * processed from interrupts coming in quickly after one another or + * even at the same time because we queue both TX status events and + * RX frames to be processed by a tasklet and process them in the + * same order that they were received or TX status last. Hence, there + * is no race as long as the frame RX is processed before the next TX + * status, which drivers can ensure, see below. + * + * Note that this can only happen if the hardware or firmware can + * actually add STAs to the filter list, if this is done by the + * driver in response to set_tim() (which will only reduce the race + * this whole filtering tries to solve, not completely solve it) + * this situation cannot happen. + * + * To completely solve this race drivers need to make sure that they + * (a) don't mix the irq-safe/not irq-safe TX status/RX processing + * functions and + * (b) always process RX events before TX status events if ordering + * can be unknown, for example with different interrupt status + * bits. + */ + if (sta->flags & WLAN_STA_PS && + skb_queue_len(&sta->tx_filtered) < STA_MAX_TX_BUFFER) { + ieee80211_remove_tx_extra(local, sta->key, skb, + &status->control); + skb_queue_tail(&sta->tx_filtered, skb); + return; + } + + if (!(sta->flags & WLAN_STA_PS) && + !(status->control.flags & IEEE80211_TXCTL_REQUEUE)) { + /* Software retry the packet once */ + status->control.flags |= IEEE80211_TXCTL_REQUEUE; + ieee80211_remove_tx_extra(local, sta->key, skb, + &status->control); + dev_queue_xmit(skb); + return; + } + + if (net_ratelimit()) + printk(KERN_DEBUG "%s: dropped TX filtered frame, " + "queue_len=%d PS=%d @%lu\n", + wiphy_name(local->hw.wiphy), + skb_queue_len(&sta->tx_filtered), + !!(sta->flags & WLAN_STA_PS), jiffies); + dev_kfree_skb(skb); +} + +void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_tx_status *status) +{ + struct sk_buff *skb2; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_local *local = hw_to_local(hw); + u16 frag, type; + struct ieee80211_tx_status_rtap_hdr *rthdr; + struct ieee80211_sub_if_data *sdata; + struct net_device *prev_dev = NULL; + + if (!status) { + printk(KERN_ERR + "%s: ieee80211_tx_status called with NULL status\n", + wiphy_name(local->hw.wiphy)); + dev_kfree_skb(skb); + return; + } + + rcu_read_lock(); + + if (status->excessive_retries) { + struct sta_info *sta; + sta = sta_info_get(local, hdr->addr1); + if (sta) { + if (sta->flags & WLAN_STA_PS) { + /* + * The STA is in power save mode, so assume + * that this TX packet failed because of that. + */ + status->excessive_retries = 0; + status->flags |= IEEE80211_TX_STATUS_TX_FILTERED; + ieee80211_handle_filtered_frame(local, sta, + skb, status); + rcu_read_unlock(); + return; + } + } + } + + if (status->flags & IEEE80211_TX_STATUS_TX_FILTERED) { + struct sta_info *sta; + sta = sta_info_get(local, hdr->addr1); + if (sta) { + ieee80211_handle_filtered_frame(local, sta, skb, + status); + rcu_read_unlock(); + return; + } + } else + rate_control_tx_status(local->mdev, skb, status); + + rcu_read_unlock(); + + ieee80211_led_tx(local, 0); + + /* SNMP counters + * Fragments are passed to low-level drivers as separate skbs, so these + * are actually fragments, not frames. Update frame counters only for + * the first fragment of the frame. */ + + frag = le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; + type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; + + if (status->flags & IEEE80211_TX_STATUS_ACK) { + if (frag == 0) { + local->dot11TransmittedFrameCount++; + if (is_multicast_ether_addr(hdr->addr1)) + local->dot11MulticastTransmittedFrameCount++; + if (status->retry_count > 0) + local->dot11RetryCount++; + if (status->retry_count > 1) + local->dot11MultipleRetryCount++; + } + + /* This counter shall be incremented for an acknowledged MPDU + * with an individual address in the address 1 field or an MPDU + * with a multicast address in the address 1 field of type Data + * or Management. */ + if (!is_multicast_ether_addr(hdr->addr1) || + type == IEEE80211_FTYPE_DATA || + type == IEEE80211_FTYPE_MGMT) + local->dot11TransmittedFragmentCount++; + } else { + if (frag == 0) + local->dot11FailedCount++; + } + + /* this was a transmitted frame, but now we want to reuse it */ + skb_orphan(skb); + + /* + * This is a bit racy but we can avoid a lot of work + * with this test... + */ + if (!local->monitors && !local->cooked_mntrs) { + dev_kfree_skb(skb); + return; + } + + /* send frame to monitor interfaces now */ + + if (skb_headroom(skb) < sizeof(*rthdr)) { + printk(KERN_ERR "ieee80211_tx_status: headroom too small\n"); + dev_kfree_skb(skb); + return; + } + + rthdr = (struct ieee80211_tx_status_rtap_hdr*) + skb_push(skb, sizeof(*rthdr)); + + memset(rthdr, 0, sizeof(*rthdr)); + rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); + rthdr->hdr.it_present = + cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | + (1 << IEEE80211_RADIOTAP_DATA_RETRIES)); + + if (!(status->flags & IEEE80211_TX_STATUS_ACK) && + !is_multicast_ether_addr(hdr->addr1)) + rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); + + if ((status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) && + (status->control.flags & IEEE80211_TXCTL_USE_CTS_PROTECT)) + rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); + else if (status->control.flags & IEEE80211_TXCTL_USE_RTS_CTS) + rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); + + rthdr->data_retries = status->retry_count; + + /* XXX: is this sufficient for BPF? */ + skb_set_mac_header(skb, 0); + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->pkt_type = PACKET_OTHERHOST; + skb->protocol = htons(ETH_P_802_2); + memset(skb->cb, 0, sizeof(skb->cb)); + + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + if (sdata->vif.type == IEEE80211_IF_TYPE_MNTR) { + if (!netif_running(sdata->dev)) + continue; + + if (prev_dev) { + skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) { + skb2->dev = prev_dev; + netif_rx(skb2); + } + } + + prev_dev = sdata->dev; + } + } + if (prev_dev) { + skb->dev = prev_dev; + netif_rx(skb); + skb = NULL; + } + rcu_read_unlock(); + dev_kfree_skb(skb); +} +EXPORT_SYMBOL(ieee80211_tx_status); + +struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, + const struct ieee80211_ops *ops) +{ + struct ieee80211_local *local; + int priv_size; + struct wiphy *wiphy; + + /* Ensure 32-byte alignment of our private data and hw private data. + * We use the wiphy priv data for both our ieee80211_local and for + * the driver's private data + * + * In memory it'll be like this: + * + * +-------------------------+ + * | struct wiphy | + * +-------------------------+ + * | struct ieee80211_local | + * +-------------------------+ + * | driver's private data | + * +-------------------------+ + * + */ + priv_size = ((sizeof(struct ieee80211_local) + + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST) + + priv_data_len; + + wiphy = wiphy_new(&mac80211_config_ops, priv_size); + + if (!wiphy) + return NULL; + + wiphy->privid = mac80211_wiphy_privid; + + local = wiphy_priv(wiphy); + local->hw.wiphy = wiphy; + + local->hw.priv = (char *)local + + ((sizeof(struct ieee80211_local) + + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); + + BUG_ON(!ops->tx); + BUG_ON(!ops->start); + BUG_ON(!ops->stop); + BUG_ON(!ops->config); + BUG_ON(!ops->add_interface); + BUG_ON(!ops->remove_interface); + BUG_ON(!ops->configure_filter); + local->ops = ops; + + local->hw.queues = 1; /* default */ + + local->bridge_packets = 1; + + local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; + local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; + local->short_retry_limit = 7; + local->long_retry_limit = 4; + local->hw.conf.radio_enabled = 1; + + INIT_LIST_HEAD(&local->interfaces); + + INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); + + sta_info_init(local); + + tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, + (unsigned long)local); + tasklet_disable(&local->tx_pending_tasklet); + + tasklet_init(&local->tasklet, + ieee80211_tasklet_handler, + (unsigned long) local); + tasklet_disable(&local->tasklet); + + skb_queue_head_init(&local->skb_queue); + skb_queue_head_init(&local->skb_queue_unreliable); + + return local_to_hw(local); +} +EXPORT_SYMBOL(ieee80211_alloc_hw); + +int ieee80211_register_hw(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + const char *name; + int result; + enum ieee80211_band band; + struct net_device *mdev; + struct ieee80211_sub_if_data *sdata; + + /* + * generic code guarantees at least one band, + * set this very early because much code assumes + * that hw.conf.channel is assigned + */ + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[band]; + if (sband) { + /* init channel we're on */ + local->hw.conf.channel = + local->oper_channel = + local->scan_channel = &sband->channels[0]; + break; + } + } + + result = wiphy_register(local->hw.wiphy); + if (result < 0) + return result; + + /* for now, mdev needs sub_if_data :/ */ + mdev = alloc_netdev(sizeof(struct ieee80211_sub_if_data), + "wmaster%d", ether_setup); + if (!mdev) + goto fail_mdev_alloc; + + sdata = IEEE80211_DEV_TO_SUB_IF(mdev); + mdev->ieee80211_ptr = &sdata->wdev; + sdata->wdev.wiphy = local->hw.wiphy; + + local->mdev = mdev; + + ieee80211_rx_bss_list_init(mdev); + + mdev->hard_start_xmit = ieee80211_master_start_xmit; + mdev->open = ieee80211_master_open; + mdev->stop = ieee80211_master_stop; + mdev->type = ARPHRD_IEEE80211; + mdev->header_ops = &ieee80211_header_ops; + mdev->set_multicast_list = ieee80211_master_set_multicast_list; + + sdata->vif.type = IEEE80211_IF_TYPE_AP; + sdata->dev = mdev; + sdata->local = local; + sdata->u.ap.force_unicast_rateidx = -1; + sdata->u.ap.max_ratectrl_rateidx = -1; + ieee80211_if_sdata_init(sdata); + + /* no RCU needed since we're still during init phase */ + list_add_tail(&sdata->list, &local->interfaces); + + name = wiphy_dev(local->hw.wiphy)->driver->name; + local->hw.workqueue = create_singlethread_workqueue(name); + if (!local->hw.workqueue) { + result = -ENOMEM; + goto fail_workqueue; + } + + /* + * The hardware needs headroom for sending the frame, + * and we need some headroom for passing the frame to monitor + * interfaces, but never both at the same time. + */ + local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, + sizeof(struct ieee80211_tx_status_rtap_hdr)); + + debugfs_hw_add(local); + + local->hw.conf.beacon_int = 1000; + + local->wstats_flags |= local->hw.max_rssi ? + IW_QUAL_LEVEL_UPDATED : IW_QUAL_LEVEL_INVALID; + local->wstats_flags |= local->hw.max_signal ? + IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID; + local->wstats_flags |= local->hw.max_noise ? + IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID; + if (local->hw.max_rssi < 0 || local->hw.max_noise < 0) + local->wstats_flags |= IW_QUAL_DBM; + + result = sta_info_start(local); + if (result < 0) + goto fail_sta_info; + + rtnl_lock(); + result = dev_alloc_name(local->mdev, local->mdev->name); + if (result < 0) + goto fail_dev; + + memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN); + SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy)); + + result = register_netdevice(local->mdev); + if (result < 0) + goto fail_dev; + + ieee80211_debugfs_add_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); + ieee80211_if_set_type(local->mdev, IEEE80211_IF_TYPE_AP); + + result = ieee80211_init_rate_ctrl_alg(local, + hw->rate_control_algorithm); + if (result < 0) { + printk(KERN_DEBUG "%s: Failed to initialize rate control " + "algorithm\n", wiphy_name(local->hw.wiphy)); + goto fail_rate; + } + + result = ieee80211_wep_init(local); + + if (result < 0) { + printk(KERN_DEBUG "%s: Failed to initialize wep\n", + wiphy_name(local->hw.wiphy)); + goto fail_wep; + } + + ieee80211_install_qdisc(local->mdev); + + /* add one default STA interface */ + result = ieee80211_if_add(local->mdev, "wlan%d", NULL, + IEEE80211_IF_TYPE_STA, NULL); + if (result) + printk(KERN_WARNING "%s: Failed to add default virtual iface\n", + wiphy_name(local->hw.wiphy)); + + local->reg_state = IEEE80211_DEV_REGISTERED; + rtnl_unlock(); + + ieee80211_led_init(local); + + return 0; + +fail_wep: + rate_control_deinitialize(local); +fail_rate: + ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev)); + unregister_netdevice(local->mdev); +fail_dev: + rtnl_unlock(); + sta_info_stop(local); +fail_sta_info: + debugfs_hw_del(local); + destroy_workqueue(local->hw.workqueue); +fail_workqueue: + ieee80211_if_free(local->mdev); + local->mdev = NULL; +fail_mdev_alloc: + wiphy_unregister(local->hw.wiphy); + return result; +} +EXPORT_SYMBOL(ieee80211_register_hw); + +void ieee80211_unregister_hw(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata, *tmp; + + tasklet_kill(&local->tx_pending_tasklet); + tasklet_kill(&local->tasklet); + + rtnl_lock(); + + BUG_ON(local->reg_state != IEEE80211_DEV_REGISTERED); + + local->reg_state = IEEE80211_DEV_UNREGISTERED; + + /* + * At this point, interface list manipulations are fine + * because the driver cannot be handing us frames any + * more and the tasklet is killed. + */ + + /* + * First, we remove all non-master interfaces. Do this because they + * may have bss pointer dependency on the master, and when we free + * the master these would be freed as well, breaking our list + * iteration completely. + */ + list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { + if (sdata->dev == local->mdev) + continue; + list_del(&sdata->list); + __ieee80211_if_del(local, sdata); + } + + /* then, finally, remove the master interface */ + __ieee80211_if_del(local, IEEE80211_DEV_TO_SUB_IF(local->mdev)); + + rtnl_unlock(); + + ieee80211_rx_bss_list_deinit(local->mdev); + ieee80211_clear_tx_pending(local); + sta_info_stop(local); + rate_control_deinitialize(local); + debugfs_hw_del(local); + + if (skb_queue_len(&local->skb_queue) + || skb_queue_len(&local->skb_queue_unreliable)) + printk(KERN_WARNING "%s: skb_queue not empty\n", + wiphy_name(local->hw.wiphy)); + skb_queue_purge(&local->skb_queue); + skb_queue_purge(&local->skb_queue_unreliable); + + destroy_workqueue(local->hw.workqueue); + wiphy_unregister(local->hw.wiphy); + ieee80211_wep_free(local); + ieee80211_led_exit(local); + ieee80211_if_free(local->mdev); + local->mdev = NULL; +} +EXPORT_SYMBOL(ieee80211_unregister_hw); + +void ieee80211_free_hw(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + + wiphy_free(local->hw.wiphy); +} +EXPORT_SYMBOL(ieee80211_free_hw); + +static int __init ieee80211_init(void) +{ + struct sk_buff *skb; + int ret; + + BUILD_BUG_ON(sizeof(struct ieee80211_tx_packet_data) > sizeof(skb->cb)); + + ret = rc80211_pid_init(); + if (ret) + goto out; + + ret = ieee80211_wme_register(); + if (ret) { + printk(KERN_DEBUG "ieee80211_init: failed to " + "initialize WME (err=%d)\n", ret); + goto out_cleanup_pid; + } + + ieee80211_debugfs_netdev_init(); + + return 0; + + out_cleanup_pid: + rc80211_pid_exit(); + out: + return ret; +} + +static void __exit ieee80211_exit(void) +{ + rc80211_pid_exit(); + + /* + * For key todo, it'll be empty by now but the work + * might still be scheduled. + */ + flush_scheduled_work(); + + if (mesh_allocated) + ieee80211s_stop(); + + ieee80211_wme_unregister(); + ieee80211_debugfs_netdev_exit(); +} + + +subsys_initcall(ieee80211_init); +module_exit(ieee80211_exit); + +MODULE_DESCRIPTION("IEEE 802.11 subsystem"); +MODULE_LICENSE("GPL"); diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 67271baa5b61..37f0c2b94ae7 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -9,7 +9,7 @@ #include #include #include "ieee80211_i.h" -#include "ieee80211_rate.h" +#include "rate.h" #include "mesh.h" #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c new file mode 100644 index 000000000000..bdaab1391d4e --- /dev/null +++ b/net/mac80211/mlme.c @@ -0,0 +1,4249 @@ +/* + * BSS client mode implementation + * Copyright 2003, Jouni Malinen + * Copyright 2004, Instant802 Networks, Inc. + * Copyright 2005, Devicescape Software, Inc. + * Copyright 2006-2007 Jiri Benc + * Copyright 2007, Michael Wu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* TODO: + * order BSS list by RSSI(?) ("quality of AP") + * scan result table filtering (by capability (privacy, IBSS/BSS, WPA/RSN IE, + * SSID) + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ieee80211_i.h" +#include "rate.h" +#include "led.h" +#include "mesh.h" + +#define IEEE80211_AUTH_TIMEOUT (HZ / 5) +#define IEEE80211_AUTH_MAX_TRIES 3 +#define IEEE80211_ASSOC_TIMEOUT (HZ / 5) +#define IEEE80211_ASSOC_MAX_TRIES 3 +#define IEEE80211_MONITORING_INTERVAL (2 * HZ) +#define IEEE80211_MESH_HOUSEKEEPING_INTERVAL (60 * HZ) +#define IEEE80211_PROBE_INTERVAL (60 * HZ) +#define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ) +#define IEEE80211_SCAN_INTERVAL (2 * HZ) +#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ) +#define IEEE80211_IBSS_JOIN_TIMEOUT (20 * HZ) + +#define IEEE80211_PROBE_DELAY (HZ / 33) +#define IEEE80211_CHANNEL_TIME (HZ / 33) +#define IEEE80211_PASSIVE_CHANNEL_TIME (HZ / 5) +#define IEEE80211_SCAN_RESULT_EXPIRE (10 * HZ) +#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ) +#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ) +#define IEEE80211_MESH_PEER_INACTIVITY_LIMIT (1800 * HZ) + +#define IEEE80211_IBSS_MAX_STA_ENTRIES 128 + + +#define ERP_INFO_USE_PROTECTION BIT(1) + +/* mgmt header + 1 byte action code */ +#define IEEE80211_MIN_ACTION_SIZE (24 + 1) + +#define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 +#define IEEE80211_ADDBA_PARAM_TID_MASK 0x003C +#define IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK 0xFFA0 +#define IEEE80211_DELBA_PARAM_TID_MASK 0xF000 +#define IEEE80211_DELBA_PARAM_INITIATOR_MASK 0x0800 + +/* next values represent the buffer size for A-MPDU frame. + * According to IEEE802.11n spec size varies from 8K to 64K (in powers of 2) */ +#define IEEE80211_MIN_AMPDU_BUF 0x8 +#define IEEE80211_MAX_AMPDU_BUF 0x40 + +static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, + u8 *ssid, size_t ssid_len); +static struct ieee80211_sta_bss * +ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, + u8 *ssid, u8 ssid_len); +static void ieee80211_rx_bss_put(struct net_device *dev, + struct ieee80211_sta_bss *bss); +static int ieee80211_sta_find_ibss(struct net_device *dev, + struct ieee80211_if_sta *ifsta); +static int ieee80211_sta_wep_configured(struct net_device *dev); +static int ieee80211_sta_start_scan(struct net_device *dev, + u8 *ssid, size_t ssid_len); +static int ieee80211_sta_config_auth(struct net_device *dev, + struct ieee80211_if_sta *ifsta); + + +void ieee802_11_parse_elems(u8 *start, size_t len, + struct ieee802_11_elems *elems) +{ + size_t left = len; + u8 *pos = start; + + memset(elems, 0, sizeof(*elems)); + + while (left >= 2) { + u8 id, elen; + + id = *pos++; + elen = *pos++; + left -= 2; + + if (elen > left) + return; + + switch (id) { + case WLAN_EID_SSID: + elems->ssid = pos; + elems->ssid_len = elen; + break; + case WLAN_EID_SUPP_RATES: + elems->supp_rates = pos; + elems->supp_rates_len = elen; + break; + case WLAN_EID_FH_PARAMS: + elems->fh_params = pos; + elems->fh_params_len = elen; + break; + case WLAN_EID_DS_PARAMS: + elems->ds_params = pos; + elems->ds_params_len = elen; + break; + case WLAN_EID_CF_PARAMS: + elems->cf_params = pos; + elems->cf_params_len = elen; + break; + case WLAN_EID_TIM: + elems->tim = pos; + elems->tim_len = elen; + break; + case WLAN_EID_IBSS_PARAMS: + elems->ibss_params = pos; + elems->ibss_params_len = elen; + break; + case WLAN_EID_CHALLENGE: + elems->challenge = pos; + elems->challenge_len = elen; + break; + case WLAN_EID_WPA: + if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && + pos[2] == 0xf2) { + /* Microsoft OUI (00:50:F2) */ + if (pos[3] == 1) { + /* OUI Type 1 - WPA IE */ + elems->wpa = pos; + elems->wpa_len = elen; + } else if (elen >= 5 && pos[3] == 2) { + if (pos[4] == 0) { + elems->wmm_info = pos; + elems->wmm_info_len = elen; + } else if (pos[4] == 1) { + elems->wmm_param = pos; + elems->wmm_param_len = elen; + } + } + } + break; + case WLAN_EID_RSN: + elems->rsn = pos; + elems->rsn_len = elen; + break; + case WLAN_EID_ERP_INFO: + elems->erp_info = pos; + elems->erp_info_len = elen; + break; + case WLAN_EID_EXT_SUPP_RATES: + elems->ext_supp_rates = pos; + elems->ext_supp_rates_len = elen; + break; + case WLAN_EID_HT_CAPABILITY: + elems->ht_cap_elem = pos; + elems->ht_cap_elem_len = elen; + break; + case WLAN_EID_HT_EXTRA_INFO: + elems->ht_info_elem = pos; + elems->ht_info_elem_len = elen; + break; + case WLAN_EID_MESH_ID: + elems->mesh_id = pos; + elems->mesh_id_len = elen; + break; + case WLAN_EID_MESH_CONFIG: + elems->mesh_config = pos; + elems->mesh_config_len = elen; + break; + case WLAN_EID_PEER_LINK: + elems->peer_link = pos; + elems->peer_link_len = elen; + break; + case WLAN_EID_PREQ: + elems->preq = pos; + elems->preq_len = elen; + break; + case WLAN_EID_PREP: + elems->prep = pos; + elems->prep_len = elen; + break; + case WLAN_EID_PERR: + elems->perr = pos; + elems->perr_len = elen; + break; + default: + break; + } + + left -= elen; + pos += elen; + } +} + + +static int ecw2cw(int ecw) +{ + return (1 << ecw) - 1; +} + + +static void ieee80211_sta_def_wmm_params(struct net_device *dev, + struct ieee80211_sta_bss *bss, + int ibss) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + int i, have_higher_than_11mbit = 0; + + + /* cf. IEEE 802.11 9.2.12 */ + for (i = 0; i < bss->supp_rates_len; i++) + if ((bss->supp_rates[i] & 0x7f) * 5 > 110) + have_higher_than_11mbit = 1; + + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + have_higher_than_11mbit) + sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; + else + sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; + + + if (local->ops->conf_tx) { + struct ieee80211_tx_queue_params qparam; + + memset(&qparam, 0, sizeof(qparam)); + + qparam.aifs = 2; + + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE)) + qparam.cw_min = 31; + else + qparam.cw_min = 15; + + qparam.cw_max = 1023; + qparam.txop = 0; + + for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++) + local->ops->conf_tx(local_to_hw(local), + i + IEEE80211_TX_QUEUE_DATA0, + &qparam); + + if (ibss) { + /* IBSS uses different parameters for Beacon sending */ + qparam.cw_min++; + qparam.cw_min *= 2; + qparam.cw_min--; + local->ops->conf_tx(local_to_hw(local), + IEEE80211_TX_QUEUE_BEACON, &qparam); + } + } +} + +static void ieee80211_sta_wmm_params(struct net_device *dev, + struct ieee80211_if_sta *ifsta, + u8 *wmm_param, size_t wmm_param_len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_tx_queue_params params; + size_t left; + int count; + u8 *pos; + + if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) + return; + count = wmm_param[6] & 0x0f; + if (count == ifsta->wmm_last_param_set) + return; + ifsta->wmm_last_param_set = count; + + pos = wmm_param + 8; + left = wmm_param_len - 8; + + memset(¶ms, 0, sizeof(params)); + + if (!local->ops->conf_tx) + return; + + local->wmm_acm = 0; + for (; left >= 4; left -= 4, pos += 4) { + int aci = (pos[0] >> 5) & 0x03; + int acm = (pos[0] >> 4) & 0x01; + int queue; + + switch (aci) { + case 1: + queue = IEEE80211_TX_QUEUE_DATA3; + if (acm) { + local->wmm_acm |= BIT(0) | BIT(3); + } + break; + case 2: + queue = IEEE80211_TX_QUEUE_DATA1; + if (acm) { + local->wmm_acm |= BIT(4) | BIT(5); + } + break; + case 3: + queue = IEEE80211_TX_QUEUE_DATA0; + if (acm) { + local->wmm_acm |= BIT(6) | BIT(7); + } + break; + case 0: + default: + queue = IEEE80211_TX_QUEUE_DATA2; + if (acm) { + local->wmm_acm |= BIT(1) | BIT(2); + } + break; + } + + params.aifs = pos[0] & 0x0f; + params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); + params.cw_min = ecw2cw(pos[1] & 0x0f); + params.txop = pos[2] | (pos[3] << 8); +#ifdef CONFIG_MAC80211_DEBUG + printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " + "cWmin=%d cWmax=%d txop=%d\n", + dev->name, queue, aci, acm, params.aifs, params.cw_min, + params.cw_max, params.txop); +#endif + /* TODO: handle ACM (block TX, fallback to next lowest allowed + * AC for now) */ + if (local->ops->conf_tx(local_to_hw(local), queue, ¶ms)) { + printk(KERN_DEBUG "%s: failed to set TX queue " + "parameters for queue %d\n", dev->name, queue); + } + } +} + + +static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata, + u8 erp_value) +{ + struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; + bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0; + DECLARE_MAC_BUF(mac); + u32 changed = 0; + + if (use_protection != bss_conf->use_cts_prot) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: CTS protection %s (BSSID=" + "%s)\n", + sdata->dev->name, + use_protection ? "enabled" : "disabled", + print_mac(mac, ifsta->bssid)); + } + bss_conf->use_cts_prot = use_protection; + changed |= BSS_CHANGED_ERP_CTS_PROT; + } + + if (use_short_preamble != bss_conf->use_short_preamble) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: switched to %s barker preamble" + " (BSSID=%s)\n", + sdata->dev->name, + use_short_preamble ? "short" : "long", + print_mac(mac, ifsta->bssid)); + } + bss_conf->use_short_preamble = use_short_preamble; + changed |= BSS_CHANGED_ERP_PREAMBLE; + } + + return changed; +} + +int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, + struct ieee80211_ht_info *ht_info) +{ + + if (ht_info == NULL) + return -EINVAL; + + memset(ht_info, 0, sizeof(*ht_info)); + + if (ht_cap_ie) { + u8 ampdu_info = ht_cap_ie->ampdu_params_info; + + ht_info->ht_supported = 1; + ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info); + ht_info->ampdu_factor = + ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR; + ht_info->ampdu_density = + (ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2; + memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16); + } else + ht_info->ht_supported = 0; + + return 0; +} + +int ieee80211_ht_addt_info_ie_to_ht_bss_info( + struct ieee80211_ht_addt_info *ht_add_info_ie, + struct ieee80211_ht_bss_info *bss_info) +{ + if (bss_info == NULL) + return -EINVAL; + + memset(bss_info, 0, sizeof(*bss_info)); + + if (ht_add_info_ie) { + u16 op_mode; + op_mode = le16_to_cpu(ht_add_info_ie->operation_mode); + + bss_info->primary_channel = ht_add_info_ie->control_chan; + bss_info->bss_cap = ht_add_info_ie->ht_param; + bss_info->bss_op_mode = (u8)(op_mode & 0xff); + } + + return 0; +} + +static void ieee80211_sta_send_associnfo(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + char *buf; + size_t len; + int i; + union iwreq_data wrqu; + + if (!ifsta->assocreq_ies && !ifsta->assocresp_ies) + return; + + buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len + + ifsta->assocresp_ies_len), GFP_KERNEL); + if (!buf) + return; + + len = sprintf(buf, "ASSOCINFO("); + if (ifsta->assocreq_ies) { + len += sprintf(buf + len, "ReqIEs="); + for (i = 0; i < ifsta->assocreq_ies_len; i++) { + len += sprintf(buf + len, "%02x", + ifsta->assocreq_ies[i]); + } + } + if (ifsta->assocresp_ies) { + if (ifsta->assocreq_ies) + len += sprintf(buf + len, " "); + len += sprintf(buf + len, "RespIEs="); + for (i = 0; i < ifsta->assocresp_ies_len; i++) { + len += sprintf(buf + len, "%02x", + ifsta->assocresp_ies[i]); + } + } + len += sprintf(buf + len, ")"); + + if (len > IW_CUSTOM_MAX) { + len = sprintf(buf, "ASSOCRESPIE="); + for (i = 0; i < ifsta->assocresp_ies_len; i++) { + len += sprintf(buf + len, "%02x", + ifsta->assocresp_ies[i]); + } + } + + memset(&wrqu, 0, sizeof(wrqu)); + wrqu.data.length = len; + wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); + + kfree(buf); +} + + +static void ieee80211_set_associated(struct net_device *dev, + struct ieee80211_if_sta *ifsta, + bool assoc) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; + struct ieee80211_conf *conf = &local_to_hw(local)->conf; + union iwreq_data wrqu; + u32 changed = BSS_CHANGED_ASSOC; + + if (assoc) { + struct ieee80211_sta_bss *bss; + + ifsta->flags |= IEEE80211_STA_ASSOCIATED; + + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) + return; + + bss = ieee80211_rx_bss_get(dev, ifsta->bssid, + conf->channel->center_freq, + ifsta->ssid, ifsta->ssid_len); + if (bss) { + /* set timing information */ + sdata->bss_conf.beacon_int = bss->beacon_int; + sdata->bss_conf.timestamp = bss->timestamp; + + if (bss->has_erp_value) + changed |= ieee80211_handle_erp_ie( + sdata, bss->erp_value); + + ieee80211_rx_bss_put(dev, bss); + } + + if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { + changed |= BSS_CHANGED_HT; + sdata->bss_conf.assoc_ht = 1; + sdata->bss_conf.ht_conf = &conf->ht_conf; + sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf; + } + + netif_carrier_on(dev); + ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; + memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); + memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN); + ieee80211_sta_send_associnfo(dev, ifsta); + } else { + ieee80211_sta_tear_down_BA_sessions(dev, ifsta->bssid); + ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; + netif_carrier_off(dev); + ieee80211_reset_erp_info(dev); + + sdata->bss_conf.assoc_ht = 0; + sdata->bss_conf.ht_conf = NULL; + sdata->bss_conf.ht_bss_conf = NULL; + + memset(wrqu.ap_addr.sa_data, 0, ETH_ALEN); + } + ifsta->last_probe = jiffies; + ieee80211_led_assoc(local, assoc); + + sdata->bss_conf.assoc = assoc; + ieee80211_bss_info_change_notify(sdata, changed); + wrqu.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); +} + +static void ieee80211_set_disassoc(struct net_device *dev, + struct ieee80211_if_sta *ifsta, int deauth) +{ + if (deauth) + ifsta->auth_tries = 0; + ifsta->assoc_tries = 0; + ieee80211_set_associated(dev, ifsta, 0); +} + +void ieee80211_sta_tx(struct net_device *dev, struct sk_buff *skb, + int encrypt) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_tx_packet_data *pkt_data; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + skb->dev = sdata->local->mdev; + skb_set_mac_header(skb, 0); + skb_set_network_header(skb, 0); + skb_set_transport_header(skb, 0); + + pkt_data = (struct ieee80211_tx_packet_data *) skb->cb; + memset(pkt_data, 0, sizeof(struct ieee80211_tx_packet_data)); + pkt_data->ifindex = sdata->dev->ifindex; + if (!encrypt) + pkt_data->flags |= IEEE80211_TXPD_DO_NOT_ENCRYPT; + + dev_queue_xmit(skb); +} + + +static void ieee80211_send_auth(struct net_device *dev, + struct ieee80211_if_sta *ifsta, + int transaction, u8 *extra, size_t extra_len, + int encrypt) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + sizeof(*mgmt) + 6 + extra_len); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for auth " + "frame\n", dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); + memset(mgmt, 0, 24 + 6); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_AUTH); + if (encrypt) + mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg); + mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); + ifsta->auth_transaction = transaction + 1; + mgmt->u.auth.status_code = cpu_to_le16(0); + if (extra) + memcpy(skb_put(skb, extra_len), extra, extra_len); + + ieee80211_sta_tx(dev, skb, encrypt); +} + + +static void ieee80211_authenticate(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + DECLARE_MAC_BUF(mac); + + ifsta->auth_tries++; + if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) { + printk(KERN_DEBUG "%s: authentication with AP %s" + " timed out\n", + dev->name, print_mac(mac, ifsta->bssid)); + ifsta->state = IEEE80211_DISABLED; + return; + } + + ifsta->state = IEEE80211_AUTHENTICATE; + printk(KERN_DEBUG "%s: authenticate with AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); + + ieee80211_send_auth(dev, ifsta, 1, NULL, 0, 0); + + mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); +} + + +static void ieee80211_send_assoc(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u8 *pos, *ies; + int i, len; + u16 capab; + struct ieee80211_sta_bss *bss; + int wmm = 0; + struct ieee80211_supported_band *sband; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + + sizeof(*mgmt) + 200 + ifsta->extra_ie_len + + ifsta->ssid_len); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for assoc " + "frame\n", dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + capab = ifsta->capab; + + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) { + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME; + if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)) + capab |= WLAN_CAPABILITY_SHORT_PREAMBLE; + } + + bss = ieee80211_rx_bss_get(dev, ifsta->bssid, + local->hw.conf.channel->center_freq, + ifsta->ssid, ifsta->ssid_len); + if (bss) { + if (bss->capability & WLAN_CAPABILITY_PRIVACY) + capab |= WLAN_CAPABILITY_PRIVACY; + if (bss->wmm_ie) { + wmm = 1; + } + ieee80211_rx_bss_put(dev, bss); + } + + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + + if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) { + skb_put(skb, 10); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_REASSOC_REQ); + mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab); + mgmt->u.reassoc_req.listen_interval = cpu_to_le16(1); + memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid, + ETH_ALEN); + } else { + skb_put(skb, 4); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_ASSOC_REQ); + mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); + mgmt->u.assoc_req.listen_interval = cpu_to_le16(1); + } + + /* SSID */ + ies = pos = skb_put(skb, 2 + ifsta->ssid_len); + *pos++ = WLAN_EID_SSID; + *pos++ = ifsta->ssid_len; + memcpy(pos, ifsta->ssid, ifsta->ssid_len); + + len = sband->n_bitrates; + if (len > 8) + len = 8; + pos = skb_put(skb, len + 2); + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = len; + for (i = 0; i < len; i++) { + int rate = sband->bitrates[i].bitrate; + *pos++ = (u8) (rate / 5); + } + + if (sband->n_bitrates > len) { + pos = skb_put(skb, sband->n_bitrates - len + 2); + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos++ = sband->n_bitrates - len; + for (i = len; i < sband->n_bitrates; i++) { + int rate = sband->bitrates[i].bitrate; + *pos++ = (u8) (rate / 5); + } + } + + if (ifsta->extra_ie) { + pos = skb_put(skb, ifsta->extra_ie_len); + memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len); + } + + if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { + pos = skb_put(skb, 9); + *pos++ = WLAN_EID_VENDOR_SPECIFIC; + *pos++ = 7; /* len */ + *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */ + *pos++ = 0x50; + *pos++ = 0xf2; + *pos++ = 2; /* WME */ + *pos++ = 0; /* WME info */ + *pos++ = 1; /* WME ver */ + *pos++ = 0; + } + /* wmm support is a must to HT */ + if (wmm && sband->ht_info.ht_supported) { + __le16 tmp = cpu_to_le16(sband->ht_info.cap); + pos = skb_put(skb, sizeof(struct ieee80211_ht_cap)+2); + *pos++ = WLAN_EID_HT_CAPABILITY; + *pos++ = sizeof(struct ieee80211_ht_cap); + memset(pos, 0, sizeof(struct ieee80211_ht_cap)); + memcpy(pos, &tmp, sizeof(u16)); + pos += sizeof(u16); + /* TODO: needs a define here for << 2 */ + *pos++ = sband->ht_info.ampdu_factor | + (sband->ht_info.ampdu_density << 2); + memcpy(pos, sband->ht_info.supp_mcs_set, 16); + } + + kfree(ifsta->assocreq_ies); + ifsta->assocreq_ies_len = (skb->data + skb->len) - ies; + ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL); + if (ifsta->assocreq_ies) + memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len); + + ieee80211_sta_tx(dev, skb, 0); +} + + +static void ieee80211_send_deauth(struct net_device *dev, + struct ieee80211_if_sta *ifsta, u16 reason) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for deauth " + "frame\n", dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_DEAUTH); + skb_put(skb, 2); + mgmt->u.deauth.reason_code = cpu_to_le16(reason); + + ieee80211_sta_tx(dev, skb, 0); +} + + +static void ieee80211_send_disassoc(struct net_device *dev, + struct ieee80211_if_sta *ifsta, u16 reason) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt)); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for disassoc " + "frame\n", dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, ifsta->bssid, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_DISASSOC); + skb_put(skb, 2); + mgmt->u.disassoc.reason_code = cpu_to_le16(reason); + + ieee80211_sta_tx(dev, skb, 0); +} + + +static int ieee80211_privacy_mismatch(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sta_bss *bss; + int bss_privacy; + int wep_privacy; + int privacy_invoked; + + if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL)) + return 0; + + bss = ieee80211_rx_bss_get(dev, ifsta->bssid, + local->hw.conf.channel->center_freq, + ifsta->ssid, ifsta->ssid_len); + if (!bss) + return 0; + + bss_privacy = !!(bss->capability & WLAN_CAPABILITY_PRIVACY); + wep_privacy = !!ieee80211_sta_wep_configured(dev); + privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED); + + ieee80211_rx_bss_put(dev, bss); + + if ((bss_privacy == wep_privacy) || (bss_privacy == privacy_invoked)) + return 0; + + return 1; +} + + +static void ieee80211_associate(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + DECLARE_MAC_BUF(mac); + + ifsta->assoc_tries++; + if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { + printk(KERN_DEBUG "%s: association with AP %s" + " timed out\n", + dev->name, print_mac(mac, ifsta->bssid)); + ifsta->state = IEEE80211_DISABLED; + return; + } + + ifsta->state = IEEE80211_ASSOCIATE; + printk(KERN_DEBUG "%s: associate with AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); + if (ieee80211_privacy_mismatch(dev, ifsta)) { + printk(KERN_DEBUG "%s: mismatch in privacy configuration and " + "mixed-cell disabled - abort association\n", dev->name); + ifsta->state = IEEE80211_DISABLED; + return; + } + + ieee80211_send_assoc(dev, ifsta); + + mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT); +} + + +static void ieee80211_associated(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta; + int disassoc; + DECLARE_MAC_BUF(mac); + + /* TODO: start monitoring current AP signal quality and number of + * missed beacons. Scan other channels every now and then and search + * for better APs. */ + /* TODO: remove expired BSSes */ + + ifsta->state = IEEE80211_ASSOCIATED; + + rcu_read_lock(); + + sta = sta_info_get(local, ifsta->bssid); + if (!sta) { + printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", + dev->name, print_mac(mac, ifsta->bssid)); + disassoc = 1; + } else { + disassoc = 0; + if (time_after(jiffies, + sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { + if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) { + printk(KERN_DEBUG "%s: No ProbeResp from " + "current AP %s - assume out of " + "range\n", + dev->name, print_mac(mac, ifsta->bssid)); + disassoc = 1; + sta_info_unlink(&sta); + } else + ieee80211_send_probe_req(dev, ifsta->bssid, + local->scan_ssid, + local->scan_ssid_len); + ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL; + } else { + ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL; + if (time_after(jiffies, ifsta->last_probe + + IEEE80211_PROBE_INTERVAL)) { + ifsta->last_probe = jiffies; + ieee80211_send_probe_req(dev, ifsta->bssid, + ifsta->ssid, + ifsta->ssid_len); + } + } + } + + rcu_read_unlock(); + + if (disassoc && sta) + sta_info_destroy(sta); + + if (disassoc) { + ifsta->state = IEEE80211_DISABLED; + ieee80211_set_associated(dev, ifsta, 0); + } else { + mod_timer(&ifsta->timer, jiffies + + IEEE80211_MONITORING_INTERVAL); + } +} + + +static void ieee80211_send_probe_req(struct net_device *dev, u8 *dst, + u8 *ssid, size_t ssid_len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_supported_band *sband; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u8 *pos, *supp_rates, *esupp_rates = NULL; + int i; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for probe " + "request\n", dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_PROBE_REQ); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + if (dst) { + memcpy(mgmt->da, dst, ETH_ALEN); + memcpy(mgmt->bssid, dst, ETH_ALEN); + } else { + memset(mgmt->da, 0xff, ETH_ALEN); + memset(mgmt->bssid, 0xff, ETH_ALEN); + } + pos = skb_put(skb, 2 + ssid_len); + *pos++ = WLAN_EID_SSID; + *pos++ = ssid_len; + memcpy(pos, ssid, ssid_len); + + supp_rates = skb_put(skb, 2); + supp_rates[0] = WLAN_EID_SUPP_RATES; + supp_rates[1] = 0; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *rate = &sband->bitrates[i]; + if (esupp_rates) { + pos = skb_put(skb, 1); + esupp_rates[1]++; + } else if (supp_rates[1] == 8) { + esupp_rates = skb_put(skb, 3); + esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; + esupp_rates[1] = 1; + pos = &esupp_rates[2]; + } else { + pos = skb_put(skb, 1); + supp_rates[1]++; + } + *pos = rate->bitrate / 5; + } + + ieee80211_sta_tx(dev, skb, 0); +} + + +static int ieee80211_sta_wep_configured(struct net_device *dev) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (!sdata || !sdata->default_key || + sdata->default_key->conf.alg != ALG_WEP) + return 0; + return 1; +} + + +static void ieee80211_auth_completed(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + printk(KERN_DEBUG "%s: authenticated\n", dev->name); + ifsta->flags |= IEEE80211_STA_AUTHENTICATED; + ieee80211_associate(dev, ifsta); +} + + +static void ieee80211_auth_challenge(struct net_device *dev, + struct ieee80211_if_sta *ifsta, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + u8 *pos; + struct ieee802_11_elems elems; + + printk(KERN_DEBUG "%s: replying to auth challenge\n", dev->name); + pos = mgmt->u.auth.variable; + ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); + if (!elems.challenge) { + printk(KERN_DEBUG "%s: no challenge IE in shared key auth " + "frame\n", dev->name); + return; + } + ieee80211_send_auth(dev, ifsta, 3, elems.challenge - 2, + elems.challenge_len + 2, 1); +} + +static void ieee80211_send_addba_resp(struct net_device *dev, u8 *da, u16 tid, + u8 dialog_token, u16 status, u16 policy, + u16 buf_size, u16 timeout) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u16 capab; + + skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + + sizeof(mgmt->u.action.u.addba_resp)); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer " + "for addba resp frame\n", dev->name); + return; + } + + skb_reserve(skb, local->hw.extra_tx_headroom); + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, da, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) + memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN); + else + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_ACTION); + + skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_resp)); + mgmt->u.action.category = WLAN_CATEGORY_BACK; + mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP; + mgmt->u.action.u.addba_resp.dialog_token = dialog_token; + + capab = (u16)(policy << 1); /* bit 1 aggregation policy */ + capab |= (u16)(tid << 2); /* bit 5:2 TID number */ + capab |= (u16)(buf_size << 6); /* bit 15:6 max size of aggregation */ + + mgmt->u.action.u.addba_resp.capab = cpu_to_le16(capab); + mgmt->u.action.u.addba_resp.timeout = cpu_to_le16(timeout); + mgmt->u.action.u.addba_resp.status = cpu_to_le16(status); + + ieee80211_sta_tx(dev, skb, 0); + + return; +} + +void ieee80211_send_addba_request(struct net_device *dev, const u8 *da, + u16 tid, u8 dialog_token, u16 start_seq_num, + u16 agg_size, u16 timeout) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u16 capab; + + skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + + sizeof(mgmt->u.action.u.addba_req)); + + + if (!skb) { + printk(KERN_ERR "%s: failed to allocate buffer " + "for addba request frame\n", dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, da, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) + memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN); + else + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_ACTION); + + skb_put(skb, 1 + sizeof(mgmt->u.action.u.addba_req)); + + mgmt->u.action.category = WLAN_CATEGORY_BACK; + mgmt->u.action.u.addba_req.action_code = WLAN_ACTION_ADDBA_REQ; + + mgmt->u.action.u.addba_req.dialog_token = dialog_token; + capab = (u16)(1 << 1); /* bit 1 aggregation policy */ + capab |= (u16)(tid << 2); /* bit 5:2 TID number */ + capab |= (u16)(agg_size << 6); /* bit 15:6 max size of aggergation */ + + mgmt->u.action.u.addba_req.capab = cpu_to_le16(capab); + + mgmt->u.action.u.addba_req.timeout = cpu_to_le16(timeout); + mgmt->u.action.u.addba_req.start_seq_num = + cpu_to_le16(start_seq_num << 4); + + ieee80211_sta_tx(dev, skb, 0); +} + +static void ieee80211_sta_process_addba_request(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = &local->hw; + struct ieee80211_conf *conf = &hw->conf; + struct sta_info *sta; + struct tid_ampdu_rx *tid_agg_rx; + u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; + u8 dialog_token; + int ret = -EOPNOTSUPP; + DECLARE_MAC_BUF(mac); + + rcu_read_lock(); + + sta = sta_info_get(local, mgmt->sa); + if (!sta) { + rcu_read_unlock(); + return; + } + + /* extract session parameters from addba request frame */ + dialog_token = mgmt->u.action.u.addba_req.dialog_token; + timeout = le16_to_cpu(mgmt->u.action.u.addba_req.timeout); + start_seq_num = + le16_to_cpu(mgmt->u.action.u.addba_req.start_seq_num) >> 4; + + capab = le16_to_cpu(mgmt->u.action.u.addba_req.capab); + ba_policy = (capab & IEEE80211_ADDBA_PARAM_POLICY_MASK) >> 1; + tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; + + status = WLAN_STATUS_REQUEST_DECLINED; + + /* sanity check for incoming parameters: + * check if configuration can support the BA policy + * and if buffer size does not exceeds max value */ + if (((ba_policy != 1) + && (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA))) + || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { + status = WLAN_STATUS_INVALID_QOS_PARAM; +#ifdef CONFIG_MAC80211_HT_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "AddBA Req with bad params from " + "%s on tid %u. policy %d, buffer size %d\n", + print_mac(mac, mgmt->sa), tid, ba_policy, + buf_size); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + goto end_no_lock; + } + /* determine default buffer size */ + if (buf_size == 0) { + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[conf->channel->band]; + buf_size = IEEE80211_MIN_AMPDU_BUF; + buf_size = buf_size << sband->ht_info.ampdu_factor; + } + + + /* examine state machine */ + spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + + if (sta->ampdu_mlme.tid_state_rx[tid] != HT_AGG_STATE_IDLE) { +#ifdef CONFIG_MAC80211_HT_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "unexpected AddBA Req from " + "%s on tid %u\n", + print_mac(mac, mgmt->sa), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + goto end; + } + + /* prepare A-MPDU MLME for Rx aggregation */ + sta->ampdu_mlme.tid_rx[tid] = + kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC); + if (!sta->ampdu_mlme.tid_rx[tid]) { + if (net_ratelimit()) + printk(KERN_ERR "allocate rx mlme to tid %d failed\n", + tid); + goto end; + } + /* rx timer */ + sta->ampdu_mlme.tid_rx[tid]->session_timer.function = + sta_rx_agg_session_timer_expired; + sta->ampdu_mlme.tid_rx[tid]->session_timer.data = + (unsigned long)&sta->timer_to_tid[tid]; + init_timer(&sta->ampdu_mlme.tid_rx[tid]->session_timer); + + tid_agg_rx = sta->ampdu_mlme.tid_rx[tid]; + + /* prepare reordering buffer */ + tid_agg_rx->reorder_buf = + kmalloc(buf_size * sizeof(struct sk_buf *), GFP_ATOMIC); + if (!tid_agg_rx->reorder_buf) { + if (net_ratelimit()) + printk(KERN_ERR "can not allocate reordering buffer " + "to tid %d\n", tid); + kfree(sta->ampdu_mlme.tid_rx[tid]); + goto end; + } + memset(tid_agg_rx->reorder_buf, 0, + buf_size * sizeof(struct sk_buf *)); + + if (local->ops->ampdu_action) + ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_START, + sta->addr, tid, &start_seq_num); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Rx A-MPDU request on tid %d result %d\n", tid, ret); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + if (ret) { + kfree(tid_agg_rx->reorder_buf); + kfree(tid_agg_rx); + sta->ampdu_mlme.tid_rx[tid] = NULL; + goto end; + } + + /* change state and send addba resp */ + sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_OPERATIONAL; + tid_agg_rx->dialog_token = dialog_token; + tid_agg_rx->ssn = start_seq_num; + tid_agg_rx->head_seq_num = start_seq_num; + tid_agg_rx->buf_size = buf_size; + tid_agg_rx->timeout = timeout; + tid_agg_rx->stored_mpdu_num = 0; + status = WLAN_STATUS_SUCCESS; +end: + spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + +end_no_lock: + ieee80211_send_addba_resp(sta->sdata->dev, sta->addr, tid, + dialog_token, status, 1, buf_size, timeout); + rcu_read_unlock(); +} + +static void ieee80211_sta_process_addba_resp(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = &local->hw; + struct sta_info *sta; + u16 capab; + u16 tid; + u8 *state; + + rcu_read_lock(); + + sta = sta_info_get(local, mgmt->sa); + if (!sta) { + rcu_read_unlock(); + return; + } + + capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); + tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2; + + state = &sta->ampdu_mlme.tid_state_tx[tid]; + + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + + if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + printk(KERN_DEBUG "state not HT_ADDBA_REQUESTED_MSK:" + "%d\n", *state); + goto addba_resp_exit; + } + + if (mgmt->u.action.u.addba_resp.dialog_token != + sta->ampdu_mlme.tid_tx[tid]->dialog_token) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "wrong addBA response token, tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + goto addba_resp_exit; + } + + del_timer_sync(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "switched off addBA timer for tid %d \n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + if (le16_to_cpu(mgmt->u.action.u.addba_resp.status) + == WLAN_STATUS_SUCCESS) { + if (*state & HT_ADDBA_RECEIVED_MSK) + printk(KERN_DEBUG "double addBA response\n"); + + *state |= HT_ADDBA_RECEIVED_MSK; + sta->ampdu_mlme.addba_req_num[tid] = 0; + + if (*state == HT_AGG_STATE_OPERATIONAL) { + printk(KERN_DEBUG "Aggregation on for tid %d \n", tid); + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + } + + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + printk(KERN_DEBUG "recipient accepted agg: tid %d \n", tid); + } else { + printk(KERN_DEBUG "recipient rejected agg: tid %d \n", tid); + + sta->ampdu_mlme.addba_req_num[tid]++; + /* this will allow the state check in stop_BA_session */ + *state = HT_AGG_STATE_OPERATIONAL; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + ieee80211_stop_tx_ba_session(hw, sta->addr, tid, + WLAN_BACK_INITIATOR); + } + +addba_resp_exit: + rcu_read_unlock(); +} + +void ieee80211_send_delba(struct net_device *dev, const u8 *da, u16 tid, + u16 initiator, u16 reason_code) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + u16 params; + + skb = dev_alloc_skb(sizeof(*mgmt) + local->hw.extra_tx_headroom + 1 + + sizeof(mgmt->u.action.u.delba)); + + if (!skb) { + printk(KERN_ERR "%s: failed to allocate buffer " + "for delba frame\n", dev->name); + return; + } + + skb_reserve(skb, local->hw.extra_tx_headroom); + mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); + memset(mgmt, 0, 24); + memcpy(mgmt->da, da, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) + memcpy(mgmt->bssid, dev->dev_addr, ETH_ALEN); + else + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_ACTION); + + skb_put(skb, 1 + sizeof(mgmt->u.action.u.delba)); + + mgmt->u.action.category = WLAN_CATEGORY_BACK; + mgmt->u.action.u.delba.action_code = WLAN_ACTION_DELBA; + params = (u16)(initiator << 11); /* bit 11 initiator */ + params |= (u16)(tid << 12); /* bit 15:12 TID number */ + + mgmt->u.action.u.delba.params = cpu_to_le16(params); + mgmt->u.action.u.delba.reason_code = cpu_to_le16(reason_code); + + ieee80211_sta_tx(dev, skb, 0); +} + +void ieee80211_sta_stop_rx_ba_session(struct net_device *dev, u8 *ra, u16 tid, + u16 initiator, u16 reason) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_hw *hw = &local->hw; + struct sta_info *sta; + int ret, i; + DECLARE_MAC_BUF(mac); + + rcu_read_lock(); + + sta = sta_info_get(local, ra); + if (!sta) { + rcu_read_unlock(); + return; + } + + /* check if TID is in operational state */ + spin_lock_bh(&sta->ampdu_mlme.ampdu_rx); + if (sta->ampdu_mlme.tid_state_rx[tid] + != HT_AGG_STATE_OPERATIONAL) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + rcu_read_unlock(); + return; + } + sta->ampdu_mlme.tid_state_rx[tid] = + HT_AGG_STATE_REQ_STOP_BA_MSK | + (initiator << HT_AGG_STATE_INITIATOR_SHIFT); + spin_unlock_bh(&sta->ampdu_mlme.ampdu_rx); + + /* stop HW Rx aggregation. ampdu_action existence + * already verified in session init so we add the BUG_ON */ + BUG_ON(!local->ops->ampdu_action); + +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Rx BA session stop requested for %s tid %u\n", + print_mac(mac, ra), tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, + ra, tid, NULL); + if (ret) + printk(KERN_DEBUG "HW problem - can not stop rx " + "aggergation for tid %d\n", tid); + + /* shutdown timer has not expired */ + if (initiator != WLAN_BACK_TIMER) + del_timer_sync(&sta->ampdu_mlme.tid_rx[tid]->session_timer); + + /* check if this is a self generated aggregation halt */ + if (initiator == WLAN_BACK_RECIPIENT || initiator == WLAN_BACK_TIMER) + ieee80211_send_delba(dev, ra, tid, 0, reason); + + /* free the reordering buffer */ + for (i = 0; i < sta->ampdu_mlme.tid_rx[tid]->buf_size; i++) { + if (sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]) { + /* release the reordered frames */ + dev_kfree_skb(sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i]); + sta->ampdu_mlme.tid_rx[tid]->stored_mpdu_num--; + sta->ampdu_mlme.tid_rx[tid]->reorder_buf[i] = NULL; + } + } + /* free resources */ + kfree(sta->ampdu_mlme.tid_rx[tid]->reorder_buf); + kfree(sta->ampdu_mlme.tid_rx[tid]); + sta->ampdu_mlme.tid_rx[tid] = NULL; + sta->ampdu_mlme.tid_state_rx[tid] = HT_AGG_STATE_IDLE; + + rcu_read_unlock(); +} + + +static void ieee80211_sta_process_delba(struct net_device *dev, + struct ieee80211_mgmt *mgmt, size_t len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta; + u16 tid, params; + u16 initiator; + DECLARE_MAC_BUF(mac); + + rcu_read_lock(); + + sta = sta_info_get(local, mgmt->sa); + if (!sta) { + rcu_read_unlock(); + return; + } + + params = le16_to_cpu(mgmt->u.action.u.delba.params); + tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; + initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11; + +#ifdef CONFIG_MAC80211_HT_DEBUG + if (net_ratelimit()) + printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n", + print_mac(mac, mgmt->sa), + initiator ? "initiator" : "recipient", tid, + mgmt->u.action.u.delba.reason_code); +#endif /* CONFIG_MAC80211_HT_DEBUG */ + + if (initiator == WLAN_BACK_INITIATOR) + ieee80211_sta_stop_rx_ba_session(dev, sta->addr, tid, + WLAN_BACK_INITIATOR, 0); + else { /* WLAN_BACK_RECIPIENT */ + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + sta->ampdu_mlme.tid_state_tx[tid] = + HT_AGG_STATE_OPERATIONAL; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + ieee80211_stop_tx_ba_session(&local->hw, sta->addr, tid, + WLAN_BACK_RECIPIENT); + } + rcu_read_unlock(); +} + +/* + * After sending add Block Ack request we activated a timer until + * add Block Ack response will arrive from the recipient. + * If this timer expires sta_addba_resp_timer_expired will be executed. + */ +void sta_addba_resp_timer_expired(unsigned long data) +{ + /* not an elegant detour, but there is no choice as the timer passes + * only one argument, and both sta_info and TID are needed, so init + * flow in sta_info_create gives the TID as data, while the timer_to_id + * array gives the sta through container_of */ + u16 tid = *(int *)data; + struct sta_info *temp_sta = container_of((void *)data, + struct sta_info, timer_to_tid[tid]); + + struct ieee80211_local *local = temp_sta->local; + struct ieee80211_hw *hw = &local->hw; + struct sta_info *sta; + u8 *state; + + rcu_read_lock(); + + sta = sta_info_get(local, temp_sta->addr); + if (!sta) { + rcu_read_unlock(); + return; + } + + state = &sta->ampdu_mlme.tid_state_tx[tid]; + /* check if the TID waits for addBA response */ + spin_lock_bh(&sta->ampdu_mlme.ampdu_tx); + if (!(*state & HT_ADDBA_REQUESTED_MSK)) { + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + *state = HT_AGG_STATE_IDLE; + printk(KERN_DEBUG "timer expired on tid %d but we are not " + "expecting addBA response there", tid); + goto timer_expired_exit; + } + + printk(KERN_DEBUG "addBA response timer expired on tid %d\n", tid); + + /* go through the state check in stop_BA_session */ + *state = HT_AGG_STATE_OPERATIONAL; + spin_unlock_bh(&sta->ampdu_mlme.ampdu_tx); + ieee80211_stop_tx_ba_session(hw, temp_sta->addr, tid, + WLAN_BACK_INITIATOR); + +timer_expired_exit: + rcu_read_unlock(); +} + +/* + * After accepting the AddBA Request we activated a timer, + * resetting it after each frame that arrives from the originator. + * if this timer expires ieee80211_sta_stop_rx_ba_session will be executed. + */ +void sta_rx_agg_session_timer_expired(unsigned long data) +{ + /* not an elegant detour, but there is no choice as the timer passes + * only one argument, and verious sta_info are needed here, so init + * flow in sta_info_create gives the TID as data, while the timer_to_id + * array gives the sta through container_of */ + u8 *ptid = (u8 *)data; + u8 *timer_to_id = ptid - *ptid; + struct sta_info *sta = container_of(timer_to_id, struct sta_info, + timer_to_tid[0]); + + printk(KERN_DEBUG "rx session timer expired on tid %d\n", (u16)*ptid); + ieee80211_sta_stop_rx_ba_session(sta->sdata->dev, sta->addr, + (u16)*ptid, WLAN_BACK_TIMER, + WLAN_REASON_QSTA_TIMEOUT); +} + +void ieee80211_sta_tear_down_BA_sessions(struct net_device *dev, u8 *addr) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + int i; + + for (i = 0; i < STA_TID_NUM; i++) { + ieee80211_stop_tx_ba_session(&local->hw, addr, i, + WLAN_BACK_INITIATOR); + ieee80211_sta_stop_rx_ba_session(dev, addr, i, + WLAN_BACK_RECIPIENT, + WLAN_REASON_QSTA_LEAVE_QBSS); + } +} + +static void ieee80211_rx_mgmt_auth(struct net_device *dev, + struct ieee80211_if_sta *ifsta, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + u16 auth_alg, auth_transaction, status_code; + DECLARE_MAC_BUF(mac); + + if (ifsta->state != IEEE80211_AUTHENTICATE && + sdata->vif.type != IEEE80211_IF_TYPE_IBSS) { + printk(KERN_DEBUG "%s: authentication frame received from " + "%s, but not in authenticate state - ignored\n", + dev->name, print_mac(mac, mgmt->sa)); + return; + } + + if (len < 24 + 6) { + printk(KERN_DEBUG "%s: too short (%zd) authentication frame " + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); + return; + } + + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && + memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { + printk(KERN_DEBUG "%s: authentication frame received from " + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); + return; + } + + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && + memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) { + printk(KERN_DEBUG "%s: authentication frame received from " + "unknown BSSID (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); + return; + } + + auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg); + auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction); + status_code = le16_to_cpu(mgmt->u.auth.status_code); + + printk(KERN_DEBUG "%s: RX authentication from %s (alg=%d " + "transaction=%d status=%d)\n", + dev->name, print_mac(mac, mgmt->sa), auth_alg, + auth_transaction, status_code); + + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + /* IEEE 802.11 standard does not require authentication in IBSS + * networks and most implementations do not seem to use it. + * However, try to reply to authentication attempts if someone + * has actually implemented this. + * TODO: Could implement shared key authentication. */ + if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) { + printk(KERN_DEBUG "%s: unexpected IBSS authentication " + "frame (alg=%d transaction=%d)\n", + dev->name, auth_alg, auth_transaction); + return; + } + ieee80211_send_auth(dev, ifsta, 2, NULL, 0, 0); + } + + if (auth_alg != ifsta->auth_alg || + auth_transaction != ifsta->auth_transaction) { + printk(KERN_DEBUG "%s: unexpected authentication frame " + "(alg=%d transaction=%d)\n", + dev->name, auth_alg, auth_transaction); + return; + } + + if (status_code != WLAN_STATUS_SUCCESS) { + printk(KERN_DEBUG "%s: AP denied authentication (auth_alg=%d " + "code=%d)\n", dev->name, ifsta->auth_alg, status_code); + if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) { + u8 algs[3]; + const int num_algs = ARRAY_SIZE(algs); + int i, pos; + algs[0] = algs[1] = algs[2] = 0xff; + if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) + algs[0] = WLAN_AUTH_OPEN; + if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) + algs[1] = WLAN_AUTH_SHARED_KEY; + if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) + algs[2] = WLAN_AUTH_LEAP; + if (ifsta->auth_alg == WLAN_AUTH_OPEN) + pos = 0; + else if (ifsta->auth_alg == WLAN_AUTH_SHARED_KEY) + pos = 1; + else + pos = 2; + for (i = 0; i < num_algs; i++) { + pos++; + if (pos >= num_algs) + pos = 0; + if (algs[pos] == ifsta->auth_alg || + algs[pos] == 0xff) + continue; + if (algs[pos] == WLAN_AUTH_SHARED_KEY && + !ieee80211_sta_wep_configured(dev)) + continue; + ifsta->auth_alg = algs[pos]; + printk(KERN_DEBUG "%s: set auth_alg=%d for " + "next try\n", + dev->name, ifsta->auth_alg); + break; + } + } + return; + } + + switch (ifsta->auth_alg) { + case WLAN_AUTH_OPEN: + case WLAN_AUTH_LEAP: + ieee80211_auth_completed(dev, ifsta); + break; + case WLAN_AUTH_SHARED_KEY: + if (ifsta->auth_transaction == 4) + ieee80211_auth_completed(dev, ifsta); + else + ieee80211_auth_challenge(dev, ifsta, mgmt, len); + break; + } +} + + +static void ieee80211_rx_mgmt_deauth(struct net_device *dev, + struct ieee80211_if_sta *ifsta, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + u16 reason_code; + DECLARE_MAC_BUF(mac); + + if (len < 24 + 2) { + printk(KERN_DEBUG "%s: too short (%zd) deauthentication frame " + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); + return; + } + + if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { + printk(KERN_DEBUG "%s: deauthentication frame received from " + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); + return; + } + + reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); + + printk(KERN_DEBUG "%s: RX deauthentication from %s" + " (reason=%d)\n", + dev->name, print_mac(mac, mgmt->sa), reason_code); + + if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) { + printk(KERN_DEBUG "%s: deauthenticated\n", dev->name); + } + + if (ifsta->state == IEEE80211_AUTHENTICATE || + ifsta->state == IEEE80211_ASSOCIATE || + ifsta->state == IEEE80211_ASSOCIATED) { + ifsta->state = IEEE80211_AUTHENTICATE; + mod_timer(&ifsta->timer, jiffies + + IEEE80211_RETRY_AUTH_INTERVAL); + } + + ieee80211_set_disassoc(dev, ifsta, 1); + ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED; +} + + +static void ieee80211_rx_mgmt_disassoc(struct net_device *dev, + struct ieee80211_if_sta *ifsta, + struct ieee80211_mgmt *mgmt, + size_t len) +{ + u16 reason_code; + DECLARE_MAC_BUF(mac); + + if (len < 24 + 2) { + printk(KERN_DEBUG "%s: too short (%zd) disassociation frame " + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); + return; + } + + if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { + printk(KERN_DEBUG "%s: disassociation frame received from " + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); + return; + } + + reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); + + printk(KERN_DEBUG "%s: RX disassociation from %s" + " (reason=%d)\n", + dev->name, print_mac(mac, mgmt->sa), reason_code); + + if (ifsta->flags & IEEE80211_STA_ASSOCIATED) + printk(KERN_DEBUG "%s: disassociated\n", dev->name); + + if (ifsta->state == IEEE80211_ASSOCIATED) { + ifsta->state = IEEE80211_ASSOCIATE; + mod_timer(&ifsta->timer, jiffies + + IEEE80211_RETRY_AUTH_INTERVAL); + } + + ieee80211_set_disassoc(dev, ifsta, 0); +} + + +static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, + struct ieee80211_if_sta *ifsta, + struct ieee80211_mgmt *mgmt, + size_t len, + int reassoc) +{ + struct ieee80211_local *local = sdata->local; + struct net_device *dev = sdata->dev; + struct ieee80211_supported_band *sband; + struct sta_info *sta; + u64 rates, basic_rates; + u16 capab_info, status_code, aid; + struct ieee802_11_elems elems; + struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; + u8 *pos; + int i, j; + DECLARE_MAC_BUF(mac); + bool have_higher_than_11mbit = false; + + /* AssocResp and ReassocResp have identical structure, so process both + * of them in this function. */ + + if (ifsta->state != IEEE80211_ASSOCIATE) { + printk(KERN_DEBUG "%s: association frame received from " + "%s, but not in associate state - ignored\n", + dev->name, print_mac(mac, mgmt->sa)); + return; + } + + if (len < 24 + 6) { + printk(KERN_DEBUG "%s: too short (%zd) association frame " + "received from %s - ignored\n", + dev->name, len, print_mac(mac, mgmt->sa)); + return; + } + + if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0) { + printk(KERN_DEBUG "%s: association frame received from " + "unknown AP (SA=%s BSSID=%s) - " + "ignored\n", dev->name, print_mac(mac, mgmt->sa), + print_mac(mac, mgmt->bssid)); + return; + } + + capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); + status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); + aid = le16_to_cpu(mgmt->u.assoc_resp.aid); + + printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x " + "status=%d aid=%d)\n", + dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa), + capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); + + if (status_code != WLAN_STATUS_SUCCESS) { + printk(KERN_DEBUG "%s: AP denied association (code=%d)\n", + dev->name, status_code); + /* if this was a reassociation, ensure we try a "full" + * association next time. This works around some broken APs + * which do not correctly reject reassociation requests. */ + ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; + return; + } + + if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) + printk(KERN_DEBUG "%s: invalid aid value %d; bits 15:14 not " + "set\n", dev->name, aid); + aid &= ~(BIT(15) | BIT(14)); + + pos = mgmt->u.assoc_resp.variable; + ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); + + if (!elems.supp_rates) { + printk(KERN_DEBUG "%s: no SuppRates element in AssocResp\n", + dev->name); + return; + } + + printk(KERN_DEBUG "%s: associated\n", dev->name); + ifsta->aid = aid; + ifsta->ap_capab = capab_info; + + kfree(ifsta->assocresp_ies); + ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt); + ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_KERNEL); + if (ifsta->assocresp_ies) + memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len); + + rcu_read_lock(); + + /* Add STA entry for the AP */ + sta = sta_info_get(local, ifsta->bssid); + if (!sta) { + struct ieee80211_sta_bss *bss; + int err; + + sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC); + if (!sta) { + printk(KERN_DEBUG "%s: failed to alloc STA entry for" + " the AP\n", dev->name); + rcu_read_unlock(); + return; + } + bss = ieee80211_rx_bss_get(dev, ifsta->bssid, + local->hw.conf.channel->center_freq, + ifsta->ssid, ifsta->ssid_len); + if (bss) { + sta->last_rssi = bss->rssi; + sta->last_signal = bss->signal; + sta->last_noise = bss->noise; + ieee80211_rx_bss_put(dev, bss); + } + + err = sta_info_insert(sta); + if (err) { + printk(KERN_DEBUG "%s: failed to insert STA entry for" + " the AP (error %d)\n", dev->name, err); + rcu_read_unlock(); + return; + } + } + + /* + * FIXME: Do we really need to update the sta_info's information here? + * We already know about the AP (we found it in our list) so it + * should already be filled with the right info, no? + * As is stands, all this is racy because typically we assume + * the information that is filled in here (except flags) doesn't + * change while a STA structure is alive. As such, it should move + * to between the sta_info_alloc() and sta_info_insert() above. + */ + + sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP | + WLAN_STA_AUTHORIZED; + + rates = 0; + basic_rates = 0; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + for (i = 0; i < elems.supp_rates_len; i++) { + int rate = (elems.supp_rates[i] & 0x7f) * 5; + + if (rate > 110) + have_higher_than_11mbit = true; + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) + rates |= BIT(j); + if (elems.supp_rates[i] & 0x80) + basic_rates |= BIT(j); + } + } + + for (i = 0; i < elems.ext_supp_rates_len; i++) { + int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; + + if (rate > 110) + have_higher_than_11mbit = true; + + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) + rates |= BIT(j); + if (elems.ext_supp_rates[i] & 0x80) + basic_rates |= BIT(j); + } + } + + sta->supp_rates[local->hw.conf.channel->band] = rates; + sdata->basic_rates = basic_rates; + + /* cf. IEEE 802.11 9.2.12 */ + if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && + have_higher_than_11mbit) + sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; + else + sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; + + if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) { + struct ieee80211_ht_bss_info bss_info; + ieee80211_ht_cap_ie_to_ht_info( + (struct ieee80211_ht_cap *) + elems.ht_cap_elem, &sta->ht_info); + ieee80211_ht_addt_info_ie_to_ht_bss_info( + (struct ieee80211_ht_addt_info *) + elems.ht_info_elem, &bss_info); + ieee80211_handle_ht(local, 1, &sta->ht_info, &bss_info); + } + + rate_control_rate_init(sta, local); + + if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { + sta->flags |= WLAN_STA_WME; + rcu_read_unlock(); + ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, + elems.wmm_param_len); + } else + rcu_read_unlock(); + + /* set AID and assoc capability, + * ieee80211_set_associated() will tell the driver */ + bss_conf->aid = aid; + bss_conf->assoc_capability = capab_info; + ieee80211_set_associated(dev, ifsta, 1); + + ieee80211_associated(dev, ifsta); +} + + +/* Caller must hold local->sta_bss_lock */ +static void __ieee80211_rx_bss_hash_add(struct net_device *dev, + struct ieee80211_sta_bss *bss) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + u8 hash_idx; + + if (bss_mesh_cfg(bss)) + hash_idx = mesh_id_hash(bss_mesh_id(bss), + bss_mesh_id_len(bss)); + else + hash_idx = STA_HASH(bss->bssid); + + bss->hnext = local->sta_bss_hash[hash_idx]; + local->sta_bss_hash[hash_idx] = bss; +} + + +/* Caller must hold local->sta_bss_lock */ +static void __ieee80211_rx_bss_hash_del(struct net_device *dev, + struct ieee80211_sta_bss *bss) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sta_bss *b, *prev = NULL; + b = local->sta_bss_hash[STA_HASH(bss->bssid)]; + while (b) { + if (b == bss) { + if (!prev) + local->sta_bss_hash[STA_HASH(bss->bssid)] = + bss->hnext; + else + prev->hnext = bss->hnext; + break; + } + prev = b; + b = b->hnext; + } +} + + +static struct ieee80211_sta_bss * +ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int freq, + u8 *ssid, u8 ssid_len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sta_bss *bss; + + bss = kzalloc(sizeof(*bss), GFP_ATOMIC); + if (!bss) + return NULL; + atomic_inc(&bss->users); + atomic_inc(&bss->users); + memcpy(bss->bssid, bssid, ETH_ALEN); + bss->freq = freq; + if (ssid && ssid_len <= IEEE80211_MAX_SSID_LEN) { + memcpy(bss->ssid, ssid, ssid_len); + bss->ssid_len = ssid_len; + } + + spin_lock_bh(&local->sta_bss_lock); + /* TODO: order by RSSI? */ + list_add_tail(&bss->list, &local->sta_bss_list); + __ieee80211_rx_bss_hash_add(dev, bss); + spin_unlock_bh(&local->sta_bss_lock); + return bss; +} + +static struct ieee80211_sta_bss * +ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int freq, + u8 *ssid, u8 ssid_len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sta_bss *bss; + + spin_lock_bh(&local->sta_bss_lock); + bss = local->sta_bss_hash[STA_HASH(bssid)]; + while (bss) { + if (!bss_mesh_cfg(bss) && + !memcmp(bss->bssid, bssid, ETH_ALEN) && + bss->freq == freq && + bss->ssid_len == ssid_len && + (ssid_len == 0 || !memcmp(bss->ssid, ssid, ssid_len))) { + atomic_inc(&bss->users); + break; + } + bss = bss->hnext; + } + spin_unlock_bh(&local->sta_bss_lock); + return bss; +} + +#ifdef CONFIG_MAC80211_MESH +static struct ieee80211_sta_bss * +ieee80211_rx_mesh_bss_get(struct net_device *dev, u8 *mesh_id, int mesh_id_len, + u8 *mesh_cfg, int freq) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sta_bss *bss; + + spin_lock_bh(&local->sta_bss_lock); + bss = local->sta_bss_hash[mesh_id_hash(mesh_id, mesh_id_len)]; + while (bss) { + if (bss_mesh_cfg(bss) && + !memcmp(bss_mesh_cfg(bss), mesh_cfg, MESH_CFG_CMP_LEN) && + bss->freq == freq && + mesh_id_len == bss->mesh_id_len && + (mesh_id_len == 0 || !memcmp(bss->mesh_id, mesh_id, + mesh_id_len))) { + atomic_inc(&bss->users); + break; + } + bss = bss->hnext; + } + spin_unlock_bh(&local->sta_bss_lock); + return bss; +} + +static struct ieee80211_sta_bss * +ieee80211_rx_mesh_bss_add(struct net_device *dev, u8 *mesh_id, int mesh_id_len, + u8 *mesh_cfg, int mesh_config_len, int freq) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sta_bss *bss; + + if (mesh_config_len != MESH_CFG_LEN) + return NULL; + + bss = kzalloc(sizeof(*bss), GFP_ATOMIC); + if (!bss) + return NULL; + + bss->mesh_cfg = kmalloc(MESH_CFG_CMP_LEN, GFP_ATOMIC); + if (!bss->mesh_cfg) { + kfree(bss); + return NULL; + } + + if (mesh_id_len && mesh_id_len <= IEEE80211_MAX_MESH_ID_LEN) { + bss->mesh_id = kmalloc(mesh_id_len, GFP_ATOMIC); + if (!bss->mesh_id) { + kfree(bss->mesh_cfg); + kfree(bss); + return NULL; + } + memcpy(bss->mesh_id, mesh_id, mesh_id_len); + } + + atomic_inc(&bss->users); + atomic_inc(&bss->users); + memcpy(bss->mesh_cfg, mesh_cfg, MESH_CFG_CMP_LEN); + bss->mesh_id_len = mesh_id_len; + bss->freq = freq; + spin_lock_bh(&local->sta_bss_lock); + /* TODO: order by RSSI? */ + list_add_tail(&bss->list, &local->sta_bss_list); + __ieee80211_rx_bss_hash_add(dev, bss); + spin_unlock_bh(&local->sta_bss_lock); + return bss; +} +#endif + +static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) +{ + kfree(bss->wpa_ie); + kfree(bss->rsn_ie); + kfree(bss->wmm_ie); + kfree(bss->ht_ie); + kfree(bss_mesh_id(bss)); + kfree(bss_mesh_cfg(bss)); + kfree(bss); +} + + +static void ieee80211_rx_bss_put(struct net_device *dev, + struct ieee80211_sta_bss *bss) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + if (!atomic_dec_and_test(&bss->users)) + return; + + spin_lock_bh(&local->sta_bss_lock); + __ieee80211_rx_bss_hash_del(dev, bss); + list_del(&bss->list); + spin_unlock_bh(&local->sta_bss_lock); + ieee80211_rx_bss_free(bss); +} + + +void ieee80211_rx_bss_list_init(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + spin_lock_init(&local->sta_bss_lock); + INIT_LIST_HEAD(&local->sta_bss_list); +} + + +void ieee80211_rx_bss_list_deinit(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sta_bss *bss, *tmp; + + list_for_each_entry_safe(bss, tmp, &local->sta_bss_list, list) + ieee80211_rx_bss_put(dev, bss); +} + + +static int ieee80211_sta_join_ibss(struct net_device *dev, + struct ieee80211_if_sta *ifsta, + struct ieee80211_sta_bss *bss) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + int res, rates, i, j; + struct sk_buff *skb; + struct ieee80211_mgmt *mgmt; + struct ieee80211_tx_control control; + struct rate_selection ratesel; + u8 *pos; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + /* Remove possible STA entries from other IBSS networks. */ + sta_info_flush_delayed(sdata); + + if (local->ops->reset_tsf) { + /* Reset own TSF to allow time synchronization work. */ + local->ops->reset_tsf(local_to_hw(local)); + } + memcpy(ifsta->bssid, bss->bssid, ETH_ALEN); + res = ieee80211_if_config(dev); + if (res) + return res; + + local->hw.conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10; + + sdata->drop_unencrypted = bss->capability & + WLAN_CAPABILITY_PRIVACY ? 1 : 0; + + res = ieee80211_set_freq(local, bss->freq); + + if (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) { + printk(KERN_DEBUG "%s: IBSS not allowed on frequency " + "%d MHz\n", dev->name, local->oper_channel->center_freq); + return -1; + } + + /* Set beacon template */ + skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); + do { + if (!skb) + break; + + skb_reserve(skb, local->hw.extra_tx_headroom); + + mgmt = (struct ieee80211_mgmt *) + skb_put(skb, 24 + sizeof(mgmt->u.beacon)); + memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); + mgmt->frame_control = IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_BEACON); + memset(mgmt->da, 0xff, ETH_ALEN); + memcpy(mgmt->sa, dev->dev_addr, ETH_ALEN); + memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN); + mgmt->u.beacon.beacon_int = + cpu_to_le16(local->hw.conf.beacon_int); + mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability); + + pos = skb_put(skb, 2 + ifsta->ssid_len); + *pos++ = WLAN_EID_SSID; + *pos++ = ifsta->ssid_len; + memcpy(pos, ifsta->ssid, ifsta->ssid_len); + + rates = bss->supp_rates_len; + if (rates > 8) + rates = 8; + pos = skb_put(skb, 2 + rates); + *pos++ = WLAN_EID_SUPP_RATES; + *pos++ = rates; + memcpy(pos, bss->supp_rates, rates); + + if (bss->band == IEEE80211_BAND_2GHZ) { + pos = skb_put(skb, 2 + 1); + *pos++ = WLAN_EID_DS_PARAMS; + *pos++ = 1; + *pos++ = ieee80211_frequency_to_channel(bss->freq); + } + + pos = skb_put(skb, 2 + 2); + *pos++ = WLAN_EID_IBSS_PARAMS; + *pos++ = 2; + /* FIX: set ATIM window based on scan results */ + *pos++ = 0; + *pos++ = 0; + + if (bss->supp_rates_len > 8) { + rates = bss->supp_rates_len - 8; + pos = skb_put(skb, 2 + rates); + *pos++ = WLAN_EID_EXT_SUPP_RATES; + *pos++ = rates; + memcpy(pos, &bss->supp_rates[8], rates); + } + + memset(&control, 0, sizeof(control)); + rate_control_get_rate(dev, sband, skb, &ratesel); + if (!ratesel.rate) { + printk(KERN_DEBUG "%s: Failed to determine TX rate " + "for IBSS beacon\n", dev->name); + break; + } + control.vif = &sdata->vif; + control.tx_rate = ratesel.rate; + if (sdata->bss_conf.use_short_preamble && + ratesel.rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + control.flags |= IEEE80211_TXCTL_SHORT_PREAMBLE; + control.antenna_sel_tx = local->hw.conf.antenna_sel_tx; + control.flags |= IEEE80211_TXCTL_NO_ACK; + control.retry_limit = 1; + + ifsta->probe_resp = skb_copy(skb, GFP_ATOMIC); + if (ifsta->probe_resp) { + mgmt = (struct ieee80211_mgmt *) + ifsta->probe_resp->data; + mgmt->frame_control = + IEEE80211_FC(IEEE80211_FTYPE_MGMT, + IEEE80211_STYPE_PROBE_RESP); + } else { + printk(KERN_DEBUG "%s: Could not allocate ProbeResp " + "template for IBSS\n", dev->name); + } + + if (local->ops->beacon_update && + local->ops->beacon_update(local_to_hw(local), + skb, &control) == 0) { + printk(KERN_DEBUG "%s: Configured IBSS beacon " + "template\n", dev->name); + skb = NULL; + } + + rates = 0; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + for (i = 0; i < bss->supp_rates_len; i++) { + int bitrate = (bss->supp_rates[i] & 0x7f) * 5; + for (j = 0; j < sband->n_bitrates; j++) + if (sband->bitrates[j].bitrate == bitrate) + rates |= BIT(j); + } + ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates; + + ieee80211_sta_def_wmm_params(dev, bss, 1); + } while (0); + + if (skb) { + printk(KERN_DEBUG "%s: Failed to configure IBSS beacon " + "template\n", dev->name); + dev_kfree_skb(skb); + } + + ifsta->state = IEEE80211_IBSS_JOINED; + mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); + + ieee80211_rx_bss_put(dev, bss); + + return res; +} + +u64 ieee80211_sta_get_rates(struct ieee80211_local *local, + struct ieee802_11_elems *elems, + enum ieee80211_band band) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_rate *bitrates; + size_t num_rates; + u64 supp_rates; + int i, j; + sband = local->hw.wiphy->bands[band]; + + if (!sband) { + WARN_ON(1); + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + } + + bitrates = sband->bitrates; + num_rates = sband->n_bitrates; + supp_rates = 0; + for (i = 0; i < elems->supp_rates_len + + elems->ext_supp_rates_len; i++) { + u8 rate = 0; + int own_rate; + if (i < elems->supp_rates_len) + rate = elems->supp_rates[i]; + else if (elems->ext_supp_rates) + rate = elems->ext_supp_rates + [i - elems->supp_rates_len]; + own_rate = 5 * (rate & 0x7f); + for (j = 0; j < num_rates; j++) + if (bitrates[j].bitrate == own_rate) + supp_rates |= BIT(j); + } + return supp_rates; +} + + +static void ieee80211_rx_bss_info(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status, + int beacon) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee802_11_elems elems; + size_t baselen; + int freq, clen; + struct ieee80211_sta_bss *bss; + struct sta_info *sta; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + u64 beacon_timestamp, rx_timestamp; + struct ieee80211_channel *channel; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + + if (!beacon && memcmp(mgmt->da, dev->dev_addr, ETH_ALEN)) + return; /* ignore ProbeResp to foreign address */ + +#if 0 + printk(KERN_DEBUG "%s: RX %s from %s to %s\n", + dev->name, beacon ? "Beacon" : "Probe Response", + print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da)); +#endif + + baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; + if (baselen > len) + return; + + beacon_timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); + ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); + + if (ieee80211_vif_is_mesh(&sdata->vif) && elems.mesh_id && + elems.mesh_config && mesh_matches_local(&elems, dev)) { + u64 rates = ieee80211_sta_get_rates(local, &elems, + rx_status->band); + + mesh_neighbour_update(mgmt->sa, rates, dev, + mesh_peer_accepts_plinks(&elems, dev)); + } + + rcu_read_lock(); + + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && elems.supp_rates && + memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0 && + (sta = sta_info_get(local, mgmt->sa))) { + u64 prev_rates; + u64 supp_rates = ieee80211_sta_get_rates(local, &elems, + rx_status->band); + + prev_rates = sta->supp_rates[rx_status->band]; + sta->supp_rates[rx_status->band] &= supp_rates; + if (sta->supp_rates[rx_status->band] == 0) { + /* No matching rates - this should not really happen. + * Make sure that at least one rate is marked + * supported to avoid issues with TX rate ctrl. */ + sta->supp_rates[rx_status->band] = + sdata->u.sta.supp_rates_bits[rx_status->band]; + } + if (sta->supp_rates[rx_status->band] != prev_rates) { + printk(KERN_DEBUG "%s: updated supp_rates set for " + "%s based on beacon info (0x%llx & 0x%llx -> " + "0x%llx)\n", + dev->name, print_mac(mac, sta->addr), + (unsigned long long) prev_rates, + (unsigned long long) supp_rates, + (unsigned long long) sta->supp_rates[rx_status->band]); + } + } + + rcu_read_unlock(); + + if (elems.ds_params && elems.ds_params_len == 1) + freq = ieee80211_channel_to_frequency(elems.ds_params[0]); + else + freq = rx_status->freq; + + channel = ieee80211_get_channel(local->hw.wiphy, freq); + + if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) + return; + +#ifdef CONFIG_MAC80211_MESH + if (elems.mesh_config) + bss = ieee80211_rx_mesh_bss_get(dev, elems.mesh_id, + elems.mesh_id_len, elems.mesh_config, freq); + else +#endif + bss = ieee80211_rx_bss_get(dev, mgmt->bssid, freq, + elems.ssid, elems.ssid_len); + if (!bss) { +#ifdef CONFIG_MAC80211_MESH + if (elems.mesh_config) + bss = ieee80211_rx_mesh_bss_add(dev, elems.mesh_id, + elems.mesh_id_len, elems.mesh_config, + elems.mesh_config_len, freq); + else +#endif + bss = ieee80211_rx_bss_add(dev, mgmt->bssid, freq, + elems.ssid, elems.ssid_len); + if (!bss) + return; + } else { +#if 0 + /* TODO: order by RSSI? */ + spin_lock_bh(&local->sta_bss_lock); + list_move_tail(&bss->list, &local->sta_bss_list); + spin_unlock_bh(&local->sta_bss_lock); +#endif + } + + bss->band = rx_status->band; + + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && + bss->probe_resp && beacon) { + /* STA mode: + * Do not allow beacon to override data from Probe Response. */ + ieee80211_rx_bss_put(dev, bss); + return; + } + + /* save the ERP value so that it is available at association time */ + if (elems.erp_info && elems.erp_info_len >= 1) { + bss->erp_value = elems.erp_info[0]; + bss->has_erp_value = 1; + } + + bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); + bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); + + bss->supp_rates_len = 0; + if (elems.supp_rates) { + clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; + if (clen > elems.supp_rates_len) + clen = elems.supp_rates_len; + memcpy(&bss->supp_rates[bss->supp_rates_len], elems.supp_rates, + clen); + bss->supp_rates_len += clen; + } + if (elems.ext_supp_rates) { + clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; + if (clen > elems.ext_supp_rates_len) + clen = elems.ext_supp_rates_len; + memcpy(&bss->supp_rates[bss->supp_rates_len], + elems.ext_supp_rates, clen); + bss->supp_rates_len += clen; + } + + if (elems.wpa && + (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len || + memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) { + kfree(bss->wpa_ie); + bss->wpa_ie = kmalloc(elems.wpa_len + 2, GFP_ATOMIC); + if (bss->wpa_ie) { + memcpy(bss->wpa_ie, elems.wpa - 2, elems.wpa_len + 2); + bss->wpa_ie_len = elems.wpa_len + 2; + } else + bss->wpa_ie_len = 0; + } else if (!elems.wpa && bss->wpa_ie) { + kfree(bss->wpa_ie); + bss->wpa_ie = NULL; + bss->wpa_ie_len = 0; + } + + if (elems.rsn && + (!bss->rsn_ie || bss->rsn_ie_len != elems.rsn_len || + memcmp(bss->rsn_ie, elems.rsn, elems.rsn_len))) { + kfree(bss->rsn_ie); + bss->rsn_ie = kmalloc(elems.rsn_len + 2, GFP_ATOMIC); + if (bss->rsn_ie) { + memcpy(bss->rsn_ie, elems.rsn - 2, elems.rsn_len + 2); + bss->rsn_ie_len = elems.rsn_len + 2; + } else + bss->rsn_ie_len = 0; + } else if (!elems.rsn && bss->rsn_ie) { + kfree(bss->rsn_ie); + bss->rsn_ie = NULL; + bss->rsn_ie_len = 0; + } + + if (elems.wmm_param && + (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len || + memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) { + kfree(bss->wmm_ie); + bss->wmm_ie = kmalloc(elems.wmm_param_len + 2, GFP_ATOMIC); + if (bss->wmm_ie) { + memcpy(bss->wmm_ie, elems.wmm_param - 2, + elems.wmm_param_len + 2); + bss->wmm_ie_len = elems.wmm_param_len + 2; + } else + bss->wmm_ie_len = 0; + } else if (!elems.wmm_param && bss->wmm_ie) { + kfree(bss->wmm_ie); + bss->wmm_ie = NULL; + bss->wmm_ie_len = 0; + } + if (elems.ht_cap_elem && + (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len || + memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) { + kfree(bss->ht_ie); + bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC); + if (bss->ht_ie) { + memcpy(bss->ht_ie, elems.ht_cap_elem - 2, + elems.ht_cap_elem_len + 2); + bss->ht_ie_len = elems.ht_cap_elem_len + 2; + } else + bss->ht_ie_len = 0; + } else if (!elems.ht_cap_elem && bss->ht_ie) { + kfree(bss->ht_ie); + bss->ht_ie = NULL; + bss->ht_ie_len = 0; + } + + bss->timestamp = beacon_timestamp; + bss->last_update = jiffies; + bss->rssi = rx_status->ssi; + bss->signal = rx_status->signal; + bss->noise = rx_status->noise; + if (!beacon) + bss->probe_resp++; + + /* check if we need to merge IBSS */ + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && + !local->sta_sw_scanning && !local->sta_hw_scanning && + bss->capability & WLAN_CAPABILITY_IBSS && + bss->freq == local->oper_channel->center_freq && + elems.ssid_len == sdata->u.sta.ssid_len && + memcmp(elems.ssid, sdata->u.sta.ssid, sdata->u.sta.ssid_len) == 0) { + if (rx_status->flag & RX_FLAG_TSFT) { + /* in order for correct IBSS merging we need mactime + * + * since mactime is defined as the time the first data + * symbol of the frame hits the PHY, and the timestamp + * of the beacon is defined as "the time that the data + * symbol containing the first bit of the timestamp is + * transmitted to the PHY plus the transmitting STA’s + * delays through its local PHY from the MAC-PHY + * interface to its interface with the WM" + * (802.11 11.1.2) - equals the time this bit arrives at + * the receiver - we have to take into account the + * offset between the two. + * e.g: at 1 MBit that means mactime is 192 usec earlier + * (=24 bytes * 8 usecs/byte) than the beacon timestamp. + */ + int rate = local->hw.wiphy->bands[rx_status->band]-> + bitrates[rx_status->rate_idx].bitrate; + rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate); + } else if (local && local->ops && local->ops->get_tsf) + /* second best option: get current TSF */ + rx_timestamp = local->ops->get_tsf(local_to_hw(local)); + else + /* can't merge without knowing the TSF */ + rx_timestamp = -1LLU; +#ifdef CONFIG_MAC80211_IBSS_DEBUG + printk(KERN_DEBUG "RX beacon SA=%s BSSID=" + "%s TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", + print_mac(mac, mgmt->sa), + print_mac(mac2, mgmt->bssid), + (unsigned long long)rx_timestamp, + (unsigned long long)beacon_timestamp, + (unsigned long long)(rx_timestamp - beacon_timestamp), + jiffies); +#endif /* CONFIG_MAC80211_IBSS_DEBUG */ + if (beacon_timestamp > rx_timestamp) { +#ifndef CONFIG_MAC80211_IBSS_DEBUG + if (net_ratelimit()) +#endif + printk(KERN_DEBUG "%s: beacon TSF higher than " + "local TSF - IBSS merge with BSSID %s\n", + dev->name, print_mac(mac, mgmt->bssid)); + ieee80211_sta_join_ibss(dev, &sdata->u.sta, bss); + ieee80211_ibss_add_sta(dev, NULL, + mgmt->bssid, mgmt->sa); + } + } + + ieee80211_rx_bss_put(dev, bss); +} + + +static void ieee80211_rx_mgmt_probe_resp(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status) +{ + ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 0); +} + + +static void ieee80211_rx_mgmt_beacon(struct net_device *dev, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_sta *ifsta; + size_t baselen; + struct ieee802_11_elems elems; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_conf *conf = &local->hw.conf; + u32 changed = 0; + + ieee80211_rx_bss_info(dev, mgmt, len, rx_status, 1); + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) + return; + ifsta = &sdata->u.sta; + + if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED) || + memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0) + return; + + /* Process beacon from the current BSS */ + baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; + if (baselen > len) + return; + + ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); + + if (elems.erp_info && elems.erp_info_len >= 1) + changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]); + + if (elems.ht_cap_elem && elems.ht_info_elem && + elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { + struct ieee80211_ht_bss_info bss_info; + + ieee80211_ht_addt_info_ie_to_ht_bss_info( + (struct ieee80211_ht_addt_info *) + elems.ht_info_elem, &bss_info); + changed |= ieee80211_handle_ht(local, 1, &conf->ht_conf, + &bss_info); + } + + if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { + ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, + elems.wmm_param_len); + } + + ieee80211_bss_info_change_notify(sdata, changed); +} + + +static void ieee80211_rx_mgmt_probe_req(struct net_device *dev, + struct ieee80211_if_sta *ifsta, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int tx_last_beacon; + struct sk_buff *skb; + struct ieee80211_mgmt *resp; + u8 *pos, *end; + DECLARE_MAC_BUF(mac); +#ifdef CONFIG_MAC80211_IBSS_DEBUG + DECLARE_MAC_BUF(mac2); + DECLARE_MAC_BUF(mac3); +#endif + + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS || + ifsta->state != IEEE80211_IBSS_JOINED || + len < 24 + 2 || !ifsta->probe_resp) + return; + + if (local->ops->tx_last_beacon) + tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local)); + else + tx_last_beacon = 1; + +#ifdef CONFIG_MAC80211_IBSS_DEBUG + printk(KERN_DEBUG "%s: RX ProbeReq SA=%s DA=%s BSSID=" + "%s (tx_last_beacon=%d)\n", + dev->name, print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da), + print_mac(mac3, mgmt->bssid), tx_last_beacon); +#endif /* CONFIG_MAC80211_IBSS_DEBUG */ + + if (!tx_last_beacon) + return; + + if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0 && + memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) + return; + + end = ((u8 *) mgmt) + len; + pos = mgmt->u.probe_req.variable; + if (pos[0] != WLAN_EID_SSID || + pos + 2 + pos[1] > end) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " + "from %s\n", + dev->name, print_mac(mac, mgmt->sa)); + } + return; + } + if (pos[1] != 0 && + (pos[1] != ifsta->ssid_len || + memcmp(pos + 2, ifsta->ssid, ifsta->ssid_len) != 0)) { + /* Ignore ProbeReq for foreign SSID */ + return; + } + + /* Reply with ProbeResp */ + skb = skb_copy(ifsta->probe_resp, GFP_KERNEL); + if (!skb) + return; + + resp = (struct ieee80211_mgmt *) skb->data; + memcpy(resp->da, mgmt->sa, ETH_ALEN); +#ifdef CONFIG_MAC80211_IBSS_DEBUG + printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n", + dev->name, print_mac(mac, resp->da)); +#endif /* CONFIG_MAC80211_IBSS_DEBUG */ + ieee80211_sta_tx(dev, skb, 0); +} + +static void ieee80211_rx_mgmt_action(struct net_device *dev, + struct ieee80211_if_sta *ifsta, + struct ieee80211_mgmt *mgmt, + size_t len, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (len < IEEE80211_MIN_ACTION_SIZE) + return; + + switch (mgmt->u.action.category) { + case WLAN_CATEGORY_BACK: + switch (mgmt->u.action.u.addba_req.action_code) { + case WLAN_ACTION_ADDBA_REQ: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.addba_req))) + break; + ieee80211_sta_process_addba_request(dev, mgmt, len); + break; + case WLAN_ACTION_ADDBA_RESP: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.addba_resp))) + break; + ieee80211_sta_process_addba_resp(dev, mgmt, len); + break; + case WLAN_ACTION_DELBA: + if (len < (IEEE80211_MIN_ACTION_SIZE + + sizeof(mgmt->u.action.u.delba))) + break; + ieee80211_sta_process_delba(dev, mgmt, len); + break; + default: + if (net_ratelimit()) + printk(KERN_DEBUG "%s: Rx unknown A-MPDU action\n", + dev->name); + break; + } + break; + case PLINK_CATEGORY: + if (ieee80211_vif_is_mesh(&sdata->vif)) + mesh_rx_plink_frame(dev, mgmt, len, rx_status); + break; + case MESH_PATH_SEL_CATEGORY: + if (ieee80211_vif_is_mesh(&sdata->vif)) + mesh_rx_path_sel_frame(dev, mgmt, len); + break; + default: + if (net_ratelimit()) + printk(KERN_DEBUG "%s: Rx unknown action frame - " + "category=%d\n", dev->name, mgmt->u.action.category); + break; + } +} + +void ieee80211_sta_rx_mgmt(struct net_device *dev, struct sk_buff *skb, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_sta *ifsta; + struct ieee80211_mgmt *mgmt; + u16 fc; + + if (skb->len < 24) + goto fail; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + ifsta = &sdata->u.sta; + + mgmt = (struct ieee80211_mgmt *) skb->data; + fc = le16_to_cpu(mgmt->frame_control); + + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_PROBE_REQ: + case IEEE80211_STYPE_PROBE_RESP: + case IEEE80211_STYPE_BEACON: + case IEEE80211_STYPE_ACTION: + memcpy(skb->cb, rx_status, sizeof(*rx_status)); + case IEEE80211_STYPE_AUTH: + case IEEE80211_STYPE_ASSOC_RESP: + case IEEE80211_STYPE_REASSOC_RESP: + case IEEE80211_STYPE_DEAUTH: + case IEEE80211_STYPE_DISASSOC: + skb_queue_tail(&ifsta->skb_queue, skb); + queue_work(local->hw.workqueue, &ifsta->work); + return; + default: + printk(KERN_DEBUG "%s: received unknown management frame - " + "stype=%d\n", dev->name, + (fc & IEEE80211_FCTL_STYPE) >> 4); + break; + } + + fail: + kfree_skb(skb); +} + + +static void ieee80211_sta_rx_queued_mgmt(struct net_device *dev, + struct sk_buff *skb) +{ + struct ieee80211_rx_status *rx_status; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_sta *ifsta; + struct ieee80211_mgmt *mgmt; + u16 fc; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + ifsta = &sdata->u.sta; + + rx_status = (struct ieee80211_rx_status *) skb->cb; + mgmt = (struct ieee80211_mgmt *) skb->data; + fc = le16_to_cpu(mgmt->frame_control); + + switch (fc & IEEE80211_FCTL_STYPE) { + case IEEE80211_STYPE_PROBE_REQ: + ieee80211_rx_mgmt_probe_req(dev, ifsta, mgmt, skb->len, + rx_status); + break; + case IEEE80211_STYPE_PROBE_RESP: + ieee80211_rx_mgmt_probe_resp(dev, mgmt, skb->len, rx_status); + break; + case IEEE80211_STYPE_BEACON: + ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, rx_status); + break; + case IEEE80211_STYPE_AUTH: + ieee80211_rx_mgmt_auth(dev, ifsta, mgmt, skb->len); + break; + case IEEE80211_STYPE_ASSOC_RESP: + ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 0); + break; + case IEEE80211_STYPE_REASSOC_RESP: + ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt, skb->len, 1); + break; + case IEEE80211_STYPE_DEAUTH: + ieee80211_rx_mgmt_deauth(dev, ifsta, mgmt, skb->len); + break; + case IEEE80211_STYPE_DISASSOC: + ieee80211_rx_mgmt_disassoc(dev, ifsta, mgmt, skb->len); + break; + case IEEE80211_STYPE_ACTION: + ieee80211_rx_mgmt_action(dev, ifsta, mgmt, skb->len, rx_status); + break; + } + + kfree_skb(skb); +} + + +ieee80211_rx_result +ieee80211_sta_rx_scan(struct net_device *dev, struct sk_buff *skb, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_mgmt *mgmt; + u16 fc; + + if (skb->len < 2) + return RX_DROP_UNUSABLE; + + mgmt = (struct ieee80211_mgmt *) skb->data; + fc = le16_to_cpu(mgmt->frame_control); + + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_CTL) + return RX_CONTINUE; + + if (skb->len < 24) + return RX_DROP_MONITOR; + + if ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) { + if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_PROBE_RESP) { + ieee80211_rx_mgmt_probe_resp(dev, mgmt, + skb->len, rx_status); + dev_kfree_skb(skb); + return RX_QUEUED; + } else if ((fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON) { + ieee80211_rx_mgmt_beacon(dev, mgmt, skb->len, + rx_status); + dev_kfree_skb(skb); + return RX_QUEUED; + } + } + return RX_CONTINUE; +} + + +static int ieee80211_sta_active_ibss(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + int active = 0; + struct sta_info *sta; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + rcu_read_lock(); + + list_for_each_entry_rcu(sta, &local->sta_list, list) { + if (sta->sdata == sdata && + time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL, + jiffies)) { + active++; + break; + } + } + + rcu_read_unlock(); + + return active; +} + + +static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta, *tmp; + LIST_HEAD(tmp_list); + DECLARE_MAC_BUF(mac); + unsigned long flags; + + spin_lock_irqsave(&local->sta_lock, flags); + list_for_each_entry_safe(sta, tmp, &local->sta_list, list) + if (time_after(jiffies, sta->last_rx + exp_time)) { + printk(KERN_DEBUG "%s: expiring inactive STA %s\n", + dev->name, print_mac(mac, sta->addr)); + __sta_info_unlink(&sta); + if (sta) + list_add(&sta->list, &tmp_list); + } + spin_unlock_irqrestore(&local->sta_lock, flags); + + list_for_each_entry_safe(sta, tmp, &tmp_list, list) + sta_info_destroy(sta); +} + + +static void ieee80211_sta_merge_ibss(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL); + + ieee80211_sta_expire(dev, IEEE80211_IBSS_INACTIVITY_LIMIT); + if (ieee80211_sta_active_ibss(dev)) + return; + + printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other " + "IBSS networks with same SSID (merge)\n", dev->name); + ieee80211_sta_req_scan(dev, ifsta->ssid, ifsta->ssid_len); +} + + +#ifdef CONFIG_MAC80211_MESH +static void ieee80211_mesh_housekeeping(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + bool free_plinks; + + ieee80211_sta_expire(dev, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); + mesh_path_expire(dev); + + free_plinks = mesh_plink_availables(sdata); + if (free_plinks != sdata->u.sta.accepting_plinks) + ieee80211_if_config_beacon(dev); + + mod_timer(&ifsta->timer, jiffies + + IEEE80211_MESH_HOUSEKEEPING_INTERVAL); +} + + +void ieee80211_start_mesh(struct net_device *dev) +{ + struct ieee80211_if_sta *ifsta; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + ifsta = &sdata->u.sta; + ifsta->state = IEEE80211_MESH_UP; + ieee80211_sta_timer((unsigned long)sdata); +} +#endif + + +void ieee80211_sta_timer(unsigned long data) +{ + struct ieee80211_sub_if_data *sdata = + (struct ieee80211_sub_if_data *) data; + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct ieee80211_local *local = wdev_priv(&sdata->wdev); + + set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); + queue_work(local->hw.workqueue, &ifsta->work); +} + +void ieee80211_sta_work(struct work_struct *work) +{ + struct ieee80211_sub_if_data *sdata = + container_of(work, struct ieee80211_sub_if_data, u.sta.work); + struct net_device *dev = sdata->dev; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_if_sta *ifsta; + struct sk_buff *skb; + + if (!netif_running(dev)) + return; + + if (local->sta_sw_scanning || local->sta_hw_scanning) + return; + + if (sdata->vif.type != IEEE80211_IF_TYPE_STA && + sdata->vif.type != IEEE80211_IF_TYPE_IBSS && + sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT) { + printk(KERN_DEBUG "%s: ieee80211_sta_work: non-STA interface " + "(type=%d)\n", dev->name, sdata->vif.type); + return; + } + ifsta = &sdata->u.sta; + + while ((skb = skb_dequeue(&ifsta->skb_queue))) + ieee80211_sta_rx_queued_mgmt(dev, skb); + +#ifdef CONFIG_MAC80211_MESH + if (ifsta->preq_queue_len && + time_after(jiffies, + ifsta->last_preq + msecs_to_jiffies(ifsta->mshcfg.dot11MeshHWMPpreqMinInterval))) + mesh_path_start_discovery(dev); +#endif + + if (ifsta->state != IEEE80211_AUTHENTICATE && + ifsta->state != IEEE80211_ASSOCIATE && + test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) { + if (ifsta->scan_ssid_len) + ieee80211_sta_start_scan(dev, ifsta->scan_ssid, ifsta->scan_ssid_len); + else + ieee80211_sta_start_scan(dev, NULL, 0); + return; + } + + if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) { + if (ieee80211_sta_config_auth(dev, ifsta)) + return; + clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request); + } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request)) + return; + + switch (ifsta->state) { + case IEEE80211_DISABLED: + break; + case IEEE80211_AUTHENTICATE: + ieee80211_authenticate(dev, ifsta); + break; + case IEEE80211_ASSOCIATE: + ieee80211_associate(dev, ifsta); + break; + case IEEE80211_ASSOCIATED: + ieee80211_associated(dev, ifsta); + break; + case IEEE80211_IBSS_SEARCH: + ieee80211_sta_find_ibss(dev, ifsta); + break; + case IEEE80211_IBSS_JOINED: + ieee80211_sta_merge_ibss(dev, ifsta); + break; +#ifdef CONFIG_MAC80211_MESH + case IEEE80211_MESH_UP: + ieee80211_mesh_housekeeping(dev, ifsta); + break; +#endif + default: + printk(KERN_DEBUG "ieee80211_sta_work: Unknown state %d\n", + ifsta->state); + break; + } + + if (ieee80211_privacy_mismatch(dev, ifsta)) { + printk(KERN_DEBUG "%s: privacy configuration mismatch and " + "mixed-cell disabled - disassociate\n", dev->name); + + ieee80211_send_disassoc(dev, ifsta, WLAN_REASON_UNSPECIFIED); + ieee80211_set_disassoc(dev, ifsta, 0); + } +} + + +static void ieee80211_sta_reset_auth(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + if (local->ops->reset_tsf) { + /* Reset own TSF to allow time synchronization work. */ + local->ops->reset_tsf(local_to_hw(local)); + } + + ifsta->wmm_last_param_set = -1; /* allow any WMM update */ + + + if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN) + ifsta->auth_alg = WLAN_AUTH_OPEN; + else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY) + ifsta->auth_alg = WLAN_AUTH_SHARED_KEY; + else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP) + ifsta->auth_alg = WLAN_AUTH_LEAP; + else + ifsta->auth_alg = WLAN_AUTH_OPEN; + printk(KERN_DEBUG "%s: Initial auth_alg=%d\n", dev->name, + ifsta->auth_alg); + ifsta->auth_transaction = -1; + ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; + ifsta->auth_tries = ifsta->assoc_tries = 0; + netif_carrier_off(dev); +} + + +void ieee80211_sta_req_auth(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) + return; + + if ((ifsta->flags & (IEEE80211_STA_BSSID_SET | + IEEE80211_STA_AUTO_BSSID_SEL)) && + (ifsta->flags & (IEEE80211_STA_SSID_SET | + IEEE80211_STA_AUTO_SSID_SEL))) { + set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); + queue_work(local->hw.workqueue, &ifsta->work); + } +} + +static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, + const char *ssid, int ssid_len) +{ + int tmp, hidden_ssid; + + if (ssid_len == ifsta->ssid_len && + !memcmp(ifsta->ssid, ssid, ssid_len)) + return 1; + + if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) + return 0; + + hidden_ssid = 1; + tmp = ssid_len; + while (tmp--) { + if (ssid[tmp] != '\0') { + hidden_ssid = 0; + break; + } + } + + if (hidden_ssid && ifsta->ssid_len == ssid_len) + return 1; + + if (ssid_len == 1 && ssid[0] == ' ') + return 1; + + return 0; +} + +static int ieee80211_sta_config_auth(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sta_bss *bss, *selected = NULL; + int top_rssi = 0, freq; + + if (!(ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL | + IEEE80211_STA_AUTO_BSSID_SEL | IEEE80211_STA_AUTO_CHANNEL_SEL))) { + ifsta->state = IEEE80211_AUTHENTICATE; + ieee80211_sta_reset_auth(dev, ifsta); + return 0; + } + + spin_lock_bh(&local->sta_bss_lock); + freq = local->oper_channel->center_freq; + list_for_each_entry(bss, &local->sta_bss_list, list) { + if (!(bss->capability & WLAN_CAPABILITY_ESS)) + continue; + + if (!!(bss->capability & WLAN_CAPABILITY_PRIVACY) ^ + !!sdata->default_key) + continue; + + if (!(ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL) && + bss->freq != freq) + continue; + + if (!(ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL) && + memcmp(bss->bssid, ifsta->bssid, ETH_ALEN)) + continue; + + if (!(ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) && + !ieee80211_sta_match_ssid(ifsta, bss->ssid, bss->ssid_len)) + continue; + + if (!selected || top_rssi < bss->rssi) { + selected = bss; + top_rssi = bss->rssi; + } + } + if (selected) + atomic_inc(&selected->users); + spin_unlock_bh(&local->sta_bss_lock); + + if (selected) { + ieee80211_set_freq(local, selected->freq); + if (!(ifsta->flags & IEEE80211_STA_SSID_SET)) + ieee80211_sta_set_ssid(dev, selected->ssid, + selected->ssid_len); + ieee80211_sta_set_bssid(dev, selected->bssid); + ieee80211_sta_def_wmm_params(dev, selected, 0); + ieee80211_rx_bss_put(dev, selected); + ifsta->state = IEEE80211_AUTHENTICATE; + ieee80211_sta_reset_auth(dev, ifsta); + return 0; + } else { + if (ifsta->state != IEEE80211_AUTHENTICATE) { + if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) + ieee80211_sta_start_scan(dev, NULL, 0); + else + ieee80211_sta_start_scan(dev, ifsta->ssid, + ifsta->ssid_len); + ifsta->state = IEEE80211_AUTHENTICATE; + set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request); + } else + ifsta->state = IEEE80211_DISABLED; + } + return -1; +} + + +static int ieee80211_sta_create_ibss(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sta_bss *bss; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_supported_band *sband; + u8 bssid[ETH_ALEN], *pos; + int i; + DECLARE_MAC_BUF(mac); + +#if 0 + /* Easier testing, use fixed BSSID. */ + memset(bssid, 0xfe, ETH_ALEN); +#else + /* Generate random, not broadcast, locally administered BSSID. Mix in + * own MAC address to make sure that devices that do not have proper + * random number generator get different BSSID. */ + get_random_bytes(bssid, ETH_ALEN); + for (i = 0; i < ETH_ALEN; i++) + bssid[i] ^= dev->dev_addr[i]; + bssid[0] &= ~0x01; + bssid[0] |= 0x02; +#endif + + printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", + dev->name, print_mac(mac, bssid)); + + bss = ieee80211_rx_bss_add(dev, bssid, + local->hw.conf.channel->center_freq, + sdata->u.sta.ssid, sdata->u.sta.ssid_len); + if (!bss) + return -ENOMEM; + + bss->band = local->hw.conf.channel->band; + sband = local->hw.wiphy->bands[bss->band]; + + if (local->hw.conf.beacon_int == 0) + local->hw.conf.beacon_int = 10000; + bss->beacon_int = local->hw.conf.beacon_int; + bss->last_update = jiffies; + bss->capability = WLAN_CAPABILITY_IBSS; + if (sdata->default_key) { + bss->capability |= WLAN_CAPABILITY_PRIVACY; + } else + sdata->drop_unencrypted = 0; + bss->supp_rates_len = sband->n_bitrates; + pos = bss->supp_rates; + for (i = 0; i < sband->n_bitrates; i++) { + int rate = sband->bitrates[i].bitrate; + *pos++ = (u8) (rate / 5); + } + + return ieee80211_sta_join_ibss(dev, ifsta, bss); +} + + +static int ieee80211_sta_find_ibss(struct net_device *dev, + struct ieee80211_if_sta *ifsta) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sta_bss *bss; + int found = 0; + u8 bssid[ETH_ALEN]; + int active_ibss; + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); + + if (ifsta->ssid_len == 0) + return -EINVAL; + + active_ibss = ieee80211_sta_active_ibss(dev); +#ifdef CONFIG_MAC80211_IBSS_DEBUG + printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n", + dev->name, active_ibss); +#endif /* CONFIG_MAC80211_IBSS_DEBUG */ + spin_lock_bh(&local->sta_bss_lock); + list_for_each_entry(bss, &local->sta_bss_list, list) { + if (ifsta->ssid_len != bss->ssid_len || + memcmp(ifsta->ssid, bss->ssid, bss->ssid_len) != 0 + || !(bss->capability & WLAN_CAPABILITY_IBSS)) + continue; +#ifdef CONFIG_MAC80211_IBSS_DEBUG + printk(KERN_DEBUG " bssid=%s found\n", + print_mac(mac, bss->bssid)); +#endif /* CONFIG_MAC80211_IBSS_DEBUG */ + memcpy(bssid, bss->bssid, ETH_ALEN); + found = 1; + if (active_ibss || memcmp(bssid, ifsta->bssid, ETH_ALEN) != 0) + break; + } + spin_unlock_bh(&local->sta_bss_lock); + +#ifdef CONFIG_MAC80211_IBSS_DEBUG + printk(KERN_DEBUG " sta_find_ibss: selected %s current " + "%s\n", print_mac(mac, bssid), print_mac(mac2, ifsta->bssid)); +#endif /* CONFIG_MAC80211_IBSS_DEBUG */ + if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0 && + (bss = ieee80211_rx_bss_get(dev, bssid, + local->hw.conf.channel->center_freq, + ifsta->ssid, ifsta->ssid_len))) { + printk(KERN_DEBUG "%s: Selected IBSS BSSID %s" + " based on configured SSID\n", + dev->name, print_mac(mac, bssid)); + return ieee80211_sta_join_ibss(dev, ifsta, bss); + } +#ifdef CONFIG_MAC80211_IBSS_DEBUG + printk(KERN_DEBUG " did not try to join ibss\n"); +#endif /* CONFIG_MAC80211_IBSS_DEBUG */ + + /* Selected IBSS not found in current scan results - try to scan */ + if (ifsta->state == IEEE80211_IBSS_JOINED && + !ieee80211_sta_active_ibss(dev)) { + mod_timer(&ifsta->timer, jiffies + + IEEE80211_IBSS_MERGE_INTERVAL); + } else if (time_after(jiffies, local->last_scan_completed + + IEEE80211_SCAN_INTERVAL)) { + printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " + "join\n", dev->name); + return ieee80211_sta_req_scan(dev, ifsta->ssid, + ifsta->ssid_len); + } else if (ifsta->state != IEEE80211_IBSS_JOINED) { + int interval = IEEE80211_SCAN_INTERVAL; + + if (time_after(jiffies, ifsta->ibss_join_req + + IEEE80211_IBSS_JOIN_TIMEOUT)) { + if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) && + (!(local->oper_channel->flags & + IEEE80211_CHAN_NO_IBSS))) + return ieee80211_sta_create_ibss(dev, ifsta); + if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) { + printk(KERN_DEBUG "%s: IBSS not allowed on" + " %d MHz\n", dev->name, + local->hw.conf.channel->center_freq); + } + + /* No IBSS found - decrease scan interval and continue + * scanning. */ + interval = IEEE80211_SCAN_INTERVAL_SLOW; + } + + ifsta->state = IEEE80211_IBSS_SEARCH; + mod_timer(&ifsta->timer, jiffies + interval); + return 0; + } + + return 0; +} + + +int ieee80211_sta_set_ssid(struct net_device *dev, char *ssid, size_t len) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta; + + if (len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; + + ifsta = &sdata->u.sta; + + if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) + ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; + memcpy(ifsta->ssid, ssid, len); + memset(ifsta->ssid + len, 0, IEEE80211_MAX_SSID_LEN - len); + ifsta->ssid_len = len; + + if (len) + ifsta->flags |= IEEE80211_STA_SSID_SET; + else + ifsta->flags &= ~IEEE80211_STA_SSID_SET; + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && + !(ifsta->flags & IEEE80211_STA_BSSID_SET)) { + ifsta->ibss_join_req = jiffies; + ifsta->state = IEEE80211_IBSS_SEARCH; + return ieee80211_sta_find_ibss(dev, ifsta); + } + return 0; +} + + +int ieee80211_sta_get_ssid(struct net_device *dev, char *ssid, size_t *len) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + memcpy(ssid, ifsta->ssid, ifsta->ssid_len); + *len = ifsta->ssid_len; + return 0; +} + + +int ieee80211_sta_set_bssid(struct net_device *dev, u8 *bssid) +{ + struct ieee80211_sub_if_data *sdata; + struct ieee80211_if_sta *ifsta; + int res; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + ifsta = &sdata->u.sta; + + if (memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { + memcpy(ifsta->bssid, bssid, ETH_ALEN); + res = ieee80211_if_config(dev); + if (res) { + printk(KERN_DEBUG "%s: Failed to config new BSSID to " + "the low-level driver\n", dev->name); + return res; + } + } + + if (is_valid_ether_addr(bssid)) + ifsta->flags |= IEEE80211_STA_BSSID_SET; + else + ifsta->flags &= ~IEEE80211_STA_BSSID_SET; + + return 0; +} + + +static void ieee80211_send_nullfunc(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + int powersave) +{ + struct sk_buff *skb; + struct ieee80211_hdr *nullfunc; + u16 fc; + + skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc " + "frame\n", sdata->dev->name); + return; + } + skb_reserve(skb, local->hw.extra_tx_headroom); + + nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24); + memset(nullfunc, 0, 24); + fc = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC | + IEEE80211_FCTL_TODS; + if (powersave) + fc |= IEEE80211_FCTL_PM; + nullfunc->frame_control = cpu_to_le16(fc); + memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN); + memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN); + memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN); + + ieee80211_sta_tx(sdata->dev, skb, 0); +} + + +static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata) +{ + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + ieee80211_vif_is_mesh(&sdata->vif)) + ieee80211_sta_timer((unsigned long)sdata); +} + +void ieee80211_scan_completed(struct ieee80211_hw *hw) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct net_device *dev = local->scan_dev; + struct ieee80211_sub_if_data *sdata; + union iwreq_data wrqu; + + local->last_scan_completed = jiffies; + memset(&wrqu, 0, sizeof(wrqu)); + wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + + if (local->sta_hw_scanning) { + local->sta_hw_scanning = 0; + if (ieee80211_hw_config(local)) + printk(KERN_DEBUG "%s: failed to restore operational " + "channel after scan\n", dev->name); + /* Restart STA timer for HW scan case */ + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) + ieee80211_restart_sta_timer(sdata); + rcu_read_unlock(); + + goto done; + } + + local->sta_sw_scanning = 0; + if (ieee80211_hw_config(local)) + printk(KERN_DEBUG "%s: failed to restore operational " + "channel after scan\n", dev->name); + + + netif_tx_lock_bh(local->mdev); + local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC; + local->ops->configure_filter(local_to_hw(local), + FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); + + netif_tx_unlock_bh(local->mdev); + + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + + /* No need to wake the master device. */ + if (sdata->dev == local->mdev) + continue; + + /* Tell AP we're back */ + if (sdata->vif.type == IEEE80211_IF_TYPE_STA && + sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) + ieee80211_send_nullfunc(local, sdata, 0); + + ieee80211_restart_sta_timer(sdata); + + netif_wake_queue(sdata->dev); + } + rcu_read_unlock(); + +done: + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + if (!(ifsta->flags & IEEE80211_STA_BSSID_SET) || + (!ifsta->state == IEEE80211_IBSS_JOINED && + !ieee80211_sta_active_ibss(dev))) + ieee80211_sta_find_ibss(dev, ifsta); + } +} +EXPORT_SYMBOL(ieee80211_scan_completed); + +void ieee80211_sta_scan_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, scan_work.work); + struct net_device *dev = local->scan_dev; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_supported_band *sband; + struct ieee80211_channel *chan; + int skip; + unsigned long next_delay = 0; + + if (!local->sta_sw_scanning) + return; + + switch (local->scan_state) { + case SCAN_SET_CHANNEL: + /* + * Get current scan band. scan_band may be IEEE80211_NUM_BANDS + * after we successfully scanned the last channel of the last + * band (and the last band is supported by the hw) + */ + if (local->scan_band < IEEE80211_NUM_BANDS) + sband = local->hw.wiphy->bands[local->scan_band]; + else + sband = NULL; + + /* + * If we are at an unsupported band and have more bands + * left to scan, advance to the next supported one. + */ + while (!sband && local->scan_band < IEEE80211_NUM_BANDS - 1) { + local->scan_band++; + sband = local->hw.wiphy->bands[local->scan_band]; + local->scan_channel_idx = 0; + } + + /* if no more bands/channels left, complete scan */ + if (!sband || local->scan_channel_idx >= sband->n_channels) { + ieee80211_scan_completed(local_to_hw(local)); + return; + } + skip = 0; + chan = &sband->channels[local->scan_channel_idx]; + + if (chan->flags & IEEE80211_CHAN_DISABLED || + (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && + chan->flags & IEEE80211_CHAN_NO_IBSS)) + skip = 1; + + if (!skip) { + local->scan_channel = chan; + if (ieee80211_hw_config(local)) { + printk(KERN_DEBUG "%s: failed to set freq to " + "%d MHz for scan\n", dev->name, + chan->center_freq); + skip = 1; + } + } + + /* advance state machine to next channel/band */ + local->scan_channel_idx++; + if (local->scan_channel_idx >= sband->n_channels) { + /* + * scan_band may end up == IEEE80211_NUM_BANDS, but + * we'll catch that case above and complete the scan + * if that is the case. + */ + local->scan_band++; + local->scan_channel_idx = 0; + } + + if (skip) + break; + + next_delay = IEEE80211_PROBE_DELAY + + usecs_to_jiffies(local->hw.channel_change_time); + local->scan_state = SCAN_SEND_PROBE; + break; + case SCAN_SEND_PROBE: + next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + local->scan_state = SCAN_SET_CHANNEL; + + if (local->scan_channel->flags & IEEE80211_CHAN_PASSIVE_SCAN) + break; + ieee80211_send_probe_req(dev, NULL, local->scan_ssid, + local->scan_ssid_len); + next_delay = IEEE80211_CHANNEL_TIME; + break; + } + + if (local->sta_sw_scanning) + queue_delayed_work(local->hw.workqueue, &local->scan_work, + next_delay); +} + + +static int ieee80211_sta_start_scan(struct net_device *dev, + u8 *ssid, size_t ssid_len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata; + + if (ssid_len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; + + /* MLME-SCAN.request (page 118) page 144 (11.1.3.1) + * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS + * BSSID: MACAddress + * SSID + * ScanType: ACTIVE, PASSIVE + * ProbeDelay: delay (in microseconds) to be used prior to transmitting + * a Probe frame during active scanning + * ChannelList + * MinChannelTime (>= ProbeDelay), in TU + * MaxChannelTime: (>= MinChannelTime), in TU + */ + + /* MLME-SCAN.confirm + * BSSDescriptionSet + * ResultCode: SUCCESS, INVALID_PARAMETERS + */ + + if (local->sta_sw_scanning || local->sta_hw_scanning) { + if (local->scan_dev == dev) + return 0; + return -EBUSY; + } + + if (local->ops->hw_scan) { + int rc = local->ops->hw_scan(local_to_hw(local), + ssid, ssid_len); + if (!rc) { + local->sta_hw_scanning = 1; + local->scan_dev = dev; + } + return rc; + } + + local->sta_sw_scanning = 1; + + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + + /* Don't stop the master interface, otherwise we can't transmit + * probes! */ + if (sdata->dev == local->mdev) + continue; + + netif_stop_queue(sdata->dev); + if (sdata->vif.type == IEEE80211_IF_TYPE_STA && + (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED)) + ieee80211_send_nullfunc(local, sdata, 1); + } + rcu_read_unlock(); + + if (ssid) { + local->scan_ssid_len = ssid_len; + memcpy(local->scan_ssid, ssid, ssid_len); + } else + local->scan_ssid_len = 0; + local->scan_state = SCAN_SET_CHANNEL; + local->scan_channel_idx = 0; + local->scan_band = IEEE80211_BAND_2GHZ; + local->scan_dev = dev; + + netif_tx_lock_bh(local->mdev); + local->filter_flags |= FIF_BCN_PRBRESP_PROMISC; + local->ops->configure_filter(local_to_hw(local), + FIF_BCN_PRBRESP_PROMISC, + &local->filter_flags, + local->mdev->mc_count, + local->mdev->mc_list); + netif_tx_unlock_bh(local->mdev); + + /* TODO: start scan as soon as all nullfunc frames are ACKed */ + queue_delayed_work(local->hw.workqueue, &local->scan_work, + IEEE80211_CHANNEL_TIME); + + return 0; +} + + +int ieee80211_sta_req_scan(struct net_device *dev, u8 *ssid, size_t ssid_len) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) + return ieee80211_sta_start_scan(dev, ssid, ssid_len); + + if (local->sta_sw_scanning || local->sta_hw_scanning) { + if (local->scan_dev == dev) + return 0; + return -EBUSY; + } + + ifsta->scan_ssid_len = ssid_len; + if (ssid_len) + memcpy(ifsta->scan_ssid, ssid, ssid_len); + set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request); + queue_work(local->hw.workqueue, &ifsta->work); + return 0; +} + +static char * +ieee80211_sta_scan_result(struct net_device *dev, + struct ieee80211_sta_bss *bss, + char *current_ev, char *end_buf) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct iw_event iwe; + + if (time_after(jiffies, + bss->last_update + IEEE80211_SCAN_RESULT_EXPIRE)) + return current_ev; + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, bss->bssid, ETH_ALEN); + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_ADDR_LEN); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWESSID; + if (bss_mesh_cfg(bss)) { + iwe.u.data.length = bss_mesh_id_len(bss); + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + bss_mesh_id(bss)); + } else { + iwe.u.data.length = bss->ssid_len; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + bss->ssid); + } + + if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) + || bss_mesh_cfg(bss)) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWMODE; + if (bss_mesh_cfg(bss)) + iwe.u.mode = IW_MODE_MESH; + else if (bss->capability & WLAN_CAPABILITY_ESS) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_ADHOC; + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_UINT_LEN); + } + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = bss->freq; + iwe.u.freq.e = 6; + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_FREQ_LEN); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = ieee80211_frequency_to_channel(bss->freq); + iwe.u.freq.e = 0; + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_FREQ_LEN); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVQUAL; + iwe.u.qual.qual = bss->signal; + iwe.u.qual.level = bss->rssi; + iwe.u.qual.noise = bss->noise; + iwe.u.qual.updated = local->wstats_flags; + current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, + IW_EV_QUAL_LEN); + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWENCODE; + if (bss->capability & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, ""); + + if (bss && bss->wpa_ie) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = bss->wpa_ie_len; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + bss->wpa_ie); + } + + if (bss && bss->rsn_ie) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = bss->rsn_ie_len; + current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, + bss->rsn_ie); + } + + if (bss && bss->supp_rates_len > 0) { + /* display all supported rates in readable format */ + char *p = current_ev + IW_EV_LCP_LEN; + int i; + + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = SIOCGIWRATE; + /* Those two flags are ignored... */ + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + + for (i = 0; i < bss->supp_rates_len; i++) { + iwe.u.bitrate.value = ((bss->supp_rates[i] & + 0x7f) * 500000); + p = iwe_stream_add_value(current_ev, p, + end_buf, &iwe, IW_EV_PARAM_LEN); + } + current_ev = p; + } + + if (bss) { + char *buf; + buf = kmalloc(30, GFP_ATOMIC); + if (buf) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "tsf=%016llx", (unsigned long long)(bss->timestamp)); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + kfree(buf); + } + } + + if (bss_mesh_cfg(bss)) { + char *buf; + u8 *cfg = bss_mesh_cfg(bss); + buf = kmalloc(50, GFP_ATOMIC); + if (buf) { + memset(&iwe, 0, sizeof(iwe)); + iwe.cmd = IWEVCUSTOM; + sprintf(buf, "Mesh network (version %d)", cfg[0]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + sprintf(buf, "Path Selection Protocol ID: " + "0x%02X%02X%02X%02X", cfg[1], cfg[2], cfg[3], + cfg[4]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + sprintf(buf, "Path Selection Metric ID: " + "0x%02X%02X%02X%02X", cfg[5], cfg[6], cfg[7], + cfg[8]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + sprintf(buf, "Congestion Control Mode ID: " + "0x%02X%02X%02X%02X", cfg[9], cfg[10], + cfg[11], cfg[12]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + sprintf(buf, "Channel Precedence: " + "0x%02X%02X%02X%02X", cfg[13], cfg[14], + cfg[15], cfg[16]); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + kfree(buf); + } + } + + return current_ev; +} + + +int ieee80211_sta_scan_results(struct net_device *dev, char *buf, size_t len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + char *current_ev = buf; + char *end_buf = buf + len; + struct ieee80211_sta_bss *bss; + + spin_lock_bh(&local->sta_bss_lock); + list_for_each_entry(bss, &local->sta_bss_list, list) { + if (buf + len - current_ev <= IW_EV_ADDR_LEN) { + spin_unlock_bh(&local->sta_bss_lock); + return -E2BIG; + } + current_ev = ieee80211_sta_scan_result(dev, bss, current_ev, + end_buf); + } + spin_unlock_bh(&local->sta_bss_lock); + return current_ev - buf; +} + + +int ieee80211_sta_set_extra_ie(struct net_device *dev, char *ie, size_t len) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + kfree(ifsta->extra_ie); + if (len == 0) { + ifsta->extra_ie = NULL; + ifsta->extra_ie_len = 0; + return 0; + } + ifsta->extra_ie = kmalloc(len, GFP_KERNEL); + if (!ifsta->extra_ie) { + ifsta->extra_ie_len = 0; + return -ENOMEM; + } + memcpy(ifsta->extra_ie, ie, len); + ifsta->extra_ie_len = len; + return 0; +} + + +struct sta_info * ieee80211_ibss_add_sta(struct net_device *dev, + struct sk_buff *skb, u8 *bssid, + u8 *addr) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + DECLARE_MAC_BUF(mac); + + /* TODO: Could consider removing the least recently used entry and + * allow new one to be added. */ + if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: No room for a new IBSS STA " + "entry %s\n", dev->name, print_mac(mac, addr)); + } + return NULL; + } + + printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", + wiphy_name(local->hw.wiphy), print_mac(mac, addr), dev->name); + + sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); + if (!sta) + return NULL; + + sta->flags |= WLAN_STA_AUTHORIZED; + + sta->supp_rates[local->hw.conf.channel->band] = + sdata->u.sta.supp_rates_bits[local->hw.conf.channel->band]; + + rate_control_rate_init(sta, local); + + if (sta_info_insert(sta)) + return NULL; + + return sta; +} + + +int ieee80211_sta_deauthenticate(struct net_device *dev, u16 reason) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + + printk(KERN_DEBUG "%s: deauthenticate(reason=%d)\n", + dev->name, reason); + + if (sdata->vif.type != IEEE80211_IF_TYPE_STA && + sdata->vif.type != IEEE80211_IF_TYPE_IBSS) + return -EINVAL; + + ieee80211_send_deauth(dev, ifsta, reason); + ieee80211_set_disassoc(dev, ifsta, 1); + return 0; +} + + +int ieee80211_sta_disassociate(struct net_device *dev, u16 reason) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_if_sta *ifsta = &sdata->u.sta; + + printk(KERN_DEBUG "%s: disassociate(reason=%d)\n", + dev->name, reason); + + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) + return -EINVAL; + + if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED)) + return -1; + + ieee80211_send_disassoc(dev, ifsta, reason); + ieee80211_set_disassoc(dev, ifsta, 0); + return 0; +} + +void ieee80211_notify_mac(struct ieee80211_hw *hw, + enum ieee80211_notification_types notif_type) +{ + struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_sub_if_data *sdata; + + switch (notif_type) { + case IEEE80211_NOTIFY_RE_ASSOC: + rcu_read_lock(); + list_for_each_entry_rcu(sdata, &local->interfaces, list) { + + if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { + ieee80211_sta_req_auth(sdata->dev, + &sdata->u.sta); + } + + } + rcu_read_unlock(); + break; + } +} +EXPORT_SYMBOL(ieee80211_notify_mac); diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c new file mode 100644 index 000000000000..841df93807fc --- /dev/null +++ b/net/mac80211/rate.c @@ -0,0 +1,249 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright (c) 2006 Jiri Benc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include "rate.h" +#include "ieee80211_i.h" + +struct rate_control_alg { + struct list_head list; + struct rate_control_ops *ops; +}; + +static LIST_HEAD(rate_ctrl_algs); +static DEFINE_MUTEX(rate_ctrl_mutex); + +static char *ieee80211_default_rc_algo = CONFIG_MAC80211_RC_DEFAULT; +module_param(ieee80211_default_rc_algo, charp, 0644); +MODULE_PARM_DESC(ieee80211_default_rc_algo, + "Default rate control algorithm for mac80211 to use"); + +int ieee80211_rate_control_register(struct rate_control_ops *ops) +{ + struct rate_control_alg *alg; + + if (!ops->name) + return -EINVAL; + + mutex_lock(&rate_ctrl_mutex); + list_for_each_entry(alg, &rate_ctrl_algs, list) { + if (!strcmp(alg->ops->name, ops->name)) { + /* don't register an algorithm twice */ + WARN_ON(1); + mutex_unlock(&rate_ctrl_mutex); + return -EALREADY; + } + } + + alg = kzalloc(sizeof(*alg), GFP_KERNEL); + if (alg == NULL) { + mutex_unlock(&rate_ctrl_mutex); + return -ENOMEM; + } + alg->ops = ops; + + list_add_tail(&alg->list, &rate_ctrl_algs); + mutex_unlock(&rate_ctrl_mutex); + + return 0; +} +EXPORT_SYMBOL(ieee80211_rate_control_register); + +void ieee80211_rate_control_unregister(struct rate_control_ops *ops) +{ + struct rate_control_alg *alg; + + mutex_lock(&rate_ctrl_mutex); + list_for_each_entry(alg, &rate_ctrl_algs, list) { + if (alg->ops == ops) { + list_del(&alg->list); + kfree(alg); + break; + } + } + mutex_unlock(&rate_ctrl_mutex); +} +EXPORT_SYMBOL(ieee80211_rate_control_unregister); + +static struct rate_control_ops * +ieee80211_try_rate_control_ops_get(const char *name) +{ + struct rate_control_alg *alg; + struct rate_control_ops *ops = NULL; + + if (!name) + return NULL; + + mutex_lock(&rate_ctrl_mutex); + list_for_each_entry(alg, &rate_ctrl_algs, list) { + if (!strcmp(alg->ops->name, name)) + if (try_module_get(alg->ops->module)) { + ops = alg->ops; + break; + } + } + mutex_unlock(&rate_ctrl_mutex); + return ops; +} + +/* Get the rate control algorithm. */ +static struct rate_control_ops * +ieee80211_rate_control_ops_get(const char *name) +{ + struct rate_control_ops *ops; + const char *alg_name; + + if (!name) + alg_name = ieee80211_default_rc_algo; + else + alg_name = name; + + ops = ieee80211_try_rate_control_ops_get(alg_name); + if (!ops) { + request_module("rc80211_%s", alg_name); + ops = ieee80211_try_rate_control_ops_get(alg_name); + } + if (!ops && name) + /* try default if specific alg requested but not found */ + ops = ieee80211_try_rate_control_ops_get(ieee80211_default_rc_algo); + + /* try built-in one if specific alg requested but not found */ + if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT)) + ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT); + + return ops; +} + +static void ieee80211_rate_control_ops_put(struct rate_control_ops *ops) +{ + module_put(ops->module); +} + +struct rate_control_ref *rate_control_alloc(const char *name, + struct ieee80211_local *local) +{ + struct rate_control_ref *ref; + + ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL); + if (!ref) + goto fail_ref; + kref_init(&ref->kref); + ref->ops = ieee80211_rate_control_ops_get(name); + if (!ref->ops) + goto fail_ops; + ref->priv = ref->ops->alloc(local); + if (!ref->priv) + goto fail_priv; + return ref; + +fail_priv: + ieee80211_rate_control_ops_put(ref->ops); +fail_ops: + kfree(ref); +fail_ref: + return NULL; +} + +static void rate_control_release(struct kref *kref) +{ + struct rate_control_ref *ctrl_ref; + + ctrl_ref = container_of(kref, struct rate_control_ref, kref); + ctrl_ref->ops->free(ctrl_ref->priv); + ieee80211_rate_control_ops_put(ctrl_ref->ops); + kfree(ctrl_ref); +} + +void rate_control_get_rate(struct net_device *dev, + struct ieee80211_supported_band *sband, + struct sk_buff *skb, + struct rate_selection *sel) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct rate_control_ref *ref = local->rate_ctrl; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct sta_info *sta; + int i; + + rcu_read_lock(); + sta = sta_info_get(local, hdr->addr1); + + memset(sel, 0, sizeof(struct rate_selection)); + + ref->ops->get_rate(ref->priv, dev, sband, skb, sel); + + /* Select a non-ERP backup rate. */ + if (!sel->nonerp) { + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *rate = &sband->bitrates[i]; + if (sel->rate->bitrate < rate->bitrate) + break; + + if (rate_supported(sta, sband->band, i) && + !(rate->flags & IEEE80211_RATE_ERP_G)) + sel->nonerp = rate; + } + } + + rcu_read_unlock(); +} + +struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) +{ + kref_get(&ref->kref); + return ref; +} + +void rate_control_put(struct rate_control_ref *ref) +{ + kref_put(&ref->kref, rate_control_release); +} + +int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, + const char *name) +{ + struct rate_control_ref *ref, *old; + + ASSERT_RTNL(); + if (local->open_count || netif_running(local->mdev)) + return -EBUSY; + + ref = rate_control_alloc(name, local); + if (!ref) { + printk(KERN_WARNING "%s: Failed to select rate control " + "algorithm\n", wiphy_name(local->hw.wiphy)); + return -ENOENT; + } + + old = local->rate_ctrl; + local->rate_ctrl = ref; + if (old) { + rate_control_put(old); + sta_info_flush(local, NULL); + } + + printk(KERN_DEBUG "%s: Selected rate control " + "algorithm '%s'\n", wiphy_name(local->hw.wiphy), + ref->ops->name); + + + return 0; +} + +void rate_control_deinitialize(struct ieee80211_local *local) +{ + struct rate_control_ref *ref; + + ref = local->rate_ctrl; + local->rate_ctrl = NULL; + rate_control_put(ref); +} + diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h new file mode 100644 index 000000000000..5b45f33cb766 --- /dev/null +++ b/net/mac80211/rate.h @@ -0,0 +1,189 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005, Devicescape Software, Inc. + * Copyright (c) 2006 Jiri Benc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef IEEE80211_RATE_H +#define IEEE80211_RATE_H + +#include +#include +#include +#include +#include +#include "ieee80211_i.h" +#include "sta_info.h" + +/* TODO: kdoc */ +struct rate_selection { + /* Selected transmission rate */ + struct ieee80211_rate *rate; + /* Non-ERP rate to use if mac80211 decides it cannot use an ERP rate */ + struct ieee80211_rate *nonerp; + /* probe with this rate, or NULL for no probing */ + struct ieee80211_rate *probe; +}; + +struct rate_control_ops { + struct module *module; + const char *name; + void (*tx_status)(void *priv, struct net_device *dev, + struct sk_buff *skb, + struct ieee80211_tx_status *status); + void (*get_rate)(void *priv, struct net_device *dev, + struct ieee80211_supported_band *band, + struct sk_buff *skb, + struct rate_selection *sel); + void (*rate_init)(void *priv, void *priv_sta, + struct ieee80211_local *local, struct sta_info *sta); + void (*clear)(void *priv); + + void *(*alloc)(struct ieee80211_local *local); + void (*free)(void *priv); + void *(*alloc_sta)(void *priv, gfp_t gfp); + void (*free_sta)(void *priv, void *priv_sta); + + int (*add_attrs)(void *priv, struct kobject *kobj); + void (*remove_attrs)(void *priv, struct kobject *kobj); + void (*add_sta_debugfs)(void *priv, void *priv_sta, + struct dentry *dir); + void (*remove_sta_debugfs)(void *priv, void *priv_sta); +}; + +struct rate_control_ref { + struct rate_control_ops *ops; + void *priv; + struct kref kref; +}; + +int ieee80211_rate_control_register(struct rate_control_ops *ops); +void ieee80211_rate_control_unregister(struct rate_control_ops *ops); + +/* Get a reference to the rate control algorithm. If `name' is NULL, get the + * first available algorithm. */ +struct rate_control_ref *rate_control_alloc(const char *name, + struct ieee80211_local *local); +void rate_control_get_rate(struct net_device *dev, + struct ieee80211_supported_band *sband, + struct sk_buff *skb, + struct rate_selection *sel); +struct rate_control_ref *rate_control_get(struct rate_control_ref *ref); +void rate_control_put(struct rate_control_ref *ref); + +static inline void rate_control_tx_status(struct net_device *dev, + struct sk_buff *skb, + struct ieee80211_tx_status *status) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct rate_control_ref *ref = local->rate_ctrl; + + ref->ops->tx_status(ref->priv, dev, skb, status); +} + + +static inline void rate_control_rate_init(struct sta_info *sta, + struct ieee80211_local *local) +{ + struct rate_control_ref *ref = sta->rate_ctrl; + ref->ops->rate_init(ref->priv, sta->rate_ctrl_priv, local, sta); +} + + +static inline void rate_control_clear(struct ieee80211_local *local) +{ + struct rate_control_ref *ref = local->rate_ctrl; + ref->ops->clear(ref->priv); +} + +static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, + gfp_t gfp) +{ + return ref->ops->alloc_sta(ref->priv, gfp); +} + +static inline void rate_control_free_sta(struct rate_control_ref *ref, + void *priv) +{ + ref->ops->free_sta(ref->priv, priv); +} + +static inline void rate_control_add_sta_debugfs(struct sta_info *sta) +{ +#ifdef CONFIG_MAC80211_DEBUGFS + struct rate_control_ref *ref = sta->rate_ctrl; + if (sta->debugfs.dir && ref->ops->add_sta_debugfs) + ref->ops->add_sta_debugfs(ref->priv, sta->rate_ctrl_priv, + sta->debugfs.dir); +#endif +} + +static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) +{ +#ifdef CONFIG_MAC80211_DEBUGFS + struct rate_control_ref *ref = sta->rate_ctrl; + if (ref->ops->remove_sta_debugfs) + ref->ops->remove_sta_debugfs(ref->priv, sta->rate_ctrl_priv); +#endif +} + +static inline int rate_supported(struct sta_info *sta, + enum ieee80211_band band, + int index) +{ + return (sta == NULL || sta->supp_rates[band] & BIT(index)); +} + +static inline int +rate_lowest_index(struct ieee80211_local *local, + struct ieee80211_supported_band *sband, + struct sta_info *sta) +{ + int i; + + for (i = 0; i < sband->n_bitrates; i++) + if (rate_supported(sta, sband->band, i)) + return i; + + /* warn when we cannot find a rate. */ + WARN_ON(1); + + return 0; +} + +static inline struct ieee80211_rate * +rate_lowest(struct ieee80211_local *local, + struct ieee80211_supported_band *sband, + struct sta_info *sta) +{ + return &sband->bitrates[rate_lowest_index(local, sband, sta)]; +} + + +/* functions for rate control related to a device */ +int ieee80211_init_rate_ctrl_alg(struct ieee80211_local *local, + const char *name); +void rate_control_deinitialize(struct ieee80211_local *local); + + +/* Rate control algorithms */ +#if defined(RC80211_PID_COMPILE) || \ + (defined(CONFIG_MAC80211_RC_PID) && \ + !defined(CONFIG_MAC80211_RC_PID_MODULE)) +extern int rc80211_pid_init(void); +extern void rc80211_pid_exit(void); +#else +static inline int rc80211_pid_init(void) +{ + return 0; +} +static inline void rc80211_pid_exit(void) +{ +} +#endif + +#endif /* IEEE80211_RATE_H */ diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index a1993161de99..a849b745bdb5 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -14,7 +14,7 @@ #include #include #include -#include "ieee80211_rate.h" +#include "rate.h" #include "mesh.h" #include "rc80211_pid.h" diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c index 88b8dc9999bb..ae75d4178739 100644 --- a/net/mac80211/rc80211_pid_debugfs.c +++ b/net/mac80211/rc80211_pid_debugfs.c @@ -13,7 +13,7 @@ #include #include -#include "ieee80211_rate.h" +#include "rate.h" #include "rc80211_pid.h" diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 0ac6db5c09ea..306eadb01fc4 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -19,7 +19,7 @@ #include #include "ieee80211_i.h" -#include "ieee80211_led.h" +#include "led.h" #include "mesh.h" #include "wep.h" #include "wpa.h" diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 5540cbf7c445..7d4fe4a52929 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -19,7 +19,7 @@ #include #include "ieee80211_i.h" -#include "ieee80211_rate.h" +#include "rate.h" #include "sta_info.h" #include "debugfs_sta.h" #include "mesh.h" diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 30fd328e9991..f8c95bc9659c 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -12,7 +12,7 @@ #include #include #include -#include "ieee80211_key.h" +#include "key.h" /** * enum ieee80211_sta_info_flags - Stations flags diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 45d59f19c29f..dddbfd60f351 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -12,7 +12,7 @@ #include #include -#include "ieee80211_key.h" +#include "key.h" #include "tkip.h" #include "wep.h" diff --git a/net/mac80211/tkip.h b/net/mac80211/tkip.h index ffaee3253e19..b7c2ee763d9d 100644 --- a/net/mac80211/tkip.h +++ b/net/mac80211/tkip.h @@ -11,7 +11,7 @@ #include #include -#include "ieee80211_key.h" +#include "key.h" u8 * ieee80211_tkip_add_iv(u8 *pos, struct ieee80211_key *key, u8 iv0, u8 iv1, u8 iv2); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ea3fa0f91906..f35eaea98e73 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -25,12 +25,12 @@ #include #include "ieee80211_i.h" -#include "ieee80211_led.h" +#include "led.h" #include "mesh.h" #include "wep.h" #include "wpa.h" #include "wme.h" -#include "ieee80211_rate.h" +#include "rate.h" #define IEEE80211_TX_OK 0 #define IEEE80211_TX_AGAIN 1 diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 57c404f3f6d0..cc9f715c7bfc 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -25,7 +25,7 @@ #include #include "ieee80211_i.h" -#include "ieee80211_rate.h" +#include "rate.h" #include "mesh.h" #include "wme.h" diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index 9f723938b63f..363779c50658 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -14,7 +14,7 @@ #include #include #include "ieee80211_i.h" -#include "ieee80211_key.h" +#include "key.h" int ieee80211_wep_init(struct ieee80211_local *local); void ieee80211_wep_free(struct ieee80211_local *local); diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c new file mode 100644 index 000000000000..69aed16faff3 --- /dev/null +++ b/net/mac80211/wext.c @@ -0,0 +1,1144 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ieee80211_i.h" +#include "led.h" +#include "rate.h" +#include "wpa.h" +#include "aes_ccm.h" + + +static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, + int idx, int alg, int remove, + int set_tx_key, const u8 *_key, + size_t key_len) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta; + struct ieee80211_key *key; + struct ieee80211_sub_if_data *sdata; + int err; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (idx < 0 || idx >= NUM_DEFAULT_KEYS) { + printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n", + dev->name, idx); + return -EINVAL; + } + + if (remove) { + rcu_read_lock(); + + err = 0; + + if (is_broadcast_ether_addr(sta_addr)) { + key = sdata->keys[idx]; + } else { + sta = sta_info_get(local, sta_addr); + if (!sta) { + err = -ENOENT; + goto out_unlock; + } + key = sta->key; + } + + ieee80211_key_free(key); + } else { + key = ieee80211_key_alloc(alg, idx, key_len, _key); + if (!key) + return -ENOMEM; + + sta = NULL; + err = 0; + + rcu_read_lock(); + + if (!is_broadcast_ether_addr(sta_addr)) { + set_tx_key = 0; + /* + * According to the standard, the key index of a + * pairwise key must be zero. However, some AP are + * broken when it comes to WEP key indices, so we + * work around this. + */ + if (idx != 0 && alg != ALG_WEP) { + ieee80211_key_free(key); + err = -EINVAL; + goto out_unlock; + } + + sta = sta_info_get(local, sta_addr); + if (!sta) { + ieee80211_key_free(key); + err = -ENOENT; + goto out_unlock; + } + } + + ieee80211_key_link(key, sdata, sta); + + if (set_tx_key || (!sta && !sdata->default_key && key)) + ieee80211_set_default_key(sdata, idx); + } + + out_unlock: + rcu_read_unlock(); + + return err; +} + +static int ieee80211_ioctl_siwgenie(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) + return -EOPNOTSUPP; + + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length); + if (ret) + return ret; + sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; + ieee80211_sta_req_auth(dev, &sdata->u.sta); + return 0; + } + + return -EOPNOTSUPP; +} + +static int ieee80211_ioctl_giwname(struct net_device *dev, + struct iw_request_info *info, + char *name, char *extra) +{ + strcpy(name, "IEEE 802.11"); + + return 0; +} + + +static int ieee80211_ioctl_giwrange(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct iw_range *range = (struct iw_range *) extra; + enum ieee80211_band band; + int c = 0; + + data->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 21; + range->retry_capa = IW_RETRY_LIMIT; + range->retry_flags = IW_RETRY_LIMIT; + range->min_retry = 0; + range->max_retry = 255; + range->min_rts = 0; + range->max_rts = 2347; + range->min_frag = 256; + range->max_frag = 2346; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = NUM_DEFAULT_KEYS; + + range->max_qual.qual = local->hw.max_signal; + range->max_qual.level = local->hw.max_rssi; + range->max_qual.noise = local->hw.max_noise; + range->max_qual.updated = local->wstats_flags; + + range->avg_qual.qual = local->hw.max_signal/2; + range->avg_qual.level = 0; + range->avg_qual.noise = 0; + range->avg_qual.updated = local->wstats_flags; + + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + + + for (band = 0; band < IEEE80211_NUM_BANDS; band ++) { + int i; + struct ieee80211_supported_band *sband; + + sband = local->hw.wiphy->bands[band]; + + if (!sband) + continue; + + for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) { + struct ieee80211_channel *chan = &sband->channels[i]; + + if (!(chan->flags & IEEE80211_CHAN_DISABLED)) { + range->freq[c].i = + ieee80211_frequency_to_channel( + chan->center_freq); + range->freq[c].m = chan->center_freq; + range->freq[c].e = 6; + c++; + } + } + } + range->num_channels = c; + range->num_frequency = c; + + IW_EVENT_CAPA_SET_KERNEL(range->event_capa); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); + + range->scan_capa |= IW_SCAN_CAPA_ESSID; + + return 0; +} + + +static int ieee80211_ioctl_siwmode(struct net_device *dev, + struct iw_request_info *info, + __u32 *mode, char *extra) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int type; + + if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN) + return -EOPNOTSUPP; + + switch (*mode) { + case IW_MODE_INFRA: + type = IEEE80211_IF_TYPE_STA; + break; + case IW_MODE_ADHOC: + type = IEEE80211_IF_TYPE_IBSS; + break; + case IW_MODE_MONITOR: + type = IEEE80211_IF_TYPE_MNTR; + break; + default: + return -EINVAL; + } + + if (type == sdata->vif.type) + return 0; + if (netif_running(dev)) + return -EBUSY; + + ieee80211_if_reinit(dev); + ieee80211_if_set_type(dev, type); + + return 0; +} + + +static int ieee80211_ioctl_giwmode(struct net_device *dev, + struct iw_request_info *info, + __u32 *mode, char *extra) +{ + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + switch (sdata->vif.type) { + case IEEE80211_IF_TYPE_AP: + *mode = IW_MODE_MASTER; + break; + case IEEE80211_IF_TYPE_STA: + *mode = IW_MODE_INFRA; + break; + case IEEE80211_IF_TYPE_IBSS: + *mode = IW_MODE_ADHOC; + break; + case IEEE80211_IF_TYPE_MNTR: + *mode = IW_MODE_MONITOR; + break; + case IEEE80211_IF_TYPE_WDS: + *mode = IW_MODE_REPEAT; + break; + case IEEE80211_IF_TYPE_VLAN: + *mode = IW_MODE_SECOND; /* FIXME */ + break; + default: + *mode = IW_MODE_AUTO; + break; + } + return 0; +} + +int ieee80211_set_freq(struct ieee80211_local *local, int freqMHz) +{ + int ret = -EINVAL; + struct ieee80211_channel *chan; + + chan = ieee80211_get_channel(local->hw.wiphy, freqMHz); + + if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { + local->oper_channel = chan; + + if (local->sta_sw_scanning || local->sta_hw_scanning) + ret = 0; + else + ret = ieee80211_hw_config(local); + + rate_control_clear(local); + } + + return ret; +} + +static int ieee80211_ioctl_siwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->vif.type == IEEE80211_IF_TYPE_STA) + sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL; + + /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */ + if (freq->e == 0) { + if (freq->m < 0) { + if (sdata->vif.type == IEEE80211_IF_TYPE_STA) + sdata->u.sta.flags |= + IEEE80211_STA_AUTO_CHANNEL_SEL; + return 0; + } else + return ieee80211_set_freq(local, + ieee80211_channel_to_frequency(freq->m)); + } else { + int i, div = 1000000; + for (i = 0; i < freq->e; i++) + div /= 10; + if (div > 0) + return ieee80211_set_freq(local, freq->m / div); + else + return -EINVAL; + } +} + + +static int ieee80211_ioctl_giwfreq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *freq, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + freq->m = local->hw.conf.channel->center_freq; + freq->e = 6; + + return 0; +} + + +static int ieee80211_ioctl_siwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + struct ieee80211_sub_if_data *sdata; + size_t len = data->length; + + /* iwconfig uses nul termination in SSID.. */ + if (len > 0 && ssid[len - 1] == '\0') + len--; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + int ret; + if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { + if (len > IEEE80211_MAX_SSID_LEN) + return -EINVAL; + memcpy(sdata->u.sta.ssid, ssid, len); + sdata->u.sta.ssid_len = len; + return 0; + } + if (data->flags) + sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL; + else + sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL; + ret = ieee80211_sta_set_ssid(dev, ssid, len); + if (ret) + return ret; + ieee80211_sta_req_auth(dev, &sdata->u.sta); + return 0; + } + + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { + memcpy(sdata->u.ap.ssid, ssid, len); + memset(sdata->u.ap.ssid + len, 0, + IEEE80211_MAX_SSID_LEN - len); + sdata->u.ap.ssid_len = len; + return ieee80211_if_config(dev); + } + return -EOPNOTSUPP; +} + + +static int ieee80211_ioctl_giwessid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *ssid) +{ + size_t len; + + struct ieee80211_sub_if_data *sdata; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + int res = ieee80211_sta_get_ssid(dev, ssid, &len); + if (res == 0) { + data->length = len; + data->flags = 1; + } else + data->flags = 0; + return res; + } + + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { + len = sdata->u.ap.ssid_len; + if (len > IW_ESSID_MAX_SIZE) + len = IW_ESSID_MAX_SIZE; + memcpy(ssid, sdata->u.ap.ssid, len); + data->length = len; + data->flags = 1; + return 0; + } + return -EOPNOTSUPP; +} + + +static int ieee80211_ioctl_siwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + int ret; + if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) { + memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data, + ETH_ALEN); + return 0; + } + if (is_zero_ether_addr((u8 *) &ap_addr->sa_data)) + sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL | + IEEE80211_STA_AUTO_CHANNEL_SEL; + else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data)) + sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL; + else + sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL; + ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data); + if (ret) + return ret; + ieee80211_sta_req_auth(dev, &sdata->u.sta); + return 0; + } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) { + /* + * If it is necessary to update the WDS peer address + * while the interface is running, then we need to do + * more work here, namely if it is running we need to + * add a new and remove the old STA entry, this is + * normally handled by _open() and _stop(). + */ + if (netif_running(dev)) + return -EBUSY; + + memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data, + ETH_ALEN); + + return 0; + } + + return -EOPNOTSUPP; +} + + +static int ieee80211_ioctl_giwap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *ap_addr, char *extra) +{ + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) { + ap_addr->sa_family = ARPHRD_ETHER; + memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN); + return 0; + } else if (sdata->vif.type == IEEE80211_IF_TYPE_WDS) { + ap_addr->sa_family = ARPHRD_ETHER; + memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN); + return 0; + } + + return -EOPNOTSUPP; +} + + +static int ieee80211_ioctl_siwscan(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct iw_scan_req *req = NULL; + u8 *ssid = NULL; + size_t ssid_len = 0; + + if (!netif_running(dev)) + return -ENETDOWN; + + if (sdata->vif.type != IEEE80211_IF_TYPE_STA && + sdata->vif.type != IEEE80211_IF_TYPE_IBSS && + sdata->vif.type != IEEE80211_IF_TYPE_MESH_POINT && + sdata->vif.type != IEEE80211_IF_TYPE_AP) + return -EOPNOTSUPP; + + /* if SSID was specified explicitly then use that */ + if (wrqu->data.length == sizeof(struct iw_scan_req) && + wrqu->data.flags & IW_SCAN_THIS_ESSID) { + req = (struct iw_scan_req *)extra; + ssid = req->essid; + ssid_len = req->essid_len; + } + + return ieee80211_sta_req_scan(dev, ssid, ssid_len); +} + + +static int ieee80211_ioctl_giwscan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + int res; + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + if (local->sta_sw_scanning || local->sta_hw_scanning) + return -EAGAIN; + + res = ieee80211_sta_scan_results(dev, extra, data->length); + if (res >= 0) { + data->length = res; + return 0; + } + data->length = 0; + return res; +} + + +static int ieee80211_ioctl_siwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rate, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + int i, err = -EINVAL; + u32 target_rate = rate->value / 100000; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (!sdata->bss) + return -ENODEV; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates + * target_rate = X, rate->fixed = 1 means only rate X + * target_rate = X, rate->fixed = 0 means all rates <= X */ + sdata->bss->max_ratectrl_rateidx = -1; + sdata->bss->force_unicast_rateidx = -1; + if (rate->value < 0) + return 0; + + for (i=0; i< sband->n_bitrates; i++) { + struct ieee80211_rate *brate = &sband->bitrates[i]; + int this_rate = brate->bitrate; + + if (target_rate == this_rate) { + sdata->bss->max_ratectrl_rateidx = i; + if (rate->fixed) + sdata->bss->force_unicast_rateidx = i; + err = 0; + break; + } + } + return err; +} + +static int ieee80211_ioctl_giwrate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rate, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct sta_info *sta; + struct ieee80211_sub_if_data *sdata; + struct ieee80211_supported_band *sband; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) + return -EOPNOTSUPP; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + rcu_read_lock(); + + sta = sta_info_get(local, sdata->u.sta.bssid); + + if (sta && sta->txrate_idx < sband->n_bitrates) + rate->value = sband->bitrates[sta->txrate_idx].bitrate; + else + rate->value = 0; + + rcu_read_unlock(); + + if (!sta) + return -ENODEV; + + rate->value *= 100000; + + return 0; +} + +static int ieee80211_ioctl_siwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + bool need_reconfig = 0; + int new_power_level; + + if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) + return -EINVAL; + if (data->txpower.flags & IW_TXPOW_RANGE) + return -EINVAL; + + if (data->txpower.fixed) { + new_power_level = data->txpower.value; + } else { + /* + * Automatic power level. Use maximum power for the current + * channel. Should be part of rate control. + */ + struct ieee80211_channel* chan = local->hw.conf.channel; + if (!chan) + return -EINVAL; + + new_power_level = chan->max_power; + } + + if (local->hw.conf.power_level != new_power_level) { + local->hw.conf.power_level = new_power_level; + need_reconfig = 1; + } + + if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { + local->hw.conf.radio_enabled = !(data->txpower.disabled); + need_reconfig = 1; + ieee80211_led_radio(local, local->hw.conf.radio_enabled); + } + + if (need_reconfig) { + ieee80211_hw_config(local); + /* The return value of hw_config is not of big interest here, + * as it doesn't say that it failed because of _this_ config + * change or something else. Ignore it. */ + } + + return 0; +} + +static int ieee80211_ioctl_giwtxpower(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + data->txpower.fixed = 1; + data->txpower.disabled = !(local->hw.conf.radio_enabled); + data->txpower.value = local->hw.conf.power_level; + data->txpower.flags = IW_TXPOW_DBM; + + return 0; +} + +static int ieee80211_ioctl_siwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + if (rts->disabled) + local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; + else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD) + return -EINVAL; + else + local->rts_threshold = rts->value; + + /* If the wlan card performs RTS/CTS in hardware/firmware, + * configure it here */ + + if (local->ops->set_rts_threshold) + local->ops->set_rts_threshold(local_to_hw(local), + local->rts_threshold); + + return 0; +} + +static int ieee80211_ioctl_giwrts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *rts, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + rts->value = local->rts_threshold; + rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD); + rts->fixed = 1; + + return 0; +} + + +static int ieee80211_ioctl_siwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + if (frag->disabled) + local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; + else if (frag->value < 256 || + frag->value > IEEE80211_MAX_FRAG_THRESHOLD) + return -EINVAL; + else { + /* Fragment length must be even, so strip LSB. */ + local->fragmentation_threshold = frag->value & ~0x1; + } + + /* If the wlan card performs fragmentation in hardware/firmware, + * configure it here */ + + if (local->ops->set_frag_threshold) + local->ops->set_frag_threshold( + local_to_hw(local), + local->fragmentation_threshold); + + return 0; +} + +static int ieee80211_ioctl_giwfrag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *frag, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + frag->value = local->fragmentation_threshold; + frag->disabled = (frag->value >= IEEE80211_MAX_RTS_THRESHOLD); + frag->fixed = 1; + + return 0; +} + + +static int ieee80211_ioctl_siwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *retry, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + if (retry->disabled || + (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) + return -EINVAL; + + if (retry->flags & IW_RETRY_MAX) + local->long_retry_limit = retry->value; + else if (retry->flags & IW_RETRY_MIN) + local->short_retry_limit = retry->value; + else { + local->long_retry_limit = retry->value; + local->short_retry_limit = retry->value; + } + + if (local->ops->set_retry_limit) { + return local->ops->set_retry_limit( + local_to_hw(local), + local->short_retry_limit, + local->long_retry_limit); + } + + return 0; +} + + +static int ieee80211_ioctl_giwretry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *retry, char *extra) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + + retry->disabled = 0; + if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) { + /* first return min value, iwconfig will ask max value + * later if needed */ + retry->flags |= IW_RETRY_LIMIT; + retry->value = local->short_retry_limit; + if (local->long_retry_limit != local->short_retry_limit) + retry->flags |= IW_RETRY_MIN; + return 0; + } + if (retry->flags & IW_RETRY_MAX) { + retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + retry->value = local->long_retry_limit; + } + + return 0; +} + +static int ieee80211_ioctl_siwmlme(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *data, char *extra) +{ + struct ieee80211_sub_if_data *sdata; + struct iw_mlme *mlme = (struct iw_mlme *) extra; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (sdata->vif.type != IEEE80211_IF_TYPE_STA && + sdata->vif.type != IEEE80211_IF_TYPE_IBSS) + return -EINVAL; + + switch (mlme->cmd) { + case IW_MLME_DEAUTH: + /* TODO: mlme->addr.sa_data */ + return ieee80211_sta_deauthenticate(dev, mlme->reason_code); + case IW_MLME_DISASSOC: + /* TODO: mlme->addr.sa_data */ + return ieee80211_sta_disassociate(dev, mlme->reason_code); + default: + return -EOPNOTSUPP; + } +} + + +static int ieee80211_ioctl_siwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *keybuf) +{ + struct ieee80211_sub_if_data *sdata; + int idx, i, alg = ALG_WEP; + u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + int remove = 0; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx == 0) { + if (sdata->default_key) + for (i = 0; i < NUM_DEFAULT_KEYS; i++) { + if (sdata->default_key == sdata->keys[i]) { + idx = i; + break; + } + } + } else if (idx < 1 || idx > 4) + return -EINVAL; + else + idx--; + + if (erq->flags & IW_ENCODE_DISABLED) + remove = 1; + else if (erq->length == 0) { + /* No key data - just set the default TX key index */ + ieee80211_set_default_key(sdata, idx); + return 0; + } + + return ieee80211_set_encryption( + dev, bcaddr, + idx, alg, remove, + !sdata->default_key, + keybuf, erq->length); +} + + +static int ieee80211_ioctl_giwencode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *key) +{ + struct ieee80211_sub_if_data *sdata; + int idx, i; + + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx < 1 || idx > 4) { + idx = -1; + if (!sdata->default_key) + idx = 0; + else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { + if (sdata->default_key == sdata->keys[i]) { + idx = i; + break; + } + } + if (idx < 0) + return -EINVAL; + } else + idx--; + + erq->flags = idx + 1; + + if (!sdata->keys[idx]) { + erq->length = 0; + erq->flags |= IW_ENCODE_DISABLED; + return 0; + } + + memcpy(key, sdata->keys[idx]->conf.key, + min_t(int, erq->length, sdata->keys[idx]->conf.keylen)); + erq->length = sdata->keys[idx]->conf.keylen; + erq->flags |= IW_ENCODE_ENABLED; + + return 0; +} + +static int ieee80211_ioctl_siwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int ret = 0; + + switch (data->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_WPA_ENABLED: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_KEY_MGMT: + break; + case IW_AUTH_DROP_UNENCRYPTED: + sdata->drop_unencrypted = !!data->value; + break; + case IW_AUTH_PRIVACY_INVOKED: + if (sdata->vif.type != IEEE80211_IF_TYPE_STA) + ret = -EINVAL; + else { + sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED; + /* + * Privacy invoked by wpa_supplicant, store the + * value and allow associating to a protected + * network without having a key up front. + */ + if (data->value) + sdata->u.sta.flags |= + IEEE80211_STA_PRIVACY_INVOKED; + } + break; + case IW_AUTH_80211_AUTH_ALG: + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) + sdata->u.sta.auth_algs = data->value; + else + ret = -EOPNOTSUPP; + break; + default: + ret = -EOPNOTSUPP; + break; + } + return ret; +} + +/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ +static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev) +{ + struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); + struct iw_statistics *wstats = &local->wstats; + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct sta_info *sta = NULL; + + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) + sta = sta_info_get(local, sdata->u.sta.bssid); + if (!sta) { + wstats->discard.fragment = 0; + wstats->discard.misc = 0; + wstats->qual.qual = 0; + wstats->qual.level = 0; + wstats->qual.noise = 0; + wstats->qual.updated = IW_QUAL_ALL_INVALID; + } else { + wstats->qual.level = sta->last_rssi; + wstats->qual.qual = sta->last_signal; + wstats->qual.noise = sta->last_noise; + wstats->qual.updated = local->wstats_flags; + } + return wstats; +} + +static int ieee80211_ioctl_giwauth(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *data, char *extra) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + int ret = 0; + + switch (data->flags & IW_AUTH_INDEX) { + case IW_AUTH_80211_AUTH_ALG: + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || + sdata->vif.type == IEEE80211_IF_TYPE_IBSS) + data->value = sdata->u.sta.auth_algs; + else + ret = -EOPNOTSUPP; + break; + default: + ret = -EOPNOTSUPP; + break; + } + return ret; +} + + +static int ieee80211_ioctl_siwencodeext(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *erq, char *extra) +{ + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; + int uninitialized_var(alg), idx, i, remove = 0; + + switch (ext->alg) { + case IW_ENCODE_ALG_NONE: + remove = 1; + break; + case IW_ENCODE_ALG_WEP: + alg = ALG_WEP; + break; + case IW_ENCODE_ALG_TKIP: + alg = ALG_TKIP; + break; + case IW_ENCODE_ALG_CCMP: + alg = ALG_CCMP; + break; + default: + return -EOPNOTSUPP; + } + + if (erq->flags & IW_ENCODE_DISABLED) + remove = 1; + + idx = erq->flags & IW_ENCODE_INDEX; + if (idx < 1 || idx > 4) { + idx = -1; + if (!sdata->default_key) + idx = 0; + else for (i = 0; i < NUM_DEFAULT_KEYS; i++) { + if (sdata->default_key == sdata->keys[i]) { + idx = i; + break; + } + } + if (idx < 0) + return -EINVAL; + } else + idx--; + + return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg, + remove, + ext->ext_flags & + IW_ENCODE_EXT_SET_TX_KEY, + ext->key, ext->key_len); +} + + +/* Structures to export the Wireless Handlers */ + +static const iw_handler ieee80211_handler[] = +{ + (iw_handler) NULL, /* SIOCSIWCOMMIT */ + (iw_handler) ieee80211_ioctl_giwname, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */ + (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */ + (iw_handler) ieee80211_ioctl_siwmode, /* SIOCSIWMODE */ + (iw_handler) ieee80211_ioctl_giwmode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ + (iw_handler) ieee80211_ioctl_giwrange, /* SIOCGIWRANGE */ + (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */ + (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */ + (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* SIOCSIWTHRSPY */ + (iw_handler) NULL, /* SIOCGIWTHRSPY */ + (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */ + (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */ + (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */ + (iw_handler) NULL, /* SIOCGIWAPLIST */ + (iw_handler) ieee80211_ioctl_siwscan, /* SIOCSIWSCAN */ + (iw_handler) ieee80211_ioctl_giwscan, /* SIOCGIWSCAN */ + (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */ + (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */ + (iw_handler) NULL, /* SIOCSIWNICKN */ + (iw_handler) NULL, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */ + (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */ + (iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */ + (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */ + (iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */ + (iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */ + (iw_handler) ieee80211_ioctl_siwtxpower, /* SIOCSIWTXPOW */ + (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ + (iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */ + (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */ + (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */ + (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */ + (iw_handler) NULL, /* SIOCSIWPOWER */ + (iw_handler) NULL, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) ieee80211_ioctl_siwgenie, /* SIOCSIWGENIE */ + (iw_handler) NULL, /* SIOCGIWGENIE */ + (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */ + (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */ + (iw_handler) ieee80211_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) NULL, /* SIOCGIWENCODEEXT */ + (iw_handler) NULL, /* SIOCSIWPMKSA */ + (iw_handler) NULL, /* -- hole -- */ +}; + +const struct iw_handler_def ieee80211_iw_handler_def = +{ + .num_standard = ARRAY_SIZE(ieee80211_handler), + .standard = (iw_handler *) ieee80211_handler, + .get_wireless_stats = ieee80211_get_wireless_stats, +}; -- cgit v1.2.3-59-g8ed1b From d9c58f30b08bfe1e689537af5bc855a76d0fae25 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 8 Apr 2008 16:46:36 -0400 Subject: mac80211: fix key debugfs default_key link The default_key symlink points to the key index rather than they key counter, fix it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/debugfs_key.c | 3 ++- net/mac80211/key.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index bf7027e9ce9f..879e7210458a 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -195,6 +195,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key) return; sprintf(buf, "%d", keycount); + key->debugfs.cnt = keycount; keycount++; key->debugfs.dir = debugfs_create_dir(buf, key->local->debugfs.keys); @@ -258,7 +259,7 @@ void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata) if (!sdata->debugfsdir) return; - sprintf(buf, "../keys/%d", sdata->default_key->conf.keyidx); + sprintf(buf, "../keys/%d", sdata->default_key->debugfs.cnt); sdata->debugfs.default_key = debugfs_create_symlink("default_key", sdata->debugfsdir, buf); } diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 467890c6fe81..5d48518985b3 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -125,6 +125,7 @@ struct ieee80211_key { struct dentry *replays; struct dentry *key; struct dentry *ifindex; + int cnt; } debugfs; #endif -- cgit v1.2.3-59-g8ed1b From b715631fad3ed320b85d386a84a6fb0b3f86b0b9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Apr 2008 01:33:47 -0700 Subject: socket: sk_filter minor cleanups Some minor style cleanups: * Move __KERNEL__ definitions to one place in filter.h * Use const for sk_filter_len * Line wrapping * Put EXPORT_SYMBOL next to function definition Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/filter.h | 31 +++++++++++++++---------------- net/core/filter.c | 5 ++--- 2 files changed, 17 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/include/linux/filter.h b/include/linux/filter.h index ddfa0372a3b7..bfc5d319b946 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -37,21 +37,6 @@ struct sock_fprog /* Required for SO_ATTACH_FILTER. */ struct sock_filter __user *filter; }; -#ifdef __KERNEL__ -struct sk_filter -{ - atomic_t refcnt; - unsigned int len; /* Number of filter blocks */ - struct rcu_head rcu; - struct sock_filter insns[0]; -}; - -static inline unsigned int sk_filter_len(struct sk_filter *fp) -{ - return fp->len*sizeof(struct sock_filter) + sizeof(*fp); -} -#endif - /* * Instruction classes */ @@ -141,10 +126,24 @@ static inline unsigned int sk_filter_len(struct sk_filter *fp) #define SKF_LL_OFF (-0x200000) #ifdef __KERNEL__ +struct sk_filter +{ + atomic_t refcnt; + unsigned int len; /* Number of filter blocks */ + struct rcu_head rcu; + struct sock_filter insns[0]; +}; + +static inline unsigned int sk_filter_len(const struct sk_filter *fp) +{ + return fp->len * sizeof(struct sock_filter) + sizeof(*fp); +} + struct sk_buff; struct sock; -extern unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen); +extern unsigned int sk_run_filter(struct sk_buff *skb, + struct sock_filter *filter, int flen); extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); extern int sk_detach_filter(struct sock *sk); extern int sk_chk_filter(struct sock_filter *filter, int flen); diff --git a/net/core/filter.c b/net/core/filter.c index e0a06942c025..85a5febab567 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -275,6 +275,7 @@ load_b: return 0; } +EXPORT_SYMBOL(sk_run_filter); /** * sk_chk_filter - verify socket filter code @@ -385,6 +386,7 @@ int sk_chk_filter(struct sock_filter *filter, int flen) return (BPF_CLASS(filter[flen - 1].code) == BPF_RET) ? 0 : -EINVAL; } +EXPORT_SYMBOL(sk_chk_filter); /** * sk_filter_rcu_release: Release a socket filter by rcu_head @@ -467,6 +469,3 @@ int sk_detach_filter(struct sock *sk) rcu_read_unlock_bh(); return ret; } - -EXPORT_SYMBOL(sk_chk_filter); -EXPORT_SYMBOL(sk_run_filter); -- cgit v1.2.3-59-g8ed1b From 43db6d65e0ef943a361cb91f8baa49132009227b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Apr 2008 01:43:09 -0700 Subject: socket: sk_filter deinline The sk_filter function is too big to be inlined. This saves 2296 bytes of text on allyesconfig. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/filter.h | 1 + include/net/sock.h | 35 ----------------------------------- net/core/filter.c | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 35 deletions(-) (limited to 'net') diff --git a/include/linux/filter.h b/include/linux/filter.h index bfc5d319b946..673e5677ebcc 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -142,6 +142,7 @@ static inline unsigned int sk_filter_len(const struct sk_filter *fp) struct sk_buff; struct sock; +extern int sk_filter(struct sock *sk, struct sk_buff *skb); extern unsigned int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen); extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); diff --git a/include/net/sock.h b/include/net/sock.h index f4fdd101c9a2..09255eae93e9 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -927,41 +927,6 @@ extern void sk_common_release(struct sock *sk); /* Initialise core socket variables */ extern void sock_init_data(struct socket *sock, struct sock *sk); -/** - * sk_filter - run a packet through a socket filter - * @sk: sock associated with &sk_buff - * @skb: buffer to filter - * @needlock: set to 1 if the sock is not locked by caller. - * - * Run the filter code and then cut skb->data to correct size returned by - * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller - * than pkt_len we keep whole skb->data. This is the socket level - * wrapper to sk_run_filter. It returns 0 if the packet should - * be accepted or -EPERM if the packet should be tossed. - * - */ - -static inline int sk_filter(struct sock *sk, struct sk_buff *skb) -{ - int err; - struct sk_filter *filter; - - err = security_sock_rcv_skb(sk, skb); - if (err) - return err; - - rcu_read_lock_bh(); - filter = rcu_dereference(sk->sk_filter); - if (filter) { - unsigned int pkt_len = sk_run_filter(skb, filter->insns, - filter->len); - err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; - } - rcu_read_unlock_bh(); - - return err; -} - /** * sk_filter_release: Release a socket filter * @sk: socket diff --git a/net/core/filter.c b/net/core/filter.c index 85a5febab567..bbb53c69857c 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -63,6 +63,41 @@ static inline void *load_pointer(struct sk_buff *skb, int k, } } +/** + * sk_filter - run a packet through a socket filter + * @sk: sock associated with &sk_buff + * @skb: buffer to filter + * @needlock: set to 1 if the sock is not locked by caller. + * + * Run the filter code and then cut skb->data to correct size returned by + * sk_run_filter. If pkt_len is 0 we toss packet. If skb->len is smaller + * than pkt_len we keep whole skb->data. This is the socket level + * wrapper to sk_run_filter. It returns 0 if the packet should + * be accepted or -EPERM if the packet should be tossed. + * + */ +int sk_filter(struct sock *sk, struct sk_buff *skb) +{ + int err; + struct sk_filter *filter; + + err = security_sock_rcv_skb(sk, skb); + if (err) + return err; + + rcu_read_lock_bh(); + filter = rcu_dereference(sk->sk_filter); + if (filter) { + unsigned int pkt_len = sk_run_filter(skb, filter->insns, + filter->len); + err = pkt_len ? pskb_trim(skb, pkt_len) : -EPERM; + } + rcu_read_unlock_bh(); + + return err; +} +EXPORT_SYMBOL(sk_filter); + /** * sk_run_filter - run a filter on a socket * @skb: buffer to run the filter on -- cgit v1.2.3-59-g8ed1b From 5969f71d57928511b9cd8744aaf1ed9bc5e88ea2 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Apr 2008 01:52:09 -0700 Subject: IPV4: route inline changes Don't mark functions that are large as inline, let compiler decide. Also, use inline rather than __inline__. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/route.c | 54 +++++++++++++++++++++++++++--------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 230716c2dfe0..d758ea1d80f6 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -600,18 +600,18 @@ static inline int ip_rt_proc_init(void) } #endif /* CONFIG_PROC_FS */ -static __inline__ void rt_free(struct rtable *rt) +static inline void rt_free(struct rtable *rt) { call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free); } -static __inline__ void rt_drop(struct rtable *rt) +static inline void rt_drop(struct rtable *rt) { ip_rt_put(rt); call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free); } -static __inline__ int rt_fast_clean(struct rtable *rth) +static inline int rt_fast_clean(struct rtable *rth) { /* Kill broadcast/multicast entries very aggresively, if they collide in hash table with more useful entries */ @@ -619,7 +619,7 @@ static __inline__ int rt_fast_clean(struct rtable *rth) rth->fl.iif && rth->u.dst.rt_next; } -static __inline__ int rt_valuable(struct rtable *rth) +static inline int rt_valuable(struct rtable *rth) { return (rth->rt_flags & (RTCF_REDIRECTED | RTCF_NOTIFY)) || rth->u.dst.expires; @@ -1420,7 +1420,7 @@ out: kfree_skb(skb); static const unsigned short mtu_plateau[] = {32000, 17914, 8166, 4352, 2002, 1492, 576, 296, 216, 128 }; -static __inline__ unsigned short guess_mtu(unsigned short old_mtu) +static inline unsigned short guess_mtu(unsigned short old_mtu) { int i; @@ -1750,11 +1750,11 @@ static void ip_handle_martian_source(struct net_device *dev, #endif } -static inline int __mkroute_input(struct sk_buff *skb, - struct fib_result* res, - struct in_device *in_dev, - __be32 daddr, __be32 saddr, u32 tos, - struct rtable **result) +static int __mkroute_input(struct sk_buff *skb, + struct fib_result *res, + struct in_device *in_dev, + __be32 daddr, __be32 saddr, u32 tos, + struct rtable **result) { struct rtable *rth; @@ -1846,11 +1846,11 @@ static inline int __mkroute_input(struct sk_buff *skb, return err; } -static inline int ip_mkroute_input(struct sk_buff *skb, - struct fib_result* res, - const struct flowi *fl, - struct in_device *in_dev, - __be32 daddr, __be32 saddr, u32 tos) +static int ip_mkroute_input(struct sk_buff *skb, + struct fib_result *res, + const struct flowi *fl, + struct in_device *in_dev, + __be32 daddr, __be32 saddr, u32 tos) { struct rtable* rth = NULL; int err; @@ -2132,12 +2132,12 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, return ip_route_input_slow(skb, daddr, saddr, tos, dev); } -static inline int __mkroute_output(struct rtable **result, - struct fib_result* res, - const struct flowi *fl, - const struct flowi *oldflp, - struct net_device *dev_out, - unsigned flags) +static int __mkroute_output(struct rtable **result, + struct fib_result *res, + const struct flowi *fl, + const struct flowi *oldflp, + struct net_device *dev_out, + unsigned flags) { struct rtable *rth; struct in_device *in_dev; @@ -2252,12 +2252,12 @@ static inline int __mkroute_output(struct rtable **result, return err; } -static inline int ip_mkroute_output(struct rtable **rp, - struct fib_result* res, - const struct flowi *fl, - const struct flowi *oldflp, - struct net_device *dev_out, - unsigned flags) +static int ip_mkroute_output(struct rtable **rp, + struct fib_result *res, + const struct flowi *fl, + const struct flowi *oldflp, + struct net_device *dev_out, + unsigned flags) { struct rtable *rth = NULL; int err = __mkroute_output(&rth, res, fl, oldflp, dev_out, flags); -- cgit v1.2.3-59-g8ed1b From 1294fc4a4868d7e83ff749597fbf4e9d5f4d1aa0 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Apr 2008 01:54:01 -0700 Subject: IPV4: route use jhash3 Since route hash is a triple, use jhash_3words rather doing the mixing directly. This should be as fast and give better distribution. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/route.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index d758ea1d80f6..7cdd2bf88e0c 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -259,16 +259,14 @@ static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat); #define RT_CACHE_STAT_INC(field) \ (__raw_get_cpu_var(rt_cache_stat).field++) -static unsigned int rt_hash_code(u32 daddr, u32 saddr) +static inline unsigned int rt_hash(__be32 daddr, __be32 saddr, int idx) { - return jhash_2words(daddr, saddr, atomic_read(&rt_genid)) + return jhash_3words((__force u32)(__be32)(daddr), + (__force u32)(__be32)(saddr), + idx, atomic_read(&rt_genid)) & rt_hash_mask; } -#define rt_hash(daddr, saddr, idx) \ - rt_hash_code((__force u32)(__be32)(daddr),\ - (__force u32)(__be32)(saddr) ^ ((idx) << 5)) - #ifdef CONFIG_PROC_FS struct rt_cache_iter_state { struct seq_net_private p; -- cgit v1.2.3-59-g8ed1b From 2fa7527ba1d38175d1e42f7cb72bae5de3d55cc7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Apr 2008 01:55:27 -0700 Subject: IPV4: route rekey timer can be deferrable No urgency on the rehash interval timer, so mark it as deferrable. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/route.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 7cdd2bf88e0c..a1c5b8dbdfed 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -3058,7 +3058,9 @@ int __init ip_rt_init(void) devinet_init(); ip_fib_init(); - setup_timer(&rt_secret_timer, rt_secret_rebuild, 0); + rt_secret_timer.function = rt_secret_rebuild; + rt_secret_timer.data = 0; + init_timer_deferrable(&rt_secret_timer); /* All the timers, started at system startup tend to synchronize. Perturb it a bit. -- cgit v1.2.3-59-g8ed1b From e8c38751be84e2e930642be60331fbb6d3c4becb Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Thu, 10 Apr 2008 01:57:24 -0700 Subject: SCTP: fix wrong debug counting of datamsg Should not count it if the allocation of this object failed. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- net/sctp/chunk.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index ed857643e3ff..1748ef90950c 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -66,9 +66,10 @@ SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(gfp_t gfp) { struct sctp_datamsg *msg; msg = kmalloc(sizeof(struct sctp_datamsg), gfp); - if (msg) + if (msg) { sctp_datamsg_init(msg); - SCTP_DBG_OBJCNT_INC(datamsg); + SCTP_DBG_OBJCNT_INC(datamsg); + } return msg; } -- cgit v1.2.3-59-g8ed1b From 935a7f6e4d2f2c69a2d94cbda377684fffbdcb27 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Thu, 10 Apr 2008 01:58:06 -0700 Subject: SCTP: fix wrong debug counting of bind_bucket Should not count it if the allocation of the object is failed. Signed-off-by: Li Zefan Signed-off-by: David S. Miller --- net/sctp/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 00ebd0610be2..025f467d80dd 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -5761,8 +5761,8 @@ static struct sctp_bind_bucket *sctp_bucket_create( struct sctp_bind_bucket *pp; pp = kmem_cache_alloc(sctp_bucket_cachep, GFP_ATOMIC); - SCTP_DBG_OBJCNT_INC(bind_bucket); if (pp) { + SCTP_DBG_OBJCNT_INC(bind_bucket); pp->port = snum; pp->fastreuse = 0; INIT_HLIST_HEAD(&pp->owner); -- cgit v1.2.3-59-g8ed1b From eab2e0b2ec150aec8887d0cf178f7c989296266f Mon Sep 17 00:00:00 2001 From: Gui Jianfeng Date: Thu, 10 Apr 2008 02:00:23 -0700 Subject: SCTP: Remove useless assignment from __sctp_rcv_lookup_endpoint Signed-off-by: Gui Jianfeng Signed-off-by: David S. Miller --- net/sctp/input.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/sctp/input.c b/net/sctp/input.c index c1d7e3b5c4b4..ca6b022b1df2 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -725,7 +725,6 @@ static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *l } ep = sctp_sk((sctp_get_ctl_sock()))->ep; - epb = &ep->base; hit: sctp_endpoint_hold(ep); -- cgit v1.2.3-59-g8ed1b From 4738c1db1593687713869fa69e733eebc7b0d6d8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 10 Apr 2008 02:02:28 -0700 Subject: [SKFILTER]: Add SKF_ADF_NLATTR instruction SKF_ADF_NLATTR searches for a netlink attribute, which avoids manually parsing and walking attributes. It takes the offset at which to start searching in the 'A' register and the attribute type in the 'X' register and returns the offset in the 'A' register. When the attribute is not found it returns zero. A top-level attribute can be located using a filter like this (example for nfnetlink, using struct nfgenmsg): ... { /* A = offset of first attribute */ .code = BPF_LD | BPF_IMM, .k = sizeof(struct nlmsghdr) + sizeof(struct nfgenmsg) }, { /* X = CTA_PROTOINFO */ .code = BPF_LDX | BPF_IMM, .k = CTA_PROTOINFO, }, { /* A = netlink attribute offset */ .code = BPF_LD | BPF_B | BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR }, { /* Exit if not found */ .code = BPF_JMP | BPF_JEQ | BPF_K, .k = 0, .jt = }, ... A nested attribute below the CTA_PROTOINFO attribute would then be parsed like this: ... { /* A += sizeof(struct nlattr) */ .code = BPF_ALU | BPF_ADD | BPF_K, .k = sizeof(struct nlattr), }, { /* X = CTA_PROTOINFO_TCP */ .code = BPF_LDX | BPF_IMM, .k = CTA_PROTOINFO_TCP, }, { /* A = netlink attribute offset */ .code = BPF_LD | BPF_B | BPF_ABS, .k = SKF_AD_OFF + SKF_AD_NLATTR }, ... The data of an attribute can be loaded into 'A' like this: ... { /* X = A (attribute offset) */ .code = BPF_MISC | BPF_TAX, }, { /* A = skb->data[X + k] */ .code = BPF_LD | BPF_B | BPF_IND, .k = sizeof(struct nlattr), }, ... Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/filter.h | 3 ++- net/core/filter.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/filter.h b/include/linux/filter.h index 673e5677ebcc..b6ea9aa9e853 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -121,7 +121,8 @@ struct sock_fprog /* Required for SO_ATTACH_FILTER. */ #define SKF_AD_PROTOCOL 0 #define SKF_AD_PKTTYPE 4 #define SKF_AD_IFINDEX 8 -#define SKF_AD_MAX 12 +#define SKF_AD_NLATTR 12 +#define SKF_AD_MAX 16 #define SKF_NET_OFF (-0x100000) #define SKF_LL_OFF (-0x200000) diff --git a/net/core/filter.c b/net/core/filter.c index bbb53c69857c..f5f3cf603064 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -303,6 +304,22 @@ load_b: case SKF_AD_IFINDEX: A = skb->dev->ifindex; continue; + case SKF_AD_NLATTR: { + struct nlattr *nla; + + if (skb_is_nonlinear(skb)) + return 0; + if (A > skb->len - sizeof(struct nlattr)) + return 0; + + nla = nla_find((struct nlattr *)&skb->data[A], + skb->len - A, X); + if (nla) + A = (void *)nla - (void *)skb->data; + else + A = 0; + continue; + } default: return 0; } -- cgit v1.2.3-59-g8ed1b From 3db8ce35c37b62d27e7656fe5e7d2d2865002045 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Thu, 10 Apr 2008 02:11:24 -0700 Subject: af_iucv: Use non-deprecated __RW_LOCK_UNLOCKED macro. Signed-off-by: Robert P. J. Day Signed-off-by: Ursula Braun Signed-off-by: David S. Miller --- net/iucv/af_iucv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index fee22caf1bad..7b0038f45b16 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c @@ -53,7 +53,7 @@ static int iucv_callback_connreq(struct iucv_path *, u8 ipvmid[8], static void iucv_callback_connrej(struct iucv_path *, u8 ipuser[16]); static struct iucv_sock_list iucv_sk_list = { - .lock = RW_LOCK_UNLOCKED, + .lock = __RW_LOCK_UNLOCKED(iucv_sk_list.lock), .autobind_name = ATOMIC_INIT(0) }; -- cgit v1.2.3-59-g8ed1b From 9284d6c704b5cfc7f2eb44f81255b4762bcfe4c5 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 10 Apr 2008 02:12:03 -0700 Subject: iucv: get rid of in_atomic() use. This BUG_ON is not needed, since all (debug) checks are also done in smp_call_function() which gets called by this function. Signed-off-by: Heiko Carstens Signed-off-by: Ursula Braun Signed-off-by: David S. Miller --- net/iucv/iucv.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index d764f4c1b7e4..a65e69eaea2f 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -795,7 +795,6 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, union iucv_param *parm; int rc; - BUG_ON(in_atomic()); spin_lock_bh(&iucv_table_lock); iucv_cleanup_queue(); parm = iucv_param[smp_processor_id()]; -- cgit v1.2.3-59-g8ed1b From 2d7bf36746b6329d9d54c6c6efe2b55666dd1f53 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 10 Apr 2008 02:12:45 -0700 Subject: iucv: Delay bus registration until core is ready. If we register the iucv bus after the infrastructure is ready, userspace can start relying on it when it receives the uevent for the bus. Signed-off-by: Cornelia Huck Signed-off-by: Heiko Carstens Signed-off-by: Ursula Braun Signed-off-by: David S. Miller --- net/iucv/iucv.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index a65e69eaea2f..918970762131 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -1608,13 +1608,10 @@ static int __init iucv_init(void) rc = register_external_interrupt(0x4000, iucv_external_interrupt); if (rc) goto out; - rc = bus_register(&iucv_bus); - if (rc) - goto out_int; iucv_root = s390_root_dev_register("iucv"); if (IS_ERR(iucv_root)) { rc = PTR_ERR(iucv_root); - goto out_bus; + goto out_int; } for_each_online_cpu(cpu) { @@ -1634,13 +1631,20 @@ static int __init iucv_init(void) goto out_free; } } - register_hotcpu_notifier(&iucv_cpu_notifier); + rc = register_hotcpu_notifier(&iucv_cpu_notifier); + if (rc) + goto out_free; ASCEBC(iucv_error_no_listener, 16); ASCEBC(iucv_error_no_memory, 16); ASCEBC(iucv_error_pathid, 16); iucv_available = 1; + rc = bus_register(&iucv_bus); + if (rc) + goto out_cpu; return 0; +out_cpu: + unregister_hotcpu_notifier(&iucv_cpu_notifier); out_free: for_each_possible_cpu(cpu) { kfree(iucv_param[cpu]); @@ -1649,8 +1653,6 @@ out_free: iucv_irq_data[cpu] = NULL; } s390_root_dev_unregister(iucv_root); -out_bus: - bus_unregister(&iucv_bus); out_int: unregister_external_interrupt(0x4000, iucv_external_interrupt); out: -- cgit v1.2.3-59-g8ed1b From 15be75cdb5db442d0e33d37b20832b88f3ccd383 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Apr 2008 02:56:38 -0700 Subject: IPV4: fib_trie use vmalloc for large tnodes Use vmalloc rather than alloc_pages to avoid wasting memory. The problem is that tnode structure has a power of 2 sized array, plus a header. So the current code wastes almost half the memory allocated because it always needs the next bigger size to hold that small header. This is similar to an earlier patch by Eric, but instead of a list and lock, I used a workqueue to handle the fact that vfree can't be done in interrupt context. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/fib_trie.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 9e491e70e855..64a274282042 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -122,7 +122,10 @@ struct tnode { unsigned char bits; /* 2log(KEYLENGTH) bits needed */ unsigned int full_children; /* KEYLENGTH bits needed */ unsigned int empty_children; /* KEYLENGTH bits needed */ - struct rcu_head rcu; + union { + struct rcu_head rcu; + struct work_struct work; + }; struct node *child[0]; }; @@ -346,16 +349,16 @@ static inline void free_leaf_info(struct leaf_info *leaf) static struct tnode *tnode_alloc(size_t size) { - struct page *pages; - if (size <= PAGE_SIZE) return kzalloc(size, GFP_KERNEL); + else + return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL); +} - pages = alloc_pages(GFP_KERNEL|__GFP_ZERO, get_order(size)); - if (!pages) - return NULL; - - return page_address(pages); +static void __tnode_vfree(struct work_struct *arg) +{ + struct tnode *tn = container_of(arg, struct tnode, work); + vfree(tn); } static void __tnode_free_rcu(struct rcu_head *head) @@ -366,8 +369,10 @@ static void __tnode_free_rcu(struct rcu_head *head) if (size <= PAGE_SIZE) kfree(tn); - else - free_pages((unsigned long)tn, get_order(size)); + else { + INIT_WORK(&tn->work, __tnode_vfree); + schedule_work(&tn->work); + } } static inline void tnode_free(struct tnode *tn) -- cgit v1.2.3-59-g8ed1b From 4dfc2817025965a2fc78a18c50f540736a6b5c24 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Thu, 10 Apr 2008 03:12:40 -0700 Subject: [Syncookies]: Add support for TCP options via timestamps. Allow the use of SACK and window scaling when syncookies are used and the client supports tcp timestamps. Options are encoded into the timestamp sent in the syn-ack and restored from the timestamp echo when the ack is received. Based on earlier work by Glenn Griffin. This patch avoids increasing the size of structs by encoding TCP options into the least significant bits of the timestamp and by not using any 'timestamp offset'. The downside is that the timestamp sent in the packet after the synack will increase by several seconds. changes since v1: don't duplicate timestamp echo decoding function, put it into ipv4/syncookie.c and have ipv6/syncookies.c use it. Feedback from Glenn Griffin: fix line indented with spaces, kill redundant if () Reviewed-by: Hagen Paul Pfeifer Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- include/net/request_sock.h | 2 +- include/net/tcp.h | 4 +++ net/ipv4/syncookies.c | 89 +++++++++++++++++++++++++++++++++++++++++++--- net/ipv4/tcp_ipv4.c | 5 ++- net/ipv4/tcp_output.c | 6 +++- net/ipv6/syncookies.c | 20 ++++++++--- net/ipv6/tcp_ipv6.c | 5 ++- 7 files changed, 114 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/include/net/request_sock.h b/include/net/request_sock.h index 0369f98e9f3a..b220b5f624de 100644 --- a/include/net/request_sock.h +++ b/include/net/request_sock.h @@ -45,7 +45,7 @@ struct request_sock { struct request_sock *dl_next; /* Must be first member! */ u16 mss; u8 retrans; - u8 __pad; + u8 cookie_ts; /* syncookie: encode tcpopts in timestamp */ /* The following two fields can be easily recomputed I think -AK */ u32 window_clamp; /* window clamp at creation time */ u32 rcv_wnd; /* rcv_wnd offered first time */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 723b36851dde..7b41bb962b9c 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -442,6 +442,9 @@ extern struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mss); +extern __u32 cookie_init_timestamp(struct request_sock *req); +extern void cookie_check_timestamp(struct tcp_options_received *tcp_opt); + /* From net/ipv6/syncookies.c */ extern struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb); extern __u32 cookie_v6_init_sequence(struct sock *sk, struct sk_buff *skb, @@ -956,6 +959,7 @@ static inline void tcp_openreq_init(struct request_sock *req, struct inet_request_sock *ireq = inet_rsk(req); req->rcv_wnd = 0; /* So that tcp_send_synack() knows! */ + req->cookie_ts = 0; tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq; req->mss = rx_opt->mss_clamp; req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0; diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index abc752d45cf7..73ba98921d64 100644 --- a/net/ipv4/syncookies.c +++ b/net/ipv4/syncookies.c @@ -19,6 +19,10 @@ #include #include +/* Timestamps: lowest 9 bits store TCP options */ +#define TSBITS 9 +#define TSMASK (((__u32)1 << TSBITS) - 1) + extern int sysctl_tcp_syncookies; __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS]; @@ -51,6 +55,39 @@ static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, return tmp[17]; } + +/* + * when syncookies are in effect and tcp timestamps are enabled we encode + * tcp options in the lowest 9 bits of the timestamp value that will be + * sent in the syn-ack. + * Since subsequent timestamps use the normal tcp_time_stamp value, we + * must make sure that the resulting initial timestamp is <= tcp_time_stamp. + */ +__u32 cookie_init_timestamp(struct request_sock *req) +{ + struct inet_request_sock *ireq; + u32 ts, ts_now = tcp_time_stamp; + u32 options = 0; + + ireq = inet_rsk(req); + if (ireq->wscale_ok) { + options = ireq->snd_wscale; + options |= ireq->rcv_wscale << 4; + } + options |= ireq->sack_ok << 8; + + ts = ts_now & ~TSMASK; + ts |= options; + if (ts > ts_now) { + ts >>= TSBITS; + ts--; + ts <<= TSBITS; + ts |= options; + } + return ts; +} + + static __u32 secure_tcp_syn_cookie(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, __u32 sseq, __u32 count, __u32 data) @@ -185,6 +222,35 @@ static inline struct sock *get_cookie_sock(struct sock *sk, struct sk_buff *skb, return child; } + +/* + * when syncookies are in effect and tcp timestamps are enabled we stored + * additional tcp options in the timestamp. + * This extracts these options from the timestamp echo. + * + * The lowest 4 bits are for snd_wscale + * The next 4 lsb are for rcv_wscale + * The next lsb is for sack_ok + */ +void cookie_check_timestamp(struct tcp_options_received *tcp_opt) +{ + /* echoed timestamp, 9 lowest bits contain options */ + u32 options = tcp_opt->rcv_tsecr & TSMASK; + + tcp_opt->snd_wscale = options & 0xf; + options >>= 4; + tcp_opt->rcv_wscale = options & 0xf; + + tcp_opt->sack_ok = (options >> 4) & 0x1; + + if (tcp_opt->sack_ok) + tcp_sack_reset(tcp_opt); + + if (tcp_opt->snd_wscale || tcp_opt->rcv_wscale) + tcp_opt->wscale_ok = 1; +} +EXPORT_SYMBOL(cookie_check_timestamp); + struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, struct ip_options *opt) { @@ -198,6 +264,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, int mss; struct rtable *rt; __u8 rcv_wscale; + struct tcp_options_received tcp_opt; if (!sysctl_tcp_syncookies || !th->ack) goto out; @@ -210,6 +277,13 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV); + /* check for timestamp cookie support */ + memset(&tcp_opt, 0, sizeof(tcp_opt)); + tcp_parse_options(skb, &tcp_opt, 0); + + if (tcp_opt.saw_tstamp) + cookie_check_timestamp(&tcp_opt); + ret = NULL; req = reqsk_alloc(&tcp_request_sock_ops); /* for safety */ if (!req) @@ -228,6 +302,12 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, ireq->loc_addr = ip_hdr(skb)->daddr; ireq->rmt_addr = ip_hdr(skb)->saddr; ireq->opt = NULL; + ireq->snd_wscale = tcp_opt.snd_wscale; + ireq->rcv_wscale = tcp_opt.rcv_wscale; + ireq->sack_ok = tcp_opt.sack_ok; + ireq->wscale_ok = tcp_opt.wscale_ok; + ireq->tstamp_ok = tcp_opt.saw_tstamp; + req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; /* We throwed the options of the initial SYN away, so we hope * the ACK carries the same options again (see RFC1122 4.2.3.8) @@ -242,8 +322,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, } } - ireq->snd_wscale = ireq->rcv_wscale = ireq->tstamp_ok = 0; - ireq->wscale_ok = ireq->sack_ok = 0; req->expires = 0UL; req->retrans = 0; @@ -272,11 +350,12 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, } /* Try to redo what tcp_v4_send_synack did. */ - req->window_clamp = dst_metric(&rt->u.dst, RTAX_WINDOW); + req->window_clamp = tp->window_clamp ? :dst_metric(&rt->u.dst, RTAX_WINDOW); + tcp_select_initial_window(tcp_full_space(sk), req->mss, &req->rcv_wnd, &req->window_clamp, - 0, &rcv_wscale); - /* BTW win scale with syncookies is 0 by definition */ + ireq->wscale_ok, &rcv_wscale); + ireq->rcv_wscale = rcv_wscale; ret = get_cookie_sock(sk, skb, req, &rt->u.dst); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index df89a566a5a1..52e3ae603ca9 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1299,10 +1299,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) tcp_parse_options(skb, &tmp_opt, 0); - if (want_cookie) { + if (want_cookie && !tmp_opt.saw_tstamp) tcp_clear_options(&tmp_opt); - tmp_opt.saw_tstamp = 0; - } if (tmp_opt.saw_tstamp && !tmp_opt.rcv_tsval) { /* Some OSes (unknown ones, but I see them on web server, which @@ -1330,6 +1328,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) if (want_cookie) { #ifdef CONFIG_SYN_COOKIES syn_flood_warning(skb); + req->cookie_ts = tmp_opt.tstamp_ok; #endif isn = cookie_v4_init_sequence(sk, skb, &req->mss); } else if (!isn) { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index a627616314ba..76b3653e9b4c 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -2233,7 +2233,11 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ th->window = htons(min(req->rcv_wnd, 65535U)); - +#ifdef CONFIG_SYN_COOKIES + if (unlikely(req->cookie_ts)) + TCP_SKB_CB(skb)->when = cookie_init_timestamp(req); + else +#endif TCP_SKB_CB(skb)->when = tcp_time_stamp; tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale, diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 3a622e7abc02..938ce4ecde55 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -170,6 +170,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) int mss; struct dst_entry *dst; __u8 rcv_wscale; + struct tcp_options_received tcp_opt; if (!sysctl_tcp_syncookies || !th->ack) goto out; @@ -182,6 +183,13 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) NET_INC_STATS_BH(LINUX_MIB_SYNCOOKIESRECV); + /* check for timestamp cookie support */ + memset(&tcp_opt, 0, sizeof(tcp_opt)); + tcp_parse_options(skb, &tcp_opt, 0); + + if (tcp_opt.saw_tstamp) + cookie_check_timestamp(&tcp_opt); + ret = NULL; req = inet6_reqsk_alloc(&tcp6_request_sock_ops); if (!req) @@ -216,8 +224,12 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) req->expires = 0UL; req->retrans = 0; - ireq->snd_wscale = ireq->rcv_wscale = ireq->tstamp_ok = 0; - ireq->wscale_ok = ireq->sack_ok = 0; + ireq->snd_wscale = tcp_opt.snd_wscale; + ireq->rcv_wscale = tcp_opt.rcv_wscale; + ireq->sack_ok = tcp_opt.sack_ok; + ireq->wscale_ok = tcp_opt.wscale_ok; + ireq->tstamp_ok = tcp_opt.saw_tstamp; + req->ts_recent = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0; treq->rcv_isn = ntohl(th->seq) - 1; treq->snt_isn = cookie; @@ -253,10 +265,10 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) goto out; } - req->window_clamp = dst_metric(dst, RTAX_WINDOW); + req->window_clamp = tp->window_clamp ? :dst_metric(dst, RTAX_WINDOW); tcp_select_initial_window(tcp_full_space(sk), req->mss, &req->rcv_wnd, &req->window_clamp, - 0, &rcv_wscale); + ireq->wscale_ok, &rcv_wscale); ireq->rcv_wscale = rcv_wscale; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 378cc4002a76..8ebf6de29562 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1290,10 +1290,8 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) tcp_parse_options(skb, &tmp_opt, 0); - if (want_cookie) { + if (want_cookie && !tmp_opt.saw_tstamp) tcp_clear_options(&tmp_opt); - tmp_opt.saw_tstamp = 0; - } tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; tcp_openreq_init(req, &tmp_opt, skb); @@ -1307,6 +1305,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) if (want_cookie) { isn = cookie_v6_init_sequence(sk, skb, &req->mss); + req->cookie_ts = tmp_opt.tstamp_ok; } else if (!isn) { if (ipv6_opt_accepted(sk, skb) || np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo || -- cgit v1.2.3-59-g8ed1b From 2e1e9848accba7e5f6a731bf0d0fc2c84f3ee748 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 10 Apr 2008 03:33:03 -0700 Subject: [ATM]: Use SEQ_START_TOKEN Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/atm/lec.c | 8 ++++---- net/atm/proc.c | 16 ++++++++-------- net/atm/resources.c | 5 +++-- 3 files changed, 15 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/atm/lec.c b/net/atm/lec.c index aa3785ebf6d1..9bd64bd706b9 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -1014,7 +1014,7 @@ static void *lec_tbl_walk(struct lec_state *state, struct hlist_head *tbl, if (!e) e = tbl->first; - if (e == (void *)1) { + if (e == SEQ_START_TOKEN) { e = tbl->first; --*l; } @@ -1116,9 +1116,9 @@ static void *lec_seq_start(struct seq_file *seq, loff_t *pos) state->locked = NULL; state->arp_table = 0; state->misc_table = 0; - state->node = (void *)1; + state->node = SEQ_START_TOKEN; - return *pos ? lec_get_idx(state, *pos) : (void *)1; + return *pos ? lec_get_idx(state, *pos) : SEQ_START_TOKEN; } static void lec_seq_stop(struct seq_file *seq, void *v) @@ -1147,7 +1147,7 @@ static int lec_seq_show(struct seq_file *seq, void *v) " Status Flags " "VPI/VCI Recv VPI/VCI\n"; - if (v == (void *)1) + if (v == SEQ_START_TOKEN) seq_puts(seq, lec_banner); else { struct lec_state *state = seq->private; diff --git a/net/atm/proc.c b/net/atm/proc.c index b995b66b5585..5c9f3d148135 100644 --- a/net/atm/proc.c +++ b/net/atm/proc.c @@ -78,7 +78,7 @@ static int __vcc_walk(struct sock **sock, int family, int *bucket, loff_t l) { struct sock *sk = *sock; - if (sk == (void *)1) { + if (sk == SEQ_START_TOKEN) { for (*bucket = 0; *bucket < VCC_HTABLE_SIZE; ++*bucket) { struct hlist_head *head = &vcc_hash[*bucket]; @@ -98,7 +98,7 @@ try_again: sk = sk_head(&vcc_hash[*bucket]); goto try_again; } - sk = (void *)1; + sk = SEQ_START_TOKEN; out: *sock = sk; return (l < 0); @@ -130,8 +130,8 @@ static void *vcc_seq_start(struct seq_file *seq, loff_t *pos) loff_t left = *pos; read_lock(&vcc_sklist_lock); - state->sk = (void *)1; - return left ? vcc_walk(state, left) : (void *)1; + state->sk = SEQ_START_TOKEN; + return left ? vcc_walk(state, left) : SEQ_START_TOKEN; } static void vcc_seq_stop(struct seq_file *seq, void *v) @@ -235,7 +235,7 @@ static int atm_dev_seq_show(struct seq_file *seq, void *v) "Itf Type ESI/\"MAC\"addr " "AAL(TX,err,RX,err,drop) ... [refcnt]\n"; - if (v == (void *)1) + if (v == SEQ_START_TOKEN) seq_puts(seq, atm_dev_banner); else { struct atm_dev *dev = list_entry(v, struct atm_dev, dev_list); @@ -269,7 +269,7 @@ static int pvc_seq_show(struct seq_file *seq, void *v) static char atm_pvc_banner[] = "Itf VPI VCI AAL RX(PCR,Class) TX(PCR,Class)\n"; - if (v == (void *)1) + if (v == SEQ_START_TOKEN) seq_puts(seq, atm_pvc_banner); else { struct vcc_state *state = seq->private; @@ -301,7 +301,7 @@ static const struct file_operations pvc_seq_fops = { static int vcc_seq_show(struct seq_file *seq, void *v) { - if (v == (void *)1) { + if (v == SEQ_START_TOKEN) { seq_printf(seq, sizeof(void *) == 4 ? "%-8s%s" : "%-16s%s", "Address ", "Itf VPI VCI Fam Flags Reply " "Send buffer Recv buffer [refcnt]\n"); @@ -338,7 +338,7 @@ static int svc_seq_show(struct seq_file *seq, void *v) static char atm_svc_banner[] = "Itf VPI VCI State Remote\n"; - if (v == (void *)1) + if (v == SEQ_START_TOKEN) seq_puts(seq, atm_svc_banner); else { struct vcc_state *state = seq->private; diff --git a/net/atm/resources.c b/net/atm/resources.c index 1bcf6dc8d409..a34ba948af96 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -415,7 +415,7 @@ static __inline__ void *dev_get_idx(loff_t left) void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) { mutex_lock(&atm_dev_mutex); - return *pos ? dev_get_idx(*pos) : (void *) 1; + return *pos ? dev_get_idx(*pos) : SEQ_START_TOKEN; } void atm_dev_seq_stop(struct seq_file *seq, void *v) @@ -426,7 +426,8 @@ void atm_dev_seq_stop(struct seq_file *seq, void *v) void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) { ++*pos; - v = (v == (void *)1) ? atm_devs.next : ((struct list_head *)v)->next; + v = (v == SEQ_START_TOKEN) + ? atm_devs.next : ((struct list_head *)v)->next; return (v == &atm_devs) ? NULL : v; } -- cgit v1.2.3-59-g8ed1b From ef3660ce0649fa10265455f539b72607cff53d02 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Apr 2008 03:46:12 -0700 Subject: ipv4: fib_trie remove unused argument The trie pointer is passed down to flush_list and flush_leaf but never used. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/fib_trie.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 64a274282042..595a2eedb2dc 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1670,7 +1670,7 @@ static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg) return 0; } -static int trie_flush_list(struct trie *t, struct list_head *head) +static int trie_flush_list(struct list_head *head) { struct fib_alias *fa, *fa_node; int found = 0; @@ -1688,7 +1688,7 @@ static int trie_flush_list(struct trie *t, struct list_head *head) return found; } -static int trie_flush_leaf(struct trie *t, struct leaf *l) +static int trie_flush_leaf(struct leaf *l) { int found = 0; struct hlist_head *lih = &l->list; @@ -1696,7 +1696,7 @@ static int trie_flush_leaf(struct trie *t, struct leaf *l) struct leaf_info *li = NULL; hlist_for_each_entry_safe(li, node, tmp, lih, hlist) { - found += trie_flush_list(t, &li->falh); + found += trie_flush_list(&li->falh); if (list_empty(&li->falh)) { hlist_del_rcu(&li->hlist); @@ -1787,7 +1787,7 @@ static int fn_trie_flush(struct fib_table *tb) int found = 0; for (l = trie_firstleaf(t); l; l = trie_nextleaf(l)) { - found += trie_flush_leaf(t, l); + found += trie_flush_leaf(l); if (ll && hlist_empty(&ll->list)) trie_leaf_remove(t, ll); -- cgit v1.2.3-59-g8ed1b From 387a5487f5a1f8bfc3b2c5818e50dfd19eeb4f3f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Apr 2008 03:47:34 -0700 Subject: ipv4: fib_trie leaf free optimization Avoid unneeded test in the case where object to be freed has to be a leaf. Don't need to use the generic tnode_free() function, instead just setup leaf to be freed. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/ipv4/fib_trie.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 595a2eedb2dc..1ada5a6b03ea 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -163,7 +163,6 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, static struct node *resize(struct trie *t, struct tnode *tn); static struct tnode *inflate(struct trie *t, struct tnode *tn); static struct tnode *halve(struct trie *t, struct tnode *tn); -static void tnode_free(struct tnode *tn); static struct kmem_cache *fn_alias_kmem __read_mostly; static struct kmem_cache *trie_leaf_kmem __read_mostly; @@ -337,6 +336,11 @@ static void __leaf_free_rcu(struct rcu_head *head) kmem_cache_free(trie_leaf_kmem, l); } +static inline void free_leaf(struct leaf *l) +{ + call_rcu_bh(&l->rcu, __leaf_free_rcu); +} + static void __leaf_info_free_rcu(struct rcu_head *head) { kfree(container_of(head, struct leaf_info, rcu)); @@ -377,10 +381,9 @@ static void __tnode_free_rcu(struct rcu_head *head) static inline void tnode_free(struct tnode *tn) { - if (IS_LEAF(tn)) { - struct leaf *l = (struct leaf *) tn; - call_rcu_bh(&l->rcu, __leaf_free_rcu); - } else + if (IS_LEAF(tn)) + free_leaf((struct leaf *) tn); + else call_rcu(&tn->rcu, __tnode_free_rcu); } @@ -1091,7 +1094,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen) li = leaf_info_new(plen); if (!li) { - tnode_free((struct tnode *) l); + free_leaf(l); return NULL; } @@ -1127,7 +1130,7 @@ static struct list_head *fib_insert_node(struct trie *t, u32 key, int plen) if (!tn) { free_leaf_info(li); - tnode_free((struct tnode *) l); + free_leaf(l); return NULL; } @@ -1583,7 +1586,7 @@ static void trie_leaf_remove(struct trie *t, struct leaf *l) } else rcu_assign_pointer(t->trie, NULL); - tnode_free((struct tnode *) l); + free_leaf(l); } /* -- cgit v1.2.3-59-g8ed1b From 24e8b7e48471514c9311c733b3f399bd20d014fe Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 03:48:43 -0700 Subject: [DCCP]: Use snmp_mib_{init,free}(). Signed-off-by: YOSHIFUJI Hideaki Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/proto.c | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) (limited to 'net') diff --git a/net/dccp/proto.c b/net/dccp/proto.c index e3f5d37b84be..d534cdf9603b 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -1010,33 +1010,14 @@ void dccp_shutdown(struct sock *sk, int how) EXPORT_SYMBOL_GPL(dccp_shutdown); -static int __init dccp_mib_init(void) +static inline int dccp_mib_init(void) { - int rc = -ENOMEM; - - dccp_statistics[0] = alloc_percpu(struct dccp_mib); - if (dccp_statistics[0] == NULL) - goto out; - - dccp_statistics[1] = alloc_percpu(struct dccp_mib); - if (dccp_statistics[1] == NULL) - goto out_free_one; - - rc = 0; -out: - return rc; -out_free_one: - free_percpu(dccp_statistics[0]); - dccp_statistics[0] = NULL; - goto out; - + return snmp_mib_init((void**)dccp_statistics, sizeof(struct dccp_mib)); } -static void dccp_mib_exit(void) +static inline void dccp_mib_exit(void) { - free_percpu(dccp_statistics[0]); - free_percpu(dccp_statistics[1]); - dccp_statistics[0] = dccp_statistics[1] = NULL; + snmp_mib_free((void**)dccp_statistics); } static int thash_entries; -- cgit v1.2.3-59-g8ed1b From 996b1dbadcbcafb899f022303e01d46ab87920eb Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 03:50:13 -0700 Subject: [SCTP]: Use snmp_mib_{init,free}(). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/sctp/protocol.c | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 067c8a1658d6..b34437fdea26 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -972,24 +972,14 @@ int sctp_register_pf(struct sctp_pf *pf, sa_family_t family) return 1; } -static int __init init_sctp_mibs(void) +static inline int init_sctp_mibs(void) { - sctp_statistics[0] = alloc_percpu(struct sctp_mib); - if (!sctp_statistics[0]) - return -ENOMEM; - sctp_statistics[1] = alloc_percpu(struct sctp_mib); - if (!sctp_statistics[1]) { - free_percpu(sctp_statistics[0]); - return -ENOMEM; - } - return 0; - + return snmp_mib_init((void**)sctp_statistics, sizeof(struct sctp_mib)); } -static void cleanup_sctp_mibs(void) +static inline void cleanup_sctp_mibs(void) { - free_percpu(sctp_statistics[0]); - free_percpu(sctp_statistics[1]); + snmp_mib_free((void**)sctp_statistics); } static void sctp_v4_pf_init(void) -- cgit v1.2.3-59-g8ed1b From c0b8c32b1c96afc9b32b717927330025cc1c501e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 10 Apr 2008 04:00:28 -0700 Subject: IPV4: use xor rather than multiple ands for route compare The comparison in ip_route_input is a hot path, by recoding the C "and" as bit operations, fewer conditional branches get generated so the code should be faster. Maybe someday Gcc will be smart enough to do this? Signed-off-by: Stephen Hemminger Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/route.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv4/route.c b/net/ipv4/route.c index a1c5b8dbdfed..139799f8a8a1 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2077,12 +2077,12 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, rcu_read_lock(); for (rth = rcu_dereference(rt_hash_table[hash].chain); rth; rth = rcu_dereference(rth->u.dst.rt_next)) { - if (rth->fl.fl4_dst == daddr && - rth->fl.fl4_src == saddr && - rth->fl.iif == iif && - rth->fl.oif == 0 && + if (((rth->fl.fl4_dst ^ daddr) | + (rth->fl.fl4_src ^ saddr) | + (rth->fl.iif ^ iif) | + rth->fl.oif | + (rth->fl.fl4_tos ^ tos)) == 0 && rth->fl.mark == skb->mark && - rth->fl.fl4_tos == tos && net_eq(dev_net(rth->u.dst.dev), net) && rth->rt_genid == atomic_read(&rt_genid)) { dst_use(&rth->u.dst, jiffies); -- cgit v1.2.3-59-g8ed1b From aba6096b21e151bc55da74605fe77b92cfcccb12 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 15:41:26 +0900 Subject: [IPV6]: Kill several warnings without CONFIG_IPV6_MROUTE. Pointed out by Andrew Morton . Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/ip6_input.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 09a3201e408a..4e5c8615832c 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -262,21 +262,23 @@ int ip6_mc_input(struct sk_buff *skb) * is for MLD (0x0000). */ if ((ptr[2] | ptr[3]) == 0) { + deliver = 0; + if (!ipv6_ext_hdr(nexthdr)) { /* BUG */ - goto discard; + goto out; } offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr); if (offset < 0) - goto discard; + goto out; if (nexthdr != IPPROTO_ICMPV6) - goto discard; + goto out; if (!pskb_may_pull(skb, (skb_network_header(skb) + offset + 1 - skb->data))) - goto discard; + goto out; icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset); @@ -285,12 +287,9 @@ int ip6_mc_input(struct sk_buff *skb) case ICMPV6_MGM_REPORT: case ICMPV6_MGM_REDUCTION: case ICMPV6_MLD2_REPORT: + deliver = 1; break; - default: - /* Bogus */ - goto discard; } - deliver = 1; goto out; } /* unknown RA - process it normally */ @@ -308,15 +307,14 @@ int ip6_mc_input(struct sk_buff *skb) ip6_mr_input(skb2); } } -#endif out: - if (likely(deliver)) { +#endif + if (likely(deliver)) ip6_input(skb); - return 0; + else { + /* discard */ + kfree_skb(skb); } -discard: - /* discard */ - kfree_skb(skb); return 0; } -- cgit v1.2.3-59-g8ed1b From 02e10b90cd478bda81b4644102b0009bcd1d14ab Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 15:41:27 +0900 Subject: [IPV6] SIT: Sparse: Use NULL pointer instead of 0. | net/ipv6/sit.c:382:42: warning: Using plain integer as NULL pointer Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/sit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index cc16fe07bbff..91e46fbe6ce2 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -379,7 +379,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev) dev_put(dev); } else { ipip6_tunnel_unlink(netdev_priv(dev)); - ipip6_tunnel_del_prl(netdev_priv(dev), 0); + ipip6_tunnel_del_prl(netdev_priv(dev), NULL); dev_put(dev); } } -- cgit v1.2.3-59-g8ed1b From a9f83bf3858672164ed531cbc60ee9082d21d53f Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 15:41:28 +0900 Subject: [IPV6]: Sparse: Reuse previous delaration where appropriate. | net/ipv6/ipv6_sockglue.c:162:16: warning: symbol 'net' shadows an earlier one | net/ipv6/ipv6_sockglue.c:111:13: originally declared here | net/ipv6/ipv6_sockglue.c:175:16: warning: symbol 'net' shadows an earlier one | net/ipv6/ipv6_sockglue.c:111:13: originally declared here | net/ipv6/ip6mr.c:1241:10: warning: symbol 'ret' shadows an earlier one | net/ipv6/ip6mr.c:1163:6: originally declared here Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/ip6mr.c | 2 +- net/ipv6/ipv6_sockglue.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index da673ef75e12..433042114148 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1238,7 +1238,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int #ifdef CONFIG_IPV6_PIMSM_V2 case MRT6_PIM: { - int v, ret; + int v; if (get_user(v, (int __user *)optval)) return -EFAULT; v = !!v; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 99624109c010..bf9695375219 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -159,8 +159,6 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, if (sk->sk_protocol == IPPROTO_TCP) { struct inet_connection_sock *icsk = inet_csk(sk); - struct net *net = sock_net(sk); - local_bh_disable(); sock_prot_inuse_add(net, sk->sk_prot, -1); sock_prot_inuse_add(net, &tcp_prot, 1); @@ -172,7 +170,6 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); } else { struct proto *prot = &udp_prot; - struct net *net = sock_net(sk); if (sk->sk_protocol == IPPROTO_UDPLITE) prot = &udplite_prot; -- cgit v1.2.3-59-g8ed1b From ff4e1fb0be7386e97580d50f09a804b33b58377a Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 15:41:28 +0900 Subject: [IPV6] FIB_RULE: Sparse: fib6_rules_cleanup() is of void. | net/ipv6/fib6_rules.c:319:2: warning: returning void-valued expression Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/fib6_rules.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index cac580749ebe..8d05527524e3 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -316,5 +316,5 @@ int __init fib6_rules_init(void) void fib6_rules_cleanup(void) { - return unregister_pernet_subsys(&fib6_rules_net_ops); + unregister_pernet_subsys(&fib6_rules_net_ops); } -- cgit v1.2.3-59-g8ed1b From caad295fed8b652c67159911d11c65d476351d2f Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 15:42:07 +0900 Subject: [IPV6]: Use ipv6_addr_equal() instead of !ipv6_addr_cmp(). Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/addrconf.c | 2 +- net/ipv6/tcp_ipv6.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 924158393d04..ed9938014cf9 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2951,7 +2951,7 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) { if (!net_eq(dev_net(ifp->idev->dev), net)) continue; - if (ipv6_addr_cmp(&ifp->addr, addr) == 0 && + if (ipv6_addr_equal(&ifp->addr, addr) && (ifp->flags & IFA_F_HOMEADDRESS)) { ret = 1; break; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8ebf6de29562..80eab71e77ff 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -543,7 +543,7 @@ static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk, return NULL; for (i = 0; i < tp->md5sig_info->entries6; i++) { - if (ipv6_addr_cmp(&tp->md5sig_info->keys6[i].addr, addr) == 0) + if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, addr)) return &tp->md5sig_info->keys6[i].base; } return NULL; @@ -632,7 +632,7 @@ static int tcp_v6_md5_do_del(struct sock *sk, struct in6_addr *peer) int i; for (i = 0; i < tp->md5sig_info->entries6; i++) { - if (ipv6_addr_cmp(&tp->md5sig_info->keys6[i].addr, peer) == 0) { + if (ipv6_addr_equal(&tp->md5sig_info->keys6[i].addr, peer)) { /* Free the key */ kfree(tp->md5sig_info->keys6[i].base.key); tp->md5sig_info->entries6--; -- cgit v1.2.3-59-g8ed1b From 3eb84f49290461e2b83d6e8ee1f3f0e504340c8b Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 15:42:08 +0900 Subject: [IPV6] ADDRCONF: Uninline ipv6_addr_hash(). The function is only used in net/ipv6/addrconf.c. Signed-off-by: YOSHIFUJI Hideaki --- include/net/addrconf.h | 19 ------------------- net/ipv6/addrconf.c | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 1dc9d03372d9..1ba4e5bf5801 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -189,25 +189,6 @@ static inline void in6_ifa_put(struct inet6_ifaddr *ifp) #define in6_ifa_hold(ifp) atomic_inc(&(ifp)->refcnt) -/* - * Hash function taken from net_alias.c - */ - -static __inline__ u8 ipv6_addr_hash(const struct in6_addr *addr) -{ - __u32 word; - - /* - * We perform the hash function over the last 64 bits of the address - * This will include the IEEE address token on links that support it. - */ - - word = (__force u32)(addr->s6_addr32[2] ^ addr->s6_addr32[3]); - word ^= (word >> 16); - word ^= (word >> 8); - - return ((word ^ (word >> 4)) & 0x0f); -} /* * compute link-local solicited-node multicast address diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ed9938014cf9..b17fafc56241 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -541,6 +541,25 @@ ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) *ifap = ifp; } +/* + * Hash function taken from net_alias.c + */ +static u8 ipv6_addr_hash(const struct in6_addr *addr) +{ + __u32 word; + + /* + * We perform the hash function over the last 64 bits of the address + * This will include the IEEE address token on links that support it. + */ + + word = (__force u32)(addr->s6_addr32[2] ^ addr->s6_addr32[3]); + word ^= (word >> 16); + word ^= (word >> 8); + + return ((word ^ (word >> 4)) & 0x0f); +} + /* On success it returns ifp with increased reference count */ static struct inet6_ifaddr * -- cgit v1.2.3-59-g8ed1b From dfd982baff01c18e3e1717c97fdac79c28f105ce Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 15:42:09 +0900 Subject: [IPV6] ADDRCONF: Uninline ipv6_isatap_eui64(). Signed-off-by: YOSHIFUJI Hideaki --- include/net/addrconf.h | 15 +-------------- net/ipv6/addrconf.c | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 1ba4e5bf5801..8317c1bcd86c 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -233,20 +233,7 @@ static inline int ipv6_addr_is_ll_all_routers(const struct in6_addr *addr) (addr->s6_addr32[3] ^ htonl(0x00000002))) == 0); } -static inline int ipv6_isatap_eui64(u8 *eui, __be32 addr) -{ - eui[0] = (ipv4_is_zeronet(addr) || ipv4_is_private_10(addr) || - ipv4_is_loopback(addr) || ipv4_is_linklocal_169(addr) || - ipv4_is_private_172(addr) || ipv4_is_test_192(addr) || - ipv4_is_anycast_6to4(addr) || ipv4_is_private_192(addr) || - ipv4_is_test_198(addr) || ipv4_is_multicast(addr) || - ipv4_is_lbcast(addr)) ? 0x00 : 0x02; - eui[1] = 0; - eui[2] = 0x5E; - eui[3] = 0xFE; - memcpy (eui+4, &addr, 4); - return 0; -} +extern int __ipv6_isatap_ifid(u8 *eui, __be32 addr); static inline int ipv6_addr_is_isatap(const struct in6_addr *addr) { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index b17fafc56241..d15f3e095e7e 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1494,6 +1494,29 @@ static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev) return 0; } +int __ipv6_isatap_ifid(u8 *eui, __be32 addr) +{ + eui[0] = (ipv4_is_zeronet(addr) || ipv4_is_private_10(addr) || + ipv4_is_loopback(addr) || ipv4_is_linklocal_169(addr) || + ipv4_is_private_172(addr) || ipv4_is_test_192(addr) || + ipv4_is_anycast_6to4(addr) || ipv4_is_private_192(addr) || + ipv4_is_test_198(addr) || ipv4_is_multicast(addr) || + ipv4_is_lbcast(addr)) ? 0x00 : 0x02; + eui[1] = 0; + eui[2] = 0x5E; + eui[3] = 0xFE; + memcpy(eui + 4, &addr, 4); + return 0; +} +EXPORT_SYMBOL(__ipv6_isatap_ifid); + +static int addrconf_ifid_sit(u8 *eui, struct net_device *dev) +{ + if (dev->priv_flags & IFF_ISATAP) + return __ipv6_isatap_ifid(eui, *(__be32 *)dev->dev_addr); + return -1; +} + static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) { switch (dev->type) { @@ -1506,8 +1529,7 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) case ARPHRD_INFINIBAND: return addrconf_ifid_infiniband(eui, dev); case ARPHRD_SIT: - if (dev->priv_flags & IFF_ISATAP) - return ipv6_isatap_eui64(eui, *(__be32 *)dev->dev_addr); + return addrconf_ifid_sit(eui, dev); } return -1; } -- cgit v1.2.3-59-g8ed1b From 9acd9f3ae92d0dc0ca7504fb48c1040e8bbc39fe Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 15:42:10 +0900 Subject: [IPV6]: Make address arguments const. - net/ipv6/addrconf.c: ipv6_get_ifaddr(), ipv6_dev_get_saddr() - net/ipv6/mcast.c: ipv6_sock_mc_join(), ipv6_sock_mc_drop(), inet6_mc_check(), ipv6_dev_mc_inc(), __ipv6_dev_mc_dec(), ipv6_dev_mc_dec(), ipv6_chk_mcast_addr() - net/ipv6/route.c: rt6_lookup(), icmp6_dst_alloc() - net/ipv6/ip6_output.c: ip6_nd_hdr() - net/ipv6/ndisc.c: ndisc_send_ns(), ndisc_send_rs(), ndisc_send_redirect(), ndisc_get_neigh(), __ndisc_send() Signed-off-by: YOSHIFUJI Hideaki --- include/net/addrconf.h | 28 +++++++++++++++------------- include/net/ip6_route.h | 6 +++--- include/net/ipv6.h | 4 ++-- include/net/ndisc.h | 14 +++++++------- net/ipv6/addrconf.c | 6 +++--- net/ipv6/ip6_output.c | 2 +- net/ipv6/mcast.c | 20 +++++++++----------- net/ipv6/ndisc.c | 22 ++++++++++++---------- net/ipv6/route.c | 6 +++--- 9 files changed, 55 insertions(+), 53 deletions(-) (limited to 'net') diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 8317c1bcd86c..92af23d66eb9 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -76,12 +76,12 @@ extern int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev); extern struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, - struct in6_addr *addr, + const struct in6_addr *addr, struct net_device *dev, int strict); extern int ipv6_dev_get_saddr(struct net_device *dev, - struct in6_addr *daddr, + const struct in6_addr *daddr, unsigned int srcprefs, struct in6_addr *saddr); extern int ipv6_get_lladdr(struct net_device *dev, @@ -105,25 +105,27 @@ extern u32 ipv6_addr_label(const struct in6_addr *addr, /* * multicast prototypes (mcast.c) */ -extern int ipv6_sock_mc_join(struct sock *sk, int ifindex, - struct in6_addr *addr); -extern int ipv6_sock_mc_drop(struct sock *sk, int ifindex, - struct in6_addr *addr); +extern int ipv6_sock_mc_join(struct sock *sk, int ifindex, + const struct in6_addr *addr); +extern int ipv6_sock_mc_drop(struct sock *sk, int ifindex, + const struct in6_addr *addr); extern void ipv6_sock_mc_close(struct sock *sk); -extern int inet6_mc_check(struct sock *sk, struct in6_addr *mc_addr, - struct in6_addr *src_addr); +extern int inet6_mc_check(struct sock *sk, + const struct in6_addr *mc_addr, + const struct in6_addr *src_addr); -extern int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr); -extern int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr); -extern int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr); +extern int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr); +extern int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr); +extern int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr); extern void ipv6_mc_up(struct inet6_dev *idev); extern void ipv6_mc_down(struct inet6_dev *idev); extern void ipv6_mc_init_dev(struct inet6_dev *idev); extern void ipv6_mc_destroy_dev(struct inet6_dev *idev); extern void addrconf_dad_failure(struct inet6_ifaddr *ifp); -extern int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group, - struct in6_addr *src_addr); +extern int ipv6_chk_mcast_addr(struct net_device *dev, + const struct in6_addr *group, + const struct in6_addr *src_addr); extern int ipv6_is_mld(struct sk_buff *skb, int nexthdr); extern void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len); diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 9080076ce0e5..9313491e3dad 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -61,13 +61,13 @@ extern int ip6_ins_rt(struct rt6_info *); extern int ip6_del_rt(struct rt6_info *); extern struct rt6_info *rt6_lookup(struct net *net, - struct in6_addr *daddr, - struct in6_addr *saddr, + const struct in6_addr *daddr, + const struct in6_addr *saddr, int oif, int flags); extern struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct neighbour *neigh, - struct in6_addr *addr); + const struct in6_addr *addr); extern int icmp6_dst_gc(int *more); extern void fib6_force_start_gc(struct net *net); diff --git a/include/net/ipv6.h b/include/net/ipv6.h index a0c285b6311e..49c48983019f 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -451,8 +451,8 @@ extern int ip6_xmit(struct sock *sk, extern int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev, - struct in6_addr *saddr, - struct in6_addr *daddr, + const struct in6_addr *saddr, + const struct in6_addr *daddr, int proto, int len); extern int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr); diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 16424236fe2f..9c451ff2f4f4 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -94,17 +94,17 @@ extern int ndisc_rcv(struct sk_buff *skb); extern void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, - struct in6_addr *solicit, - struct in6_addr *daddr, - struct in6_addr *saddr); + const struct in6_addr *solicit, + const struct in6_addr *daddr, + const struct in6_addr *saddr); extern void ndisc_send_rs(struct net_device *dev, - struct in6_addr *saddr, - struct in6_addr *daddr); + const struct in6_addr *saddr, + const struct in6_addr *daddr); extern void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, - struct in6_addr *target); + const struct in6_addr *target); extern int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir); @@ -134,7 +134,7 @@ extern int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, extern void inet6_ifinfo_notify(int event, struct inet6_dev *idev); -static inline struct neighbour * ndisc_get_neigh(struct net_device *dev, struct in6_addr *addr) +static inline struct neighbour * ndisc_get_neigh(struct net_device *dev, const struct in6_addr *addr) { if (dev) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d15f3e095e7e..4048c2b73b0b 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -940,7 +940,7 @@ struct ipv6_saddr_score { }; struct ipv6_saddr_dst { - struct in6_addr *addr; + const struct in6_addr *addr; int ifindex; int scope; int label; @@ -1074,7 +1074,7 @@ out: } int ipv6_dev_get_saddr(struct net_device *dst_dev, - struct in6_addr *daddr, unsigned int prefs, + const struct in6_addr *daddr, unsigned int prefs, struct in6_addr *saddr) { struct ipv6_saddr_score scores[2], @@ -1309,7 +1309,7 @@ int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev) EXPORT_SYMBOL(ipv6_chk_prefix); -struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, struct in6_addr *addr, +struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr, struct net_device *dev, int strict) { struct inet6_ifaddr * ifp; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index c0dbe549cc42..0af2e055f883 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -286,7 +286,7 @@ EXPORT_SYMBOL(ip6_xmit); */ int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev, - struct in6_addr *saddr, struct in6_addr *daddr, + const struct in6_addr *saddr, const struct in6_addr *daddr, int proto, int len) { struct ipv6_pinfo *np = inet6_sk(sk); diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 2e6a53f3cc38..0a0132a1c443 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -127,8 +127,6 @@ static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; /* Big mc list lock for all the sockets */ static DEFINE_RWLOCK(ipv6_sk_mc_lock); -int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr); - static void igmp6_join_group(struct ifmcaddr6 *ma); static void igmp6_leave_group(struct ifmcaddr6 *ma); static void igmp6_timer_handler(unsigned long data); @@ -177,7 +175,7 @@ int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; * socket join on multicast group */ -int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) +int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) { struct net_device *dev = NULL; struct ipv6_mc_socklist *mc_lst; @@ -252,7 +250,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) /* * socket leave on multicast group */ -int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) +int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_mc_socklist *mc_lst, **lnk; @@ -664,8 +662,8 @@ done: return err; } -int inet6_mc_check(struct sock *sk, struct in6_addr *mc_addr, - struct in6_addr *src_addr) +int inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, + const struct in6_addr *src_addr) { struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_mc_socklist *mc; @@ -871,7 +869,7 @@ static void mld_clear_delrec(struct inet6_dev *idev) /* * device multicast group inc (add if not found) */ -int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr) +int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr) { struct ifmcaddr6 *mc; struct inet6_dev *idev; @@ -942,7 +940,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr) /* * device multicast group del */ -int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr) +int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr) { struct ifmcaddr6 *ma, **map; @@ -967,7 +965,7 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr) return -ENOENT; } -int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr) +int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr) { struct inet6_dev *idev = in6_dev_get(dev); int err; @@ -1012,8 +1010,8 @@ int ipv6_is_mld(struct sk_buff *skb, int nexthdr) /* * check if the interface/address pair is valid */ -int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group, - struct in6_addr *src_addr) +int ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, + const struct in6_addr *src_addr) { struct inet6_dev *idev; struct ifmcaddr6 *mc; diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index b3295d82fece..5b9ad5e2f56d 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -442,8 +442,9 @@ static void pndisc_destructor(struct pneigh_entry *n) */ static void __ndisc_send(struct net_device *dev, struct neighbour *neigh, - struct in6_addr *daddr, struct in6_addr *saddr, - struct icmp6hdr *icmp6h, struct in6_addr *target, + const struct in6_addr *daddr, + const struct in6_addr *saddr, + struct icmp6hdr *icmp6h, const struct in6_addr *target, int llinfo) { struct flowi fl; @@ -529,12 +530,13 @@ static void __ndisc_send(struct net_device *dev, } static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, - struct in6_addr *daddr, struct in6_addr *solicited_addr, - int router, int solicited, int override, int inc_opt) + const struct in6_addr *daddr, + const struct in6_addr *solicited_addr, + int router, int solicited, int override, int inc_opt) { struct in6_addr tmpaddr; struct inet6_ifaddr *ifp; - struct in6_addr *src_addr; + const struct in6_addr *src_addr; struct icmp6hdr icmp6h = { .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, }; @@ -564,8 +566,8 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, } void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, - struct in6_addr *solicit, - struct in6_addr *daddr, struct in6_addr *saddr) + const struct in6_addr *solicit, + const struct in6_addr *daddr, const struct in6_addr *saddr) { struct in6_addr addr_buf; struct icmp6hdr icmp6h = { @@ -584,8 +586,8 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, !ipv6_addr_any(saddr) ? ND_OPT_SOURCE_LL_ADDR : 0); } -void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, - struct in6_addr *daddr) +void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, + const struct in6_addr *daddr) { struct icmp6hdr icmp6h = { .icmp6_type = NDISC_ROUTER_SOLICITATION, @@ -1447,7 +1449,7 @@ static void ndisc_redirect_rcv(struct sk_buff *skb) } void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, - struct in6_addr *target) + const struct in6_addr *target) { struct net_device *dev = skb->dev; struct net *net = dev_net(dev); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 269b76093288..6293cb91ed1d 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -556,8 +556,8 @@ out: } -struct rt6_info *rt6_lookup(struct net *net, struct in6_addr *daddr, - struct in6_addr *saddr, int oif, int strict) +struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, + const struct in6_addr *saddr, int oif, int strict) { struct flowi fl = { .oif = oif, @@ -925,7 +925,7 @@ static DEFINE_SPINLOCK(icmp6_dst_lock); struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct neighbour *neigh, - struct in6_addr *addr) + const struct in6_addr *addr) { struct rt6_info *rt; struct inet6_dev *idev = in6_dev_get(dev); -- cgit v1.2.3-59-g8ed1b From f3ee4010e84452aa133e5163e6cfabc52b194e94 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 15:42:11 +0900 Subject: [IPV6]: Define constants for link-local multicast addresses. - Define link-local all-node / all-router multicast addresses. - Remove ipv6_addr_all_nodes() and ipv6_addr_all_routers(). Signed-off-by: YOSHIFUJI Hideaki --- include/linux/in6.h | 8 ++++++++ include/net/addrconf.h | 11 ----------- net/ipv6/addrconf.c | 25 +++++++------------------ net/ipv6/mcast.c | 23 ++++++++--------------- net/ipv6/ndisc.c | 5 +---- 5 files changed, 24 insertions(+), 48 deletions(-) (limited to 'net') diff --git a/include/linux/in6.h b/include/linux/in6.h index e6aa8de2b939..bc492048c349 100644 --- a/include/linux/in6.h +++ b/include/linux/in6.h @@ -48,6 +48,14 @@ extern const struct in6_addr in6addr_any; #define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } extern const struct in6_addr in6addr_loopback; #define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } +#ifdef __KERNEL__ +extern const struct in6_addr in6addr_linklocal_allnodes; +#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \ + { { { 0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } +extern const struct in6_addr in6addr_linklocal_allrouters; +#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \ + { { { 0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2 } } } +#endif struct sockaddr_in6 { unsigned short int sin6_family; /* AF_INET6 */ diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 92af23d66eb9..0a2f0372df31 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -205,17 +205,6 @@ static inline void addrconf_addr_solict_mult(const struct in6_addr *addr, htonl(0xFF000000) | addr->s6_addr32[3]); } - -static inline void ipv6_addr_all_nodes(struct in6_addr *addr) -{ - ipv6_addr_set(addr, htonl(0xFF020000), 0, 0, htonl(0x1)); -} - -static inline void ipv6_addr_all_routers(struct in6_addr *addr) -{ - ipv6_addr_set(addr, htonl(0xFF020000), 0, 0, htonl(0x2)); -} - static inline int ipv6_addr_is_multicast(const struct in6_addr *addr) { return (addr->s6_addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000); diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4048c2b73b0b..7df04d294924 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -222,6 +222,8 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; +const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; +const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; /* Check if a valid qdisc is available */ static inline int addrconf_qdisc_ok(struct net_device *dev) @@ -321,7 +323,6 @@ EXPORT_SYMBOL(in6_dev_finish_destroy); static struct inet6_dev * ipv6_add_dev(struct net_device *dev) { struct inet6_dev *ndev; - struct in6_addr maddr; ASSERT_RTNL(); @@ -406,8 +407,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) rcu_assign_pointer(dev->ip6_ptr, ndev); /* Join all-node multicast group */ - ipv6_addr_all_nodes(&maddr); - ipv6_dev_mc_inc(dev, &maddr); + ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes); return ndev; } @@ -433,18 +433,15 @@ static void dev_forward_change(struct inet6_dev *idev) { struct net_device *dev; struct inet6_ifaddr *ifa; - struct in6_addr addr; if (!idev) return; dev = idev->dev; if (dev && (dev->flags & IFF_MULTICAST)) { - ipv6_addr_all_routers(&addr); - if (idev->cnf.forwarding) - ipv6_dev_mc_inc(dev, &addr); + ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); else - ipv6_dev_mc_dec(dev, &addr); + ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters); } for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) { if (ifa->flags&IFA_F_TENTATIVE) @@ -2654,8 +2651,6 @@ static void addrconf_rs_timer(unsigned long data) spin_lock(&ifp->lock); if (ifp->probes++ < ifp->idev->cnf.rtr_solicits) { - struct in6_addr all_routers; - /* The wait after the last probe can be shorter */ addrconf_mod_timer(ifp, AC_RS, (ifp->probes == ifp->idev->cnf.rtr_solicits) ? @@ -2663,9 +2658,7 @@ static void addrconf_rs_timer(unsigned long data) ifp->idev->cnf.rtr_solicit_interval); spin_unlock(&ifp->lock); - ipv6_addr_all_routers(&all_routers); - - ndisc_send_rs(ifp->idev->dev, &ifp->addr, &all_routers); + ndisc_send_rs(ifp->idev->dev, &ifp->addr, &in6addr_linklocal_allrouters); } else { spin_unlock(&ifp->lock); /* @@ -2806,16 +2799,12 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp) ifp->idev->cnf.rtr_solicits > 0 && (dev->flags&IFF_LOOPBACK) == 0 && (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) { - struct in6_addr all_routers; - - ipv6_addr_all_routers(&all_routers); - /* * If a host as already performed a random delay * [...] as part of DAD [...] there is no need * to delay again before sending the first RS */ - ndisc_send_rs(ifp->idev->dev, &ifp->addr, &all_routers); + ndisc_send_rs(ifp->idev->dev, &ifp->addr, &in6addr_linklocal_allrouters); spin_lock_bh(&ifp->lock); ifp->probes = 1; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 0a0132a1c443..c2dc2e2b6c07 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1766,10 +1766,9 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) struct inet6_dev *idev; struct sk_buff *skb; struct icmp6hdr *hdr; - struct in6_addr *snd_addr; + const struct in6_addr *snd_addr; struct in6_addr *addrp; struct in6_addr addr_buf; - struct in6_addr all_routers; int err, len, payload_len, full_len; u8 ra[8] = { IPPROTO_ICMPV6, 0, IPV6_TLV_ROUTERALERT, 2, 0, 0, @@ -1780,11 +1779,10 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) IP6_INC_STATS(__in6_dev_get(dev), IPSTATS_MIB_OUTREQUESTS); rcu_read_unlock(); - snd_addr = addr; - if (type == ICMPV6_MGM_REDUCTION) { - snd_addr = &all_routers; - ipv6_addr_all_routers(&all_routers); - } + if (type == ICMPV6_MGM_REDUCTION) + snd_addr = &in6addr_linklocal_allrouters; + else + snd_addr = addr; len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr); payload_len = len + sizeof(ra); @@ -2309,24 +2307,19 @@ void ipv6_mc_init_dev(struct inet6_dev *idev) void ipv6_mc_destroy_dev(struct inet6_dev *idev) { struct ifmcaddr6 *i; - struct in6_addr maddr; /* Deactivate timers */ ipv6_mc_down(idev); /* Delete all-nodes address. */ - ipv6_addr_all_nodes(&maddr); - /* We cannot call ipv6_dev_mc_dec() directly, our caller in * addrconf.c has NULL'd out dev->ip6_ptr so in6_dev_get() will * fail. */ - __ipv6_dev_mc_dec(idev, &maddr); + __ipv6_dev_mc_dec(idev, &in6addr_linklocal_allnodes); - if (idev->cnf.forwarding) { - ipv6_addr_all_routers(&maddr); - __ipv6_dev_mc_dec(idev, &maddr); - } + if (idev->cnf.forwarding) + __ipv6_dev_mc_dec(idev, &in6addr_linklocal_allrouters); write_lock_bh(&idev->lock); while ((i = idev->mc_list) != NULL) { diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 5b9ad5e2f56d..2c74885f8355 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -818,10 +818,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) is_router = !!idev->cnf.forwarding; if (dad) { - struct in6_addr maddr; - - ipv6_addr_all_nodes(&maddr); - ndisc_send_na(dev, NULL, &maddr, &msg->target, + ndisc_send_na(dev, NULL, &in6addr_linklocal_allnodes, &msg->target, is_router, 0, (ifp != NULL), 1); goto out; } -- cgit v1.2.3-59-g8ed1b From d7aabf22efb50e6d52ed953ed2a43996152a7fb0 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 15:42:11 +0900 Subject: [IPV6]: Use in6addr_any where appropriate. Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/addrconf.c | 4 +--- net/ipv6/mcast.c | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 7df04d294924..e93fa62089f8 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2745,7 +2745,6 @@ static void addrconf_dad_timer(unsigned long data) { struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; struct inet6_dev *idev = ifp->idev; - struct in6_addr unspec; struct in6_addr mcaddr; read_lock_bh(&idev->lock); @@ -2774,9 +2773,8 @@ static void addrconf_dad_timer(unsigned long data) read_unlock_bh(&idev->lock); /* send a neighbour solicitation for our addr */ - memset(&unspec, 0, sizeof(unspec)); addrconf_addr_solict_mult(&ifp->addr, &mcaddr); - ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &unspec); + ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &in6addr_any); out: in6_ifa_put(ifp); } diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index c2dc2e2b6c07..54f91efdae58 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1404,6 +1404,7 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) struct sk_buff *skb; struct mld2_report *pmr; struct in6_addr addr_buf; + const struct in6_addr *saddr; int err; u8 ra[8] = { IPPROTO_ICMPV6, 0, IPV6_TLV_ROUTERALERT, 2, 0, 0, @@ -1422,10 +1423,11 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) * use unspecified address as the source address * when a valid link-local address is not available. */ - memset(&addr_buf, 0, sizeof(addr_buf)); - } + saddr = &in6addr_any; + } else + saddr = &addr_buf; - ip6_nd_hdr(sk, skb, dev, &addr_buf, &mld2_all_mcr, NEXTHDR_HOP, 0); + ip6_nd_hdr(sk, skb, dev, saddr, &mld2_all_mcr, NEXTHDR_HOP, 0); memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); @@ -1766,7 +1768,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) struct inet6_dev *idev; struct sk_buff *skb; struct icmp6hdr *hdr; - const struct in6_addr *snd_addr; + const struct in6_addr *snd_addr, *saddr; struct in6_addr *addrp; struct in6_addr addr_buf; int err, len, payload_len, full_len; @@ -1805,10 +1807,11 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) * use unspecified address as the source address * when a valid link-local address is not available. */ - memset(&addr_buf, 0, sizeof(addr_buf)); - } + saddr = &in6addr_any; + } else + saddr = &addr_buf; - ip6_nd_hdr(sk, skb, dev, &addr_buf, snd_addr, NEXTHDR_HOP, payload_len); + ip6_nd_hdr(sk, skb, dev, saddr, snd_addr, NEXTHDR_HOP, payload_len); memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); @@ -1819,7 +1822,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr)); ipv6_addr_copy(addrp, addr); - hdr->icmp6_cksum = csum_ipv6_magic(&addr_buf, snd_addr, len, + hdr->icmp6_cksum = csum_ipv6_magic(saddr, snd_addr, len, IPPROTO_ICMPV6, csum_partial((__u8 *) hdr, len, 0)); -- cgit v1.2.3-59-g8ed1b From 7f1eced8b0a001c4d5a8cfa5ac7b5cbc89fedab8 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 10 Apr 2008 15:42:12 +0900 Subject: [IPV6] MIP6: Use our standard definitions for paddings. MIP6_OPT_PAD_X are actually for paddings in destination option header. Replace them with our standard IPV6_TLV_PADX. Signed-off-by: YOSHIFUJI Hideaki --- include/net/mip6.h | 3 --- net/ipv6/mip6.c | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/include/net/mip6.h b/include/net/mip6.h index 63272610a24a..a83ad1982a90 100644 --- a/include/net/mip6.h +++ b/include/net/mip6.h @@ -28,9 +28,6 @@ #include #include -#define MIP6_OPT_PAD_1 0 -#define MIP6_OPT_PAD_N 1 - /* * Mobility Header */ diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 42403c626c27..ad1cc5bbf977 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -44,9 +44,9 @@ static inline void *mip6_padn(__u8 *data, __u8 padlen) if (!data) return NULL; if (padlen == 1) { - data[0] = MIP6_OPT_PAD_1; + data[0] = IPV6_TLV_PAD0; } else if (padlen > 1) { - data[0] = MIP6_OPT_PAD_N; + data[0] = IPV6_TLV_PADN; data[1] = padlen - 2; if (padlen > 2) memset(data+2, 0, data[1]); -- cgit v1.2.3-59-g8ed1b From a28398ba6112be28c6a92aacf06aca1979b454b7 Mon Sep 17 00:00:00 2001 From: Wang Chen Date: Mon, 7 Apr 2008 09:42:07 +0800 Subject: [IPV6]: Check length of optval provided by user in setsockopt(). Check length of setsockopt's optval, which provided by user, before copy it from user space. For POSIX compliant, return -EINVAL for setsockopt of short lengths. Signed-off-by: Wang Chen Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/ipv6_sockglue.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index bf9695375219..bd3fb129b393 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -449,6 +449,9 @@ done: { struct ipv6_mreq mreq; + if (optlen < sizeof(struct ipv6_mreq)) + goto e_inval; + retv = -EPROTO; if (inet_sk(sk)->is_icsk) break; @@ -468,7 +471,7 @@ done: { struct ipv6_mreq mreq; - if (optlen != sizeof(struct ipv6_mreq)) + if (optlen < sizeof(struct ipv6_mreq)) goto e_inval; retv = -EFAULT; @@ -487,6 +490,9 @@ done: struct group_req greq; struct sockaddr_in6 *psin6; + if (optlen < sizeof(struct group_req)) + goto e_inval; + retv = -EFAULT; if (copy_from_user(&greq, optval, sizeof(struct group_req))) break; @@ -511,7 +517,7 @@ done: struct group_source_req greqs; int omode, add; - if (optlen != sizeof(struct group_source_req)) + if (optlen < sizeof(struct group_source_req)) goto e_inval; if (copy_from_user(&greqs, optval, sizeof(greqs))) { retv = -EFAULT; -- cgit v1.2.3-59-g8ed1b From b2a9d7c2f8ab151fff78db06f1ae9b22a856e95e Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sat, 12 Apr 2008 12:59:42 +0900 Subject: [IPV6]: Check length of int/boolean optval provided by user in setsockopt(). Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/ipv6_sockglue.c | 68 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index bd3fb129b393..2f1244dc5ebf 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -16,7 +16,6 @@ * * FIXME: Make the setsockopt code POSIX compliant: That is * - * o Return -EINVAL for setsockopt of short lengths * o Truncate getsockopt returns * o Return an optlen of the truncated length if need be * @@ -114,8 +113,13 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, if (optval == NULL) val=0; - else if (get_user(val, (int __user *) optval)) - return -EFAULT; + else { + if (optlen >= sizeof(int)) { + if (get_user(val, (int __user *) optval)) + return -EFAULT; + } else + val = 0; + } valbool = (val!=0); @@ -127,6 +131,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, switch (optname) { case IPV6_ADDRFORM: + if (optlen < sizeof(int)) + goto e_inval; if (val == PF_INET) { struct ipv6_txoptions *opt; struct sk_buff *pktopt; @@ -201,63 +207,86 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, goto e_inval; case IPV6_V6ONLY: - if (inet_sk(sk)->num) + if (optlen < sizeof(int) || + inet_sk(sk)->num) goto e_inval; np->ipv6only = valbool; retv = 0; break; case IPV6_RECVPKTINFO: + if (optlen < sizeof(int)) + goto e_inval; np->rxopt.bits.rxinfo = valbool; retv = 0; break; case IPV6_2292PKTINFO: + if (optlen < sizeof(int)) + goto e_inval; np->rxopt.bits.rxoinfo = valbool; retv = 0; break; case IPV6_RECVHOPLIMIT: + if (optlen < sizeof(int)) + goto e_inval; np->rxopt.bits.rxhlim = valbool; retv = 0; break; case IPV6_2292HOPLIMIT: + if (optlen < sizeof(int)) + goto e_inval; np->rxopt.bits.rxohlim = valbool; retv = 0; break; case IPV6_RECVRTHDR: + if (optlen < sizeof(int)) + goto e_inval; np->rxopt.bits.srcrt = valbool; retv = 0; break; case IPV6_2292RTHDR: + if (optlen < sizeof(int)) + goto e_inval; np->rxopt.bits.osrcrt = valbool; retv = 0; break; case IPV6_RECVHOPOPTS: + if (optlen < sizeof(int)) + goto e_inval; np->rxopt.bits.hopopts = valbool; retv = 0; break; case IPV6_2292HOPOPTS: + if (optlen < sizeof(int)) + goto e_inval; np->rxopt.bits.ohopopts = valbool; retv = 0; break; case IPV6_RECVDSTOPTS: + if (optlen < sizeof(int)) + goto e_inval; np->rxopt.bits.dstopts = valbool; retv = 0; break; case IPV6_2292DSTOPTS: + if (optlen < sizeof(int)) + goto e_inval; np->rxopt.bits.odstopts = valbool; retv = 0; break; case IPV6_TCLASS: + if (optlen < sizeof(int)) + goto e_inval; if (val < -1 || val > 0xff) goto e_inval; np->tclass = val; @@ -265,11 +294,15 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, break; case IPV6_RECVTCLASS: + if (optlen < sizeof(int)) + goto e_inval; np->rxopt.bits.rxtclass = valbool; retv = 0; break; case IPV6_FLOWINFO: + if (optlen < sizeof(int)) + goto e_inval; np->rxopt.bits.rxflow = valbool; retv = 0; break; @@ -288,9 +321,9 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, if (optname != IPV6_RTHDR && !capable(CAP_NET_RAW)) break; - retv = -EINVAL; - if (optlen & 0x7 || optlen > 8 * 255) - break; + if (optlen < sizeof(struct ipv6_opt_hdr) || + optlen & 0x7 || optlen > 8 * 255) + goto e_inval; opt = ipv6_renew_options(sk, np->opt, optname, (struct ipv6_opt_hdr __user *)optval, @@ -408,6 +441,8 @@ done: break; } case IPV6_UNICAST_HOPS: + if (optlen < sizeof(int)) + goto e_inval; if (val > 255 || val < -1) goto e_inval; np->hop_limit = val; @@ -417,6 +452,8 @@ done: case IPV6_MULTICAST_HOPS: if (sk->sk_type == SOCK_STREAM) goto e_inval; + if (optlen < sizeof(int)) + goto e_inval; if (val > 255 || val < -1) goto e_inval; np->mcast_hops = val; @@ -424,6 +461,8 @@ done: break; case IPV6_MULTICAST_LOOP: + if (optlen < sizeof(int)) + goto e_inval; np->mc_loop = valbool; retv = 0; break; @@ -431,6 +470,8 @@ done: case IPV6_MULTICAST_IF: if (sk->sk_type == SOCK_STREAM) goto e_inval; + if (optlen < sizeof(int)) + goto e_inval; if (val) { if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) @@ -591,27 +632,37 @@ done: break; } case IPV6_ROUTER_ALERT: + if (optlen < sizeof(int)) + goto e_inval; retv = ip6_ra_control(sk, val, NULL); break; case IPV6_MTU_DISCOVER: + if (optlen < sizeof(int)) + goto e_inval; if (val<0 || val>3) goto e_inval; np->pmtudisc = val; retv = 0; break; case IPV6_MTU: + if (optlen < sizeof(int)) + goto e_inval; if (val && val < IPV6_MIN_MTU) goto e_inval; np->frag_size = val; retv = 0; break; case IPV6_RECVERR: + if (optlen < sizeof(int)) + goto e_inval; np->recverr = valbool; if (!val) skb_queue_purge(&sk->sk_error_queue); retv = 0; break; case IPV6_FLOWINFO_SEND: + if (optlen < sizeof(int)) + goto e_inval; np->sndflow = valbool; retv = 0; break; @@ -631,6 +682,9 @@ done: unsigned int pref = 0; unsigned int prefmask = ~0; + if (optlen < sizeof(int)) + goto e_inval; + retv = -EINVAL; /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */ -- cgit v1.2.3-59-g8ed1b From 6ac7eb0868ccc9a2c597d6fd0b1ea09dcdc396ed Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Thu, 10 Apr 2008 12:40:10 +0300 Subject: [IPV6] MROUTE: Adjust IPV6 multicast routing module to use mroute6 header declarations. - This patch adjusts IPv6 multicast routing module, net/ipv6/ip6mr.c, to use mroute6 header definitions instead of mroute. (MFC6_LINES instead of MFC_LINES, MAXMIFS instead of MAXVIFS, mifi_t instead of vifi_t.) - In addition, inclusion of some headers was removed as it is not needed. Signed-off-by: Rami Rosen Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/ip6mr.c | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 433042114148..94ede696da2a 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -27,27 +27,18 @@ #include #include #include -#include #include #include #include -#include #include #include -#include #include -#include #include #include #include -#include -#include #include -#include #include #include -#include -#include #include #include @@ -83,7 +74,7 @@ static int mroute_do_pim; #define mroute_do_pim 0 #endif -static struct mfc6_cache *mfc6_cache_array[MFC_LINES]; /* Forwarding cache */ +static struct mfc6_cache *mfc6_cache_array[MFC6_LINES]; /* Forwarding cache */ static struct mfc6_cache *mfc_unres_queue; /* Queue of unresolved entries */ static atomic_t cache_resolve_queue_len; /* Size of unresolved */ @@ -102,7 +93,7 @@ static DEFINE_SPINLOCK(mfc_unres_lock); static struct kmem_cache *mrt_cachep __read_mostly; static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache); -static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert); +static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert); static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm); #ifdef CONFIG_IPV6_PIMSM_V2 @@ -597,9 +588,9 @@ static void ip6mr_update_thresholds(struct mfc6_cache *cache, unsigned char *ttl { int vifi; - cache->mfc_un.res.minvif = MAXVIFS; + cache->mfc_un.res.minvif = MAXMIFS; cache->mfc_un.res.maxvif = 0; - memset(cache->mfc_un.res.ttls, 255, MAXVIFS); + memset(cache->mfc_un.res.ttls, 255, MAXMIFS); for (vifi = 0; vifi < maxvif; vifi++) { if (MIF_EXISTS(vifi) && ttls[vifi] && ttls[vifi] < 255) { @@ -700,7 +691,7 @@ static struct mfc6_cache *ip6mr_cache_alloc(void) if (c == NULL) return NULL; memset(c, 0, sizeof(*c)); - c->mfc_un.res.minvif = MAXVIFS; + c->mfc_un.res.minvif = MAXMIFS; return c; } @@ -753,7 +744,7 @@ static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c) * Called under mrt_lock. */ -static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) +static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert) { struct sk_buff *skb; struct mrt6msg *msg; @@ -815,7 +806,7 @@ static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) msg->im6_mbz = 0; msg->im6_msgtype = assert; - msg->im6_mif = vifi; + msg->im6_mif = mifi; msg->im6_pad = 0; ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr); ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr); @@ -848,7 +839,7 @@ static int ip6mr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) */ static int -ip6mr_cache_unresolved(vifi_t vifi, struct sk_buff *skb) +ip6mr_cache_unresolved(mifi_t mifi, struct sk_buff *skb) { int err; struct mfc6_cache *c; @@ -883,7 +874,7 @@ ip6mr_cache_unresolved(vifi_t vifi, struct sk_buff *skb) /* * Reflect first query at pim6sd */ - if ((err = ip6mr_cache_report(skb, vifi, MRT6MSG_NOCACHE)) < 0) { + if ((err = ip6mr_cache_report(skb, mifi, MRT6MSG_NOCACHE)) < 0) { /* If the report failed throw the cache entry out - Brad Parker */ @@ -992,11 +983,11 @@ static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock) { int line; struct mfc6_cache *uc, *c, **cp; - unsigned char ttls[MAXVIFS]; + unsigned char ttls[MAXMIFS]; int i; - memset(ttls, 255, MAXVIFS); - for (i = 0; i < MAXVIFS; i++) { + memset(ttls, 255, MAXMIFS); + for (i = 0; i < MAXMIFS; i++) { if (IF_ISSET(i, &mfc->mf6cc_ifset)) ttls[i] = 1; @@ -1188,7 +1179,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int return -EINVAL; if (copy_from_user(&vif, optval, sizeof(vif))) return -EFAULT; - if (vif.mif6c_mifi >= MAXVIFS) + if (vif.mif6c_mifi >= MAXMIFS) return -ENFILE; rtnl_lock(); ret = mif6_add(&vif, sk == mroute6_socket); -- cgit v1.2.3-59-g8ed1b From 876c7f41961dc5172b03cbf2dca65f05003f28a0 Mon Sep 17 00:00:00 2001 From: Brian Haley Date: Fri, 11 Apr 2008 00:38:24 -0400 Subject: [IPv6]: Change IPv6 unspecified destination address to ::1 for raw and un-connected sockets This patch fixes a difference between IPv4 and IPv6 when sending packets to the unspecified address (either 0.0.0.0 or ::) when using raw or un-connected UDP sockets. There are two cases where IPv6 either fails to send anything, or sends with the destination address set to ::. For example: --> ping -c1 0.0.0.0 PING 0.0.0.0 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.032 ms --> ping6 -c1 :: PING ::(::) 56 data bytes ping: sendmsg: Invalid argument Doing a sendto("0.0.0.0") reveals: 10:55:01.495090 IP localhost.32780 > localhost.7639: UDP, length 100 Doing a sendto("::") reveals: 10:56:13.262478 IP6 fe80::217:8ff:fe7d:4718.32779 > ::.7639: UDP, length 100 If you issue a connect() first in the UDP case, it will be sent to ::1, similar to what happens with TCP. This restores the BSD-ism. Signed-off-by: Brian Haley Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/raw.c | 14 ++++---------- net/ipv6/udp.c | 5 ++++- 2 files changed, 8 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 088b80b4ce74..059298baa1dd 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -805,15 +805,6 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, fl.fl6_flowlabel = np->flow_label; } - if (ipv6_addr_any(daddr)) { - /* - * unspecified destination address - * treated as error... is this correct ? - */ - fl6_sock_release(flowlabel); - return(-EINVAL); - } - if (fl.oif == 0) fl.oif = sk->sk_bound_dev_if; @@ -846,7 +837,10 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, if (err) goto out; - ipv6_addr_copy(&fl.fl6_dst, daddr); + if (!ipv6_addr_any(daddr)) + ipv6_addr_copy(&fl.fl6_dst, daddr); + else + fl.fl6_dst.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) ipv6_addr_copy(&fl.fl6_src, &np->saddr); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 30ef7dc5d403..1fd784f3e2ec 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -752,7 +752,10 @@ do_udp_sendmsg: opt = ipv6_fixup_options(&opt_space, opt); fl.proto = sk->sk_protocol; - ipv6_addr_copy(&fl.fl6_dst, daddr); + if (!ipv6_addr_any(daddr)) + ipv6_addr_copy(&fl.fl6_dst, daddr); + else + fl.fl6_dst.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr)) ipv6_addr_copy(&fl.fl6_src, &np->saddr); fl.fl_ip_sport = inet->sport; -- cgit v1.2.3-59-g8ed1b From 05f175cdcf9d3615c1633615d87891ebfb729401 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Fri, 11 Apr 2008 23:51:26 +0900 Subject: [IPV6]: Fix IPV6_RECVERR for connected raw sockets. Based on patch from Dmitry Butskoy . Closes: 10437 Signed-off-by: YOSHIFUJI Hideaki --- net/ipv6/raw.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 059298baa1dd..6193b124cbc7 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -357,8 +357,10 @@ void raw6_icmp_error(struct sk_buff *skb, int nexthdr, read_lock(&raw_v6_hashinfo.lock); sk = sk_head(&raw_v6_hashinfo.ht[hash]); if (sk != NULL) { - saddr = &ipv6_hdr(skb)->saddr; - daddr = &ipv6_hdr(skb)->daddr; + /* Note: ipv6_hdr(skb) != skb->data */ + struct ipv6hdr *ip6h = (struct ipv6hdr *)skb->data; + saddr = &ip6h->saddr; + daddr = &ip6h->daddr; net = dev_net(skb->dev); while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr, -- cgit v1.2.3-59-g8ed1b From 30e935600776b45db38238355f0de2b8f72b3847 Mon Sep 17 00:00:00 2001 From: Neil Horman Date: Sat, 12 Apr 2008 18:53:48 -0700 Subject: [SCTP]: Correct /proc/net/assocs formatting error Recently I posted a patch to add some informational items to /proc/net/sctp/assocs. All the information is correct, but because of how the seqfile show operation is laid out, some of the formatting is backwards. This patch corrects that formatting, so that the new information appears at the end of each line, rather than in the middle. Signed-off-by: Neil Horman Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/proc.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/net/sctp/proc.c b/net/sctp/proc.c index ddca90e5e3a5..99062f5f42e3 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -322,8 +322,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) sk = epb->sk; seq_printf(seq, "%8p %8p %-3d %-3d %-2d %-4d " - "%4d %8d %8d %7d %5lu %-5d %5d " - "%8lu %5d %5d %4d %4d %4d %8d ", + "%4d %8d %8d %7d %5lu %-5d %5d ", assoc, sk, sctp_sk(sk)->type, sk->sk_state, assoc->state, hash, assoc->assoc_id, @@ -331,15 +330,16 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v) atomic_read(&assoc->rmem_alloc), sock_i_uid(sk), sock_i_ino(sk), epb->bind_addr.port, - assoc->peer.port, - assoc->hbinterval, assoc->c.sinit_max_instreams, - assoc->c.sinit_num_ostreams, assoc->max_retrans, - assoc->init_retries, assoc->shutdown_retries, - assoc->rtx_data_chunks); + assoc->peer.port); seq_printf(seq, " "); sctp_seq_dump_local_addrs(seq, epb); seq_printf(seq, "<-> "); sctp_seq_dump_remote_addrs(seq, assoc); + seq_printf(seq, "\t%8lu %5d %5d %4d %4d %4d %8d ", + assoc->hbinterval, assoc->c.sinit_max_instreams, + assoc->c.sinit_num_ostreams, assoc->max_retrans, + assoc->init_retries, assoc->shutdown_retries, + assoc->rtx_data_chunks); seq_printf(seq, "\n"); } read_unlock(&head->lock); -- cgit v1.2.3-59-g8ed1b From 9dbc15f055f05393ace4f1733f160ec3d188cf9b Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Sat, 12 Apr 2008 18:54:24 -0700 Subject: [SCTP]: "list_for_each()" -> "list_for_each_entry()" where appropriate. Replacing (almost) all invocations of list_for_each() with list_for_each_entry() tightens up the code and allows for the deletion of numerous list iterator variables that are no longer necessary. Signed-off-by: Robert P. J. Day Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/associola.c | 34 ++++++++++++----------------- net/sctp/bind_addr.c | 15 ++++--------- net/sctp/outqueue.c | 49 ++++++++++++++---------------------------- net/sctp/proc.c | 9 +++----- net/sctp/sm_make_chunk.c | 10 ++++----- net/sctp/sm_sideeffect.c | 20 ++++++----------- net/sctp/sm_statefuns.c | 10 ++++----- net/sctp/socket.c | 56 +++++++++++++++--------------------------------- 8 files changed, 69 insertions(+), 134 deletions(-) (limited to 'net') diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 422c98aa9d5c..b4cd2b71953f 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -718,12 +718,11 @@ struct sctp_transport *sctp_assoc_lookup_paddr( const union sctp_addr *address) { struct sctp_transport *t; - struct list_head *pos; /* Cycle through all transports searching for a peer address. */ - list_for_each(pos, &asoc->peer.transport_addr_list) { - t = list_entry(pos, struct sctp_transport, transports); + list_for_each_entry(t, &asoc->peer.transport_addr_list, + transports) { if (sctp_cmp_addr_exact(address, &t->ipaddr)) return t; } @@ -762,7 +761,6 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, struct sctp_transport *second; struct sctp_ulpevent *event; struct sockaddr_storage addr; - struct list_head *pos; int spc_state = 0; /* Record the transition on the transport. */ @@ -814,8 +812,8 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, */ first = NULL; second = NULL; - list_for_each(pos, &asoc->peer.transport_addr_list) { - t = list_entry(pos, struct sctp_transport, transports); + list_for_each_entry(t, &asoc->peer.transport_addr_list, + transports) { if ((t->state == SCTP_INACTIVE) || (t->state == SCTP_UNCONFIRMED)) @@ -932,7 +930,6 @@ struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc, { struct sctp_transport *active; struct sctp_transport *match; - struct list_head *entry, *pos; struct sctp_transport *transport; struct sctp_chunk *chunk; __be32 key = htonl(tsn); @@ -956,8 +953,8 @@ struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc, active = asoc->peer.active_path; - list_for_each(entry, &active->transmitted) { - chunk = list_entry(entry, struct sctp_chunk, transmitted_list); + list_for_each_entry(chunk, &active->transmitted, + transmitted_list) { if (key == chunk->subh.data_hdr->tsn) { match = active; @@ -966,14 +963,13 @@ struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc, } /* If not found, go search all the other transports. */ - list_for_each(pos, &asoc->peer.transport_addr_list) { - transport = list_entry(pos, struct sctp_transport, transports); + list_for_each_entry(transport, &asoc->peer.transport_addr_list, + transports) { if (transport == active) break; - list_for_each(entry, &transport->transmitted) { - chunk = list_entry(entry, struct sctp_chunk, - transmitted_list); + list_for_each_entry(chunk, &transport->transmitted, + transmitted_list) { if (key == chunk->subh.data_hdr->tsn) { match = transport; goto out; @@ -1154,9 +1150,8 @@ void sctp_assoc_update(struct sctp_association *asoc, } else { /* Add any peer addresses from the new association. */ - list_for_each(pos, &new->peer.transport_addr_list) { - trans = list_entry(pos, struct sctp_transport, - transports); + list_for_each_entry(trans, &new->peer.transport_addr_list, + transports) { if (!sctp_assoc_lookup_paddr(asoc, &trans->ipaddr)) sctp_assoc_add_peer(asoc, &trans->ipaddr, GFP_ATOMIC, trans->state); @@ -1306,15 +1301,14 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport( void sctp_assoc_sync_pmtu(struct sctp_association *asoc) { struct sctp_transport *t; - struct list_head *pos; __u32 pmtu = 0; if (!asoc) return; /* Get the lowest pmtu of all the transports. */ - list_for_each(pos, &asoc->peer.transport_addr_list) { - t = list_entry(pos, struct sctp_transport, transports); + list_for_each_entry(t, &asoc->peer.transport_addr_list, + transports) { if (t->pmtu_pending && t->dst) { sctp_transport_update_pmtu(t, dst_mtu(t->dst)); t->pmtu_pending = 0; diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index ceefda025e2d..80e6df06967a 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -67,15 +67,13 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest, int flags) { struct sctp_sockaddr_entry *addr; - struct list_head *pos; int error = 0; /* All addresses share the same port. */ dest->port = src->port; /* Extract the addresses which are relevant for this scope. */ - list_for_each(pos, &src->address_list) { - addr = list_entry(pos, struct sctp_sockaddr_entry, list); + list_for_each_entry(addr, &src->address_list, list) { error = sctp_copy_one_addr(dest, &addr->a, scope, gfp, flags); if (error < 0) @@ -87,9 +85,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest, * the assumption that we must be sitting behind a NAT. */ if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) { - list_for_each(pos, &src->address_list) { - addr = list_entry(pos, struct sctp_sockaddr_entry, - list); + list_for_each_entry(addr, &src->address_list, list) { error = sctp_copy_one_addr(dest, &addr->a, SCTP_SCOPE_LINK, gfp, flags); @@ -115,14 +111,12 @@ int sctp_bind_addr_dup(struct sctp_bind_addr *dest, gfp_t gfp) { struct sctp_sockaddr_entry *addr; - struct list_head *pos; int error = 0; /* All addresses share the same port. */ dest->port = src->port; - list_for_each(pos, &src->address_list) { - addr = list_entry(pos, struct sctp_sockaddr_entry, list); + list_for_each_entry(addr, &src->address_list, list) { error = sctp_add_bind_addr(dest, &addr->a, 1, gfp); if (error < 0) break; @@ -273,8 +267,7 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, addrparms = retval; - list_for_each(pos, &bp->address_list) { - addr = list_entry(pos, struct sctp_sockaddr_entry, list); + list_for_each_entry(addr, &bp->address_list, list) { af = sctp_get_af_specific(addr->a.v4.sin_family); len = af->to_addr_param(&addr->a, &rawaddr); memcpy(addrparms.v, &rawaddr, len); diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index 392012f5ab83..213c2e2926a9 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -221,12 +221,12 @@ void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q) void sctp_outq_teardown(struct sctp_outq *q) { struct sctp_transport *transport; - struct list_head *lchunk, *pos, *temp; + struct list_head *lchunk, *temp; struct sctp_chunk *chunk, *tmp; /* Throw away unacknowledged chunks. */ - list_for_each(pos, &q->asoc->peer.transport_addr_list) { - transport = list_entry(pos, struct sctp_transport, transports); + list_for_each_entry(transport, &q->asoc->peer.transport_addr_list, + transports) { while ((lchunk = sctp_list_dequeue(&transport->transmitted)) != NULL) { chunk = list_entry(lchunk, struct sctp_chunk, transmitted_list); @@ -538,7 +538,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, int rtx_timeout, int *start_timer) { struct list_head *lqueue; - struct list_head *lchunk, *lchunk1; + struct list_head *lchunk; struct sctp_transport *transport = pkt->transport; sctp_xmit_t status; struct sctp_chunk *chunk, *chunk1; @@ -649,9 +649,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, * to be marked as ineligible for a subsequent fast retransmit. */ if (rtx_timeout && !lchunk) { - list_for_each(lchunk1, lqueue) { - chunk1 = list_entry(lchunk1, struct sctp_chunk, - transmitted_list); + list_for_each_entry(chunk1, lqueue, transmitted_list) { if (chunk1->fast_retransmit > 0) chunk1->fast_retransmit = -1; } @@ -1037,7 +1035,6 @@ static void sctp_sack_update_unack_data(struct sctp_association *assoc, static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack, struct sctp_association *asoc) { - struct list_head *ltransport, *lchunk; struct sctp_transport *transport; struct sctp_chunk *chunk; __u32 highest_new_tsn, tsn; @@ -1045,12 +1042,9 @@ static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack, highest_new_tsn = ntohl(sack->cum_tsn_ack); - list_for_each(ltransport, transport_list) { - transport = list_entry(ltransport, struct sctp_transport, - transports); - list_for_each(lchunk, &transport->transmitted) { - chunk = list_entry(lchunk, struct sctp_chunk, - transmitted_list); + list_for_each_entry(transport, transport_list, transports) { + list_for_each_entry(chunk, &transport->transmitted, + transmitted_list) { tsn = ntohl(chunk->subh.data_hdr->tsn); if (!chunk->tsn_gap_acked && @@ -1073,7 +1067,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) struct sctp_association *asoc = q->asoc; struct sctp_transport *transport; struct sctp_chunk *tchunk = NULL; - struct list_head *lchunk, *transport_list, *pos, *temp; + struct list_head *lchunk, *transport_list, *temp; sctp_sack_variable_t *frags = sack->variable; __u32 sack_ctsn, ctsn, tsn; __u32 highest_tsn, highest_new_tsn; @@ -1099,9 +1093,8 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) */ if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) { primary->cacc.changeover_active = 0; - list_for_each(pos, transport_list) { - transport = list_entry(pos, struct sctp_transport, - transports); + list_for_each_entry(transport, transport_list, + transports) { transport->cacc.cycling_changeover = 0; } } @@ -1116,9 +1109,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) */ if (sack->num_gap_ack_blocks && primary->cacc.changeover_active) { - list_for_each(pos, transport_list) { - transport = list_entry(pos, struct sctp_transport, - transports); + list_for_each_entry(transport, transport_list, transports) { transport->cacc.cacc_saw_newack = 0; } } @@ -1147,9 +1138,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) * * This is a MASSIVE candidate for optimization. */ - list_for_each(pos, transport_list) { - transport = list_entry(pos, struct sctp_transport, - transports); + list_for_each_entry(transport, transport_list, transports) { sctp_check_transmitted(q, &transport->transmitted, transport, sack, highest_new_tsn); /* @@ -1161,9 +1150,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) count_of_newacks ++; } - list_for_each(pos, transport_list) { - transport = list_entry(pos, struct sctp_transport, - transports); + list_for_each_entry(transport, transport_list, transports) { sctp_mark_missing(q, &transport->transmitted, transport, highest_new_tsn, count_of_newacks); } @@ -1220,9 +1207,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack) if (!q->empty) goto finish; - list_for_each(pos, transport_list) { - transport = list_entry(pos, struct sctp_transport, - transports); + list_for_each_entry(transport, transport_list, transports) { q->empty = q->empty && list_empty(&transport->transmitted); if (!q->empty) goto finish; @@ -1596,14 +1581,12 @@ static void sctp_mark_missing(struct sctp_outq *q, int count_of_newacks) { struct sctp_chunk *chunk; - struct list_head *pos; __u32 tsn; char do_fast_retransmit = 0; struct sctp_transport *primary = q->asoc->peer.primary_path; - list_for_each(pos, transmitted_queue) { + list_for_each_entry(chunk, transmitted_queue, transmitted_list) { - chunk = list_entry(pos, struct sctp_chunk, transmitted_list); tsn = ntohl(chunk->subh.data_hdr->tsn); /* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 99062f5f42e3..0aba759cb9b7 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -124,7 +124,6 @@ void sctp_snmp_proc_exit(void) /* Dump local addresses of an association/endpoint. */ static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb) { - struct list_head *pos; struct sctp_association *asoc; struct sctp_sockaddr_entry *laddr; struct sctp_transport *peer; @@ -137,8 +136,7 @@ static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_commo primary = &peer->saddr; } - list_for_each(pos, &epb->bind_addr.address_list) { - laddr = list_entry(pos, struct sctp_sockaddr_entry, list); + list_for_each_entry(laddr, &epb->bind_addr.address_list, list) { addr = &laddr->a; af = sctp_get_af_specific(addr->sa.sa_family); if (primary && af->cmp_addr(addr, primary)) { @@ -151,14 +149,13 @@ static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_commo /* Dump remote addresses of an association. */ static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_association *assoc) { - struct list_head *pos; struct sctp_transport *transport; union sctp_addr *addr, *primary; struct sctp_af *af; primary = &assoc->peer.primary_addr; - list_for_each(pos, &assoc->peer.transport_addr_list) { - transport = list_entry(pos, struct sctp_transport, transports); + list_for_each_entry(transport, &assoc->peer.transport_addr_list, + transports) { addr = &transport->ipaddr; af = sctp_get_af_specific(addr->sa.sa_family); if (af->cmp_addr(addr, primary)) { diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index c8982452580e..0679bddf3a95 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -2246,8 +2246,8 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, * high (for example, implementations MAY use the size of the receiver * advertised window). */ - list_for_each(pos, &asoc->peer.transport_addr_list) { - transport = list_entry(pos, struct sctp_transport, transports); + list_for_each_entry(transport, &asoc->peer.transport_addr_list, + transports) { transport->ssthresh = asoc->peer.i.a_rwnd; } @@ -3043,7 +3043,6 @@ static int sctp_asconf_param_success(struct sctp_association *asoc, union sctp_addr addr; struct sctp_bind_addr *bp = &asoc->base.bind_addr; union sctp_addr_param *addr_param; - struct list_head *pos; struct sctp_transport *transport; struct sctp_sockaddr_entry *saddr; int retval = 0; @@ -3071,9 +3070,8 @@ static int sctp_asconf_param_success(struct sctp_association *asoc, local_bh_disable(); retval = sctp_del_bind_addr(bp, &addr); local_bh_enable(); - list_for_each(pos, &asoc->peer.transport_addr_list) { - transport = list_entry(pos, struct sctp_transport, - transports); + list_for_each_entry(transport, &asoc->peer.transport_addr_list, + transports) { dst_release(transport->dst); sctp_transport_route(transport, NULL, sctp_sk(asoc->base.sk)); diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 02bf32c30263..5fdb623d8281 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -545,14 +545,12 @@ static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds, struct sctp_association *asoc) { struct sctp_transport *t; - struct list_head *pos; /* Start a heartbeat timer for each transport on the association. * hold a reference on the transport to make sure none of * the needed data structures go away. */ - list_for_each(pos, &asoc->peer.transport_addr_list) { - t = list_entry(pos, struct sctp_transport, transports); + list_for_each_entry(t, &asoc->peer.transport_addr_list, transports) { if (!mod_timer(&t->hb_timer, sctp_transport_timeout(t))) sctp_transport_hold(t); @@ -563,12 +561,11 @@ static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds, struct sctp_association *asoc) { struct sctp_transport *t; - struct list_head *pos; /* Stop all heartbeat timers. */ - list_for_each(pos, &asoc->peer.transport_addr_list) { - t = list_entry(pos, struct sctp_transport, transports); + list_for_each_entry(t, &asoc->peer.transport_addr_list, + transports) { if (del_timer(&t->hb_timer)) sctp_transport_put(t); } @@ -579,10 +576,9 @@ static void sctp_cmd_t3_rtx_timers_stop(sctp_cmd_seq_t *cmds, struct sctp_association *asoc) { struct sctp_transport *t; - struct list_head *pos; - list_for_each(pos, &asoc->peer.transport_addr_list) { - t = list_entry(pos, struct sctp_transport, transports); + list_for_each_entry(t, &asoc->peer.transport_addr_list, + transports) { if (timer_pending(&t->T3_rtx_timer) && del_timer(&t->T3_rtx_timer)) { sctp_transport_put(t); @@ -1065,7 +1061,6 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, struct sctp_chunk *new_obj; struct sctp_chunk *chunk = NULL; struct sctp_packet *packet; - struct list_head *pos; struct timer_list *timer; unsigned long timeout; struct sctp_transport *t; @@ -1397,9 +1392,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, /* If we've sent any data bundled with * COOKIE-ECHO we need to resend. */ - list_for_each(pos, &asoc->peer.transport_addr_list) { - t = list_entry(pos, struct sctp_transport, - transports); + list_for_each_entry(t, &asoc->peer.transport_addr_list, + transports) { sctp_retransmit_mark(&asoc->outqueue, t, SCTP_RTXR_T1_RTX); } diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index b534dbef864f..622284805500 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -1226,7 +1226,6 @@ static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc, sctp_cmd_seq_t *commands) { struct sctp_transport *new_addr, *addr; - struct list_head *pos, *pos2; int found; /* Implementor's Guide - Sectin 5.2.2 @@ -1243,12 +1242,11 @@ static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc, new_addr = NULL; found = 0; - list_for_each(pos, &new_asoc->peer.transport_addr_list) { - new_addr = list_entry(pos, struct sctp_transport, transports); + list_for_each_entry(new_addr, &new_asoc->peer.transport_addr_list, + transports) { found = 0; - list_for_each(pos2, &asoc->peer.transport_addr_list) { - addr = list_entry(pos2, struct sctp_transport, - transports); + list_for_each_entry(addr, &asoc->peer.transport_addr_list, + transports) { if (sctp_cmp_addr_exact(&new_addr->ipaddr, &addr->ipaddr)) { found = 1; diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 025f467d80dd..8c90289ba400 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -513,7 +513,6 @@ static int sctp_send_asconf_add_ip(struct sock *sk, union sctp_addr saveaddr; void *addr_buf; struct sctp_af *af; - struct list_head *pos; struct list_head *p; int i; int retval = 0; @@ -527,8 +526,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk, SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n", __func__, sk, addrs, addrcnt); - list_for_each(pos, &ep->asocs) { - asoc = list_entry(pos, struct sctp_association, asocs); + list_for_each_entry(asoc, &ep->asocs, asocs) { if (!asoc->peer.asconf_capable) continue; @@ -699,7 +697,6 @@ static int sctp_send_asconf_del_ip(struct sock *sk, union sctp_addr *laddr; void *addr_buf; struct sctp_af *af; - struct list_head *pos, *pos1; struct sctp_sockaddr_entry *saddr; int i; int retval = 0; @@ -713,8 +710,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk, SCTP_DEBUG_PRINTK("%s: (sk: %p, addrs: %p, addrcnt: %d)\n", __func__, sk, addrs, addrcnt); - list_for_each(pos, &ep->asocs) { - asoc = list_entry(pos, struct sctp_association, asocs); + list_for_each_entry(asoc, &ep->asocs, asocs) { if (!asoc->peer.asconf_capable) continue; @@ -787,9 +783,8 @@ static int sctp_send_asconf_del_ip(struct sock *sk, * as some of the addresses in the bind address list are * about to be deleted and cannot be used as source addresses. */ - list_for_each(pos1, &asoc->peer.transport_addr_list) { - transport = list_entry(pos1, struct sctp_transport, - transports); + list_for_each_entry(transport, &asoc->peer.transport_addr_list, + transports) { dst_release(transport->dst); sctp_transport_route(transport, NULL, sctp_sk(asoc->base.sk)); @@ -1397,7 +1392,6 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, long timeo; __u16 sinfo_flags = 0; struct sctp_datamsg *datamsg; - struct list_head *pos; int msg_flags = msg->msg_flags; SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %zu)\n", @@ -1727,8 +1721,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, } /* Now send the (possibly) fragmented message. */ - list_for_each(pos, &datamsg->chunks) { - chunk = list_entry(pos, struct sctp_chunk, frag_list); + list_for_each_entry(chunk, &datamsg->chunks, frag_list) { sctp_chunk_hold(chunk); /* Do accounting for the write space. */ @@ -2301,11 +2294,8 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, * transport. */ if (!trans && asoc) { - struct list_head *pos; - - list_for_each(pos, &asoc->peer.transport_addr_list) { - trans = list_entry(pos, struct sctp_transport, - transports); + list_for_each_entry(trans, &asoc->peer.transport_addr_list, + transports) { sctp_apply_peer_addr_params(¶ms, trans, asoc, sp, hb_change, pmtud_change, sackdelay_change); @@ -2396,11 +2386,8 @@ static int sctp_setsockopt_delayed_ack_time(struct sock *sk, /* If change is for association, also apply to each transport. */ if (asoc) { - struct list_head *pos; - - list_for_each(pos, &asoc->peer.transport_addr_list) { - trans = list_entry(pos, struct sctp_transport, - transports); + list_for_each_entry(trans, &asoc->peer.transport_addr_list, + transports) { if (params.assoc_value) { trans->sackdelay = msecs_to_jiffies(params.assoc_value); @@ -2632,13 +2619,10 @@ static int sctp_setsockopt_associnfo(struct sock *sk, char __user *optval, int o if (assocparams.sasoc_asocmaxrxt != 0) { __u32 path_sum = 0; int paths = 0; - struct list_head *pos; struct sctp_transport *peer_addr; - list_for_each(pos, &asoc->peer.transport_addr_list) { - peer_addr = list_entry(pos, - struct sctp_transport, - transports); + list_for_each_entry(peer_addr, &asoc->peer.transport_addr_list, + transports) { path_sum += peer_addr->pathmaxrxt; paths++; } @@ -2716,7 +2700,6 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int op static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optlen) { struct sctp_association *asoc; - struct list_head *pos; struct sctp_sock *sp = sctp_sk(sk); int val; @@ -2729,8 +2712,7 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optl sp->user_frag = val; /* Update the frag_point of the existing associations. */ - list_for_each(pos, &(sp->ep->asocs)) { - asoc = list_entry(pos, struct sctp_association, asocs); + list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu); } @@ -4151,7 +4133,6 @@ static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len, int __user *optlen) { struct sctp_association *asoc; - struct list_head *pos; int cnt = 0; struct sctp_getaddrs_old getaddrs; struct sctp_transport *from; @@ -4176,8 +4157,8 @@ static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len, return -EINVAL; to = (void __user *)getaddrs.addrs; - list_for_each(pos, &asoc->peer.transport_addr_list) { - from = list_entry(pos, struct sctp_transport, transports); + list_for_each_entry(from, &asoc->peer.transport_addr_list, + transports) { memcpy(&temp, &from->ipaddr, sizeof(temp)); sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len; @@ -4200,7 +4181,6 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, char __user *optval, int __user *optlen) { struct sctp_association *asoc; - struct list_head *pos; int cnt = 0; struct sctp_getaddrs getaddrs; struct sctp_transport *from; @@ -4225,8 +4205,8 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, to = optval + offsetof(struct sctp_getaddrs,addrs); space_left = len - offsetof(struct sctp_getaddrs,addrs); - list_for_each(pos, &asoc->peer.transport_addr_list) { - from = list_entry(pos, struct sctp_transport, transports); + list_for_each_entry(from, &asoc->peer.transport_addr_list, + transports) { memcpy(&temp, &from->ipaddr, sizeof(temp)); sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len; @@ -6193,11 +6173,9 @@ do_nonblock: void sctp_write_space(struct sock *sk) { struct sctp_association *asoc; - struct list_head *pos; /* Wake up the tasks in each wait queue. */ - list_for_each(pos, &((sctp_sk(sk))->ep->asocs)) { - asoc = list_entry(pos, struct sctp_association, asocs); + list_for_each_entry(asoc, &((sctp_sk(sk))->ep->asocs), asocs) { __sctp_write_space(asoc); } } -- cgit v1.2.3-59-g8ed1b From 765ff02e896a4f4e0fdb223aadab629aaf3756d2 Mon Sep 17 00:00:00 2001 From: Gui Jianfeng Date: Sat, 12 Apr 2008 18:55:12 -0700 Subject: [SCTP]: Remove an unused parameter from sctp_cmd_hb_timer_update The 'asoc' parameter to sctp_cmd_hb_timer_update() is unused, and we can remove it. Signed-off-by: Gui Jianfeng Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/sm_sideeffect.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 5fdb623d8281..13beed263e31 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -589,7 +589,6 @@ static void sctp_cmd_t3_rtx_timers_stop(sctp_cmd_seq_t *cmds, /* Helper function to update the heartbeat timer. */ static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds, - struct sctp_association *asoc, struct sctp_transport *t) { /* Update the heartbeat timer. */ @@ -1451,7 +1450,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type, case SCTP_CMD_HB_TIMER_UPDATE: t = cmd->obj.transport; - sctp_cmd_hb_timer_update(commands, asoc, t); + sctp_cmd_hb_timer_update(commands, t); break; case SCTP_CMD_HB_TIMERS_STOP: -- cgit v1.2.3-59-g8ed1b From b9f3124f08fffe2ad706fd164f6702fdca409a91 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 12 Apr 2008 19:04:38 -0700 Subject: [AF_UNIX]: Use SEQ_START_TOKEN Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- net/unix/af_unix.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 50bbf6bb1a22..2851d0d15048 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -2037,7 +2037,7 @@ static void *unix_seq_start(struct seq_file *seq, loff_t *pos) __acquires(unix_table_lock) { spin_lock(&unix_table_lock); - return *pos ? unix_seq_idx(seq, *pos - 1) : ((void *) 1); + return *pos ? unix_seq_idx(seq, *pos - 1) : SEQ_START_TOKEN; } static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) @@ -2046,7 +2046,7 @@ static void *unix_seq_next(struct seq_file *seq, void *v, loff_t *pos) struct sock *sk = v; ++*pos; - if (v == (void *)1) + if (v == SEQ_START_TOKEN) sk = first_unix_socket(&iter->i); else sk = next_unix_socket(&iter->i, sk); @@ -2064,7 +2064,7 @@ static void unix_seq_stop(struct seq_file *seq, void *v) static int unix_seq_show(struct seq_file *seq, void *v) { - if (v == (void *)1) + if (v == SEQ_START_TOKEN) seq_puts(seq, "Num RefCount Protocol Flags Type St " "Inode Path\n"); else { -- cgit v1.2.3-59-g8ed1b From 03e1ad7b5d871d4189b1da3125c2f12d1b5f7d0b Mon Sep 17 00:00:00 2001 From: Paul Moore Date: Sat, 12 Apr 2008 19:07:52 -0700 Subject: LSM: Make the Labeled IPsec hooks more stack friendly The xfrm_get_policy() and xfrm_add_pol_expire() put some rather large structs on the stack to work around the LSM API. This patch attempts to fix that problem by changing the LSM API to require only the relevant "security" pointers instead of the entire SPD entry; we do this for all of the security_xfrm_policy*() functions to keep things consistent. Signed-off-by: Paul Moore Acked-by: James Morris Signed-off-by: David S. Miller --- include/linux/security.h | 48 ++++++++++++++++++++--------------------- net/key/af_key.c | 23 ++++++++++---------- net/xfrm/xfrm_policy.c | 24 +++++++++++++-------- net/xfrm/xfrm_user.c | 33 ++++++++++++++-------------- security/dummy.c | 14 ++++++------ security/security.c | 21 +++++++++--------- security/selinux/include/xfrm.h | 13 +++++------ security/selinux/xfrm.c | 39 ++++++++++++++------------------- 8 files changed, 109 insertions(+), 106 deletions(-) (limited to 'net') diff --git a/include/linux/security.h b/include/linux/security.h index c673dfd4dffc..f5eb9ff47ac5 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -910,24 +910,24 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * Security hooks for XFRM operations. * * @xfrm_policy_alloc_security: - * @xp contains the xfrm_policy being added to Security Policy Database - * used by the XFRM system. + * @ctxp is a pointer to the xfrm_sec_ctx being added to Security Policy + * Database used by the XFRM system. * @sec_ctx contains the security context information being provided by * the user-level policy update program (e.g., setkey). * Allocate a security structure to the xp->security field; the security * field is initialized to NULL when the xfrm_policy is allocated. * Return 0 if operation was successful (memory to allocate, legal context) * @xfrm_policy_clone_security: - * @old contains an existing xfrm_policy in the SPD. - * @new contains a new xfrm_policy being cloned from old. - * Allocate a security structure to the new->security field - * that contains the information from the old->security field. + * @old_ctx contains an existing xfrm_sec_ctx. + * @new_ctxp contains a new xfrm_sec_ctx being cloned from old. + * Allocate a security structure in new_ctxp that contains the + * information from the old_ctx structure. * Return 0 if operation was successful (memory to allocate). * @xfrm_policy_free_security: - * @xp contains the xfrm_policy + * @ctx contains the xfrm_sec_ctx * Deallocate xp->security. * @xfrm_policy_delete_security: - * @xp contains the xfrm_policy. + * @ctx contains the xfrm_sec_ctx. * Authorize deletion of xp->security. * @xfrm_state_alloc_security: * @x contains the xfrm_state being added to the Security Association @@ -947,7 +947,7 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @x contains the xfrm_state. * Authorize deletion of x->security. * @xfrm_policy_lookup: - * @xp contains the xfrm_policy for which the access control is being + * @ctx contains the xfrm_sec_ctx for which the access control is being * checked. * @fl_secid contains the flow security label that is used to authorize * access to the policy xp. @@ -1454,17 +1454,17 @@ struct security_operations { #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM - int (*xfrm_policy_alloc_security) (struct xfrm_policy *xp, + int (*xfrm_policy_alloc_security) (struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx); - int (*xfrm_policy_clone_security) (struct xfrm_policy *old, struct xfrm_policy *new); - void (*xfrm_policy_free_security) (struct xfrm_policy *xp); - int (*xfrm_policy_delete_security) (struct xfrm_policy *xp); + int (*xfrm_policy_clone_security) (struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctx); + void (*xfrm_policy_free_security) (struct xfrm_sec_ctx *ctx); + int (*xfrm_policy_delete_security) (struct xfrm_sec_ctx *ctx); int (*xfrm_state_alloc_security) (struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx, u32 secid); void (*xfrm_state_free_security) (struct xfrm_state *x); int (*xfrm_state_delete_security) (struct xfrm_state *x); - int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 fl_secid, u8 dir); + int (*xfrm_policy_lookup)(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); int (*xfrm_state_pol_flow_match)(struct xfrm_state *x, struct xfrm_policy *xp, struct flowi *fl); int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall); @@ -2562,16 +2562,16 @@ static inline void security_inet_conn_established(struct sock *sk, #ifdef CONFIG_SECURITY_NETWORK_XFRM -int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx); -int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); -void security_xfrm_policy_free(struct xfrm_policy *xp); -int security_xfrm_policy_delete(struct xfrm_policy *xp); +int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx); +int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctxp); +void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx); +int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx); int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx); int security_xfrm_state_alloc_acquire(struct xfrm_state *x, struct xfrm_sec_ctx *polsec, u32 secid); int security_xfrm_state_delete(struct xfrm_state *x); void security_xfrm_state_free(struct xfrm_state *x); -int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); +int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); int security_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, struct flowi *fl); int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid); @@ -2579,21 +2579,21 @@ void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl); #else /* CONFIG_SECURITY_NETWORK_XFRM */ -static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) +static inline int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx) { return 0; } -static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) +static inline int security_xfrm_policy_clone(struct xfrm_sec_ctx *old, struct xfrm_sec_ctx **new_ctxp) { return 0; } -static inline void security_xfrm_policy_free(struct xfrm_policy *xp) +static inline void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx) { } -static inline int security_xfrm_policy_delete(struct xfrm_policy *xp) +static inline int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) { return 0; } @@ -2619,7 +2619,7 @@ static inline int security_xfrm_state_delete(struct xfrm_state *x) return 0; } -static inline int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) +static inline int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) { return 0; } diff --git a/net/key/af_key.c b/net/key/af_key.c index 6db58924368a..1fb0fe42a72e 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2292,7 +2292,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h goto out; } - err = security_xfrm_policy_alloc(xp, uctx); + err = security_xfrm_policy_alloc(&xp->security, uctx); kfree(uctx); if (err) @@ -2352,10 +2352,11 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg int err; struct sadb_address *sa; struct sadb_x_policy *pol; - struct xfrm_policy *xp, tmp; + struct xfrm_policy *xp; struct xfrm_selector sel; struct km_event c; struct sadb_x_sec_ctx *sec_ctx; + struct xfrm_sec_ctx *pol_ctx; if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || @@ -2385,25 +2386,23 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg sel.dport_mask = htons(0xffff); sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; - memset(&tmp, 0, sizeof(struct xfrm_policy)); - if (sec_ctx != NULL) { struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); if (!uctx) return -ENOMEM; - err = security_xfrm_policy_alloc(&tmp, uctx); + err = security_xfrm_policy_alloc(&pol_ctx, uctx); kfree(uctx); - if (err) return err; - } - - xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, pol->sadb_x_policy_dir-1, - &sel, tmp.security, 1, &err); - security_xfrm_policy_free(&tmp); + } else + pol_ctx = NULL; + xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, + pol->sadb_x_policy_dir - 1, &sel, pol_ctx, + 1, &err); + security_xfrm_policy_free(pol_ctx); if (xp == NULL) return -ENOENT; @@ -3298,7 +3297,7 @@ static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, if ((*dir = verify_sec_ctx_len(p))) goto out; uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); - *dir = security_xfrm_policy_alloc(xp, uctx); + *dir = security_xfrm_policy_alloc(&xp->security, uctx); kfree(uctx); if (*dir) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 15d73e47cc2c..ab4d0e598a2c 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -263,7 +263,7 @@ void xfrm_policy_destroy(struct xfrm_policy *policy) list_del(&policy->bytype); write_unlock_bh(&xfrm_policy_lock); - security_xfrm_policy_free(policy); + security_xfrm_policy_free(policy->security); kfree(policy); } EXPORT_SYMBOL(xfrm_policy_destroy); @@ -676,7 +676,8 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, xfrm_sec_ctx_match(ctx, pol->security)) { xfrm_pol_hold(pol); if (delete) { - *err = security_xfrm_policy_delete(pol); + *err = security_xfrm_policy_delete( + pol->security); if (*err) { write_unlock_bh(&xfrm_policy_lock); return pol; @@ -718,7 +719,8 @@ struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete, if (pol->type == type && pol->index == id) { xfrm_pol_hold(pol); if (delete) { - *err = security_xfrm_policy_delete(pol); + *err = security_xfrm_policy_delete( + pol->security); if (*err) { write_unlock_bh(&xfrm_policy_lock); return pol; @@ -756,7 +758,7 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) &xfrm_policy_inexact[dir], bydst) { if (pol->type != type) continue; - err = security_xfrm_policy_delete(pol); + err = security_xfrm_policy_delete(pol->security); if (err) { xfrm_audit_policy_delete(pol, 0, audit_info->loginuid, @@ -770,7 +772,8 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) bydst) { if (pol->type != type) continue; - err = security_xfrm_policy_delete(pol); + err = security_xfrm_policy_delete( + pol->security); if (err) { xfrm_audit_policy_delete(pol, 0, audit_info->loginuid, @@ -931,7 +934,8 @@ static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl, match = xfrm_selector_match(sel, fl, family); if (match) - ret = security_xfrm_policy_lookup(pol, fl->secid, dir); + ret = security_xfrm_policy_lookup(pol->security, fl->secid, + dir); return ret; } @@ -1048,8 +1052,9 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc int err = 0; if (match) { - err = security_xfrm_policy_lookup(pol, fl->secid, - policy_to_flow_dir(dir)); + err = security_xfrm_policy_lookup(pol->security, + fl->secid, + policy_to_flow_dir(dir)); if (!err) xfrm_pol_hold(pol); else if (err == -ESRCH) @@ -1138,7 +1143,8 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) if (newp) { newp->selector = old->selector; - if (security_xfrm_policy_clone(old, newp)) { + if (security_xfrm_policy_clone(old->security, + &newp->security)) { kfree(newp); return NULL; /* ENOMEM */ } diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 5578c909fcf6..ecf9d67daef5 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -959,7 +959,7 @@ static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs return 0; uctx = nla_data(rt); - return security_xfrm_policy_alloc(pol, uctx); + return security_xfrm_policy_alloc(&pol->security, uctx); } static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, @@ -1143,7 +1143,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, NETLINK_CB(skb).sid); if (err) { - security_xfrm_policy_free(xp); + security_xfrm_policy_free(xp->security); kfree(xp); return err; } @@ -1337,22 +1337,23 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, xp = xfrm_policy_byid(type, p->dir, p->index, delete, &err); else { struct nlattr *rt = attrs[XFRMA_SEC_CTX]; - struct xfrm_policy tmp; + struct xfrm_sec_ctx *ctx; err = verify_sec_ctx_len(attrs); if (err) return err; - memset(&tmp, 0, sizeof(struct xfrm_policy)); if (rt) { struct xfrm_user_sec_ctx *uctx = nla_data(rt); - if ((err = security_xfrm_policy_alloc(&tmp, uctx))) + err = security_xfrm_policy_alloc(&ctx, uctx); + if (err) return err; - } - xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, + } else + ctx = NULL; + xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx, delete, &err); - security_xfrm_policy_free(&tmp); + security_xfrm_policy_free(ctx); } if (xp == NULL) return -ENOENT; @@ -1572,26 +1573,26 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err); else { struct nlattr *rt = attrs[XFRMA_SEC_CTX]; - struct xfrm_policy tmp; + struct xfrm_sec_ctx *ctx; err = verify_sec_ctx_len(attrs); if (err) return err; - memset(&tmp, 0, sizeof(struct xfrm_policy)); if (rt) { struct xfrm_user_sec_ctx *uctx = nla_data(rt); - if ((err = security_xfrm_policy_alloc(&tmp, uctx))) + err = security_xfrm_policy_alloc(&ctx, uctx); + if (err) return err; - } - xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, - 0, &err); - security_xfrm_policy_free(&tmp); + } else + ctx = NULL; + xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx, 0, &err); + security_xfrm_policy_free(ctx); } - if (xp == NULL) return -ENOENT; + read_lock(&xp->lock); if (xp->dead) { read_unlock(&xp->lock); diff --git a/security/dummy.c b/security/dummy.c index 78d8f92310a4..480366f9c41d 100644 --- a/security/dummy.c +++ b/security/dummy.c @@ -876,22 +876,23 @@ static inline void dummy_req_classify_flow(const struct request_sock *req, #endif /* CONFIG_SECURITY_NETWORK */ #ifdef CONFIG_SECURITY_NETWORK_XFRM -static int dummy_xfrm_policy_alloc_security(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *sec_ctx) +static int dummy_xfrm_policy_alloc_security(struct xfrm_sec_ctx **ctxp, + struct xfrm_user_sec_ctx *sec_ctx) { return 0; } -static inline int dummy_xfrm_policy_clone_security(struct xfrm_policy *old, struct xfrm_policy *new) +static inline int dummy_xfrm_policy_clone_security(struct xfrm_sec_ctx *old_ctx, + struct xfrm_sec_ctx **new_ctxp) { return 0; } -static void dummy_xfrm_policy_free_security(struct xfrm_policy *xp) +static void dummy_xfrm_policy_free_security(struct xfrm_sec_ctx *ctx) { } -static int dummy_xfrm_policy_delete_security(struct xfrm_policy *xp) +static int dummy_xfrm_policy_delete_security(struct xfrm_sec_ctx *ctx) { return 0; } @@ -911,7 +912,8 @@ static int dummy_xfrm_state_delete_security(struct xfrm_state *x) return 0; } -static int dummy_xfrm_policy_lookup(struct xfrm_policy *xp, u32 sk_sid, u8 dir) +static int dummy_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, + u32 sk_sid, u8 dir) { return 0; } diff --git a/security/security.c b/security/security.c index b1387a6b416d..c9ff7d18c2f4 100644 --- a/security/security.c +++ b/security/security.c @@ -1014,26 +1014,27 @@ void security_inet_conn_established(struct sock *sk, #ifdef CONFIG_SECURITY_NETWORK_XFRM -int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm_user_sec_ctx *sec_ctx) +int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, struct xfrm_user_sec_ctx *sec_ctx) { - return security_ops->xfrm_policy_alloc_security(xp, sec_ctx); + return security_ops->xfrm_policy_alloc_security(ctxp, sec_ctx); } EXPORT_SYMBOL(security_xfrm_policy_alloc); -int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) +int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, + struct xfrm_sec_ctx **new_ctxp) { - return security_ops->xfrm_policy_clone_security(old, new); + return security_ops->xfrm_policy_clone_security(old_ctx, new_ctxp); } -void security_xfrm_policy_free(struct xfrm_policy *xp) +void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx) { - security_ops->xfrm_policy_free_security(xp); + security_ops->xfrm_policy_free_security(ctx); } EXPORT_SYMBOL(security_xfrm_policy_free); -int security_xfrm_policy_delete(struct xfrm_policy *xp) +int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) { - return security_ops->xfrm_policy_delete_security(xp); + return security_ops->xfrm_policy_delete_security(ctx); } int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx) @@ -1065,9 +1066,9 @@ void security_xfrm_state_free(struct xfrm_state *x) security_ops->xfrm_state_free_security(x); } -int security_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) +int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) { - return security_ops->xfrm_policy_lookup(xp, fl_secid, dir); + return security_ops->xfrm_policy_lookup(ctx, fl_secid, dir); } int security_xfrm_state_pol_flow_match(struct xfrm_state *x, diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 36b0510efa7b..289e24b39e3e 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -7,16 +7,17 @@ #ifndef _SELINUX_XFRM_H_ #define _SELINUX_XFRM_H_ -int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *sec_ctx); -int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new); -void selinux_xfrm_policy_free(struct xfrm_policy *xp); -int selinux_xfrm_policy_delete(struct xfrm_policy *xp); +int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, + struct xfrm_user_sec_ctx *sec_ctx); +int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, + struct xfrm_sec_ctx **new_ctxp); +void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx); +int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx); int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx, u32 secid); void selinux_xfrm_state_free(struct xfrm_state *x); int selinux_xfrm_state_delete(struct xfrm_state *x); -int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir); +int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *xp, struct flowi *fl); diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index 7e158205d081..874d17c83c61 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -77,20 +77,18 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x) * LSM hook implementation that authorizes that a flow can use * a xfrm policy rule. */ -int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) +int selinux_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) { int rc; u32 sel_sid; - struct xfrm_sec_ctx *ctx; /* Context sid is either set to label or ANY_ASSOC */ - if ((ctx = xp->security)) { + if (ctx) { if (!selinux_authorizable_ctx(ctx)) return -EINVAL; sel_sid = ctx->ctx_sid; - } - else + } else /* * All flows should be treated as polmatch'ing an * otherwise applicable "non-labeled" policy. This @@ -103,7 +101,7 @@ int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir) NULL); if (rc == -EACCES) - rc = -ESRCH; + return -ESRCH; return rc; } @@ -287,15 +285,14 @@ out2: * LSM hook implementation that allocs and transfers uctx spec to * xfrm_policy. */ -int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, - struct xfrm_user_sec_ctx *uctx) +int selinux_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, + struct xfrm_user_sec_ctx *uctx) { int err; - BUG_ON(!xp); BUG_ON(!uctx); - err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0); + err = selinux_xfrm_sec_ctx_alloc(ctxp, uctx, 0); if (err == 0) atomic_inc(&selinux_xfrm_refcount); @@ -307,32 +304,29 @@ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp, * LSM hook implementation that copies security data structure from old to * new for policy cloning. */ -int selinux_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new) +int selinux_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, + struct xfrm_sec_ctx **new_ctxp) { - struct xfrm_sec_ctx *old_ctx, *new_ctx; - - old_ctx = old->security; + struct xfrm_sec_ctx *new_ctx; if (old_ctx) { - new_ctx = new->security = kmalloc(sizeof(*new_ctx) + - old_ctx->ctx_len, - GFP_KERNEL); - + new_ctx = kmalloc(sizeof(*old_ctx) + old_ctx->ctx_len, + GFP_KERNEL); if (!new_ctx) return -ENOMEM; memcpy(new_ctx, old_ctx, sizeof(*new_ctx)); memcpy(new_ctx->ctx_str, old_ctx->ctx_str, new_ctx->ctx_len); + *new_ctxp = new_ctx; } return 0; } /* - * LSM hook implementation that frees xfrm_policy security information. + * LSM hook implementation that frees xfrm_sec_ctx security information. */ -void selinux_xfrm_policy_free(struct xfrm_policy *xp) +void selinux_xfrm_policy_free(struct xfrm_sec_ctx *ctx) { - struct xfrm_sec_ctx *ctx = xp->security; if (ctx) kfree(ctx); } @@ -340,10 +334,9 @@ void selinux_xfrm_policy_free(struct xfrm_policy *xp) /* * LSM hook implementation that authorizes deletion of labeled policies. */ -int selinux_xfrm_policy_delete(struct xfrm_policy *xp) +int selinux_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) { struct task_security_struct *tsec = current->security; - struct xfrm_sec_ctx *ctx = xp->security; int rc = 0; if (ctx) { -- cgit v1.2.3-59-g8ed1b From 9673693284763417ea5edcdebc1a0c5d1dead51c Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Sun, 13 Apr 2008 21:33:17 -0700 Subject: [TIPC]: Remove redundant socket wait queue initialization This patch eliminates re-initialization of the standard socket wait queue used for sleeping in TIPC's socket creation code. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/socket.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 1b5fb6103ded..d3f9c2d87b0d 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -170,7 +170,6 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol) } sock_init_data(sock, sk); - init_waitqueue_head(sk->sk_sleep); sk->sk_rcvtimeo = 8 * HZ; /* default connect timeout = 8s */ tsock = tipc_sk(sk); -- cgit v1.2.3-59-g8ed1b From 3654ea02f2819cf8821c0acd35bc7cded5f1f2a9 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Sun, 13 Apr 2008 21:35:11 -0700 Subject: [TIPC]: Improve socket time conversions This patch modifies TIPC's socket code to use standard kernel routines to handle time conversions between jiffies and ms. This ensures proper operation even when HZ isn't 1000. Acknowledgements to Eric Sesterhenn for identifying this issue and proposing a solution. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/socket.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index d3f9c2d87b0d..ca6f52f392a9 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -58,7 +58,8 @@ #define SS_LISTENING -1 /* socket is listening */ #define SS_READY -2 /* socket is connectionless */ -#define OVERLOAD_LIMIT_BASE 5000 +#define OVERLOAD_LIMIT_BASE 5000 +#define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */ struct tipc_sock { struct sock sk; @@ -170,7 +171,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol) } sock_init_data(sock, sk); - sk->sk_rcvtimeo = 8 * HZ; /* default connect timeout = 8s */ + sk->sk_rcvtimeo = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT); tsock = tipc_sk(sk); port = tipc_get_port(ref); @@ -1529,7 +1530,7 @@ static int setsockopt(struct socket *sock, res = tipc_set_portunreturnable(tsock->p->ref, value); break; case TIPC_CONN_TIMEOUT: - sock->sk->sk_rcvtimeo = (value * HZ / 1000); + sock->sk->sk_rcvtimeo = msecs_to_jiffies(value); break; default: res = -EINVAL; @@ -1582,7 +1583,7 @@ static int getsockopt(struct socket *sock, res = tipc_portunreturnable(tsock->p->ref, &value); break; case TIPC_CONN_TIMEOUT: - value = (sock->sk->sk_rcvtimeo * 1000) / HZ; + value = jiffies_to_msecs(sock->sk->sk_rcvtimeo); break; default: res = -EINVAL; -- cgit v1.2.3-59-g8ed1b From ac6f78192054784f02dd47f8e6d7d1c8d75ab173 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Sun, 13 Apr 2008 21:50:08 -0700 Subject: [INET]: sk_reuse is valbool sk_reuse is declared as "unsigned char", but is set as type valbool in net/core/sock.c. There is no other place in net/ where sk->sk_reuse is set to a value > 1, so the test "sk_reuse > 1" can not be true. Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- net/ipv4/inet_connection_sock.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index ee55678a987d..8d70cfbacb78 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -133,8 +133,6 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum) goto tb_not_found; tb_found: if (!hlist_empty(&tb->owners)) { - if (sk->sk_reuse > 1) - goto success; if (tb->fastreuse > 0 && sk->sk_reuse && sk->sk_state != TCP_LISTEN) { goto success; -- cgit v1.2.3-59-g8ed1b From a4146b1b2c6ba995db08b1a2aef5af1b17b151e6 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sun, 13 Apr 2008 22:11:14 -0700 Subject: [TCP]: Replace struct net on tcp_iter_state with seq_net_private. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/tcp.h | 2 +- net/ipv4/tcp_ipv4.c | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/include/net/tcp.h b/include/net/tcp.h index 7b41bb962b9c..f5b61e0f01f2 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1333,7 +1333,7 @@ struct tcp_seq_afinfo { }; struct tcp_iter_state { - struct net *net; + struct seq_net_private p; sa_family_t family; enum tcp_seq_states state; struct sock *syn_wait_sk; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 52e3ae603ca9..86148cdfb21f 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1954,7 +1954,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) struct hlist_node *node; struct sock *sk = cur; struct tcp_iter_state* st = seq->private; - struct net *net = st->net; + struct net *net = seq_file_net(seq); if (!sk) { st->bucket = 0; @@ -2035,7 +2035,7 @@ static void *listening_get_idx(struct seq_file *seq, loff_t *pos) static void *established_get_first(struct seq_file *seq) { struct tcp_iter_state* st = seq->private; - struct net *net = st->net; + struct net *net = seq_file_net(seq); void *rc = NULL; for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) { @@ -2076,7 +2076,7 @@ static void *established_get_next(struct seq_file *seq, void *cur) struct inet_timewait_sock *tw; struct hlist_node *node; struct tcp_iter_state* st = seq->private; - struct net *net = st->net; + struct net *net = seq_file_net(seq); ++st->num; @@ -2233,7 +2233,7 @@ static int tcp_seq_open(struct inode *inode, struct file *file) s->seq_ops.next = tcp_seq_next; s->seq_ops.show = afinfo->seq_show; s->seq_ops.stop = tcp_seq_stop; - s->net = net; + s->p.net = net; rc = seq_open(file, &s->seq_ops); if (rc) @@ -2252,9 +2252,8 @@ out_kfree: static int tcp_seq_release(struct inode *inode, struct file *file) { struct seq_file *seq = file->private_data; - struct tcp_iter_state *s = seq->private; - put_net(s->net); + put_net(seq_file_net(seq)); seq_release_private(inode, file); return 0; } -- cgit v1.2.3-59-g8ed1b From 1abf4fb20d38cf58c92b27f4d6ad4fa92a3bb553 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sun, 13 Apr 2008 22:11:46 -0700 Subject: [TCP]: No need to check afinfo != NULL in tcp_proc_(un)register. tcp_proc_register/tcp_proc_unregister are called with a static pointer only. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 86148cdfb21f..978d9db1df34 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2263,8 +2263,6 @@ int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo) int rc = 0; struct proc_dir_entry *p; - if (!afinfo) - return -EINVAL; afinfo->seq_fops->owner = afinfo->owner; afinfo->seq_fops->open = tcp_seq_open; afinfo->seq_fops->read = seq_read; @@ -2281,8 +2279,6 @@ int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo) void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo) { - if (!afinfo) - return; proc_net_remove(net, afinfo->name); memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } -- cgit v1.2.3-59-g8ed1b From 9427c4b36b8fe652df1d7c89eae678948e1f4b32 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sun, 13 Apr 2008 22:12:13 -0700 Subject: [TCP]: Move seq_ops from tcp_iter_state to tcp_seq_afinfo. No need to create seq_operations for each instance of 'netstat'. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/tcp.h | 3 +-- net/ipv4/tcp_ipv4.c | 14 ++++++++------ net/ipv6/tcp_ipv6.c | 4 +++- 3 files changed, 12 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/net/tcp.h b/include/net/tcp.h index f5b61e0f01f2..2c9a650412c0 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1328,8 +1328,8 @@ struct tcp_seq_afinfo { struct module *owner; char *name; sa_family_t family; - int (*seq_show) (struct seq_file *m, void *v); struct file_operations *seq_fops; + struct seq_operations seq_ops; }; struct tcp_iter_state { @@ -1338,7 +1338,6 @@ struct tcp_iter_state { enum tcp_seq_states state; struct sock *syn_wait_sk; int bucket, sbucket, num, uid; - struct seq_operations seq_ops; }; extern int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 978d9db1df34..c50dd1793643 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2229,13 +2229,9 @@ static int tcp_seq_open(struct inode *inode, struct file *file) goto out_kfree; s->family = afinfo->family; - s->seq_ops.start = tcp_seq_start; - s->seq_ops.next = tcp_seq_next; - s->seq_ops.show = afinfo->seq_show; - s->seq_ops.stop = tcp_seq_stop; s->p.net = net; - rc = seq_open(file, &s->seq_ops); + rc = seq_open(file, &afinfo->seq_ops); if (rc) goto out_put_net; seq = file->private_data; @@ -2269,6 +2265,10 @@ int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo) afinfo->seq_fops->llseek = seq_lseek; afinfo->seq_fops->release = tcp_seq_release; + afinfo->seq_ops.start = tcp_seq_start; + afinfo->seq_ops.next = tcp_seq_next; + afinfo->seq_ops.stop = tcp_seq_stop; + p = proc_net_fops_create(net, afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) p->data = afinfo; @@ -2414,8 +2414,10 @@ static struct tcp_seq_afinfo tcp4_seq_afinfo = { .owner = THIS_MODULE, .name = "tcp", .family = AF_INET, - .seq_show = tcp4_seq_show, .seq_fops = &tcp4_seq_fops, + .seq_ops = { + .show = tcp4_seq_show, + }, }; static int tcp4_proc_init_net(struct net *net) diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 80eab71e77ff..8bf59ee51cdb 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2125,8 +2125,10 @@ static struct tcp_seq_afinfo tcp6_seq_afinfo = { .owner = THIS_MODULE, .name = "tcp6", .family = AF_INET6, - .seq_show = tcp6_seq_show, .seq_fops = &tcp6_seq_fops, + .seq_ops = { + .show = tcp6_seq_show, + }, }; int tcp6_proc_init(struct net *net) -- cgit v1.2.3-59-g8ed1b From 52d6f3f11bdb8c26fead701c9dbad08acd28063d Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sun, 13 Apr 2008 22:12:41 -0700 Subject: [TCP]: Cleanup /proc/tcp[6] creation/removal. Replace seq_open with seq_open_net and remove tcp_seq_release completely. seq_release_net will do this job just fine. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/tcp_ipv4.c | 41 +++++++---------------------------------- 1 file changed, 7 insertions(+), 34 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index c50dd1793643..840346b390d7 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2211,46 +2211,19 @@ static void tcp_seq_stop(struct seq_file *seq, void *v) static int tcp_seq_open(struct inode *inode, struct file *file) { struct tcp_seq_afinfo *afinfo = PDE(inode)->data; - struct seq_file *seq; struct tcp_iter_state *s; - struct net *net; - int rc; + int err; if (unlikely(afinfo == NULL)) return -EINVAL; - s = kzalloc(sizeof(*s), GFP_KERNEL); - if (!s) - return -ENOMEM; - - rc = -ENXIO; - net = get_proc_net(inode); - if (!net) - goto out_kfree; + err = seq_open_net(inode, file, &afinfo->seq_ops, + sizeof(struct tcp_iter_state)); + if (err < 0) + return err; + s = ((struct seq_file *)file->private_data)->private; s->family = afinfo->family; - s->p.net = net; - - rc = seq_open(file, &afinfo->seq_ops); - if (rc) - goto out_put_net; - seq = file->private_data; - seq->private = s; -out: - return rc; -out_put_net: - put_net(net); -out_kfree: - kfree(s); - goto out; -} - -static int tcp_seq_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - - put_net(seq_file_net(seq)); - seq_release_private(inode, file); return 0; } @@ -2263,7 +2236,7 @@ int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo) afinfo->seq_fops->open = tcp_seq_open; afinfo->seq_fops->read = seq_read; afinfo->seq_fops->llseek = seq_lseek; - afinfo->seq_fops->release = tcp_seq_release; + afinfo->seq_fops->release = seq_release_net; afinfo->seq_ops.start = tcp_seq_start; afinfo->seq_ops.next = tcp_seq_next; -- cgit v1.2.3-59-g8ed1b From 68fcadd16c371d5e0698ba366f33a4f990ce83ce Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sun, 13 Apr 2008 22:13:30 -0700 Subject: [TCP]: Place file operations directly into tcp_seq_afinfo. No need to have separate never-used variable. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/tcp.h | 2 +- net/ipv4/tcp_ipv4.c | 15 ++++++--------- net/ipv6/tcp_ipv6.c | 2 -- 3 files changed, 7 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/include/net/tcp.h b/include/net/tcp.h index 2c9a650412c0..93479ebf3e33 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1328,7 +1328,7 @@ struct tcp_seq_afinfo { struct module *owner; char *name; sa_family_t family; - struct file_operations *seq_fops; + struct file_operations seq_fops; struct seq_operations seq_ops; }; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 840346b390d7..3696c83aec19 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2232,17 +2232,17 @@ int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo) int rc = 0; struct proc_dir_entry *p; - afinfo->seq_fops->owner = afinfo->owner; - afinfo->seq_fops->open = tcp_seq_open; - afinfo->seq_fops->read = seq_read; - afinfo->seq_fops->llseek = seq_lseek; - afinfo->seq_fops->release = seq_release_net; + afinfo->seq_fops.owner = afinfo->owner; + afinfo->seq_fops.open = tcp_seq_open; + afinfo->seq_fops.read = seq_read; + afinfo->seq_fops.llseek = seq_lseek; + afinfo->seq_fops.release = seq_release_net; afinfo->seq_ops.start = tcp_seq_start; afinfo->seq_ops.next = tcp_seq_next; afinfo->seq_ops.stop = tcp_seq_stop; - p = proc_net_fops_create(net, afinfo->name, S_IRUGO, afinfo->seq_fops); + p = proc_net_fops_create(net, afinfo->name, S_IRUGO, &afinfo->seq_fops); if (p) p->data = afinfo; else @@ -2253,7 +2253,6 @@ int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo) void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo) { proc_net_remove(net, afinfo->name); - memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); } static void get_openreq4(struct sock *sk, struct request_sock *req, @@ -2382,12 +2381,10 @@ out: return 0; } -static struct file_operations tcp4_seq_fops; static struct tcp_seq_afinfo tcp4_seq_afinfo = { .owner = THIS_MODULE, .name = "tcp", .family = AF_INET, - .seq_fops = &tcp4_seq_fops, .seq_ops = { .show = tcp4_seq_show, }, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 8bf59ee51cdb..e33a3dc7a000 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2120,12 +2120,10 @@ out: return 0; } -static struct file_operations tcp6_seq_fops; static struct tcp_seq_afinfo tcp6_seq_afinfo = { .owner = THIS_MODULE, .name = "tcp6", .family = AF_INET6, - .seq_fops = &tcp6_seq_fops, .seq_ops = { .show = tcp6_seq_show, }, -- cgit v1.2.3-59-g8ed1b From 5f4472c5a640c9671ca5becaebdfd6e651482176 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Sun, 13 Apr 2008 22:13:53 -0700 Subject: [TCP]: Remove owner from tcp_seq_afinfo. Move it to tcp_seq_afinfo->seq_fops as should be. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/tcp.h | 1 - net/ipv4/tcp_ipv4.c | 5 +++-- net/ipv6/tcp_ipv6.c | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/include/net/tcp.h b/include/net/tcp.h index 93479ebf3e33..58d82822414d 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1325,7 +1325,6 @@ enum tcp_seq_states { }; struct tcp_seq_afinfo { - struct module *owner; char *name; sa_family_t family; struct file_operations seq_fops; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 3696c83aec19..02519730e0d5 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2232,7 +2232,6 @@ int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo) int rc = 0; struct proc_dir_entry *p; - afinfo->seq_fops.owner = afinfo->owner; afinfo->seq_fops.open = tcp_seq_open; afinfo->seq_fops.read = seq_read; afinfo->seq_fops.llseek = seq_lseek; @@ -2382,9 +2381,11 @@ out: } static struct tcp_seq_afinfo tcp4_seq_afinfo = { - .owner = THIS_MODULE, .name = "tcp", .family = AF_INET, + .seq_fops = { + .owner = THIS_MODULE, + }, .seq_ops = { .show = tcp4_seq_show, }, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index e33a3dc7a000..231c4dddfb8c 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2121,9 +2121,11 @@ out: } static struct tcp_seq_afinfo tcp6_seq_afinfo = { - .owner = THIS_MODULE, .name = "tcp6", .family = AF_INET6, + .seq_fops = { + .owner = THIS_MODULE, + }, .seq_ops = { .show = tcp6_seq_show, }, -- cgit v1.2.3-59-g8ed1b From 72a2d6138224298a576bcdc33d7d0004de604856 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 13 Apr 2008 22:29:13 -0700 Subject: [NETNS][DCCPV4]: Add dummy per-net operations. They will be responsible for ctl socket initialization, but currently they are void. Signed-off-by: Pavel Emelyanov Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ipv4.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'net') diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index b12803bcba56..10bba039c4b8 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -989,6 +989,20 @@ static struct inet_protosw dccp_v4_protosw = { .flags = INET_PROTOSW_ICSK, }; +static int dccp_v4_init_net(struct net *net) +{ + return 0; +} + +static void dccp_v4_exit_net(struct net *net) +{ +} + +static struct pernet_operations dccp_v4_ops = { + .init = dccp_v4_init_net, + .exit = dccp_v4_exit_net, +}; + static int __init dccp_v4_init(void) { int err = proto_register(&dccp_v4_prot, 1); @@ -1006,8 +1020,14 @@ static int __init dccp_v4_init(void) SOCK_DCCP, IPPROTO_DCCP, &init_net); if (err) goto out_unregister_protosw; + + err = register_pernet_subsys(&dccp_v4_ops); + if (err) + goto out_destroy_ctl_sock; out: return err; +out_destroy_ctl_sock: + inet_ctl_sock_destroy(dccp_v4_ctl_sk); out_unregister_protosw: inet_unregister_protosw(&dccp_v4_protosw); inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); @@ -1018,6 +1038,7 @@ out_proto_unregister: static void __exit dccp_v4_exit(void) { + unregister_pernet_subsys(&dccp_v4_ops); inet_ctl_sock_destroy(dccp_v4_ctl_sk); inet_unregister_protosw(&dccp_v4_protosw); inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); -- cgit v1.2.3-59-g8ed1b From 7b1cffa8c90269dc3dc721d084d1e0d742d87c31 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 13 Apr 2008 22:29:37 -0700 Subject: [NETNS][DCCPV4]: Move the dccp_v4_ctl_sk on the struct net. And replace all its usage with init_net's socket. Signed-off-by: Pavel Emelyanov Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- include/net/netns/dccp.h | 3 +++ net/dccp/ipv4.c | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/net/netns/dccp.h b/include/net/netns/dccp.h index 056e6adc70b6..e4f16faa898a 100644 --- a/include/net/netns/dccp.h +++ b/include/net/netns/dccp.h @@ -1,7 +1,10 @@ #ifndef __NETNS_DCCP_H__ #define __NETNS_DCCP_H__ +struct sock; + struct netns_dccp { + struct sock *v4_ctl_sk; }; #endif diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 10bba039c4b8..85931dce744c 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -32,11 +32,10 @@ #include "feat.h" /* - * This is the global socket data structure used for responding to + * The dccp_ctl_sk is the global socket data structure used for responding to * the Out-of-the-blue (OOTB) packets. A control sock will be created * for this socket at the initialization time. */ -static struct sock *dccp_v4_ctl_sk; int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { @@ -506,6 +505,7 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) const struct iphdr *rxiph; struct sk_buff *skb; struct dst_entry *dst; + struct sock *ctl_sk = init_net.dccp.v4_ctl_sk; /* Never send a reset in response to a reset. */ if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) @@ -514,11 +514,11 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) if (rxskb->rtable->rt_type != RTN_LOCAL) return; - dst = dccp_v4_route_skb(dccp_v4_ctl_sk, rxskb); + dst = dccp_v4_route_skb(ctl_sk, rxskb); if (dst == NULL) return; - skb = dccp_ctl_make_reset(dccp_v4_ctl_sk, rxskb); + skb = dccp_ctl_make_reset(ctl_sk, rxskb); if (skb == NULL) goto out; @@ -527,10 +527,10 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) rxiph->daddr); skb->dst = dst_clone(dst); - bh_lock_sock(dccp_v4_ctl_sk); - err = ip_build_and_send_pkt(skb, dccp_v4_ctl_sk, + bh_lock_sock(ctl_sk); + err = ip_build_and_send_pkt(skb, ctl_sk, rxiph->daddr, rxiph->saddr, NULL); - bh_unlock_sock(dccp_v4_ctl_sk); + bh_unlock_sock(ctl_sk); if (net_xmit_eval(err) == 0) { DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); @@ -1016,7 +1016,7 @@ static int __init dccp_v4_init(void) inet_register_protosw(&dccp_v4_protosw); - err = inet_ctl_sock_create(&dccp_v4_ctl_sk, PF_INET, + err = inet_ctl_sock_create(&init_net.dccp.v4_ctl_sk, PF_INET, SOCK_DCCP, IPPROTO_DCCP, &init_net); if (err) goto out_unregister_protosw; @@ -1027,7 +1027,7 @@ static int __init dccp_v4_init(void) out: return err; out_destroy_ctl_sock: - inet_ctl_sock_destroy(dccp_v4_ctl_sk); + inet_ctl_sock_destroy(init_net.dccp.v4_ctl_sk); out_unregister_protosw: inet_unregister_protosw(&dccp_v4_protosw); inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); @@ -1039,7 +1039,7 @@ out_proto_unregister: static void __exit dccp_v4_exit(void) { unregister_pernet_subsys(&dccp_v4_ops); - inet_ctl_sock_destroy(dccp_v4_ctl_sk); + inet_ctl_sock_destroy(init_net.dccp.v4_ctl_sk); inet_unregister_protosw(&dccp_v4_protosw); inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); proto_unregister(&dccp_v4_prot); -- cgit v1.2.3-59-g8ed1b From b76c4b27fee9c88294d3152784291fc6f6d23401 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 13 Apr 2008 22:29:59 -0700 Subject: [NETNS][DCCPV4]: Actually create ctl socket on each net and use it. Move the call to inet_ctl_sock_create to init callback (and inet_ctl_sock_destroy to exit one) and use proper ctl sock in dccp_v4_ctl_send_reset. Signed-off-by: Pavel Emelyanov Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ipv4.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 85931dce744c..cad62d8d87a0 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -505,7 +505,8 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) const struct iphdr *rxiph; struct sk_buff *skb; struct dst_entry *dst; - struct sock *ctl_sk = init_net.dccp.v4_ctl_sk; + struct net *net = dev_net(rxskb->dst->dev); + struct sock *ctl_sk = net->dccp.v4_ctl_sk; /* Never send a reset in response to a reset. */ if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) @@ -991,11 +992,16 @@ static struct inet_protosw dccp_v4_protosw = { static int dccp_v4_init_net(struct net *net) { - return 0; + int err; + + err = inet_ctl_sock_create(&net->dccp.v4_ctl_sk, PF_INET, + SOCK_DCCP, IPPROTO_DCCP, net); + return err; } static void dccp_v4_exit_net(struct net *net) { + inet_ctl_sock_destroy(net->dccp.v4_ctl_sk); } static struct pernet_operations dccp_v4_ops = { @@ -1016,19 +1022,12 @@ static int __init dccp_v4_init(void) inet_register_protosw(&dccp_v4_protosw); - err = inet_ctl_sock_create(&init_net.dccp.v4_ctl_sk, PF_INET, - SOCK_DCCP, IPPROTO_DCCP, &init_net); - if (err) - goto out_unregister_protosw; - err = register_pernet_subsys(&dccp_v4_ops); if (err) goto out_destroy_ctl_sock; out: return err; out_destroy_ctl_sock: - inet_ctl_sock_destroy(init_net.dccp.v4_ctl_sk); -out_unregister_protosw: inet_unregister_protosw(&dccp_v4_protosw); inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); out_proto_unregister: @@ -1039,7 +1038,6 @@ out_proto_unregister: static void __exit dccp_v4_exit(void) { unregister_pernet_subsys(&dccp_v4_ops); - inet_ctl_sock_destroy(init_net.dccp.v4_ctl_sk); inet_unregister_protosw(&dccp_v4_protosw); inet_del_protocol(&dccp_v4_protocol, IPPROTO_DCCP); proto_unregister(&dccp_v4_prot); -- cgit v1.2.3-59-g8ed1b From f54873982c6aac9bc5c7eef62a9ce4d52b1dfc19 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 13 Apr 2008 22:30:19 -0700 Subject: [NETNS][DCCPV4]: Use proper net to route the reset packet. The dccp_v4_route_skb used in dccp_v4_ctl_send_reset, currently works with init_net's routing tables - fix it. Signed-off-by: Pavel Emelyanov Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ipv4.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index cad62d8d87a0..11d0b8589aa7 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -445,7 +445,7 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) return sk; } -static struct dst_entry* dccp_v4_route_skb(struct sock *sk, +static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk, struct sk_buff *skb) { struct rtable *rt; @@ -462,7 +462,7 @@ static struct dst_entry* dccp_v4_route_skb(struct sock *sk, }; security_skb_classify_flow(skb, &fl); - if (ip_route_output_flow(&init_net, &rt, &fl, sk, 0)) { + if (ip_route_output_flow(net, &rt, &fl, sk, 0)) { IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); return NULL; } @@ -515,7 +515,7 @@ static void dccp_v4_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) if (rxskb->rtable->rt_type != RTN_LOCAL) return; - dst = dccp_v4_route_skb(ctl_sk, rxskb); + dst = dccp_v4_route_skb(net, ctl_sk, rxskb); if (dst == NULL) return; -- cgit v1.2.3-59-g8ed1b From b9901a84c98fe27c6a598c0f3ec944a7f17a5f97 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 13 Apr 2008 22:30:43 -0700 Subject: [NETNS][DCCPV4]: Make per-net socket lookup. The inet_lookup family of functions requires a net to lookup a socket in, so give a proper one to them. Signed-off-by: Pavel Emelyanov Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ipv4.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 11d0b8589aa7..66f860b1b916 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -211,8 +211,9 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info) return; } - sk = inet_lookup(&init_net, &dccp_hashinfo, iph->daddr, dh->dccph_dport, - iph->saddr, dh->dccph_sport, inet_iif(skb)); + sk = inet_lookup(dev_net(skb->dev), &dccp_hashinfo, + iph->daddr, dh->dccph_dport, + iph->saddr, dh->dccph_sport, inet_iif(skb)); if (sk == NULL) { ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); return; @@ -429,7 +430,7 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) if (req != NULL) return dccp_check_req(sk, skb, req, prev); - nsk = inet_lookup_established(&init_net, &dccp_hashinfo, + nsk = inet_lookup_established(sock_net(sk), &dccp_hashinfo, iph->saddr, dh->dccph_sport, iph->daddr, dh->dccph_dport, inet_iif(skb)); @@ -810,7 +811,7 @@ static int dccp_v4_rcv(struct sk_buff *skb) /* Step 2: * Look up flow ID in table and get corresponding socket */ - sk = __inet_lookup(&init_net, &dccp_hashinfo, + sk = __inet_lookup(dev_net(skb->dst->dev), &dccp_hashinfo, iph->saddr, dh->dccph_sport, iph->daddr, dh->dccph_dport, inet_iif(skb)); /* -- cgit v1.2.3-59-g8ed1b From fc5f8580d31d52890f17526ea739b124bd4e56f4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 13 Apr 2008 22:31:05 -0700 Subject: [NETNS][DCCPV4]: Enable DCCPv4 in net namespaces. This enables sockets creation with IPPROTO_DCCP and enables the ip level to pass DCCP packets to the DCCP level. Signed-off-by: Pavel Emelyanov Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ipv4.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 66f860b1b916..b9974669edb4 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -952,6 +952,7 @@ static struct net_protocol dccp_v4_protocol = { .handler = dccp_v4_rcv, .err_handler = dccp_v4_err, .no_policy = 1, + .netns_ok = 1, }; static const struct proto_ops inet_dccp_ops = { -- cgit v1.2.3-59-g8ed1b From 68d185980f70413b353df99cdf5e667510036668 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 13 Apr 2008 22:31:32 -0700 Subject: [NETNS][DCCPV6]: Don't pass NULL to ip6_dst_lookup. This call uses the sock to get the net to lookup the routing in. With CONFIG_NET_NS this code will OOPS, since the sk ptr is NULL. After looking inside the ip6_dst_lookup and drawing the analogy with respective ipv6 code, it seems, that the dccp ctl socket is a good candidate for the first argument. Signed-off-by: Pavel Emelyanov Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ipv6.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 94d749e6d494..b657dea9ee27 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -322,7 +322,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) security_skb_classify_flow(rxskb, &fl); /* sk = NULL, but it is safe for now. RST socket required. */ - if (!ip6_dst_lookup(NULL, &skb->dst, &fl)) { + if (!ip6_dst_lookup(dccp_v6_ctl_sk, &skb->dst, &fl)) { if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { ip6_xmit(dccp_v6_ctl_sk, skb, &fl, NULL, 0); DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); -- cgit v1.2.3-59-g8ed1b From 8231bd270df435f2d4d85b284dd9dbd48521dd84 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 13 Apr 2008 22:32:02 -0700 Subject: [NETNS][DCCPV6]: Add dummy per-net operations. They will be responsible for ctl socket initialization, but currently they are void. Signed-off-by: Pavel Emelyanov Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ipv6.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'net') diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index b657dea9ee27..2ca52913f4be 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1171,6 +1171,20 @@ static struct inet_protosw dccp_v6_protosw = { .flags = INET_PROTOSW_ICSK, }; +static int dccp_v6_init_net(struct net *net) +{ + return 0; +} + +static void dccp_v6_exit_net(struct net *net) +{ +} + +static struct pernet_operations dccp_v6_ops = { + .init = dccp_v6_init_net, + .exit = dccp_v6_exit_net, +}; + static int __init dccp_v6_init(void) { int err = proto_register(&dccp_v6_prot, 1); @@ -1188,8 +1202,15 @@ static int __init dccp_v6_init(void) SOCK_DCCP, IPPROTO_DCCP, &init_net); if (err != 0) goto out_unregister_protosw; + + err = register_pernet_subsys(&dccp_v6_ops); + if (err != 0) + goto out_destroy_ctl_sock; out: return err; + +out_destroy_ctl_sock: + inet_ctl_sock_destroy(dccp_v6_ctl_sk); out_unregister_protosw: inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); inet6_unregister_protosw(&dccp_v6_protosw); @@ -1200,6 +1221,7 @@ out_unregister_proto: static void __exit dccp_v6_exit(void) { + unregister_pernet_subsys(&dccp_v6_ops); inet_ctl_sock_destroy(dccp_v6_ctl_sk); inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); inet6_unregister_protosw(&dccp_v6_protosw); -- cgit v1.2.3-59-g8ed1b From 0204774191d3e7bc69e3ae6bbf328b635607505a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 13 Apr 2008 22:32:25 -0700 Subject: [NETNS][DCCPV6]: Move the dccp_v6_ctl_sk on the struct net. And replace all its usage with init_net's socket. Signed-off-by: Pavel Emelyanov Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- include/net/netns/dccp.h | 1 + net/dccp/ipv6.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/net/netns/dccp.h b/include/net/netns/dccp.h index e4f16faa898a..98d2a7ce1f71 100644 --- a/include/net/netns/dccp.h +++ b/include/net/netns/dccp.h @@ -5,6 +5,7 @@ struct sock; struct netns_dccp { struct sock *v4_ctl_sk; + struct sock *v6_ctl_sk; }; #endif diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 2ca52913f4be..109dab3550f2 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -33,8 +33,7 @@ #include "ipv6.h" #include "feat.h" -/* Socket used for sending RSTs and ACKs */ -static struct sock *dccp_v6_ctl_sk; +/* dccp_v6_ctl_sk is used for sending RSTs and ACKs */ static struct inet_connection_sock_af_ops dccp_ipv6_mapped; static struct inet_connection_sock_af_ops dccp_ipv6_af_ops; @@ -296,6 +295,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) struct ipv6hdr *rxip6h; struct sk_buff *skb; struct flowi fl; + struct sock *ctl_sk = init_net.dccp.v6_ctl_sk; if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) return; @@ -303,7 +303,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) if (!ipv6_unicast_destination(rxskb)) return; - skb = dccp_ctl_make_reset(dccp_v6_ctl_sk, rxskb); + skb = dccp_ctl_make_reset(ctl_sk, rxskb); if (skb == NULL) return; @@ -322,9 +322,9 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) security_skb_classify_flow(rxskb, &fl); /* sk = NULL, but it is safe for now. RST socket required. */ - if (!ip6_dst_lookup(dccp_v6_ctl_sk, &skb->dst, &fl)) { + if (!ip6_dst_lookup(ctl_sk, &skb->dst, &fl)) { if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { - ip6_xmit(dccp_v6_ctl_sk, skb, &fl, NULL, 0); + ip6_xmit(ctl_sk, skb, &fl, NULL, 0); DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); return; @@ -1198,7 +1198,7 @@ static int __init dccp_v6_init(void) inet6_register_protosw(&dccp_v6_protosw); - err = inet_ctl_sock_create(&dccp_v6_ctl_sk, PF_INET6, + err = inet_ctl_sock_create(&init_net.dccp.v6_ctl_sk, PF_INET6, SOCK_DCCP, IPPROTO_DCCP, &init_net); if (err != 0) goto out_unregister_protosw; @@ -1210,7 +1210,7 @@ out: return err; out_destroy_ctl_sock: - inet_ctl_sock_destroy(dccp_v6_ctl_sk); + inet_ctl_sock_destroy(init_net.dccp.v6_ctl_sk); out_unregister_protosw: inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); inet6_unregister_protosw(&dccp_v6_protosw); @@ -1222,7 +1222,7 @@ out_unregister_proto: static void __exit dccp_v6_exit(void) { unregister_pernet_subsys(&dccp_v6_ops); - inet_ctl_sock_destroy(dccp_v6_ctl_sk); + inet_ctl_sock_destroy(init_net.dccp.v6_ctl_sk); inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); inet6_unregister_protosw(&dccp_v6_protosw); proto_unregister(&dccp_v6_prot); -- cgit v1.2.3-59-g8ed1b From 334527d3511ecbffca68d6c8f75046262510cf41 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 13 Apr 2008 22:32:45 -0700 Subject: [NETNS][DCCPV6]: Actually create ctl socket on each net and use it. Move the call to inet_ctl_sock_create to init callback (and inet_ctl_sock_destroy to exit one) and use proper ctl sock in dccp_v6_ctl_send_reset. Signed-off-by: Pavel Emelyanov Acked-by: Arnaldo Carvalho de Melo Signed-off-by: David S. Miller --- net/dccp/ipv6.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 109dab3550f2..a8666902b8e4 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -295,7 +295,8 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) struct ipv6hdr *rxip6h; struct sk_buff *skb; struct flowi fl; - struct sock *ctl_sk = init_net.dccp.v6_ctl_sk; + struct net *net = dev_net(rxskb->dst->dev); + struct sock *ctl_sk = net->dccp.v6_ctl_sk; if (dccp_hdr(rxskb)->dccph_type == DCCP_PKT_RESET) return; @@ -1173,11 +1174,16 @@ static struct inet_protosw dccp_v6_protosw = { static int dccp_v6_init_net(struct net *net) { - return 0; + int err; + + err = inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6, + SOCK_DCCP, IPPROTO_DCCP, net); + return err; } static void dccp_v6_exit_net(struct net *net) { + inet_ctl_sock_destroy(net->dccp.v6_ctl_sk); } static struct pernet_operations dccp_v6_ops = { @@ -1198,11 +1204,6 @@ static int __init dccp_v6_init(void) inet6_register_protosw(&dccp_v6_protosw); - err = inet_ctl_sock_create(&init_net.dccp.v6_ctl_sk, PF_INET6, - SOCK_DCCP, IPPROTO_DCCP, &init_net); - if (err != 0) - goto out_unregister_protosw; - err = register_pernet_subsys(&dccp_v6_ops); if (err != 0) goto out_destroy_ctl_sock; @@ -1210,8 +1211,6 @@ out: return err; out_destroy_ctl_sock: - inet_ctl_sock_destroy(init_net.dccp.v6_ctl_sk); -out_unregister_protosw: inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); inet6_unregister_protosw(&dccp_v6_protosw); out_unregister_proto: @@ -1222,7 +1221,6 @@ out_unregister_proto: static void __exit dccp_v6_exit(void) { unregister_pernet_subsys(&dccp_v6_ops); - inet_ctl_sock_destroy(init_net.dccp.v6_ctl_sk); inet6_del_protocol(&dccp_v6_protocol, IPPROTO_DCCP); inet6_unregister_protosw(&dccp_v6_protosw); proto_unregister(&dccp_v6_prot); -- cgit v1.2.3-59-g8ed1b From 671a1c7401c6e48f5f2a77ac330727a13a9c8b63 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Sun, 13 Apr 2008 22:33:06 -0700 Subject: [NETNS][DCCPV6]: Make per-net socket lookup. The inet6_lookup family of functions requires a net to lookup a socket in, so give a proper one to them. No more things to do for dccpv6, since routing is OK and the ipv4-like transport layer filtering is not done for ipv6. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/dccp/ipv6.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index a8666902b8e4..94e0c9495b2c 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -94,7 +94,8 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int err; __u64 seq; - sk = inet6_lookup(&init_net, &dccp_hashinfo, &hdr->daddr, dh->dccph_dport, + sk = inet6_lookup(dev_net(skb->dev), &dccp_hashinfo, + &hdr->daddr, dh->dccph_dport, &hdr->saddr, dh->dccph_sport, inet6_iif(skb)); if (sk == NULL) { @@ -359,7 +360,7 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) if (req != NULL) return dccp_check_req(sk, skb, req, prev); - nsk = __inet6_lookup_established(&init_net, &dccp_hashinfo, + nsk = __inet6_lookup_established(sock_net(sk), &dccp_hashinfo, &iph->saddr, dh->dccph_sport, &iph->daddr, ntohs(dh->dccph_dport), inet6_iif(skb)); @@ -790,8 +791,8 @@ static int dccp_v6_rcv(struct sk_buff *skb) /* Step 2: * Look up flow ID in table and get corresponding socket */ - sk = __inet6_lookup(&init_net, &dccp_hashinfo, &ipv6_hdr(skb)->saddr, - dh->dccph_sport, + sk = __inet6_lookup(dev_net(skb->dst->dev), &dccp_hashinfo, + &ipv6_hdr(skb)->saddr, dh->dccph_sport, &ipv6_hdr(skb)->daddr, ntohs(dh->dccph_dport), inet6_iif(skb)); /* -- cgit v1.2.3-59-g8ed1b From cee8947338d46bccece54c752bf6cd4043035f05 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sun, 13 Apr 2008 23:21:16 -0700 Subject: [IPV6] MROUTE: Do not call ipv6_find_idev() directly. Since NETDEV_REGISTER notifier chain is responsible for creating inet6_dev{}, we do not need to call ipv6_find_idev() directly here. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- include/linux/mroute6.h | 3 --- net/ipv6/addrconf.c | 2 +- net/ipv6/ip6mr.c | 5 ----- 3 files changed, 1 insertion(+), 9 deletions(-) (limited to 'net') diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h index f6469fb90840..e7989593142b 100644 --- a/include/linux/mroute6.h +++ b/include/linux/mroute6.h @@ -117,9 +117,6 @@ struct sioc_mif_req6 #include /* for struct sk_buff_head */ -struct net_device; -struct inet6_dev *ipv6_find_idev(struct net_device *dev); - #ifdef CONFIG_IPV6_MROUTE static inline int ip6_mroute_opt(int opt) { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index e93fa62089f8..9d49ed2578d7 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -412,7 +412,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) return ndev; } -struct inet6_dev * ipv6_find_idev(struct net_device *dev) +static struct inet6_dev * ipv6_find_idev(struct net_device *dev) { struct inet6_dev *idev; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 94ede696da2a..6e2e3c957a31 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -435,7 +435,6 @@ static void reg_vif_setup(struct net_device *dev) static struct net_device *ip6mr_reg_vif(void) { struct net_device *dev; - struct inet6_dev *in_dev; dev = alloc_netdev(sizeof(struct net_device_stats), "pim6reg", reg_vif_setup); @@ -449,10 +448,6 @@ static struct net_device *ip6mr_reg_vif(void) } dev->iflink = 0; - in_dev = ipv6_find_idev(dev); - if (!in_dev) - goto failure; - if (dev_open(dev)) goto failure; -- cgit v1.2.3-59-g8ed1b From e7712f1a7c32a5533be25ed806b1a8f7e42b452a Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Sun, 13 Apr 2008 23:21:52 -0700 Subject: [IPV6]: Share common code-paths for sticky socket options. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ipv6_sockglue.c | 64 +++++++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 39 deletions(-) (limited to 'net') diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 2f1244dc5ebf..06de9d0e1f6b 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -103,6 +103,29 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) return 0; } +static +struct ipv6_txoptions *ipv6_update_options(struct sock *sk, + struct ipv6_txoptions *opt) +{ + if (inet_sk(sk)->is_icsk) { + if (opt && + !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) && + inet_sk(sk)->daddr != LOOPBACK4_IPV6) { + struct inet_connection_sock *icsk = inet_csk(sk); + icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen; + icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); + } + opt = xchg(&inet6_sk(sk)->opt, opt); + } else { + write_lock(&sk->sk_dst_lock); + opt = xchg(&inet6_sk(sk)->opt, opt); + write_unlock(&sk->sk_dst_lock); + } + sk_dst_reset(sk); + + return opt; +} + static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { @@ -351,25 +374,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, } retv = 0; - if (inet_sk(sk)->is_icsk) { - if (opt) { - struct inet_connection_sock *icsk = inet_csk(sk); - if (!((1 << sk->sk_state) & - (TCPF_LISTEN | TCPF_CLOSE)) - && inet_sk(sk)->daddr != LOOPBACK4_IPV6) { - icsk->icsk_ext_hdr_len = - opt->opt_flen + opt->opt_nflen; - icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); - } - } - opt = xchg(&np->opt, opt); - sk_dst_reset(sk); - } else { - write_lock(&sk->sk_dst_lock); - opt = xchg(&np->opt, opt); - write_unlock(&sk->sk_dst_lock); - sk_dst_reset(sk); - } + opt = ipv6_update_options(sk, opt); sticky_done: if (opt) sock_kfree_s(sk, opt, opt->tot_len); @@ -415,26 +420,7 @@ sticky_done: goto done; update: retv = 0; - if (inet_sk(sk)->is_icsk) { - if (opt) { - struct inet_connection_sock *icsk = inet_csk(sk); - if (!((1 << sk->sk_state) & - (TCPF_LISTEN | TCPF_CLOSE)) - && inet_sk(sk)->daddr != LOOPBACK4_IPV6) { - icsk->icsk_ext_hdr_len = - opt->opt_flen + opt->opt_nflen; - icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); - } - } - opt = xchg(&np->opt, opt); - sk_dst_reset(sk); - } else { - write_lock(&sk->sk_dst_lock); - opt = xchg(&np->opt, opt); - write_unlock(&sk->sk_dst_lock); - sk_dst_reset(sk); - } - + opt = ipv6_update_options(sk, opt); done: if (opt) sock_kfree_s(sk, opt, opt->tot_len); -- cgit v1.2.3-59-g8ed1b From 0b18542b7f5379e052d2a3132be91185776e7ceb Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Sun, 13 Apr 2008 23:30:47 -0700 Subject: [NET]: Sink IPv6 menuoptions into its own submenu Signed-off-by: Jan Engelhardt Signed-off-by: David S. Miller --- net/ipv6/Kconfig | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 6cd2f4cdcb28..42814a2ec9d7 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -3,7 +3,7 @@ # # IPv6 as module will cause a CRASH if you try to unload it -config IPV6 +menuconfig IPV6 tristate "The IPv6 protocol" default m ---help--- @@ -19,9 +19,10 @@ config IPV6 To compile this protocol support as a module, choose M here: the module will be called ipv6. +if IPV6 + config IPV6_PRIVACY bool "IPv6: Privacy Extensions support" - depends on IPV6 ---help--- Privacy Extensions for Stateless Address Autoconfiguration in IPv6 support. With this option, additional periodically-alter @@ -40,7 +41,6 @@ config IPV6_PRIVACY config IPV6_ROUTER_PREF bool "IPv6: Router Preference (RFC 4191) support" - depends on IPV6 ---help--- Router Preference is an optional extension to the Router Advertisement message to improve the ability of hosts @@ -59,7 +59,7 @@ config IPV6_ROUTE_INFO config IPV6_OPTIMISTIC_DAD bool "IPv6: Enable RFC 4429 Optimistic DAD (EXPERIMENTAL)" - depends on IPV6 && EXPERIMENTAL + depends on EXPERIMENTAL ---help--- This is experimental support for optimistic Duplicate Address Detection. It allows for autoconfigured addresses @@ -69,7 +69,6 @@ config IPV6_OPTIMISTIC_DAD config INET6_AH tristate "IPv6: AH transformation" - depends on IPV6 select XFRM select CRYPTO select CRYPTO_HMAC @@ -82,7 +81,6 @@ config INET6_AH config INET6_ESP tristate "IPv6: ESP transformation" - depends on IPV6 select XFRM select CRYPTO select CRYPTO_AUTHENC @@ -98,7 +96,6 @@ config INET6_ESP config INET6_IPCOMP tristate "IPv6: IPComp transformation" - depends on IPV6 select XFRM select INET6_XFRM_TUNNEL select CRYPTO @@ -111,7 +108,7 @@ config INET6_IPCOMP config IPV6_MIP6 tristate "IPv6: Mobility (EXPERIMENTAL)" - depends on IPV6 && EXPERIMENTAL + depends on EXPERIMENTAL select XFRM ---help--- Support for IPv6 Mobility described in RFC 3775. @@ -129,7 +126,6 @@ config INET6_TUNNEL config INET6_XFRM_MODE_TRANSPORT tristate "IPv6: IPsec transport mode" - depends on IPV6 default IPV6 select XFRM ---help--- @@ -139,7 +135,6 @@ config INET6_XFRM_MODE_TRANSPORT config INET6_XFRM_MODE_TUNNEL tristate "IPv6: IPsec tunnel mode" - depends on IPV6 default IPV6 select XFRM ---help--- @@ -149,7 +144,6 @@ config INET6_XFRM_MODE_TUNNEL config INET6_XFRM_MODE_BEET tristate "IPv6: IPsec BEET mode" - depends on IPV6 default IPV6 select XFRM ---help--- @@ -159,14 +153,13 @@ config INET6_XFRM_MODE_BEET config INET6_XFRM_MODE_ROUTEOPTIMIZATION tristate "IPv6: MIPv6 route optimization mode (EXPERIMENTAL)" - depends on IPV6 && EXPERIMENTAL + depends on EXPERIMENTAL select XFRM ---help--- Support for MIPv6 route optimization mode. config IPV6_SIT tristate "IPv6: IPv6-in-IPv4 tunnel (SIT driver)" - depends on IPV6 select INET_TUNNEL select IPV6_NDISC_NODETYPE default y @@ -185,7 +178,6 @@ config IPV6_NDISC_NODETYPE config IPV6_TUNNEL tristate "IPv6: IP-in-IPv6 tunnel (RFC2473)" select INET6_TUNNEL - depends on IPV6 ---help--- Support for IPv6-in-IPv6 and IPv4-in-IPv6 tunnels described in RFC 2473. @@ -194,7 +186,7 @@ config IPV6_TUNNEL config IPV6_MULTIPLE_TABLES bool "IPv6: Multiple Routing Tables" - depends on IPV6 && EXPERIMENTAL + depends on EXPERIMENTAL select FIB_RULES ---help--- Support multiple routing tables. @@ -227,3 +219,4 @@ config IPV6_PIMSM_V2 Support for IPv6 PIM multicast routing protocol PIM-SMv2. If unsure, say N. +endif # IPV6 -- cgit v1.2.3-59-g8ed1b From 0912ea38de61378c5c753aef78c12e2f95854313 Mon Sep 17 00:00:00 2001 From: Rami Rosen Date: Sun, 13 Apr 2008 23:59:13 -0700 Subject: [IPV6] MROUTE: Add stats in multicast routing module method ip6_mr_forward(). This patches adds a call to increment IPSTATS_MIB_OUTFORWDATAGRAMS when forwarding the packet in ip6_mr_forward() in the IPv6 multicast routing module (net/ipv6/ip6mr.c). Signed-off-by: Rami Rosen Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/ip6mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 6e2e3c957a31..c8c6e33d1163 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1354,7 +1354,7 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) static inline int ip6mr_forward2_finish(struct sk_buff *skb) { - /* XXX stats */ + IP6_INC_STATS_BH(ip6_dst_idev(skb->dst), IPSTATS_MIB_OUTFORWDATAGRAMS); return dst_output(skb); } -- cgit v1.2.3-59-g8ed1b From 7de6c033367ab86f39c7723392caf73325cbf286 Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Mon, 14 Apr 2008 00:05:09 -0700 Subject: [SKB]: __skb_append = __skb_queue_after This expresses __skb_append in terms of __skb_queue_after, exploiting that __skb_append(old, new, list) = __skb_queue_after(list, old, new). Signed-off-by: Gerrit Renker Signed-off-by: David S. Miller --- include/linux/skbuff.h | 12 +++--------- include/net/tcp.h | 2 +- net/core/skbuff.c | 2 +- net/ipv4/tcp_input.c | 2 +- 4 files changed, 6 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index bb107ab675fc..83c851846829 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -697,6 +697,9 @@ static inline void __skb_queue_after(struct sk_buff_head *list, __skb_insert(newsk, prev, prev->next, list); } +extern void skb_append(struct sk_buff *old, struct sk_buff *newsk, + struct sk_buff_head *list); + /** * __skb_queue_head - queue a buffer at the list head * @list: list to use @@ -738,15 +741,6 @@ static inline void __skb_queue_tail(struct sk_buff_head *list, next->prev = prev->next = newsk; } -/* - * Place a packet after a given packet in a list. - */ -extern void skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list); -static inline void __skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list) -{ - __skb_insert(newsk, old, old->next, list); -} - /* * remove sk_buff from list. _Must_ be called atomically, and with * the list known.. diff --git a/include/net/tcp.h b/include/net/tcp.h index 58d82822414d..2ab350eca02e 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1247,7 +1247,7 @@ static inline void tcp_insert_write_queue_after(struct sk_buff *skb, struct sk_buff *buff, struct sock *sk) { - __skb_append(skb, buff, &sk->sk_write_queue); + __skb_queue_after(&sk->sk_write_queue, skb, buff); } /* Insert skb between prev and next on the write queue of sk. */ diff --git a/net/core/skbuff.c b/net/core/skbuff.c index e4259215607f..4cd12d99b12e 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1860,7 +1860,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head unsigned long flags; spin_lock_irqsave(&list->lock, flags); - __skb_append(old, newsk, list); + __skb_queue_after(list, old, newsk); spin_unlock_irqrestore(&list->lock, flags); } diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 6e46b4c0f28c..743611956045 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3968,7 +3968,7 @@ drop: u32 end_seq = TCP_SKB_CB(skb)->end_seq; if (seq == TCP_SKB_CB(skb1)->end_seq) { - __skb_append(skb1, skb, &tp->out_of_order_queue); + __skb_queue_after(&tp->out_of_order_queue, skb1, skb); if (!tp->rx_opt.num_sacks || tp->selective_acks[0].end_seq != seq) -- cgit v1.2.3-59-g8ed1b From b916f7d4b7b4b427ad9a9486de3da41a16b24d67 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 20 Mar 2008 15:15:43 +0100 Subject: [NETFILTER]: nf_conntrack: less hairy ifdefs around proc and sysctl Patch splits creation of /proc/net/nf_conntrack, /proc/net/stat/nf_conntrack and net.netfilter hierarchy into their own functions with dummy ones if PROC_FS or SYSCTL is not set. Also, remove dead "ret = 0" write while I'm at it. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- net/netfilter/nf_conntrack_standalone.c | 116 +++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 40 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 9d0b8bb4113c..01d1f7e178f3 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -295,6 +295,41 @@ static const struct file_operations ct_cpu_seq_fops = { .llseek = seq_lseek, .release = seq_release, }; + +static int nf_conntrack_standalone_init_proc(void) +{ + struct proc_dir_entry *pde; + + pde = proc_net_fops_create(&init_net, "nf_conntrack", 0440, &ct_file_ops); + if (!pde) + goto out_nf_conntrack; + pde = create_proc_entry("nf_conntrack", S_IRUGO, init_net.proc_net_stat); + if (!pde) + goto out_stat_nf_conntrack; + pde->proc_fops = &ct_cpu_seq_fops; + pde->owner = THIS_MODULE; + return 0; + +out_stat_nf_conntrack: + proc_net_remove(&init_net, "nf_conntrack"); +out_nf_conntrack: + return -ENOMEM; +} + +static void nf_conntrack_standalone_fini_proc(void) +{ + remove_proc_entry("nf_conntrack", init_net.proc_net_stat); + proc_net_remove(&init_net, "nf_conntrack"); +} +#else +static int nf_conntrack_standalone_init_proc(void) +{ + return 0; +} + +static void nf_conntrack_standalone_fini_proc(void) +{ +} #endif /* CONFIG_PROC_FS */ /* Sysctl support */ @@ -390,60 +425,61 @@ static struct ctl_path nf_ct_path[] = { }; EXPORT_SYMBOL_GPL(nf_ct_log_invalid); + +static int nf_conntrack_standalone_init_sysctl(void) +{ + nf_ct_sysctl_header = + register_sysctl_paths(nf_ct_path, nf_ct_netfilter_table); + if (nf_ct_sysctl_header == NULL) { + printk("nf_conntrack: can't register to sysctl.\n"); + return -ENOMEM; + } + return 0; + +} + +static void nf_conntrack_standalone_fini_sysctl(void) +{ + unregister_sysctl_table(nf_ct_sysctl_header); +} +#else +static int nf_conntrack_standalone_init_sysctl(void) +{ + return 0; +} + +static void nf_conntrack_standalone_fini_sysctl(void) +{ +} #endif /* CONFIG_SYSCTL */ static int __init nf_conntrack_standalone_init(void) { -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *proc; -#endif - int ret = 0; + int ret; ret = nf_conntrack_init(); if (ret < 0) - return ret; - -#ifdef CONFIG_PROC_FS - proc = proc_net_fops_create(&init_net, "nf_conntrack", 0440, &ct_file_ops); - if (!proc) goto cleanup_init; - - if (!proc_create("nf_conntrack", S_IRUGO, - init_net.proc_net_stat, &ct_cpu_seq_fops)) - goto cleanup_proc; -#endif -#ifdef CONFIG_SYSCTL - nf_ct_sysctl_header = register_sysctl_paths(nf_ct_path, - nf_ct_netfilter_table); - if (nf_ct_sysctl_header == NULL) { - printk("nf_conntrack: can't register to sysctl.\n"); - ret = -ENOMEM; - goto cleanup_proc_stat; - } -#endif - return ret; + goto out; + ret = nf_conntrack_standalone_init_proc(); + if (ret < 0) + goto out_proc; + ret = nf_conntrack_standalone_init_sysctl(); + if (ret < 0) + goto out_sysctl; + return 0; -#ifdef CONFIG_SYSCTL - cleanup_proc_stat: -#endif -#ifdef CONFIG_PROC_FS - remove_proc_entry("nf_conntrack", init_net. proc_net_stat); - cleanup_proc: - proc_net_remove(&init_net, "nf_conntrack"); - cleanup_init: -#endif /* CNFIG_PROC_FS */ +out_sysctl: + nf_conntrack_standalone_fini_proc(); +out_proc: nf_conntrack_cleanup(); +out: return ret; } static void __exit nf_conntrack_standalone_fini(void) { -#ifdef CONFIG_SYSCTL - unregister_sysctl_table(nf_ct_sysctl_header); -#endif -#ifdef CONFIG_PROC_FS - remove_proc_entry("nf_conntrack", init_net.proc_net_stat); - proc_net_remove(&init_net, "nf_conntrack"); -#endif /* CNFIG_PROC_FS */ + nf_conntrack_standalone_fini_sysctl(); + nf_conntrack_standalone_fini_proc(); nf_conntrack_cleanup(); } -- cgit v1.2.3-59-g8ed1b From 36e2a1b0f7f2598e38952494b91490f58aa221c8 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 20 Mar 2008 15:15:45 +0100 Subject: [NETFILTER]: {ip,ip6}t_LOG: print MARK value in log output Dump the mark value in log messages similar to nfnetlink_log. This is useful for debugging complex setups where marks are used for routing or traffic classification. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ipt_LOG.c | 6 +++++- net/ipv6/netfilter/ip6t_LOG.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index b38d7850f506..c40e233e271b 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -338,12 +338,16 @@ static void dump_packet(const struct nf_loginfo *info, if ((logflags & IPT_LOG_UID) && !iphoff && skb->sk) { read_lock_bh(&skb->sk->sk_callback_lock); if (skb->sk->sk_socket && skb->sk->sk_socket->file) - printk("UID=%u GID=%u", + printk("UID=%u GID=%u ", skb->sk->sk_socket->file->f_uid, skb->sk->sk_socket->file->f_gid); read_unlock_bh(&skb->sk->sk_callback_lock); } + /* Max length: 16 "MARK=0xFFFFFFFF " */ + if (!iphoff && skb->mark) + printk("MARK=0x%x ", skb->mark); + /* Proto Max log string length */ /* IP: 40+46+6+11+127 = 230 */ /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 86a613810b69..3a2316974f83 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c @@ -363,11 +363,15 @@ static void dump_packet(const struct nf_loginfo *info, if ((logflags & IP6T_LOG_UID) && recurse && skb->sk) { read_lock_bh(&skb->sk->sk_callback_lock); if (skb->sk->sk_socket && skb->sk->sk_socket->file) - printk("UID=%u GID=%u", + printk("UID=%u GID=%u ", skb->sk->sk_socket->file->f_uid, skb->sk->sk_socket->file->f_gid); read_unlock_bh(&skb->sk->sk_callback_lock); } + + /* Max length: 16 "MARK=0xFFFFFFFF " */ + if (!recurse && skb->mark) + printk("MARK=0x%x ", skb->mark); } static struct nf_loginfo default_loginfo = { -- cgit v1.2.3-59-g8ed1b From 666953df353194bef76086fa3f126241cbac3e3a Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 14 Apr 2008 09:56:02 +0200 Subject: [NETFILTER]: ip_tables: per-netns FILTER/MANGLE/RAW tables for real Commit 9335f047fe61587ec82ff12fbb1220bcfdd32006 aka "[NETFILTER]: ip_tables: per-netns FILTER, MANGLE, RAW" added per-netns _view_ of iptables rules. They were shown to user, but ignored by filtering code. Now that it's possible to at least ping loopback, per-netns tables can affect filtering decisions. netns is taken in case of PRE_ROUTING, LOCAL_IN -- from in device, POST_ROUTING, LOCAL_OUT -- from out device, FORWARD -- from in device which should be equal to out device's netns. This code is relatively new, so BUG_ON was plugged. Wrappers were added to a) keep code the same from CONFIG_NET_NS=n users (overwhelming majority), b) consolidate code in one place -- similar changes will be done in ipv6 and arp netfilter code. Signed-off-by: Alexey Dobriyan Signed-off-by: Patrick McHardy --- include/linux/netfilter.h | 54 ++++++++++++++++++++++++++++++++++++- net/ipv4/netfilter/iptable_filter.c | 19 ++++++++++--- net/ipv4/netfilter/iptable_mangle.c | 49 ++++++++++++++++++++++++++++----- net/ipv4/netfilter/iptable_raw.c | 6 +++-- 4 files changed, 115 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 89e6c72ad295..66bc52060fd6 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -6,11 +6,13 @@ #include #include #include +#include #include #include #include #include #include +#include #endif #include @@ -76,7 +78,6 @@ extern void netfilter_init(void); #define NF_MAX_HOOKS 8 struct sk_buff; -struct net_device; typedef unsigned int nf_hookfn(unsigned int hooknum, struct sk_buff *skb, @@ -320,5 +321,56 @@ extern void (*nf_ct_destroy)(struct nf_conntrack *); static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} #endif +static inline struct net *nf_pre_routing_net(const struct net_device *in, + const struct net_device *out) +{ +#ifdef CONFIG_NET_NS + return in->nd_net; +#else + return &init_net; +#endif +} + +static inline struct net *nf_local_in_net(const struct net_device *in, + const struct net_device *out) +{ +#ifdef CONFIG_NET_NS + return in->nd_net; +#else + return &init_net; +#endif +} + +static inline struct net *nf_forward_net(const struct net_device *in, + const struct net_device *out) +{ +#ifdef CONFIG_NET_NS + BUG_ON(in->nd_net != out->nd_net); + return in->nd_net; +#else + return &init_net; +#endif +} + +static inline struct net *nf_local_out_net(const struct net_device *in, + const struct net_device *out) +{ +#ifdef CONFIG_NET_NS + return out->nd_net; +#else + return &init_net; +#endif +} + +static inline struct net *nf_post_routing_net(const struct net_device *in, + const struct net_device *out) +{ +#ifdef CONFIG_NET_NS + return out->nd_net; +#else + return &init_net; +#endif +} + #endif /*__KERNEL__*/ #endif /*__LINUX_NETFILTER_H*/ diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 69f3d7e6e96f..7fcf60adbbed 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -62,6 +62,17 @@ static struct xt_table packet_filter = { }; /* The work comes in here from netfilter.c. */ +static unsigned int +ipt_local_in_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ipt_do_table(skb, hook, in, out, + nf_local_in_net(in, out)->ipv4.iptable_filter); +} + static unsigned int ipt_hook(unsigned int hook, struct sk_buff *skb, @@ -69,7 +80,8 @@ ipt_hook(unsigned int hook, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_filter); + return ipt_do_table(skb, hook, in, out, + nf_forward_net(in, out)->ipv4.iptable_filter); } static unsigned int @@ -88,12 +100,13 @@ ipt_local_out_hook(unsigned int hook, return NF_ACCEPT; } - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_filter); + return ipt_do_table(skb, hook, in, out, + nf_local_out_net(in, out)->ipv4.iptable_filter); } static struct nf_hook_ops ipt_ops[] __read_mostly = { { - .hook = ipt_hook, + .hook = ipt_local_in_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_LOCAL_IN, diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index c55a210853a7..ba827035b691 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -74,13 +74,47 @@ static struct xt_table packet_mangler = { /* The work comes in here from netfilter.c. */ static unsigned int -ipt_route_hook(unsigned int hook, +ipt_pre_routing_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ipt_do_table(skb, hook, in, out, + nf_pre_routing_net(in, out)->ipv4.iptable_mangle); +} + +static unsigned int +ipt_post_routing_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ipt_do_table(skb, hook, in, out, + nf_post_routing_net(in, out)->ipv4.iptable_mangle); +} + +static unsigned int +ipt_local_in_hook(unsigned int hook, + struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + int (*okfn)(struct sk_buff *)) +{ + return ipt_do_table(skb, hook, in, out, + nf_local_in_net(in, out)->ipv4.iptable_mangle); +} + +static unsigned int +ipt_forward_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_mangle); + return ipt_do_table(skb, hook, in, out, + nf_forward_net(in, out)->ipv4.iptable_mangle); } static unsigned int @@ -112,7 +146,8 @@ ipt_local_hook(unsigned int hook, daddr = iph->daddr; tos = iph->tos; - ret = ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_mangle); + ret = ipt_do_table(skb, hook, in, out, + nf_local_out_net(in, out)->ipv4.iptable_mangle); /* Reroute for ANY change. */ if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) { iph = ip_hdr(skb); @@ -130,21 +165,21 @@ ipt_local_hook(unsigned int hook, static struct nf_hook_ops ipt_ops[] __read_mostly = { { - .hook = ipt_route_hook, + .hook = ipt_pre_routing_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_PRE_ROUTING, .priority = NF_IP_PRI_MANGLE, }, { - .hook = ipt_route_hook, + .hook = ipt_local_in_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_MANGLE, }, { - .hook = ipt_route_hook, + .hook = ipt_forward_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_FORWARD, @@ -158,7 +193,7 @@ static struct nf_hook_ops ipt_ops[] __read_mostly = { .priority = NF_IP_PRI_MANGLE, }, { - .hook = ipt_route_hook, + .hook = ipt_post_routing_hook, .owner = THIS_MODULE, .pf = PF_INET, .hooknum = NF_INET_POST_ROUTING, diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index e41fe8ca4e1c..4b689742d58b 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -52,7 +52,8 @@ ipt_hook(unsigned int hook, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_raw); + return ipt_do_table(skb, hook, in, out, + nf_pre_routing_net(in, out)->ipv4.iptable_raw); } static unsigned int @@ -70,7 +71,8 @@ ipt_local_hook(unsigned int hook, "packet.\n"); return NF_ACCEPT; } - return ipt_do_table(skb, hook, in, out, init_net.ipv4.iptable_raw); + return ipt_do_table(skb, hook, in, out, + nf_local_out_net(in, out)->ipv4.iptable_raw); } /* 'raw' is the very first table. */ -- cgit v1.2.3-59-g8ed1b From 0718300c06d4b86ca2f4b93084ff3813fc81f5a2 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Mon, 14 Apr 2008 09:56:03 +0200 Subject: [NETFILTER]: bridge netfilter: use non-deprecated __RW_LOCK_UNLOCKED macro. Signed-off-by: Robert P. J. Day Signed-off-by: Patrick McHardy --- net/bridge/netfilter/ebtable_broute.c | 2 +- net/bridge/netfilter/ebtable_filter.c | 2 +- net/bridge/netfilter/ebtable_nat.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c index be6f18681053..246626bb0c87 100644 --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c @@ -46,7 +46,7 @@ static struct ebt_table broute_table = .name = "broute", .table = &initial_table, .valid_hooks = 1 << NF_BR_BROUTING, - .lock = RW_LOCK_UNLOCKED, + .lock = __RW_LOCK_UNLOCKED(broute_table.lock), .check = check, .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c index fb810908732f..690bc3ab186c 100644 --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c @@ -55,7 +55,7 @@ static struct ebt_table frame_filter = .name = "filter", .table = &initial_table, .valid_hooks = FILTER_VALID_HOOKS, - .lock = RW_LOCK_UNLOCKED, + .lock = __RW_LOCK_UNLOCKED(frame_filter.lock), .check = check, .me = THIS_MODULE, }; diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c index bc712730c54a..5b495fe2d0b6 100644 --- a/net/bridge/netfilter/ebtable_nat.c +++ b/net/bridge/netfilter/ebtable_nat.c @@ -55,7 +55,7 @@ static struct ebt_table frame_nat = .name = "nat", .table = &initial_table, .valid_hooks = NAT_VALID_HOOKS, - .lock = RW_LOCK_UNLOCKED, + .lock = __RW_LOCK_UNLOCKED(frame_nat.lock), .check = check, .me = THIS_MODULE, }; -- cgit v1.2.3-59-g8ed1b From fdccecd0cc267817607acca386181439e8e1bd83 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Mon, 14 Apr 2008 09:56:03 +0200 Subject: [NETFILTER]: Use non-deprecated __RW_LOCK_UNLOCKED macro Signed-off-by: Robert P. J. Day Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/arptable_filter.c | 2 +- net/ipv4/netfilter/iptable_filter.c | 2 +- net/ipv4/netfilter/iptable_mangle.c | 2 +- net/ipv4/netfilter/iptable_raw.c | 2 +- net/ipv4/netfilter/nf_nat_rule.c | 2 +- net/ipv6/netfilter/ip6table_filter.c | 2 +- net/ipv6/netfilter/ip6table_mangle.c | 2 +- net/ipv6/netfilter/ip6table_raw.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index 4e9c496a30c2..629e4951a9b1 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -48,7 +48,7 @@ static struct static struct arpt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, - .lock = RW_LOCK_UNLOCKED, + .lock = __RW_LOCK_UNLOCKED(packet_filter.lock), .private = NULL, .me = THIS_MODULE, .af = NF_ARP, diff --git a/net/ipv4/netfilter/iptable_filter.c b/net/ipv4/netfilter/iptable_filter.c index 7fcf60adbbed..1ea677dcf845 100644 --- a/net/ipv4/netfilter/iptable_filter.c +++ b/net/ipv4/netfilter/iptable_filter.c @@ -56,7 +56,7 @@ static struct static struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, - .lock = RW_LOCK_UNLOCKED, + .lock = __RW_LOCK_UNLOCKED(packet_filter.lock), .me = THIS_MODULE, .af = AF_INET, }; diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c index ba827035b691..da59182f2226 100644 --- a/net/ipv4/netfilter/iptable_mangle.c +++ b/net/ipv4/netfilter/iptable_mangle.c @@ -67,7 +67,7 @@ static struct static struct xt_table packet_mangler = { .name = "mangle", .valid_hooks = MANGLE_VALID_HOOKS, - .lock = RW_LOCK_UNLOCKED, + .lock = __RW_LOCK_UNLOCKED(packet_mangler.lock), .me = THIS_MODULE, .af = AF_INET, }; diff --git a/net/ipv4/netfilter/iptable_raw.c b/net/ipv4/netfilter/iptable_raw.c index 4b689742d58b..fddce7754b72 100644 --- a/net/ipv4/netfilter/iptable_raw.c +++ b/net/ipv4/netfilter/iptable_raw.c @@ -39,7 +39,7 @@ static struct static struct xt_table packet_raw = { .name = "raw", .valid_hooks = RAW_VALID_HOOKS, - .lock = RW_LOCK_UNLOCKED, + .lock = __RW_LOCK_UNLOCKED(packet_raw.lock), .me = THIS_MODULE, .af = AF_INET, }; diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c index f8fda57ba20b..e330a2974de1 100644 --- a/net/ipv4/netfilter/nf_nat_rule.c +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -61,7 +61,7 @@ static struct static struct xt_table __nat_table = { .name = "nat", .valid_hooks = NAT_VALID_HOOKS, - .lock = RW_LOCK_UNLOCKED, + .lock = __RW_LOCK_UNLOCKED(__nat_table.lock), .me = THIS_MODULE, .af = AF_INET, }; diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index 2d9cd095a72c..f979e48b469b 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -54,7 +54,7 @@ static struct static struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, - .lock = RW_LOCK_UNLOCKED, + .lock = __RW_LOCK_UNLOCKED(packet_filter.lock), .me = THIS_MODULE, .af = AF_INET6, }; diff --git a/net/ipv6/netfilter/ip6table_mangle.c b/net/ipv6/netfilter/ip6table_mangle.c index 035343a90ffe..27a5e8b48d93 100644 --- a/net/ipv6/netfilter/ip6table_mangle.c +++ b/net/ipv6/netfilter/ip6table_mangle.c @@ -60,7 +60,7 @@ static struct static struct xt_table packet_mangler = { .name = "mangle", .valid_hooks = MANGLE_VALID_HOOKS, - .lock = RW_LOCK_UNLOCKED, + .lock = __RW_LOCK_UNLOCKED(packet_mangler.lock), .me = THIS_MODULE, .af = AF_INET6, }; diff --git a/net/ipv6/netfilter/ip6table_raw.c b/net/ipv6/netfilter/ip6table_raw.c index 5cd84203abfe..92b91077ac29 100644 --- a/net/ipv6/netfilter/ip6table_raw.c +++ b/net/ipv6/netfilter/ip6table_raw.c @@ -38,7 +38,7 @@ static struct static struct xt_table packet_raw = { .name = "raw", .valid_hooks = RAW_VALID_HOOKS, - .lock = RW_LOCK_UNLOCKED, + .lock = __RW_LOCK_UNLOCKED(packet_raw.lock), .me = THIS_MODULE, .af = AF_INET6, }; -- cgit v1.2.3-59-g8ed1b From 3cf93c96af7adf78542d45f8a27f0e5f8704409d Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 09:56:05 +0200 Subject: [NETFILTER]: annotate xtables targets with const and remove casts Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/ipt_CLUSTERIP.c | 12 ++++++------ net/ipv4/netfilter/ipt_ECN.c | 2 +- net/ipv4/netfilter/ipt_LOG.c | 3 ++- net/ipv4/netfilter/ipt_REJECT.c | 6 ++++-- net/ipv4/netfilter/ipt_recent.c | 6 +++--- net/ipv4/netfilter/nf_nat_rule.c | 4 ++-- net/ipv6/netfilter/ip6t_REJECT.c | 3 ++- net/ipv6/netfilter/ip6t_ipv6header.c | 3 ++- net/ipv6/netfilter/ip6t_rt.c | 3 ++- net/netfilter/xt_CONNSECMARK.c | 2 +- net/netfilter/xt_RATEEST.c | 2 +- net/netfilter/xt_connlimit.c | 6 +++--- net/netfilter/xt_dccp.c | 3 ++- net/netfilter/xt_esp.c | 3 ++- net/netfilter/xt_multiport.c | 6 ++++-- net/netfilter/xt_policy.c | 2 +- net/netfilter/xt_rateest.c | 4 ++-- net/netfilter/xt_sctp.c | 6 ++++-- net/netfilter/xt_tcpmss.c | 6 ++++-- net/netfilter/xt_tcpudp.c | 9 ++++++--- net/netfilter/xt_time.c | 2 +- 21 files changed, 55 insertions(+), 38 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 965b08a7d738..2510d4fcdb54 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -142,7 +142,7 @@ clusterip_config_init_nodelist(struct clusterip_config *c, } static struct clusterip_config * -clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip, +clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip, struct net_device *dev) { struct clusterip_config *c; @@ -416,7 +416,7 @@ clusterip_tg_check(const char *tablename, const void *e_void, /* drop reference count of cluster config when rule is deleted */ static void clusterip_tg_destroy(const struct xt_target *target, void *targinfo) { - struct ipt_clusterip_tgt_info *cipinfo = targinfo; + const struct ipt_clusterip_tgt_info *cipinfo = targinfo; /* if no more entries are referencing the config, remove it * from the list and destroy the proc entry */ @@ -565,7 +565,7 @@ struct clusterip_seq_position { static void *clusterip_seq_start(struct seq_file *s, loff_t *pos) { - struct proc_dir_entry *pde = s->private; + const struct proc_dir_entry *pde = s->private; struct clusterip_config *c = pde->data; unsigned int weight; u_int32_t local_nodes; @@ -592,7 +592,7 @@ static void *clusterip_seq_start(struct seq_file *s, loff_t *pos) static void *clusterip_seq_next(struct seq_file *s, void *v, loff_t *pos) { - struct clusterip_seq_position *idx = (struct clusterip_seq_position *)v; + struct clusterip_seq_position *idx = v; *pos = ++idx->pos; if (*pos >= idx->weight) { @@ -611,7 +611,7 @@ static void clusterip_seq_stop(struct seq_file *s, void *v) static int clusterip_seq_show(struct seq_file *s, void *v) { - struct clusterip_seq_position *idx = (struct clusterip_seq_position *)v; + struct clusterip_seq_position *idx = v; if (idx->pos != 0) seq_putc(s, ','); @@ -667,7 +667,7 @@ static ssize_t clusterip_proc_write(struct file *file, const char __user *input, { #define PROC_WRITELEN 10 char buffer[PROC_WRITELEN+1]; - struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); + const struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); struct clusterip_config *c = pde->data; unsigned long nodenum; diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c index 21395bc2b27f..d60139c134ca 100644 --- a/net/ipv4/netfilter/ipt_ECN.c +++ b/net/ipv4/netfilter/ipt_ECN.c @@ -100,7 +100,7 @@ ecn_tg_check(const char *tablename, const void *e_void, const struct xt_target *target, void *targinfo, unsigned int hook_mask) { - const struct ipt_ECN_info *einfo = (struct ipt_ECN_info *)targinfo; + const struct ipt_ECN_info *einfo = targinfo; const struct ipt_entry *e = e_void; if (einfo->operation & IPT_ECN_OP_MASK) { diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index c40e233e271b..0af14137137b 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -76,7 +76,8 @@ static void dump_packet(const struct nf_loginfo *info, if ((logflags & IPT_LOG_IPOPT) && ih->ihl * 4 > sizeof(struct iphdr)) { - unsigned char _opt[4 * 15 - sizeof(struct iphdr)], *op; + const unsigned char *op; + unsigned char _opt[4 * 15 - sizeof(struct iphdr)]; unsigned int i, optsize; optsize = ih->ihl * 4 - sizeof(struct iphdr); diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index 22606e2baa16..2639872849da 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -35,8 +35,10 @@ MODULE_DESCRIPTION("Xtables: packet \"rejection\" target for IPv4"); static void send_reset(struct sk_buff *oldskb, int hook) { struct sk_buff *nskb; - struct iphdr *oiph, *niph; - struct tcphdr _otcph, *oth, *tcph; + const struct iphdr *oiph; + struct iphdr *niph; + const struct tcphdr *oth; + struct tcphdr _otcph, *tcph; unsigned int addr_type; /* IP header checks: fragment. */ diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c index 50e06690eb5b..21cb053f5d7d 100644 --- a/net/ipv4/netfilter/ipt_recent.c +++ b/net/ipv4/netfilter/ipt_recent.c @@ -340,7 +340,7 @@ static void *recent_seq_start(struct seq_file *seq, loff_t *pos) static void *recent_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct recent_iter_state *st = seq->private; - struct recent_table *t = st->table; + const struct recent_table *t = st->table; struct recent_entry *e = v; struct list_head *head = e->list.next; @@ -361,7 +361,7 @@ static void recent_seq_stop(struct seq_file *s, void *v) static int recent_seq_show(struct seq_file *seq, void *v) { - struct recent_entry *e = v; + const struct recent_entry *e = v; unsigned int i; i = (e->index - 1) % ip_pkt_list_tot; @@ -396,7 +396,7 @@ static int recent_seq_open(struct inode *inode, struct file *file) static ssize_t recent_proc_write(struct file *file, const char __user *input, size_t size, loff_t *loff) { - struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); + const struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); struct recent_table *t = pde->data; struct recent_entry *e; char buf[sizeof("+255.255.255.255")], *c = buf; diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c index e330a2974de1..ebe0c7903ae9 100644 --- a/net/ipv4/netfilter/nf_nat_rule.c +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -143,7 +143,7 @@ static bool ipt_snat_checkentry(const char *tablename, void *targinfo, unsigned int hook_mask) { - struct nf_nat_multi_range_compat *mr = targinfo; + const struct nf_nat_multi_range_compat *mr = targinfo; /* Must be a valid range */ if (mr->rangesize != 1) { @@ -159,7 +159,7 @@ static bool ipt_dnat_checkentry(const char *tablename, void *targinfo, unsigned int hook_mask) { - struct nf_nat_multi_range_compat *mr = targinfo; + const struct nf_nat_multi_range_compat *mr = targinfo; /* Must be a valid range */ if (mr->rangesize != 1) { diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index baf829075f6f..44c8d65a2431 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -41,7 +41,8 @@ static void send_reset(struct sk_buff *oldskb) struct tcphdr otcph, *tcph; unsigned int otcplen, hh_len; int tcphoff, needs_ack; - struct ipv6hdr *oip6h = ipv6_hdr(oldskb), *ip6h; + const struct ipv6hdr *oip6h = ipv6_hdr(oldskb); + struct ipv6hdr *ip6h; struct dst_entry *dst = NULL; u8 proto; struct flowi fl; diff --git a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c index 3a940171f829..317a8960a757 100644 --- a/net/ipv6/netfilter/ip6t_ipv6header.c +++ b/net/ipv6/netfilter/ip6t_ipv6header.c @@ -49,7 +49,8 @@ ipv6header_mt6(const struct sk_buff *skb, const struct net_device *in, temp = 0; while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr _hdr, *hp; + const struct ipv6_opt_hdr *hp; + struct ipv6_opt_hdr _hdr; int hdrlen; /* Is there enough space for the next ext header? */ diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index 12a9efe9886e..81aaf7aaaabf 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c @@ -110,7 +110,8 @@ rt_mt6(const struct sk_buff *skb, const struct net_device *in, !!(rtinfo->invflags & IP6T_RT_INV_TYP))); if (ret && (rtinfo->flags & IP6T_RT_RES)) { - u_int32_t *rp, _reserved; + const u_int32_t *rp; + u_int32_t _reserved; rp = skb_header_pointer(skb, ptr + offsetof(struct rt0_hdr, reserved), diff --git a/net/netfilter/xt_CONNSECMARK.c b/net/netfilter/xt_CONNSECMARK.c index 1faa9136195d..211189eb2b67 100644 --- a/net/netfilter/xt_CONNSECMARK.c +++ b/net/netfilter/xt_CONNSECMARK.c @@ -55,7 +55,7 @@ static void secmark_save(const struct sk_buff *skb) static void secmark_restore(struct sk_buff *skb) { if (!skb->secmark) { - struct nf_conn *ct; + const struct nf_conn *ct; enum ip_conntrack_info ctinfo; ct = nf_ct_get(skb, &ctinfo); diff --git a/net/netfilter/xt_RATEEST.c b/net/netfilter/xt_RATEEST.c index 24c73ba31eaa..64d6ad380293 100644 --- a/net/netfilter/xt_RATEEST.c +++ b/net/netfilter/xt_RATEEST.c @@ -96,7 +96,7 @@ xt_rateest_tg_checkentry(const char *tablename, void *targinfo, unsigned int hook_mask) { - struct xt_rateest_target_info *info = (void *)targinfo; + struct xt_rateest_target_info *info = targinfo; struct xt_rateest *est; struct { struct nlattr opt; diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index 3b0111933f60..0ca9fe9da203 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -106,10 +106,10 @@ static int count_them(struct xt_connlimit_data *data, const union nf_inet_addr *mask, const struct xt_match *match) { - struct nf_conntrack_tuple_hash *found; + const struct nf_conntrack_tuple_hash *found; struct xt_connlimit_conn *conn; struct xt_connlimit_conn *tmp; - struct nf_conn *found_ct; + const struct nf_conn *found_ct; struct list_head *hash; bool addit = true; int matches = 0; @@ -256,7 +256,7 @@ connlimit_mt_check(const char *tablename, const void *ip, static void connlimit_mt_destroy(const struct xt_match *match, void *matchinfo) { - struct xt_connlimit_info *info = matchinfo; + const struct xt_connlimit_info *info = matchinfo; struct xt_connlimit_conn *conn; struct xt_connlimit_conn *tmp; struct list_head *hash = info->data->iphash; diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c index 667f45e72cd9..8b6522186d9f 100644 --- a/net/netfilter/xt_dccp.c +++ b/net/netfilter/xt_dccp.c @@ -98,7 +98,8 @@ dccp_mt(const struct sk_buff *skb, const struct net_device *in, const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop) { const struct xt_dccp_info *info = matchinfo; - struct dccp_hdr _dh, *dh; + const struct dccp_hdr *dh; + struct dccp_hdr _dh; if (offset) return false; diff --git a/net/netfilter/xt_esp.c b/net/netfilter/xt_esp.c index 71c7c3785266..a133eb9b23e1 100644 --- a/net/netfilter/xt_esp.c +++ b/net/netfilter/xt_esp.c @@ -47,7 +47,8 @@ esp_mt(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const struct xt_match *match, const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop) { - struct ip_esp_hdr _esp, *eh; + const struct ip_esp_hdr *eh; + struct ip_esp_hdr _esp; const struct xt_esp *espinfo = matchinfo; /* Must not be a fragment. */ diff --git a/net/netfilter/xt_multiport.c b/net/netfilter/xt_multiport.c index 31daa8192422..fd88c489b70e 100644 --- a/net/netfilter/xt_multiport.c +++ b/net/netfilter/xt_multiport.c @@ -100,7 +100,8 @@ multiport_mt_v0(const struct sk_buff *skb, const struct net_device *in, const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop) { - __be16 _ports[2], *pptr; + const __be16 *pptr; + __be16 _ports[2]; const struct xt_multiport *multiinfo = matchinfo; if (offset) @@ -126,7 +127,8 @@ multiport_mt(const struct sk_buff *skb, const struct net_device *in, const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop) { - __be16 _ports[2], *pptr; + const __be16 *pptr; + __be16 _ports[2]; const struct xt_multiport_v1 *multiinfo = matchinfo; if (offset) diff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c index 9e918add2282..d351582b2a3d 100644 --- a/net/netfilter/xt_policy.c +++ b/net/netfilter/xt_policy.c @@ -136,7 +136,7 @@ policy_mt_check(const char *tablename, const void *ip_void, const struct xt_match *match, void *matchinfo, unsigned int hook_mask) { - struct xt_policy_info *info = matchinfo; + const struct xt_policy_info *info = matchinfo; if (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT))) { printk(KERN_ERR "xt_policy: neither incoming nor " diff --git a/net/netfilter/xt_rateest.c b/net/netfilter/xt_rateest.c index fdb86a515146..ebd84f1b4f62 100644 --- a/net/netfilter/xt_rateest.c +++ b/net/netfilter/xt_rateest.c @@ -86,7 +86,7 @@ static bool xt_rateest_mt_checkentry(const char *tablename, void *matchinfo, unsigned int hook_mask) { - struct xt_rateest_match_info *info = (void *)matchinfo; + struct xt_rateest_match_info *info = matchinfo; struct xt_rateest *est1, *est2; if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS | @@ -130,7 +130,7 @@ err1: static void xt_rateest_mt_destroy(const struct xt_match *match, void *matchinfo) { - struct xt_rateest_match_info *info = (void *)matchinfo; + struct xt_rateest_match_info *info = matchinfo; xt_rateest_put(info->est1); if (info->est2) diff --git a/net/netfilter/xt_sctp.c b/net/netfilter/xt_sctp.c index b718ec64333d..e6e4681fa047 100644 --- a/net/netfilter/xt_sctp.c +++ b/net/netfilter/xt_sctp.c @@ -46,7 +46,8 @@ match_packet(const struct sk_buff *skb, bool *hotdrop) { u_int32_t chunkmapcopy[256 / sizeof (u_int32_t)]; - sctp_chunkhdr_t _sch, *sch; + const sctp_chunkhdr_t *sch; + sctp_chunkhdr_t _sch; int chunk_match_type = info->chunk_match_type; const struct xt_sctp_flag_info *flag_info = info->flag_info; int flag_count = info->flag_count; @@ -121,7 +122,8 @@ sctp_mt(const struct sk_buff *skb, const struct net_device *in, const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop) { const struct xt_sctp_info *info = matchinfo; - sctp_sctphdr_t _sh, *sh; + const sctp_sctphdr_t *sh; + sctp_sctphdr_t _sh; if (offset) { duprintf("Dropping non-first fragment.. FIXME\n"); diff --git a/net/netfilter/xt_tcpmss.c b/net/netfilter/xt_tcpmss.c index d7a5b27fe81e..6771bf01275b 100644 --- a/net/netfilter/xt_tcpmss.c +++ b/net/netfilter/xt_tcpmss.c @@ -31,9 +31,11 @@ tcpmss_mt(const struct sk_buff *skb, const struct net_device *in, bool *hotdrop) { const struct xt_tcpmss_match_info *info = matchinfo; - struct tcphdr _tcph, *th; + const struct tcphdr *th; + struct tcphdr _tcph; /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ - u8 _opt[15 * 4 - sizeof(_tcph)], *op; + const u_int8_t *op; + u8 _opt[15 * 4 - sizeof(_tcph)]; unsigned int i, optlen; /* If we don't have the whole header, drop packet. */ diff --git a/net/netfilter/xt_tcpudp.c b/net/netfilter/xt_tcpudp.c index 4fa3b669f691..951b06b8d701 100644 --- a/net/netfilter/xt_tcpudp.c +++ b/net/netfilter/xt_tcpudp.c @@ -42,7 +42,8 @@ tcp_find_option(u_int8_t option, bool *hotdrop) { /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ - u_int8_t _opt[60 - sizeof(struct tcphdr)], *op; + const u_int8_t *op; + u_int8_t _opt[60 - sizeof(struct tcphdr)]; unsigned int i; duprintf("tcp_match: finding option\n"); @@ -72,7 +73,8 @@ tcp_mt(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const struct xt_match *match, const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop) { - struct tcphdr _tcph, *th; + const struct tcphdr *th; + struct tcphdr _tcph; const struct xt_tcp *tcpinfo = matchinfo; if (offset) { @@ -144,7 +146,8 @@ udp_mt(const struct sk_buff *skb, const struct net_device *in, const struct net_device *out, const struct xt_match *match, const void *matchinfo, int offset, unsigned int protoff, bool *hotdrop) { - struct udphdr _udph, *uh; + const struct udphdr *uh; + struct udphdr _udph; const struct xt_udp *udpinfo = matchinfo; /* Must not be a fragment. */ diff --git a/net/netfilter/xt_time.c b/net/netfilter/xt_time.c index 9fa2e0824708..ed76baab4734 100644 --- a/net/netfilter/xt_time.c +++ b/net/netfilter/xt_time.c @@ -223,7 +223,7 @@ time_mt_check(const char *tablename, const void *ip, const struct xt_match *match, void *matchinfo, unsigned int hook_mask) { - struct xt_time_info *info = matchinfo; + const struct xt_time_info *info = matchinfo; if (info->daytime_start > XT_TIME_MAX_DAYTIME || info->daytime_stop > XT_TIME_MAX_DAYTIME) { -- cgit v1.2.3-59-g8ed1b From 5452e425adfdfc4647b618e303f73d48f2405b0e Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:35 +0200 Subject: [NETFILTER]: annotate {arp,ip,ip6,x}tables with const Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/linux/netfilter/x_tables.h | 4 ++-- net/ipv4/netfilter/arp_tables.c | 31 ++++++++++++++++--------------- net/ipv4/netfilter/arpt_mangle.c | 2 +- net/ipv4/netfilter/ip_tables.c | 31 ++++++++++++++++--------------- net/ipv6/netfilter/ip6_tables.c | 29 +++++++++++++++-------------- net/netfilter/x_tables.c | 18 +++++++++--------- 6 files changed, 59 insertions(+), 56 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index b2c62cc618f5..2326296b6f25 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -430,13 +430,13 @@ extern int xt_compat_add_offset(int af, unsigned int offset, short delta); extern void xt_compat_flush_offsets(int af); extern short xt_compat_calc_jump(int af, unsigned int offset); -extern int xt_compat_match_offset(struct xt_match *match); +extern int xt_compat_match_offset(const struct xt_match *match); extern int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, unsigned int *size); extern int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr, unsigned int *size); -extern int xt_compat_target_offset(struct xt_target *target); +extern int xt_compat_target_offset(const struct xt_target *target); extern void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, unsigned int *size); extern int xt_compat_target_to_user(struct xt_entry_target *t, diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 1563f29b5117..10cc442330c3 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -59,7 +59,7 @@ do { \ #endif static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap, - char *hdr_addr, int len) + const char *hdr_addr, int len) { int i, ret; @@ -80,8 +80,8 @@ static inline int arp_packet_match(const struct arphdr *arphdr, const char *outdev, const struct arpt_arp *arpinfo) { - char *arpptr = (char *)(arphdr + 1); - char *src_devaddr, *tgt_devaddr; + const char *arpptr = (char *)(arphdr + 1); + const char *src_devaddr, *tgt_devaddr; __be32 src_ipaddr, tgt_ipaddr; int i, ret; @@ -226,12 +226,12 @@ unsigned int arpt_do_table(struct sk_buff *skb, { static const char nulldevname[IFNAMSIZ]; unsigned int verdict = NF_DROP; - struct arphdr *arp; + const struct arphdr *arp; bool hotdrop = false; struct arpt_entry *e, *back; const char *indev, *outdev; void *table_base; - struct xt_table_info *private; + const struct xt_table_info *private; if (!pskb_may_pull(skb, arp_hdr_len(skb->dev))) return NF_DROP; @@ -352,7 +352,7 @@ static int mark_source_chains(struct xt_table_info *newinfo, e->counters.pcnt = pos; for (;;) { - struct arpt_standard_target *t + const struct arpt_standard_target *t = (void *)arpt_get_target(e); int visited = e->comefrom & (1 << hook); @@ -437,7 +437,7 @@ static int mark_source_chains(struct xt_table_info *newinfo, static inline int check_entry(struct arpt_entry *e, const char *name) { - struct arpt_entry_target *t; + const struct arpt_entry_target *t; if (!arp_checkentry(&e->arp)) { duprintf("arp_tables: arp check failed %p %s.\n", e, name); @@ -710,7 +710,7 @@ static inline struct xt_counters *alloc_counters(struct arpt_table *table) { unsigned int countersize; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; /* We need atomic snapshot of counters: rest doesn't change * (other than comefrom, which userspace doesn't care @@ -737,7 +737,7 @@ static int copy_entries_to_user(unsigned int total_size, unsigned int off, num; struct arpt_entry *e; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; int ret = 0; void *loc_cpu_entry; @@ -872,7 +872,7 @@ static int get_info(struct net *net, void __user *user, int *len, int compat) "arptable_%s", name); if (t && !IS_ERR(t)) { struct arpt_getinfo info; - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; #ifdef CONFIG_COMPAT if (compat) { @@ -927,7 +927,8 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr, t = xt_find_table_lock(net, NF_ARP, get.name); if (t && !IS_ERR(t)) { - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; + duprintf("t->private->number = %u\n", private->number); if (get.size == private->size) @@ -1087,11 +1088,11 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len, struct xt_counters_info tmp; struct xt_counters *paddc; unsigned int num_counters; - char *name; + const char *name; int size; void *ptmp; struct arpt_table *t; - struct xt_table_info *private; + const struct xt_table_info *private; int ret = 0; void *loc_cpu_entry; #ifdef CONFIG_COMPAT @@ -1558,7 +1559,7 @@ static int compat_copy_entries_to_user(unsigned int total_size, void __user *userptr) { struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; void __user *pos; unsigned int size; int ret = 0; @@ -1609,7 +1610,7 @@ static int compat_get_entries(struct net *net, xt_compat_lock(NF_ARP); t = xt_find_table_lock(net, NF_ARP, get.name); if (t && !IS_ERR(t)) { - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; struct xt_table_info info; duprintf("t->private->number = %u\n", private->number); diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c index 3f4222b0a803..3e732c827fc2 100644 --- a/net/ipv4/netfilter/arpt_mangle.c +++ b/net/ipv4/netfilter/arpt_mangle.c @@ -15,7 +15,7 @@ target(struct sk_buff *skb, const void *targinfo) { const struct arpt_mangle *mangle = targinfo; - struct arphdr *arp; + const struct arphdr *arp; unsigned char *arpptr; int pln, hln; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index a819d191e1aa..aa124b50cb4a 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -296,7 +296,7 @@ static void trace_packet(struct sk_buff *skb, struct ipt_entry *e) { void *table_base; - struct ipt_entry *root; + const struct ipt_entry *root; char *hookname, *chainname, *comment; unsigned int rulenum = 0; @@ -327,7 +327,7 @@ ipt_do_table(struct sk_buff *skb, { static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); u_int16_t offset; - struct iphdr *ip; + const struct iphdr *ip; u_int16_t datalen; bool hotdrop = false; /* Initializing verdict to NF_DROP keeps gcc happy. */ @@ -926,7 +926,7 @@ static struct xt_counters * alloc_counters(struct xt_table *table) { unsigned int countersize; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; /* We need atomic snapshot of counters: rest doesn't change (other than comefrom, which userspace doesn't care @@ -953,9 +953,9 @@ copy_entries_to_user(unsigned int total_size, unsigned int off, num; struct ipt_entry *e; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; int ret = 0; - void *loc_cpu_entry; + const void *loc_cpu_entry; counters = alloc_counters(table); if (IS_ERR(counters)) @@ -975,8 +975,8 @@ copy_entries_to_user(unsigned int total_size, /* ... then go back and fix counters and names */ for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){ unsigned int i; - struct ipt_entry_match *m; - struct ipt_entry_target *t; + const struct ipt_entry_match *m; + const struct ipt_entry_target *t; e = (struct ipt_entry *)(loc_cpu_entry + off); if (copy_to_user(userptr + off @@ -1116,7 +1116,7 @@ static int get_info(struct net *net, void __user *user, int *len, int compat) "iptable_%s", name); if (t && !IS_ERR(t)) { struct ipt_getinfo info; - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; #ifdef CONFIG_COMPAT if (compat) { @@ -1172,7 +1172,7 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len) t = xt_find_table_lock(net, AF_INET, get.name); if (t && !IS_ERR(t)) { - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; duprintf("t->private->number = %u\n", private->number); if (get.size == private->size) ret = copy_entries_to_user(private->size, @@ -1337,11 +1337,11 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int compat struct xt_counters_info tmp; struct xt_counters *paddc; unsigned int num_counters; - char *name; + const char *name; int size; void *ptmp; struct xt_table *t; - struct xt_table_info *private; + const struct xt_table_info *private; int ret = 0; void *loc_cpu_entry; #ifdef CONFIG_COMPAT @@ -1878,11 +1878,11 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, void __user *userptr) { struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; void __user *pos; unsigned int size; int ret = 0; - void *loc_cpu_entry; + const void *loc_cpu_entry; unsigned int i = 0; counters = alloc_counters(table); @@ -1929,7 +1929,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr, xt_compat_lock(AF_INET); t = xt_find_table_lock(net, AF_INET, get.name); if (t && !IS_ERR(t)) { - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; struct xt_table_info info; duprintf("t->private->number = %u\n", private->number); ret = compat_table_info(private, &info); @@ -2130,7 +2130,8 @@ icmp_match(const struct sk_buff *skb, unsigned int protoff, bool *hotdrop) { - struct icmphdr _icmph, *ic; + const struct icmphdr *ic; + struct icmphdr _icmph; const struct ipt_icmp *icmpinfo = matchinfo; /* Must not be a fragment. */ diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 70ef0d276cc0..782183f63366 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -325,7 +325,7 @@ static void trace_packet(struct sk_buff *skb, struct ip6t_entry *e) { void *table_base; - struct ip6t_entry *root; + const struct ip6t_entry *root; char *hookname, *chainname, *comment; unsigned int rulenum = 0; @@ -952,7 +952,7 @@ static struct xt_counters *alloc_counters(struct xt_table *table) { unsigned int countersize; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; /* We need atomic snapshot of counters: rest doesn't change (other than comefrom, which userspace doesn't care @@ -979,9 +979,9 @@ copy_entries_to_user(unsigned int total_size, unsigned int off, num; struct ip6t_entry *e; struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; int ret = 0; - void *loc_cpu_entry; + const void *loc_cpu_entry; counters = alloc_counters(table); if (IS_ERR(counters)) @@ -1001,8 +1001,8 @@ copy_entries_to_user(unsigned int total_size, /* ... then go back and fix counters and names */ for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){ unsigned int i; - struct ip6t_entry_match *m; - struct ip6t_entry_target *t; + const struct ip6t_entry_match *m; + const struct ip6t_entry_target *t; e = (struct ip6t_entry *)(loc_cpu_entry + off); if (copy_to_user(userptr + off @@ -1142,7 +1142,7 @@ static int get_info(struct net *net, void __user *user, int *len, int compat) "ip6table_%s", name); if (t && !IS_ERR(t)) { struct ip6t_getinfo info; - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; #ifdef CONFIG_COMPAT if (compat) { @@ -1225,7 +1225,7 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks, struct xt_table *t; struct xt_table_info *oldinfo; struct xt_counters *counters; - void *loc_cpu_old_entry; + const void *loc_cpu_old_entry; ret = 0; counters = vmalloc_node(num_counters * sizeof(struct xt_counters), @@ -1369,9 +1369,9 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int size; void *ptmp; struct xt_table *t; - struct xt_table_info *private; + const struct xt_table_info *private; int ret = 0; - void *loc_cpu_entry; + const void *loc_cpu_entry; #ifdef CONFIG_COMPAT struct compat_xt_counters_info compat_tmp; @@ -1905,11 +1905,11 @@ compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table, void __user *userptr) { struct xt_counters *counters; - struct xt_table_info *private = table->private; + const struct xt_table_info *private = table->private; void __user *pos; unsigned int size; int ret = 0; - void *loc_cpu_entry; + const void *loc_cpu_entry; unsigned int i = 0; counters = alloc_counters(table); @@ -1956,7 +1956,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr, xt_compat_lock(AF_INET6); t = xt_find_table_lock(net, AF_INET6, get.name); if (t && !IS_ERR(t)) { - struct xt_table_info *private = t->private; + const struct xt_table_info *private = t->private; struct xt_table_info info; duprintf("t->private->number = %u\n", private->number); ret = compat_table_info(private, &info); @@ -2155,7 +2155,8 @@ icmp6_match(const struct sk_buff *skb, unsigned int protoff, bool *hotdrop) { - struct icmp6hdr _icmph, *ic; + const struct icmp6hdr *ic; + struct icmp6hdr _icmph; const struct ip6t_icmp *icmpinfo = matchinfo; /* Must not be a fragment. */ diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 0bd95680a494..f52f7f810ac4 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -58,7 +58,7 @@ static struct xt_af *xt; #define duprintf(format, args...) #endif -static const char *xt_prefix[NPROTO] = { +static const char *const xt_prefix[NPROTO] = { [AF_INET] = "ip", [AF_INET6] = "ip6", [NF_ARP] = "arp", @@ -248,7 +248,7 @@ EXPORT_SYMBOL_GPL(xt_request_find_target); static int match_revfn(int af, const char *name, u8 revision, int *bestp) { - struct xt_match *m; + const struct xt_match *m; int have_rev = 0; list_for_each_entry(m, &xt[af].match, list) { @@ -264,7 +264,7 @@ static int match_revfn(int af, const char *name, u8 revision, int *bestp) static int target_revfn(int af, const char *name, u8 revision, int *bestp) { - struct xt_target *t; + const struct xt_target *t; int have_rev = 0; list_for_each_entry(t, &xt[af].target, list) { @@ -385,7 +385,7 @@ short xt_compat_calc_jump(int af, unsigned int offset) } EXPORT_SYMBOL_GPL(xt_compat_calc_jump); -int xt_compat_match_offset(struct xt_match *match) +int xt_compat_match_offset(const struct xt_match *match) { u_int16_t csize = match->compatsize ? : match->matchsize; return XT_ALIGN(match->matchsize) - COMPAT_XT_ALIGN(csize); @@ -395,7 +395,7 @@ EXPORT_SYMBOL_GPL(xt_compat_match_offset); int xt_compat_match_from_user(struct xt_entry_match *m, void **dstptr, unsigned int *size) { - struct xt_match *match = m->u.kernel.match; + const struct xt_match *match = m->u.kernel.match; struct compat_xt_entry_match *cm = (struct compat_xt_entry_match *)m; int pad, off = xt_compat_match_offset(match); u_int16_t msize = cm->u.user.match_size; @@ -422,7 +422,7 @@ EXPORT_SYMBOL_GPL(xt_compat_match_from_user); int xt_compat_match_to_user(struct xt_entry_match *m, void __user **dstptr, unsigned int *size) { - struct xt_match *match = m->u.kernel.match; + const struct xt_match *match = m->u.kernel.match; struct compat_xt_entry_match __user *cm = *dstptr; int off = xt_compat_match_offset(match); u_int16_t msize = m->u.user.match_size - off; @@ -479,7 +479,7 @@ int xt_check_target(const struct xt_target *target, unsigned short family, EXPORT_SYMBOL_GPL(xt_check_target); #ifdef CONFIG_COMPAT -int xt_compat_target_offset(struct xt_target *target) +int xt_compat_target_offset(const struct xt_target *target) { u_int16_t csize = target->compatsize ? : target->targetsize; return XT_ALIGN(target->targetsize) - COMPAT_XT_ALIGN(csize); @@ -489,7 +489,7 @@ EXPORT_SYMBOL_GPL(xt_compat_target_offset); void xt_compat_target_from_user(struct xt_entry_target *t, void **dstptr, unsigned int *size) { - struct xt_target *target = t->u.kernel.target; + const struct xt_target *target = t->u.kernel.target; struct compat_xt_entry_target *ct = (struct compat_xt_entry_target *)t; int pad, off = xt_compat_target_offset(target); u_int16_t tsize = ct->u.user.target_size; @@ -515,7 +515,7 @@ EXPORT_SYMBOL_GPL(xt_compat_target_from_user); int xt_compat_target_to_user(struct xt_entry_target *t, void __user **dstptr, unsigned int *size) { - struct xt_target *target = t->u.kernel.target; + const struct xt_target *target = t->u.kernel.target; struct compat_xt_entry_target __user *ct = *dstptr; int off = xt_compat_target_offset(target); u_int16_t tsize = t->u.user.target_size - off; -- cgit v1.2.3-59-g8ed1b From 58c0fb0ddd92e5105d61fc85b6e7af7b1f669067 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:42 +0200 Subject: [NETFILTER]: annotate rest of nf_conntrack_* with const Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- net/ipv6/netfilter/nf_conntrack_reasm.c | 8 ++++---- net/netfilter/nf_conntrack_amanda.c | 2 +- net/netfilter/nf_conntrack_ftp.c | 5 +++-- net/netfilter/nf_conntrack_helper.c | 2 +- net/netfilter/nf_conntrack_irc.c | 14 ++++++++------ 5 files changed, 17 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 9e5f305b2022..2dccad48058c 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -103,8 +103,8 @@ struct ctl_table nf_ct_ipv6_sysctl_table[] = { }; #endif -static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr, - struct in6_addr *daddr) +static unsigned int ip6qhashfn(__be32 id, const struct in6_addr *saddr, + const struct in6_addr *daddr) { u32 a, b, c; @@ -132,7 +132,7 @@ static unsigned int ip6qhashfn(__be32 id, struct in6_addr *saddr, static unsigned int nf_hashfn(struct inet_frag_queue *q) { - struct nf_ct_frag6_queue *nq; + const struct nf_ct_frag6_queue *nq; nq = container_of(q, struct nf_ct_frag6_queue, q); return ip6qhashfn(nq->id, &nq->saddr, &nq->daddr); @@ -222,7 +222,7 @@ oom: static int nf_ct_frag6_queue(struct nf_ct_frag6_queue *fq, struct sk_buff *skb, - struct frag_hdr *fhdr, int nhoff) + const struct frag_hdr *fhdr, int nhoff) { struct sk_buff *prev, *next; int offset, end; diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c index d14585a19b7d..ddfac99cbe63 100644 --- a/net/netfilter/nf_conntrack_amanda.c +++ b/net/netfilter/nf_conntrack_amanda.c @@ -53,7 +53,7 @@ enum amanda_strings { }; static struct { - char *string; + const char *string; size_t len; struct ts_config *ts; } search[] __read_mostly = { diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 7eff876bb8bc..87ca39b353bb 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -350,8 +350,9 @@ static int help(struct sk_buff *skb, enum ip_conntrack_info ctinfo) { unsigned int dataoff, datalen; - struct tcphdr _tcph, *th; - char *fb_ptr; + const struct tcphdr *th; + struct tcphdr _tcph; + const char *fb_ptr; int ret; u32 seq; int dir = CTINFO2DIR(ctinfo); diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index e350f56d43c9..7d1b11703741 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -126,7 +126,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) { struct nf_conntrack_tuple_hash *h; struct nf_conntrack_expect *exp; - struct hlist_node *n, *next; + const struct hlist_node *n, *next; unsigned int i; mutex_lock(&nf_ct_helper_mutex); diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c index 02f21cbe5ae7..1b1226d6653f 100644 --- a/net/netfilter/nf_conntrack_irc.c +++ b/net/netfilter/nf_conntrack_irc.c @@ -50,7 +50,7 @@ MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per " module_param(dcc_timeout, uint, 0400); MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels"); -static const char *dccprotos[] = { +static const char *const dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " }; @@ -65,7 +65,7 @@ static const char *dccprotos[] = { * ad_beg_p returns pointer to first byte of addr data * ad_end_p returns pointer to last byte of addr data */ -static int parse_dcc(char *data, char *data_end, u_int32_t *ip, +static int parse_dcc(char *data, const char *data_end, u_int32_t *ip, u_int16_t *port, char **ad_beg_p, char **ad_end_p) { /* at least 12: "AAAAAAAA P\1\n" */ @@ -93,9 +93,11 @@ static int help(struct sk_buff *skb, unsigned int protoff, struct nf_conn *ct, enum ip_conntrack_info ctinfo) { unsigned int dataoff; - struct iphdr *iph; - struct tcphdr _tcph, *th; - char *data, *data_limit, *ib_ptr; + const struct iphdr *iph; + const struct tcphdr *th; + struct tcphdr _tcph; + const char *data_limit; + char *data, *ib_ptr; int dir = CTINFO2DIR(ctinfo); struct nf_conntrack_expect *exp; struct nf_conntrack_tuple *tuple; @@ -159,7 +161,7 @@ static int help(struct sk_buff *skb, unsigned int protoff, /* we have at least * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid * data left (== 14/13 bytes) */ - if (parse_dcc((char *)data, data_limit, &dcc_ip, + if (parse_dcc(data, data_limit, &dcc_ip, &dcc_port, &addr_beg_p, &addr_end_p)) { pr_debug("unable to parse dcc command\n"); continue; -- cgit v1.2.3-59-g8ed1b From 72b72949db9aabaafd791a9077f02188a866824d Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:42 +0200 Subject: [NETFILTER]: annotate rest of nf_nat_* with const Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/nf_nat_core.c | 8 ++++---- net/ipv4/netfilter/nf_nat_snmp_basic.c | 17 ++++++++--------- net/ipv4/netfilter/nf_nat_standalone.c | 8 ++++---- 3 files changed, 16 insertions(+), 17 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 0d5fa3a54d04..9c8aa8df2d5e 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -150,9 +150,9 @@ find_appropriate_src(const struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range) { unsigned int h = hash_by_src(tuple); - struct nf_conn_nat *nat; - struct nf_conn *ct; - struct hlist_node *n; + const struct nf_conn_nat *nat; + const struct nf_conn *ct; + const struct hlist_node *n; rcu_read_lock(); hlist_for_each_entry_rcu(nat, n, &bysource[h], bysource) { @@ -426,7 +426,7 @@ int nf_nat_icmp_reply_translation(struct nf_conn *ct, struct icmphdr icmp; struct iphdr ip; } *inside; - struct nf_conntrack_l4proto *l4proto; + const struct nf_conntrack_l4proto *l4proto; struct nf_conntrack_tuple inner, target; int hdrlen = ip_hdrlen(skb); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c index 000e080bac5c..5daefad3d193 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c @@ -220,7 +220,7 @@ static unsigned char asn1_length_decode(struct asn1_ctx *ctx, if (ch < 0x80) *len = ch; else { - cnt = (unsigned char) (ch & 0x7F); + cnt = ch & 0x7F; *len = 0; while (cnt > 0) { @@ -618,8 +618,7 @@ struct snmp_cnv int syntax; }; -static struct snmp_cnv snmp_conv [] = -{ +static const struct snmp_cnv snmp_conv[] = { {ASN1_UNI, ASN1_NUL, SNMP_NULL}, {ASN1_UNI, ASN1_INT, SNMP_INTEGER}, {ASN1_UNI, ASN1_OTS, SNMP_OCTETSTR}, @@ -644,7 +643,7 @@ static unsigned char snmp_tag_cls2syntax(unsigned int tag, unsigned int cls, unsigned short *syntax) { - struct snmp_cnv *cnv; + const struct snmp_cnv *cnv; cnv = snmp_conv; @@ -904,7 +903,7 @@ static inline void mangle_address(unsigned char *begin, u_int32_t old; if (debug) - memcpy(&old, (unsigned char *)addr, sizeof(old)); + memcpy(&old, addr, sizeof(old)); *addr = map->to; @@ -999,7 +998,7 @@ err_id_free: * *****************************************************************************/ -static void hex_dump(unsigned char *buf, size_t len) +static void hex_dump(const unsigned char *buf, size_t len) { size_t i; @@ -1080,7 +1079,7 @@ static int snmp_parse_mangle(unsigned char *msg, if (cls != ASN1_CTX || con != ASN1_CON) return 0; if (debug > 1) { - unsigned char *pdus[] = { + static const unsigned char *const pdus[] = { [SNMP_PDU_GET] = "get", [SNMP_PDU_NEXT] = "get-next", [SNMP_PDU_RESPONSE] = "response", @@ -1232,8 +1231,8 @@ static int help(struct sk_buff *skb, unsigned int protoff, { int dir = CTINFO2DIR(ctinfo); unsigned int ret; - struct iphdr *iph = ip_hdr(skb); - struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl); + const struct iphdr *iph = ip_hdr(skb); + const struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl); /* SNMP replies and originating SNMP traps get mangled */ if (udph->source == htons(SNMP_PORT) && dir != IP_CT_DIR_REPLY) diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index 99b2c788d5a8..9fba42d9cdea 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -30,8 +30,8 @@ #ifdef CONFIG_XFRM static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) { - struct nf_conn *ct; - struct nf_conntrack_tuple *t; + const struct nf_conn *ct; + const struct nf_conntrack_tuple *t; enum ip_conntrack_info ctinfo; enum ip_conntrack_dir dir; unsigned long statusbit; @@ -189,7 +189,7 @@ nf_nat_out(unsigned int hooknum, int (*okfn)(struct sk_buff *)) { #ifdef CONFIG_XFRM - struct nf_conn *ct; + const struct nf_conn *ct; enum ip_conntrack_info ctinfo; #endif unsigned int ret; @@ -223,7 +223,7 @@ nf_nat_local_fn(unsigned int hooknum, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - struct nf_conn *ct; + const struct nf_conn *ct; enum ip_conntrack_info ctinfo; unsigned int ret; -- cgit v1.2.3-59-g8ed1b From 4abff0775d5e4feb20b21371e1c63a1b30fc2140 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:43 +0200 Subject: [NETFILTER]: remove arpt_table indirection macro Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/linux/netfilter_arp/arp_tables.h | 11 +++++------ net/ipv4/netfilter/arp_tables.c | 27 +++++++++++++-------------- net/ipv4/netfilter/arptable_filter.c | 2 +- 3 files changed, 19 insertions(+), 21 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index db223ca92c8b..102c4134a713 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h @@ -24,7 +24,6 @@ #define ARPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN #define ARPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN #define arpt_target xt_target -#define arpt_table xt_table #define ARPT_DEV_ADDR_LEN_MAX 16 @@ -271,15 +270,15 @@ struct arpt_error xt_register_target(tgt); }) #define arpt_unregister_target(tgt) xt_unregister_target(tgt) -extern struct arpt_table *arpt_register_table(struct net *net, - struct arpt_table *table, - const struct arpt_replace *repl); -extern void arpt_unregister_table(struct arpt_table *table); +extern struct xt_table *arpt_register_table(struct net *net, + struct xt_table *table, + const struct arpt_replace *repl); +extern void arpt_unregister_table(struct xt_table *table); extern unsigned int arpt_do_table(struct sk_buff *skb, unsigned int hook, const struct net_device *in, const struct net_device *out, - struct arpt_table *table); + struct xt_table *table); #define ARPT_ALIGN(s) XT_ALIGN(s) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 10cc442330c3..34c42c831b18 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -222,7 +222,7 @@ unsigned int arpt_do_table(struct sk_buff *skb, unsigned int hook, const struct net_device *in, const struct net_device *out, - struct arpt_table *table) + struct xt_table *table) { static const char nulldevname[IFNAMSIZ]; unsigned int verdict = NF_DROP; @@ -706,7 +706,7 @@ static void get_counters(const struct xt_table_info *t, } } -static inline struct xt_counters *alloc_counters(struct arpt_table *table) +static inline struct xt_counters *alloc_counters(struct xt_table *table) { unsigned int countersize; struct xt_counters *counters; @@ -731,13 +731,13 @@ static inline struct xt_counters *alloc_counters(struct arpt_table *table) } static int copy_entries_to_user(unsigned int total_size, - struct arpt_table *table, + struct xt_table *table, void __user *userptr) { unsigned int off, num; struct arpt_entry *e; struct xt_counters *counters; - const struct xt_table_info *private = table->private; + struct xt_table_info *private = table->private; int ret = 0; void *loc_cpu_entry; @@ -851,7 +851,7 @@ static int compat_table_info(const struct xt_table_info *info, static int get_info(struct net *net, void __user *user, int *len, int compat) { char name[ARPT_TABLE_MAXNAMELEN]; - struct arpt_table *t; + struct xt_table *t; int ret; if (*len != sizeof(struct arpt_getinfo)) { @@ -911,7 +911,7 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr, { int ret; struct arpt_get_entries get; - struct arpt_table *t; + struct xt_table *t; if (*len < sizeof(get)) { duprintf("get_entries: %u < %Zu\n", *len, sizeof(get)); @@ -954,7 +954,7 @@ static int __do_replace(struct net *net, const char *name, void __user *counters_ptr) { int ret; - struct arpt_table *t; + struct xt_table *t; struct xt_table_info *oldinfo; struct xt_counters *counters; void *loc_cpu_old_entry; @@ -1091,7 +1091,7 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len, const char *name; int size; void *ptmp; - struct arpt_table *t; + struct xt_table *t; const struct xt_table_info *private; int ret = 0; void *loc_cpu_entry; @@ -1555,7 +1555,7 @@ out: } static int compat_copy_entries_to_user(unsigned int total_size, - struct arpt_table *table, + struct xt_table *table, void __user *userptr) { struct xt_counters *counters; @@ -1593,7 +1593,7 @@ static int compat_get_entries(struct net *net, { int ret; struct compat_arpt_get_entries get; - struct arpt_table *t; + struct xt_table *t; if (*len < sizeof(get)) { duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get)); @@ -1723,9 +1723,8 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len return ret; } -struct arpt_table *arpt_register_table(struct net *net, - struct arpt_table *table, - const struct arpt_replace *repl) +struct xt_table *arpt_register_table(struct net *net, struct xt_table *table, + const struct arpt_replace *repl) { int ret; struct xt_table_info *newinfo; @@ -1767,7 +1766,7 @@ out: return ERR_PTR(ret); } -void arpt_unregister_table(struct arpt_table *table) +void arpt_unregister_table(struct xt_table *table) { struct xt_table_info *private; void *loc_cpu_entry; diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index 629e4951a9b1..9f6526c87757 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -45,7 +45,7 @@ static struct .term = ARPT_ERROR_INIT, }; -static struct arpt_table packet_filter = { +static struct xt_table packet_filter = { .name = "filter", .valid_hooks = FILTER_VALID_HOOKS, .lock = __RW_LOCK_UNLOCKED(packet_filter.lock), -- cgit v1.2.3-59-g8ed1b From 95eea855af69bfd54a7b73546190e76046ca2e07 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:43 +0200 Subject: [NETFILTER]: remove arpt_target indirection macro Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/linux/netfilter_arp/arp_tables.h | 1 - net/ipv4/netfilter/arp_tables.c | 8 ++++---- net/ipv4/netfilter/arpt_mangle.c | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index 102c4134a713..782b83e5bdb9 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h @@ -23,7 +23,6 @@ #define ARPT_FUNCTION_MAXNAMELEN XT_FUNCTION_MAXNAMELEN #define ARPT_TABLE_MAXNAMELEN XT_TABLE_MAXNAMELEN -#define arpt_target xt_target #define ARPT_DEV_ADDR_LEN_MAX 16 diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 34c42c831b18..d55f3b42eba5 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -457,7 +457,7 @@ static inline int check_entry(struct arpt_entry *e, const char *name) static inline int check_target(struct arpt_entry *e, const char *name) { struct arpt_entry_target *t; - struct arpt_target *target; + struct xt_target *target; int ret; t = arpt_get_target(e); @@ -480,7 +480,7 @@ find_check_entry(struct arpt_entry *e, const char *name, unsigned int size, unsigned int *i) { struct arpt_entry_target *t; - struct arpt_target *target; + struct xt_target *target; int ret; ret = check_entry(e, name); @@ -1784,7 +1784,7 @@ void arpt_unregister_table(struct xt_table *table) } /* The built-in targets: standard (NULL) and error. */ -static struct arpt_target arpt_standard_target __read_mostly = { +static struct xt_target arpt_standard_target __read_mostly = { .name = ARPT_STANDARD_TARGET, .targetsize = sizeof(int), .family = NF_ARP, @@ -1795,7 +1795,7 @@ static struct arpt_target arpt_standard_target __read_mostly = { #endif }; -static struct arpt_target arpt_error_target __read_mostly = { +static struct xt_target arpt_error_target __read_mostly = { .name = ARPT_ERROR_TARGET, .target = arpt_error, .targetsize = ARPT_FUNCTION_MAXNAMELEN, diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c index 3e732c827fc2..f9c102ab891b 100644 --- a/net/ipv4/netfilter/arpt_mangle.c +++ b/net/ipv4/netfilter/arpt_mangle.c @@ -73,7 +73,7 @@ checkentry(const char *tablename, const void *e, const struct xt_target *target, return true; } -static struct arpt_target arpt_mangle_reg __read_mostly = { +static struct xt_target arpt_mangle_reg __read_mostly = { .name = "mangle", .target = target, .targetsize = sizeof(struct arpt_mangle), -- cgit v1.2.3-59-g8ed1b From 3bb0362d2f53fa54a17b88c96b43fc093e47699b Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:44 +0200 Subject: [NETFILTER]: remove arpt_(un)register_target indirection macros Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/linux/netfilter_arp/arp_tables.h | 5 ----- net/ipv4/netfilter/arpt_mangle.c | 8 +++----- 2 files changed, 3 insertions(+), 10 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h index 782b83e5bdb9..dd9c97f2d436 100644 --- a/include/linux/netfilter_arp/arp_tables.h +++ b/include/linux/netfilter_arp/arp_tables.h @@ -264,11 +264,6 @@ struct arpt_error .target.errorname = "ERROR", \ } -#define arpt_register_target(tgt) \ -({ (tgt)->family = NF_ARP; \ - xt_register_target(tgt); }) -#define arpt_unregister_target(tgt) xt_unregister_target(tgt) - extern struct xt_table *arpt_register_table(struct net *net, struct xt_table *table, const struct arpt_replace *repl); diff --git a/net/ipv4/netfilter/arpt_mangle.c b/net/ipv4/netfilter/arpt_mangle.c index f9c102ab891b..a385959d2655 100644 --- a/net/ipv4/netfilter/arpt_mangle.c +++ b/net/ipv4/netfilter/arpt_mangle.c @@ -75,6 +75,7 @@ checkentry(const char *tablename, const void *e, const struct xt_target *target, static struct xt_target arpt_mangle_reg __read_mostly = { .name = "mangle", + .family = NF_ARP, .target = target, .targetsize = sizeof(struct arpt_mangle), .checkentry = checkentry, @@ -83,15 +84,12 @@ static struct xt_target arpt_mangle_reg __read_mostly = { static int __init arpt_mangle_init(void) { - if (arpt_register_target(&arpt_mangle_reg)) - return -EINVAL; - - return 0; + return xt_register_target(&arpt_mangle_reg); } static void __exit arpt_mangle_fini(void) { - arpt_unregister_target(&arpt_mangle_reg); + xt_unregister_target(&arpt_mangle_reg); } module_init(arpt_mangle_init); -- cgit v1.2.3-59-g8ed1b From c2f9c68398ec724738509f95f1599378ebcc45e0 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:44 +0200 Subject: [NETFILTER]: Explicitly initialize .priority in arptable_filter Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/arptable_filter.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index 9f6526c87757..3be4d07e7ed9 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -70,18 +70,21 @@ static struct nf_hook_ops arpt_ops[] __read_mostly = { .owner = THIS_MODULE, .pf = NF_ARP, .hooknum = NF_ARP_IN, + .priority = NF_IP_PRI_FILTER, }, { .hook = arpt_hook, .owner = THIS_MODULE, .pf = NF_ARP, .hooknum = NF_ARP_OUT, + .priority = NF_IP_PRI_FILTER, }, { .hook = arpt_hook, .owner = THIS_MODULE, .pf = NF_ARP, .hooknum = NF_ARP_FORWARD, + .priority = NF_IP_PRI_FILTER, }, }; -- cgit v1.2.3-59-g8ed1b From fa913ddf6372b20b23061996150d38f639488d42 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:15:45 +0200 Subject: [NETFILTER]: nf_conntrack_sip: clear address in parse_addr() Some callers pass uninitialized structures, clear the address to make sure later comparisions work properly. Signed-off-by: Patrick McHardy --- net/netfilter/nf_conntrack_sip.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index da5dec6e6158..f3915f8724f9 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -145,6 +145,7 @@ static int parse_addr(const struct nf_conn *ct, const char *cp, int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; int ret = 0; + memset(addr, 0, sizeof(*addr)); switch (family) { case AF_INET: ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); -- cgit v1.2.3-59-g8ed1b From 544473c1664f3a688be949ac078bdee6f4afeef1 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:15:45 +0200 Subject: [NETFILTER]: {ip,ip6,arp}_tables: return EAGAIN for invalid SO_GET_ENTRIES size Rule dumping is performed in two steps: first userspace gets the ruleset size using getsockopt(SO_GET_INFO) and allocates memory, then it calls getsockopt(SO_GET_ENTRIES) to actually dump the ruleset. When another process changes the ruleset in between the sizes from the first getsockopt call doesn't match anymore and the kernel aborts. Unfortunately it returns EAGAIN, as for multiple other possible errors, so userspace can't distinguish this case from real errors. Return EAGAIN so userspace can retry the operation. Fixes (with current iptables SVN version) netfilter bugzilla #104. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/arp_tables.c | 4 ++-- net/ipv4/netfilter/ip_tables.c | 4 ++-- net/ipv6/netfilter/ip6_tables.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index d55f3b42eba5..03e83a65aec5 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -937,7 +937,7 @@ static int get_entries(struct net *net, struct arpt_get_entries __user *uptr, else { duprintf("get_entries: I've got %u not %u!\n", private->size, get.size); - ret = -EINVAL; + ret = -EAGAIN; } module_put(t->me); xt_table_unlock(t); @@ -1621,7 +1621,7 @@ static int compat_get_entries(struct net *net, } else if (!ret) { duprintf("compat_get_entries: I've got %u not %u!\n", private->size, get.size); - ret = -EINVAL; + ret = -EAGAIN; } xt_compat_flush_offsets(NF_ARP); module_put(t->me); diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index aa124b50cb4a..4e7c719445c2 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -1180,7 +1180,7 @@ get_entries(struct net *net, struct ipt_get_entries __user *uptr, int *len) else { duprintf("get_entries: I've got %u not %u!\n", private->size, get.size); - ret = -EINVAL; + ret = -EAGAIN; } module_put(t->me); xt_table_unlock(t); @@ -1939,7 +1939,7 @@ compat_get_entries(struct net *net, struct compat_ipt_get_entries __user *uptr, } else if (!ret) { duprintf("compat_get_entries: I've got %u not %u!\n", private->size, get.size); - ret = -EINVAL; + ret = -EAGAIN; } xt_compat_flush_offsets(AF_INET); module_put(t->me); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 782183f63366..0b4557e03431 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1206,7 +1206,7 @@ get_entries(struct net *net, struct ip6t_get_entries __user *uptr, int *len) else { duprintf("get_entries: I've got %u not %u!\n", private->size, get.size); - ret = -EINVAL; + ret = -EAGAIN; } module_put(t->me); xt_table_unlock(t); @@ -1966,7 +1966,7 @@ compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr, } else if (!ret) { duprintf("compat_get_entries: I've got %u not %u!\n", private->size, get.size); - ret = -EINVAL; + ret = -EAGAIN; } xt_compat_flush_offsets(AF_INET6); module_put(t->me); -- cgit v1.2.3-59-g8ed1b From 937e0dfd87a8b7946a17161664500fba93eb13fd Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 20 Mar 2008 15:15:47 +0100 Subject: [NETFILTER]: nf_nat: add helpers for common NAT protocol operations Add generic ->in_range and ->unique_tuple ops to avoid duplicating them again and again for future NAT modules and save a few bytes of text: net/ipv4/netfilter/nf_nat_proto_tcp.c: tcp_in_range | -62 (removed) tcp_unique_tuple | -259 # 271 -> 12, # inlines: 1 -> 0, size inlines: 7 -> 0 2 functions changed, 321 bytes removed net/ipv4/netfilter/nf_nat_proto_udp.c: udp_in_range | -62 (removed) udp_unique_tuple | -259 # 271 -> 12, # inlines: 1 -> 0, size inlines: 7 -> 0 2 functions changed, 321 bytes removed net/ipv4/netfilter/nf_nat_proto_gre.c: gre_in_range | -62 (removed) 1 function changed, 62 bytes removed vmlinux: 5 functions changed, 704 bytes removed Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_nat_protocol.h | 11 +++++ net/ipv4/netfilter/Makefile | 2 +- net/ipv4/netfilter/nf_nat_proto_common.c | 85 ++++++++++++++++++++++++++++++++ net/ipv4/netfilter/nf_nat_proto_gre.c | 20 +------- net/ipv4/netfilter/nf_nat_proto_tcp.c | 65 ++---------------------- net/ipv4/netfilter/nf_nat_proto_udp.c | 64 ++---------------------- 6 files changed, 106 insertions(+), 141 deletions(-) create mode 100644 net/ipv4/netfilter/nf_nat_proto_common.c (limited to 'net') diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h index 4aa0edbb5b96..fa06f6d0de54 100644 --- a/include/net/netfilter/nf_nat_protocol.h +++ b/include/net/netfilter/nf_nat_protocol.h @@ -62,6 +62,17 @@ extern int init_protocols(void) __init; extern void cleanup_protocols(void); extern const struct nf_nat_protocol *find_nat_proto(u_int16_t protonum); +extern int nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max); + +extern int nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct, + u_int16_t *rover); + extern int nf_nat_port_range_to_nlattr(struct sk_buff *skb, const struct nf_nat_range *range); extern int nf_nat_port_nlattr_to_range(struct nlattr *tb[], diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 0c7dc78a62e9..e73d0eb9994a 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -10,7 +10,7 @@ nf_conntrack_ipv4-objs += nf_conntrack_l3proto_ipv4_compat.o endif endif -nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o +nf_nat-objs := nf_nat_core.o nf_nat_helper.o nf_nat_proto_unknown.o nf_nat_proto_common.o nf_nat_proto_tcp.o nf_nat_proto_udp.o nf_nat_proto_icmp.o iptable_nat-objs := nf_nat_rule.o nf_nat_standalone.o # connection tracking diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c new file mode 100644 index 000000000000..a124213fb9da --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_common.c @@ -0,0 +1,85 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * (C) 2008 Patrick McHardy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +int nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) +{ + __be16 port; + + if (maniptype == IP_NAT_MANIP_SRC) + port = tuple->src.u.all; + else + port = tuple->dst.u.all; + + return ntohs(port) >= ntohs(min->all) && + ntohs(port) <= ntohs(max->all); +} +EXPORT_SYMBOL_GPL(nf_nat_proto_in_range); + +int nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct, + u_int16_t *rover) +{ + unsigned int range_size, min, i; + __be16 *portptr; + + if (maniptype == IP_NAT_MANIP_SRC) + portptr = &tuple->src.u.all; + else + portptr = &tuple->dst.u.all; + + /* If no range specified... */ + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { + /* If it's dst rewrite, can't change port */ + if (maniptype == IP_NAT_MANIP_DST) + return 0; + + if (ntohs(*portptr) < 1024) { + /* Loose convention: >> 512 is credential passing */ + if (ntohs(*portptr) < 512) { + min = 1; + range_size = 511 - min + 1; + } else { + min = 600; + range_size = 1023 - min + 1; + } + } else { + min = 1024; + range_size = 65535 - 1024 + 1; + } + } else { + min = ntohs(range->min.all); + range_size = ntohs(range->max.all) - min + 1; + } + + if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) + *rover = net_random(); + + for (i = 0; i < range_size; i++, (*rover)++) { + *portptr = htons(min + *rover % range_size); + if (!nf_nat_used_tuple(tuple, ct)) + return 1; + } + return 0; +} +EXPORT_SYMBOL_GPL(nf_nat_proto_unique_tuple); diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c index a1e4da16da2e..87af63d9e692 100644 --- a/net/ipv4/netfilter/nf_nat_proto_gre.c +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c @@ -36,24 +36,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); -/* is key in given range between min and max */ -static int -gre_in_range(const struct nf_conntrack_tuple *tuple, - enum nf_nat_manip_type maniptype, - const union nf_conntrack_man_proto *min, - const union nf_conntrack_man_proto *max) -{ - __be16 key; - - if (maniptype == IP_NAT_MANIP_SRC) - key = tuple->src.u.gre.key; - else - key = tuple->dst.u.gre.key; - - return ntohs(key) >= ntohs(min->gre.key) && - ntohs(key) <= ntohs(max->gre.key); -} - /* generate unique tuple ... */ static int gre_unique_tuple(struct nf_conntrack_tuple *tuple, @@ -140,7 +122,7 @@ static const struct nf_nat_protocol gre = { .protonum = IPPROTO_GRE, .me = THIS_MODULE, .manip_pkt = gre_manip_pkt, - .in_range = gre_in_range, + .in_range = nf_nat_proto_in_range, .unique_tuple = gre_unique_tuple, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) .range_to_nlattr = nf_nat_port_range_to_nlattr, diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c index ffd5d1589eca..f8c498fc24fd 100644 --- a/net/ipv4/netfilter/nf_nat_proto_tcp.c +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c @@ -8,7 +8,6 @@ #include #include -#include #include #include @@ -19,22 +18,7 @@ #include #include -static int -tcp_in_range(const struct nf_conntrack_tuple *tuple, - enum nf_nat_manip_type maniptype, - const union nf_conntrack_man_proto *min, - const union nf_conntrack_man_proto *max) -{ - __be16 port; - - if (maniptype == IP_NAT_MANIP_SRC) - port = tuple->src.u.tcp.port; - else - port = tuple->dst.u.tcp.port; - - return ntohs(port) >= ntohs(min->tcp.port) && - ntohs(port) <= ntohs(max->tcp.port); -} +static u_int16_t tcp_port_rover; static int tcp_unique_tuple(struct nf_conntrack_tuple *tuple, @@ -42,49 +26,8 @@ tcp_unique_tuple(struct nf_conntrack_tuple *tuple, enum nf_nat_manip_type maniptype, const struct nf_conn *ct) { - static u_int16_t port; - __be16 *portptr; - unsigned int range_size, min, i; - - if (maniptype == IP_NAT_MANIP_SRC) - portptr = &tuple->src.u.tcp.port; - else - portptr = &tuple->dst.u.tcp.port; - - /* If no range specified... */ - if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { - /* If it's dst rewrite, can't change port */ - if (maniptype == IP_NAT_MANIP_DST) - return 0; - - /* Map privileged onto privileged. */ - if (ntohs(*portptr) < 1024) { - /* Loose convention: >> 512 is credential passing */ - if (ntohs(*portptr)<512) { - min = 1; - range_size = 511 - min + 1; - } else { - min = 600; - range_size = 1023 - min + 1; - } - } else { - min = 1024; - range_size = 65535 - 1024 + 1; - } - } else { - min = ntohs(range->min.tcp.port); - range_size = ntohs(range->max.tcp.port) - min + 1; - } - - if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) - port = net_random(); - - for (i = 0; i < range_size; i++, port++) { - *portptr = htons(min + port % range_size); - if (!nf_nat_used_tuple(tuple, ct)) - return 1; - } - return 0; + return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, + &tcp_port_rover); } static int @@ -142,7 +85,7 @@ const struct nf_nat_protocol nf_nat_protocol_tcp = { .protonum = IPPROTO_TCP, .me = THIS_MODULE, .manip_pkt = tcp_manip_pkt, - .in_range = tcp_in_range, + .in_range = nf_nat_proto_in_range, .unique_tuple = tcp_unique_tuple, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) .range_to_nlattr = nf_nat_port_range_to_nlattr, diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c index 4b8f49910ff2..a182f5ac3177 100644 --- a/net/ipv4/netfilter/nf_nat_proto_udp.c +++ b/net/ipv4/netfilter/nf_nat_proto_udp.c @@ -8,7 +8,6 @@ #include #include -#include #include #include @@ -18,22 +17,7 @@ #include #include -static int -udp_in_range(const struct nf_conntrack_tuple *tuple, - enum nf_nat_manip_type maniptype, - const union nf_conntrack_man_proto *min, - const union nf_conntrack_man_proto *max) -{ - __be16 port; - - if (maniptype == IP_NAT_MANIP_SRC) - port = tuple->src.u.udp.port; - else - port = tuple->dst.u.udp.port; - - return ntohs(port) >= ntohs(min->udp.port) && - ntohs(port) <= ntohs(max->udp.port); -} +static u_int16_t udp_port_rover; static int udp_unique_tuple(struct nf_conntrack_tuple *tuple, @@ -41,48 +25,8 @@ udp_unique_tuple(struct nf_conntrack_tuple *tuple, enum nf_nat_manip_type maniptype, const struct nf_conn *ct) { - static u_int16_t port; - __be16 *portptr; - unsigned int range_size, min, i; - - if (maniptype == IP_NAT_MANIP_SRC) - portptr = &tuple->src.u.udp.port; - else - portptr = &tuple->dst.u.udp.port; - - /* If no range specified... */ - if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { - /* If it's dst rewrite, can't change port */ - if (maniptype == IP_NAT_MANIP_DST) - return 0; - - if (ntohs(*portptr) < 1024) { - /* Loose convention: >> 512 is credential passing */ - if (ntohs(*portptr)<512) { - min = 1; - range_size = 511 - min + 1; - } else { - min = 600; - range_size = 1023 - min + 1; - } - } else { - min = 1024; - range_size = 65535 - 1024 + 1; - } - } else { - min = ntohs(range->min.udp.port); - range_size = ntohs(range->max.udp.port) - min + 1; - } - - if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) - port = net_random(); - - for (i = 0; i < range_size; i++, port++) { - *portptr = htons(min + port % range_size); - if (!nf_nat_used_tuple(tuple, ct)) - return 1; - } - return 0; + return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, + &udp_port_rover); } static int @@ -132,7 +76,7 @@ const struct nf_nat_protocol nf_nat_protocol_udp = { .protonum = IPPROTO_UDP, .me = THIS_MODULE, .manip_pkt = udp_manip_pkt, - .in_range = udp_in_range, + .in_range = nf_nat_proto_in_range, .unique_tuple = udp_unique_tuple, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) .range_to_nlattr = nf_nat_port_range_to_nlattr, -- cgit v1.2.3-59-g8ed1b From 5abd363f738dcd048ee790fb9b84d0768a8a407f Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:15:46 +0200 Subject: [NETFILTER]: nf_nat: fix random mode not to overwrite port rover The port rover should not get overwritten when using random mode, otherwise other rules will also use more or less random ports. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/nf_nat_proto_common.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c index a124213fb9da..871ab0eb325d 100644 --- a/net/ipv4/netfilter/nf_nat_proto_common.c +++ b/net/ipv4/netfilter/nf_nat_proto_common.c @@ -42,6 +42,7 @@ int nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, { unsigned int range_size, min, i; __be16 *portptr; + u_int16_t off; if (maniptype == IP_NAT_MANIP_SRC) portptr = &tuple->src.u.all; @@ -72,13 +73,17 @@ int nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, range_size = ntohs(range->max.all) - min + 1; } + off = *rover; if (range->flags & IP_NAT_RANGE_PROTO_RANDOM) - *rover = net_random(); + off = net_random(); - for (i = 0; i < range_size; i++, (*rover)++) { - *portptr = htons(min + *rover % range_size); - if (!nf_nat_used_tuple(tuple, ct)) - return 1; + for (i = 0; i < range_size; i++, off++) { + *portptr = htons(min + off % range_size); + if (nf_nat_used_tuple(tuple, ct)) + continue; + if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) + *rover = off; + return 1; } return 0; } -- cgit v1.2.3-59-g8ed1b From 535b57c7c1524125444aa1b874332f6ff1608ef5 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:15:47 +0200 Subject: [NETFILTER]: nf_nat: move NAT ctnetlink helpers to nf_nat_proto_common Move to nf_nat_proto_common and rename to nf_nat_proto_... since they're also used by protocols that don't have port numbers. Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_nat_protocol.h | 8 +++---- net/ipv4/netfilter/nf_nat_core.c | 40 -------------------------------- net/ipv4/netfilter/nf_nat_proto_common.c | 38 ++++++++++++++++++++++++++++++ net/ipv4/netfilter/nf_nat_proto_gre.c | 4 ++-- net/ipv4/netfilter/nf_nat_proto_icmp.c | 4 ++-- net/ipv4/netfilter/nf_nat_proto_tcp.c | 4 ++-- net/ipv4/netfilter/nf_nat_proto_udp.c | 4 ++-- 7 files changed, 50 insertions(+), 52 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h index fa06f6d0de54..8ce227624eac 100644 --- a/include/net/netfilter/nf_nat_protocol.h +++ b/include/net/netfilter/nf_nat_protocol.h @@ -73,9 +73,9 @@ extern int nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_conn *ct, u_int16_t *rover); -extern int nf_nat_port_range_to_nlattr(struct sk_buff *skb, - const struct nf_nat_range *range); -extern int nf_nat_port_nlattr_to_range(struct nlattr *tb[], - struct nf_nat_range *range); +extern int nf_nat_proto_range_to_nlattr(struct sk_buff *skb, + const struct nf_nat_range *range); +extern int nf_nat_proto_nlattr_to_range(struct nlattr *tb[], + struct nf_nat_range *range); #endif /*_NF_NAT_PROTO_H*/ diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 9c8aa8df2d5e..9320c7ac5729 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -544,46 +544,6 @@ void nf_nat_protocol_unregister(const struct nf_nat_protocol *proto) } EXPORT_SYMBOL(nf_nat_protocol_unregister); -#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) -int -nf_nat_port_range_to_nlattr(struct sk_buff *skb, - const struct nf_nat_range *range) -{ - NLA_PUT_BE16(skb, CTA_PROTONAT_PORT_MIN, range->min.tcp.port); - NLA_PUT_BE16(skb, CTA_PROTONAT_PORT_MAX, range->max.tcp.port); - - return 0; - -nla_put_failure: - return -1; -} -EXPORT_SYMBOL_GPL(nf_nat_port_nlattr_to_range); - -int -nf_nat_port_nlattr_to_range(struct nlattr *tb[], struct nf_nat_range *range) -{ - int ret = 0; - - /* we have to return whether we actually parsed something or not */ - - if (tb[CTA_PROTONAT_PORT_MIN]) { - ret = 1; - range->min.tcp.port = nla_get_be16(tb[CTA_PROTONAT_PORT_MIN]); - } - - if (!tb[CTA_PROTONAT_PORT_MAX]) { - if (ret) - range->max.tcp.port = range->min.tcp.port; - } else { - ret = 1; - range->max.tcp.port = nla_get_be16(tb[CTA_PROTONAT_PORT_MAX]); - } - - return ret; -} -EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nlattr); -#endif - /* Noone using conntrack by the time this called. */ static void nf_nat_cleanup_conntrack(struct nf_conn *ct) { diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c index 871ab0eb325d..ef4dc3988925 100644 --- a/net/ipv4/netfilter/nf_nat_proto_common.c +++ b/net/ipv4/netfilter/nf_nat_proto_common.c @@ -88,3 +88,41 @@ int nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, return 0; } EXPORT_SYMBOL_GPL(nf_nat_proto_unique_tuple); + +#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +int nf_nat_proto_range_to_nlattr(struct sk_buff *skb, + const struct nf_nat_range *range) +{ + NLA_PUT_BE16(skb, CTA_PROTONAT_PORT_MIN, range->min.all); + NLA_PUT_BE16(skb, CTA_PROTONAT_PORT_MAX, range->max.all); + return 0; + +nla_put_failure: + return -1; +} +EXPORT_SYMBOL_GPL(nf_nat_proto_nlattr_to_range); + +int nf_nat_proto_nlattr_to_range(struct nlattr *tb[], + struct nf_nat_range *range) +{ + int ret = 0; + + /* we have to return whether we actually parsed something or not */ + + if (tb[CTA_PROTONAT_PORT_MIN]) { + ret = 1; + range->min.all = nla_get_be16(tb[CTA_PROTONAT_PORT_MIN]); + } + + if (!tb[CTA_PROTONAT_PORT_MAX]) { + if (ret) + range->max.all = range->min.all; + } else { + ret = 1; + range->max.all = nla_get_be16(tb[CTA_PROTONAT_PORT_MAX]); + } + + return ret; +} +EXPORT_SYMBOL_GPL(nf_nat_proto_range_to_nlattr); +#endif diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c index 87af63d9e692..71b0935ee1c8 100644 --- a/net/ipv4/netfilter/nf_nat_proto_gre.c +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c @@ -125,8 +125,8 @@ static const struct nf_nat_protocol gre = { .in_range = nf_nat_proto_in_range, .unique_tuple = gre_unique_tuple, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .range_to_nlattr = nf_nat_port_range_to_nlattr, - .nlattr_to_range = nf_nat_port_nlattr_to_range, + .range_to_nlattr = nf_nat_proto_range_to_nlattr, + .nlattr_to_range = nf_nat_proto_nlattr_to_range, #endif }; diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c index 03a02969aa57..ca601f84c4dc 100644 --- a/net/ipv4/netfilter/nf_nat_proto_icmp.c +++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c @@ -79,7 +79,7 @@ const struct nf_nat_protocol nf_nat_protocol_icmp = { .in_range = icmp_in_range, .unique_tuple = icmp_unique_tuple, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .range_to_nlattr = nf_nat_port_range_to_nlattr, - .nlattr_to_range = nf_nat_port_nlattr_to_range, + .range_to_nlattr = nf_nat_proto_range_to_nlattr, + .nlattr_to_range = nf_nat_proto_nlattr_to_range, #endif }; diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c index f8c498fc24fd..1d73a11f55d9 100644 --- a/net/ipv4/netfilter/nf_nat_proto_tcp.c +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c @@ -88,7 +88,7 @@ const struct nf_nat_protocol nf_nat_protocol_tcp = { .in_range = nf_nat_proto_in_range, .unique_tuple = tcp_unique_tuple, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .range_to_nlattr = nf_nat_port_range_to_nlattr, - .nlattr_to_range = nf_nat_port_nlattr_to_range, + .range_to_nlattr = nf_nat_proto_range_to_nlattr, + .nlattr_to_range = nf_nat_proto_nlattr_to_range, #endif }; diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c index a182f5ac3177..f36ce552a161 100644 --- a/net/ipv4/netfilter/nf_nat_proto_udp.c +++ b/net/ipv4/netfilter/nf_nat_proto_udp.c @@ -79,7 +79,7 @@ const struct nf_nat_protocol nf_nat_protocol_udp = { .in_range = nf_nat_proto_in_range, .unique_tuple = udp_unique_tuple, #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) - .range_to_nlattr = nf_nat_port_range_to_nlattr, - .nlattr_to_range = nf_nat_port_nlattr_to_range, + .range_to_nlattr = nf_nat_proto_range_to_nlattr, + .nlattr_to_range = nf_nat_proto_nlattr_to_range, #endif }; -- cgit v1.2.3-59-g8ed1b From ca6a50749012fc17feeec91ee2f9eeacacf06f0b Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:15:47 +0200 Subject: [NETFILTER]: nf_conntrack_netlink: clean up NAT protocol parsing Move responsibility for setting the IP_NAT_RANGE_PROTO_SPECIFIED flag to the NAT protocol, properly propagate errors and get rid of ugly return value convention. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/nf_nat_proto_common.c | 18 +++++------------- net/netfilter/nf_conntrack_netlink.c | 15 +++------------ 2 files changed, 8 insertions(+), 25 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c index ef4dc3988925..4904b86265e1 100644 --- a/net/ipv4/netfilter/nf_nat_proto_common.c +++ b/net/ipv4/netfilter/nf_nat_proto_common.c @@ -105,24 +105,16 @@ EXPORT_SYMBOL_GPL(nf_nat_proto_nlattr_to_range); int nf_nat_proto_nlattr_to_range(struct nlattr *tb[], struct nf_nat_range *range) { - int ret = 0; - - /* we have to return whether we actually parsed something or not */ - if (tb[CTA_PROTONAT_PORT_MIN]) { - ret = 1; range->min.all = nla_get_be16(tb[CTA_PROTONAT_PORT_MIN]); + range->max.all = range->min.tcp.port; + range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; } - - if (!tb[CTA_PROTONAT_PORT_MAX]) { - if (ret) - range->max.all = range->min.all; - } else { - ret = 1; + if (tb[CTA_PROTONAT_PORT_MAX]) { range->max.all = nla_get_be16(tb[CTA_PROTONAT_PORT_MAX]); + range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; } - - return ret; + return 0; } EXPORT_SYMBOL_GPL(nf_nat_proto_range_to_nlattr); #endif diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 4a1b42b2b7a5..79d5ecde0ddc 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -705,19 +705,10 @@ static int nfnetlink_parse_nat_proto(struct nlattr *attr, return err; npt = nf_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); - - if (!npt->nlattr_to_range) { - nf_nat_proto_put(npt); - return 0; - } - - /* nlattr_to_range returns 1 if it parsed, 0 if not, neg. on error */ - if (npt->nlattr_to_range(tb, range) > 0) - range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; - + if (npt->nlattr_to_range) + err = npt->nlattr_to_range(tb, range); nf_nat_proto_put(npt); - - return 0; + return err; } static const struct nla_policy nat_nla_policy[CTA_NAT_MAX+1] = { -- cgit v1.2.3-59-g8ed1b From 2d2d84c40e19a7fce51ba1f124ecde105104192d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 20 Mar 2008 15:15:49 +0100 Subject: [NETFILTER]: nf_nat: remove unused name from struct nf_nat_protocol Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_nat_protocol.h | 3 --- net/ipv4/netfilter/nf_nat_proto_gre.c | 1 - net/ipv4/netfilter/nf_nat_proto_icmp.c | 1 - net/ipv4/netfilter/nf_nat_proto_tcp.c | 1 - net/ipv4/netfilter/nf_nat_proto_udp.c | 1 - net/ipv4/netfilter/nf_nat_proto_unknown.c | 1 - 6 files changed, 8 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h index 8ce227624eac..fba94a2028d5 100644 --- a/include/net/netfilter/nf_nat_protocol.h +++ b/include/net/netfilter/nf_nat_protocol.h @@ -8,9 +8,6 @@ struct nf_nat_range; struct nf_nat_protocol { - /* Protocol name */ - const char *name; - /* Protocol number. */ unsigned int protonum; diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c index 71b0935ee1c8..84bb7854137a 100644 --- a/net/ipv4/netfilter/nf_nat_proto_gre.c +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c @@ -118,7 +118,6 @@ gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, } static const struct nf_nat_protocol gre = { - .name = "GRE", .protonum = IPPROTO_GRE, .me = THIS_MODULE, .manip_pkt = gre_manip_pkt, diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c index ca601f84c4dc..ab3a0ec2a2d1 100644 --- a/net/ipv4/netfilter/nf_nat_proto_icmp.c +++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c @@ -72,7 +72,6 @@ icmp_manip_pkt(struct sk_buff *skb, } const struct nf_nat_protocol nf_nat_protocol_icmp = { - .name = "ICMP", .protonum = IPPROTO_ICMP, .me = THIS_MODULE, .manip_pkt = icmp_manip_pkt, diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c index 1d73a11f55d9..5d4c8a0e89c0 100644 --- a/net/ipv4/netfilter/nf_nat_proto_tcp.c +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c @@ -81,7 +81,6 @@ tcp_manip_pkt(struct sk_buff *skb, } const struct nf_nat_protocol nf_nat_protocol_tcp = { - .name = "TCP", .protonum = IPPROTO_TCP, .me = THIS_MODULE, .manip_pkt = tcp_manip_pkt, diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c index f36ce552a161..74a7e7b63465 100644 --- a/net/ipv4/netfilter/nf_nat_proto_udp.c +++ b/net/ipv4/netfilter/nf_nat_proto_udp.c @@ -72,7 +72,6 @@ udp_manip_pkt(struct sk_buff *skb, } const struct nf_nat_protocol nf_nat_protocol_udp = { - .name = "UDP", .protonum = IPPROTO_UDP, .me = THIS_MODULE, .manip_pkt = udp_manip_pkt, diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/ipv4/netfilter/nf_nat_proto_unknown.c index a26efeb073cb..cda21ff0e4cf 100644 --- a/net/ipv4/netfilter/nf_nat_proto_unknown.c +++ b/net/ipv4/netfilter/nf_nat_proto_unknown.c @@ -46,7 +46,6 @@ unknown_manip_pkt(struct sk_buff *skb, } const struct nf_nat_protocol nf_nat_unknown_protocol = { - .name = "unknown", /* .me isn't set: getting a ref to this cannot fail. */ .manip_pkt = unknown_manip_pkt, .in_range = unknown_in_range, -- cgit v1.2.3-59-g8ed1b From 6185f870e293a0a3eae5c81eb0106480cf03dfde Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 20 Mar 2008 15:15:51 +0100 Subject: [NETFILTER]: nf_nat: add UDP-Lite support Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/Kconfig | 5 ++ net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_proto_udplite.c | 99 +++++++++++++++++++++++++++++++ net/ipv4/netfilter/nf_nat_standalone.c | 6 +- 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 net/ipv4/netfilter/nf_nat_proto_udplite.c (limited to 'net') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 9a077cb24798..c5bd2840663b 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -245,6 +245,11 @@ config NF_NAT_PROTO_GRE tristate depends on NF_NAT && NF_CT_PROTO_GRE +config NF_NAT_PROTO_UDPLITE + tristate + depends on NF_NAT && NF_CT_PROTO_UDPLITE + default NF_NAT && NF_CT_PROTO_UDPLITE + config NF_NAT_FTP tristate depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index e73d0eb9994a..332f46fbc756 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o # NAT protocols (nf_nat) obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o +obj-$(CONFIG_NF_NAT_PROTO_UDPLITE) += nf_nat_proto_udplite.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/nf_nat_proto_udplite.c b/net/ipv4/netfilter/nf_nat_proto_udplite.c new file mode 100644 index 000000000000..b29346d0e7ab --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_udplite.c @@ -0,0 +1,99 @@ +/* (C) 1999-2001 Paul `Rusty' Russell + * (C) 2002-2006 Netfilter Core Team + * (C) 2008 Patrick McHardy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include + +static u_int16_t udplite_port_rover; + +static int +udplite_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, + &udplite_port_rover); +} + +static int +udplite_manip_pkt(struct sk_buff *skb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff); + struct udphdr *hdr; + unsigned int hdroff = iphdroff + iph->ihl*4; + __be32 oldip, newip; + __be16 *portptr, newport; + + if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) + return 0; + + iph = (struct iphdr *)(skb->data + iphdroff); + hdr = (struct udphdr *)(skb->data + hdroff); + + if (maniptype == IP_NAT_MANIP_SRC) { + /* Get rid of src ip and src pt */ + oldip = iph->saddr; + newip = tuple->src.u3.ip; + newport = tuple->src.u.udp.port; + portptr = &hdr->source; + } else { + /* Get rid of dst ip and dst pt */ + oldip = iph->daddr; + newip = tuple->dst.u3.ip; + newport = tuple->dst.u.udp.port; + portptr = &hdr->dest; + } + + inet_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1); + inet_proto_csum_replace2(&hdr->check, skb, *portptr, newport, 0); + if (!hdr->check) + hdr->check = CSUM_MANGLED_0; + + *portptr = newport; + return 1; +} + +static const struct nf_nat_protocol nf_nat_protocol_udplite = { + .protonum = IPPROTO_UDPLITE, + .me = THIS_MODULE, + .manip_pkt = udplite_manip_pkt, + .in_range = nf_nat_proto_in_range, + .unique_tuple = udplite_unique_tuple, +#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) + .range_to_nlattr = nf_nat_proto_range_to_nlattr, + .nlattr_to_range = nf_nat_proto_nlattr_to_range, +#endif +}; + +static int __init nf_nat_proto_udplite_init(void) +{ + return nf_nat_protocol_register(&nf_nat_protocol_udplite); +} + +static void __exit nf_nat_proto_udplite_fini(void) +{ + nf_nat_protocol_unregister(&nf_nat_protocol_udplite); +} + +module_init(nf_nat_proto_udplite_init); +module_exit(nf_nat_proto_udplite_fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("UDP-Lite NAT protocol helper"); +MODULE_AUTHOR("Patrick McHardy "); diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index 9fba42d9cdea..dc316b9f9b1d 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -50,7 +50,8 @@ static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) if (ct->status & statusbit) { fl->fl4_dst = t->dst.u3.ip; if (t->dst.protonum == IPPROTO_TCP || - t->dst.protonum == IPPROTO_UDP) + t->dst.protonum == IPPROTO_UDP || + t->dst.protonum == IPPROTO_UDPLITE) fl->fl_ip_dport = t->dst.u.tcp.port; } @@ -59,7 +60,8 @@ static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) if (ct->status & statusbit) { fl->fl4_src = t->src.u3.ip; if (t->dst.protonum == IPPROTO_TCP || - t->dst.protonum == IPPROTO_UDP) + t->dst.protonum == IPPROTO_UDP || + t->dst.protonum == IPPROTO_UDPLITE) fl->fl_ip_sport = t->src.u.tcp.port; } } -- cgit v1.2.3-59-g8ed1b From d63a650736f566a1f9e9434725d2089597c0d2cc Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 20 Mar 2008 15:15:53 +0100 Subject: [NETFILTER]: Add partial checksum validation helper Move the UDP-Lite conntrack checksum validation to a generic helper similar to nf_checksum() and make it fall back to nf_checksum() in case the full packet is to be checksummed and hardware checksums are available. This is to be used by DCCP conntrack, which also needs to verify partial checksums. Signed-off-by: Patrick McHardy --- include/linux/netfilter.h | 22 ++++++++++++++++ net/ipv4/netfilter.c | 37 +++++++++++++++++++++----- net/ipv6/netfilter.c | 42 +++++++++++++++++++++++++----- net/netfilter/nf_conntrack_proto_udplite.c | 33 +++++------------------ 4 files changed, 94 insertions(+), 40 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 66bc52060fd6..e4c66593b5c6 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -234,6 +234,11 @@ struct nf_afinfo { unsigned short family; __sum16 (*checksum)(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, u_int8_t protocol); + __sum16 (*checksum_partial)(struct sk_buff *skb, + unsigned int hook, + unsigned int dataoff, + unsigned int len, + u_int8_t protocol); int (*route)(struct dst_entry **dst, struct flowi *fl); void (*saveroute)(const struct sk_buff *skb, struct nf_queue_entry *entry); @@ -263,6 +268,23 @@ nf_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, return csum; } +static inline __sum16 +nf_checksum_partial(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, unsigned int len, + u_int8_t protocol, unsigned short family) +{ + const struct nf_afinfo *afinfo; + __sum16 csum = 0; + + rcu_read_lock(); + afinfo = nf_get_afinfo(family); + if (afinfo) + csum = afinfo->checksum_partial(skb, hook, dataoff, len, + protocol); + rcu_read_unlock(); + return csum; +} + extern int nf_register_afinfo(const struct nf_afinfo *afinfo); extern void nf_unregister_afinfo(const struct nf_afinfo *afinfo); diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 9a904c6c0dc8..f8edacdf991d 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -182,21 +182,44 @@ __sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, } return csum; } - EXPORT_SYMBOL(nf_ip_checksum); +static __sum16 nf_ip_checksum_partial(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, unsigned int len, + u_int8_t protocol) +{ + const struct iphdr *iph = ip_hdr(skb); + __sum16 csum = 0; + + switch (skb->ip_summed) { + case CHECKSUM_COMPLETE: + if (len == skb->len - dataoff) + return nf_ip_checksum(skb, hook, dataoff, protocol); + /* fall through */ + case CHECKSUM_NONE: + skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, protocol, + skb->len - dataoff, 0); + skb->ip_summed = CHECKSUM_NONE; + csum = __skb_checksum_complete_head(skb, dataoff + len); + if (!csum) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + return csum; +} + static int nf_ip_route(struct dst_entry **dst, struct flowi *fl) { return ip_route_output_key(&init_net, (struct rtable **)dst, fl); } static const struct nf_afinfo nf_ip_afinfo = { - .family = AF_INET, - .checksum = nf_ip_checksum, - .route = nf_ip_route, - .saveroute = nf_ip_saveroute, - .reroute = nf_ip_reroute, - .route_key_size = sizeof(struct ip_rt_info), + .family = AF_INET, + .checksum = nf_ip_checksum, + .checksum_partial = nf_ip_checksum_partial, + .route = nf_ip_route, + .saveroute = nf_ip_saveroute, + .reroute = nf_ip_reroute, + .route_key_size = sizeof(struct ip_rt_info), }; static int ipv4_netfilter_init(void) diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index aed51bcc66b4..8c6c5e71f210 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -121,16 +121,44 @@ __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, } return csum; } - EXPORT_SYMBOL(nf_ip6_checksum); +static __sum16 nf_ip6_checksum_partial(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, unsigned int len, + u_int8_t protocol) +{ + struct ipv6hdr *ip6h = ipv6_hdr(skb); + __wsum hsum; + __sum16 csum = 0; + + switch (skb->ip_summed) { + case CHECKSUM_COMPLETE: + if (len == skb->len - dataoff) + return nf_ip6_checksum(skb, hook, dataoff, protocol); + /* fall through */ + case CHECKSUM_NONE: + hsum = skb_checksum(skb, 0, dataoff, 0); + skb->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr, + &ip6h->daddr, + skb->len - dataoff, + protocol, + csum_sub(0, hsum))); + skb->ip_summed = CHECKSUM_NONE; + csum = __skb_checksum_complete_head(skb, dataoff + len); + if (!csum) + skb->ip_summed = CHECKSUM_UNNECESSARY; + } + return csum; +}; + static const struct nf_afinfo nf_ip6_afinfo = { - .family = AF_INET6, - .checksum = nf_ip6_checksum, - .route = nf_ip6_route, - .saveroute = nf_ip6_saveroute, - .reroute = nf_ip6_reroute, - .route_key_size = sizeof(struct ip6_rt_info), + .family = AF_INET6, + .checksum = nf_ip6_checksum, + .checksum_partial = nf_ip6_checksum_partial, + .route = nf_ip6_route, + .saveroute = nf_ip6_saveroute, + .reroute = nf_ip6_reroute, + .route_key_size = sizeof(struct ip6_rt_info), }; int __init ipv6_netfilter_init(void) diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index 9dd03c7aeac6..c3eaee6afffd 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c @@ -127,32 +127,13 @@ static int udplite_error(struct sk_buff *skb, unsigned int dataoff, } /* Checksum invalid? Ignore. */ - if (nf_conntrack_checksum && !skb_csum_unnecessary(skb) && - hooknum == NF_INET_PRE_ROUTING) { - if (pf == PF_INET) { - struct iphdr *iph = ip_hdr(skb); - - skb->csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, - udplen, IPPROTO_UDPLITE, 0); - } else { - struct ipv6hdr *ipv6h = ipv6_hdr(skb); - __wsum hsum = skb_checksum(skb, 0, dataoff, 0); - - skb->csum = ~csum_unfold( - csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr, - udplen, IPPROTO_UDPLITE, - csum_sub(0, hsum))); - } - - skb->ip_summed = CHECKSUM_NONE; - if (__skb_checksum_complete_head(skb, dataoff + cscov)) { - if (LOG_INVALID(IPPROTO_UDPLITE)) - nf_log_packet(pf, 0, skb, NULL, NULL, NULL, - "nf_ct_udplite: bad UDPLite " - "checksum "); - return -NF_ACCEPT; - } - skb->ip_summed = CHECKSUM_UNNECESSARY; + if (nf_conntrack_checksum && hooknum == NF_INET_PRE_ROUTING && + nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_UDP, + pf)) { + if (LOG_INVALID(IPPROTO_UDPLITE)) + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, + "nf_ct_udplite: bad UDPLite checksum "); + return -NF_ACCEPT; } return NF_ACCEPT; -- cgit v1.2.3-59-g8ed1b From 2bc780499aa33311ec0f3e42624dfaa7be0ade5e Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 20 Mar 2008 15:15:55 +0100 Subject: [NETFILTER]: nf_conntrack: add DCCP protocol support Add DCCP conntrack helper. Thanks to Gerrit Renker for review and testing. Signed-off-by: Patrick McHardy --- include/linux/netfilter/nf_conntrack_dccp.h | 40 ++ include/linux/netfilter/nfnetlink_conntrack.h | 8 + include/net/netfilter/nf_conntrack.h | 2 + include/net/netfilter/nf_conntrack_tuple.h | 6 + net/netfilter/Kconfig | 10 + net/netfilter/Makefile | 1 + net/netfilter/nf_conntrack_proto_dccp.c | 816 ++++++++++++++++++++++++++ 7 files changed, 883 insertions(+) create mode 100644 include/linux/netfilter/nf_conntrack_dccp.h create mode 100644 net/netfilter/nf_conntrack_proto_dccp.c (limited to 'net') diff --git a/include/linux/netfilter/nf_conntrack_dccp.h b/include/linux/netfilter/nf_conntrack_dccp.h new file mode 100644 index 000000000000..40dcc82058d1 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_dccp.h @@ -0,0 +1,40 @@ +#ifndef _NF_CONNTRACK_DCCP_H +#define _NF_CONNTRACK_DCCP_H + +/* Exposed to userspace over nfnetlink */ +enum ct_dccp_states { + CT_DCCP_NONE, + CT_DCCP_REQUEST, + CT_DCCP_RESPOND, + CT_DCCP_PARTOPEN, + CT_DCCP_OPEN, + CT_DCCP_CLOSEREQ, + CT_DCCP_CLOSING, + CT_DCCP_TIMEWAIT, + CT_DCCP_IGNORE, + CT_DCCP_INVALID, + __CT_DCCP_MAX +}; +#define CT_DCCP_MAX (__CT_DCCP_MAX - 1) + +enum ct_dccp_roles { + CT_DCCP_ROLE_CLIENT, + CT_DCCP_ROLE_SERVER, + __CT_DCCP_ROLE_MAX +}; +#define CT_DCCP_ROLE_MAX (__CT_DCCP_ROLE_MAX - 1) + +#ifdef __KERNEL__ +#include + +struct nf_ct_dccp { + u_int8_t role[IP_CT_DIR_MAX]; + u_int8_t state; + u_int8_t last_pkt; + u_int8_t last_dir; + u_int64_t handshake_seq; +}; + +#endif /* __KERNEL__ */ + +#endif /* _NF_CONNTRACK_DCCP_H */ diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index e3e1533aba2d..0a383ac083cb 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h @@ -80,6 +80,7 @@ enum ctattr_l4proto { enum ctattr_protoinfo { CTA_PROTOINFO_UNSPEC, CTA_PROTOINFO_TCP, + CTA_PROTOINFO_DCCP, __CTA_PROTOINFO_MAX }; #define CTA_PROTOINFO_MAX (__CTA_PROTOINFO_MAX - 1) @@ -95,6 +96,13 @@ enum ctattr_protoinfo_tcp { }; #define CTA_PROTOINFO_TCP_MAX (__CTA_PROTOINFO_TCP_MAX - 1) +enum ctattr_protoinfo_dccp { + CTA_PROTOINFO_DCCP_UNSPEC, + CTA_PROTOINFO_DCCP_STATE, + __CTA_PROTOINFO_DCCP_MAX, +}; +#define CTA_PROTOINFO_DCCP_MAX (__CTA_PROTOINFO_DCCP_MAX - 1) + enum ctattr_counters { CTA_COUNTERS_UNSPEC, CTA_COUNTERS_PACKETS, /* old 64bit counters */ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index a3567a7a6d67..bb9fc852e973 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -30,6 +31,7 @@ /* per conntrack: protocol private data */ union nf_conntrack_proto { /* insert conntrack proto private data here */ + struct nf_ct_dccp dccp; struct ip_ct_sctp sctp; struct ip_ct_tcp tcp; struct ip_ct_icmp icmp; diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h index 168c91754d89..bdeec3461384 100644 --- a/include/net/netfilter/nf_conntrack_tuple.h +++ b/include/net/netfilter/nf_conntrack_tuple.h @@ -39,6 +39,9 @@ union nf_conntrack_man_proto struct { __be16 id; } icmp; + struct { + __be16 port; + } dccp; struct { __be16 port; } sctp; @@ -77,6 +80,9 @@ struct nf_conntrack_tuple struct { u_int8_t type, code; } icmp; + struct { + __be16 port; + } dccp; struct { __be16 port; } sctp; diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index daf5b881064d..c1fc0f1a641c 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -86,6 +86,16 @@ config NF_CONNTRACK_EVENTS If unsure, say `N'. +config NF_CT_PROTO_DCCP + tristate 'DCCP protocol connection tracking support (EXPERIMENTAL)' + depends on EXPERIMENTAL && NF_CONNTRACK + depends on NETFILTER_ADVANCED + help + With this option enabled, the layer 3 independent connection + tracking code will be able to do state tracking on DCCP connections. + + If unsure, say 'N'. + config NF_CT_PROTO_GRE tristate depends on NF_CONNTRACK diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index ea7508387f95..5c4b183f6422 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o # SCTP protocol connection tracking +obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o obj-$(CONFIG_NF_CT_PROTO_UDPLITE) += nf_conntrack_proto_udplite.o diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c new file mode 100644 index 000000000000..db88c5bcc5fd --- /dev/null +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -0,0 +1,816 @@ +/* + * DCCP connection tracking protocol helper + * + * Copyright (c) 2005, 2006, 2008 Patrick McHardy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static DEFINE_RWLOCK(dccp_lock); + +static int nf_ct_dccp_loose __read_mostly = 1; + +/* Timeouts are based on values from RFC4340: + * + * - REQUEST: + * + * 8.1.2. Client Request + * + * A client MAY give up on its DCCP-Requests after some time + * (3 minutes, for example). + * + * - RESPOND: + * + * 8.1.3. Server Response + * + * It MAY also leave the RESPOND state for CLOSED after a timeout of + * not less than 4MSL (8 minutes); + * + * - PARTOPEN: + * + * 8.1.5. Handshake Completion + * + * If the client remains in PARTOPEN for more than 4MSL (8 minutes), + * it SHOULD reset the connection with Reset Code 2, "Aborted". + * + * - OPEN: + * + * The DCCP timestamp overflows after 11.9 hours. If the connection + * stays idle this long the sequence number won't be recognized + * as valid anymore. + * + * - CLOSEREQ/CLOSING: + * + * 8.3. Termination + * + * The retransmission timer should initially be set to go off in two + * round-trip times and should back off to not less than once every + * 64 seconds ... + * + * - TIMEWAIT: + * + * 4.3. States + * + * A server or client socket remains in this state for 2MSL (4 minutes) + * after the connection has been town down, ... + */ + +#define DCCP_MSL (2 * 60 * HZ) + +static unsigned int dccp_timeout[CT_DCCP_MAX + 1] __read_mostly = { + [CT_DCCP_REQUEST] = 2 * DCCP_MSL, + [CT_DCCP_RESPOND] = 4 * DCCP_MSL, + [CT_DCCP_PARTOPEN] = 4 * DCCP_MSL, + [CT_DCCP_OPEN] = 12 * 3600 * HZ, + [CT_DCCP_CLOSEREQ] = 64 * HZ, + [CT_DCCP_CLOSING] = 64 * HZ, + [CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL, +}; + +static const char * const dccp_state_names[] = { + [CT_DCCP_NONE] = "NONE", + [CT_DCCP_REQUEST] = "REQUEST", + [CT_DCCP_RESPOND] = "RESPOND", + [CT_DCCP_PARTOPEN] = "PARTOPEN", + [CT_DCCP_OPEN] = "OPEN", + [CT_DCCP_CLOSEREQ] = "CLOSEREQ", + [CT_DCCP_CLOSING] = "CLOSING", + [CT_DCCP_TIMEWAIT] = "TIMEWAIT", + [CT_DCCP_IGNORE] = "IGNORE", + [CT_DCCP_INVALID] = "INVALID", +}; + +#define sNO CT_DCCP_NONE +#define sRQ CT_DCCP_REQUEST +#define sRS CT_DCCP_RESPOND +#define sPO CT_DCCP_PARTOPEN +#define sOP CT_DCCP_OPEN +#define sCR CT_DCCP_CLOSEREQ +#define sCG CT_DCCP_CLOSING +#define sTW CT_DCCP_TIMEWAIT +#define sIG CT_DCCP_IGNORE +#define sIV CT_DCCP_INVALID + +/* + * DCCP state transistion table + * + * The assumption is the same as for TCP tracking: + * + * We are the man in the middle. All the packets go through us but might + * get lost in transit to the destination. It is assumed that the destination + * can't receive segments we haven't seen. + * + * The following states exist: + * + * NONE: Initial state, expecting Request + * REQUEST: Request seen, waiting for Response from server + * RESPOND: Response from server seen, waiting for Ack from client + * PARTOPEN: Ack after Response seen, waiting for packet other than Response, + * Reset or Sync from server + * OPEN: Packet other than Response, Reset or Sync seen + * CLOSEREQ: CloseReq from server seen, expecting Close from client + * CLOSING: Close seen, expecting Reset + * TIMEWAIT: Reset seen + * IGNORE: Not determinable whether packet is valid + * + * Some states exist only on one side of the connection: REQUEST, RESPOND, + * PARTOPEN, CLOSEREQ. For the other side these states are equivalent to + * the one it was in before. + * + * Packets are marked as ignored (sIG) if we don't know if they're valid + * (for example a reincarnation of a connection we didn't notice is dead + * already) and the server may send back a connection closing Reset or a + * Response. They're also used for Sync/SyncAck packets, which we don't + * care about. + */ +static const u_int8_t +dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = { + [CT_DCCP_ROLE_CLIENT] = { + [DCCP_PKT_REQUEST] = { + /* + * sNO -> sRQ Regular Request + * sRQ -> sRQ Retransmitted Request or reincarnation + * sRS -> sRS Retransmitted Request (apparently Response + * got lost after we saw it) or reincarnation + * sPO -> sIG Ignore, conntrack might be out of sync + * sOP -> sIG Ignore, conntrack might be out of sync + * sCR -> sIG Ignore, conntrack might be out of sync + * sCG -> sIG Ignore, conntrack might be out of sync + * sTW -> sRQ Reincarnation + * + * sNO, sRQ, sRS, sPO. sOP, sCR, sCG, sTW, */ + sRQ, sRQ, sRS, sIG, sIG, sIG, sIG, sRQ, + }, + [DCCP_PKT_RESPONSE] = { + /* + * sNO -> sIV Invalid + * sRQ -> sIG Ignore, might be response to ignored Request + * sRS -> sIG Ignore, might be response to ignored Request + * sPO -> sIG Ignore, might be response to ignored Request + * sOP -> sIG Ignore, might be response to ignored Request + * sCR -> sIG Ignore, might be response to ignored Request + * sCG -> sIG Ignore, might be response to ignored Request + * sTW -> sIV Invalid, reincarnation in reverse direction + * goes through sRQ + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIV, + }, + [DCCP_PKT_ACK] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.) + * sPO -> sPO Retransmitted Ack for Response, remain in PARTOPEN + * sOP -> sOP Regular ACK, remain in OPEN + * sCR -> sCR Ack in CLOSEREQ MAY be processed (8.3.) + * sCG -> sCG Ack in CLOSING MAY be processed (8.3.) + * sTW -> sIV + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV + }, + [DCCP_PKT_DATA] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sIV MUST use DataAck in PARTOPEN state (8.1.5.) + * sOP -> sOP Regular Data packet + * sCR -> sCR Data in CLOSEREQ MAY be processed (8.3.) + * sCG -> sCG Data in CLOSING MAY be processed (8.3.) + * sTW -> sIV + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sIV, sOP, sCR, sCG, sIV, + }, + [DCCP_PKT_DATAACK] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sPO Ack for Response, move to PARTOPEN (8.1.5.) + * sPO -> sPO Remain in PARTOPEN state + * sOP -> sOP Regular DataAck packet in OPEN state + * sCR -> sCR DataAck in CLOSEREQ MAY be processed (8.3.) + * sCG -> sCG DataAck in CLOSING MAY be processed (8.3.) + * sTW -> sIV + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sPO, sPO, sOP, sCR, sCG, sIV + }, + [DCCP_PKT_CLOSEREQ] = { + /* + * CLOSEREQ may only be sent by the server. + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV + }, + [DCCP_PKT_CLOSE] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sCG Client-initiated close + * sOP -> sCG Client-initiated close + * sCR -> sCG Close in response to CloseReq (8.3.) + * sCG -> sCG Retransmit + * sTW -> sIV Late retransmit, already in TIME_WAIT + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sCG, sCG, sCG, sIV, sIV + }, + [DCCP_PKT_RESET] = { + /* + * sNO -> sIV No connection + * sRQ -> sTW Sync received or timeout, SHOULD send Reset (8.1.1.) + * sRS -> sTW Response received without Request + * sPO -> sTW Timeout, SHOULD send Reset (8.1.5.) + * sOP -> sTW Connection reset + * sCR -> sTW Connection reset + * sCG -> sTW Connection reset + * sTW -> sIG Ignore (don't refresh timer) + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sTW, sTW, sTW, sTW, sTW, sTW, sIG + }, + [DCCP_PKT_SYNC] = { + /* + * We currently ignore Sync packets + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, + }, + [DCCP_PKT_SYNCACK] = { + /* + * We currently ignore SyncAck packets + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, + }, + }, + [CT_DCCP_ROLE_SERVER] = { + [DCCP_PKT_REQUEST] = { + /* + * sNO -> sIV Invalid + * sRQ -> sIG Ignore, conntrack might be out of sync + * sRS -> sIG Ignore, conntrack might be out of sync + * sPO -> sIG Ignore, conntrack might be out of sync + * sOP -> sIG Ignore, conntrack might be out of sync + * sCR -> sIG Ignore, conntrack might be out of sync + * sCG -> sIG Ignore, conntrack might be out of sync + * sTW -> sRQ Reincarnation, must reverse roles + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIG, sIG, sIG, sIG, sIG, sIG, sRQ + }, + [DCCP_PKT_RESPONSE] = { + /* + * sNO -> sIV Response without Request + * sRQ -> sRS Response to clients Request + * sRS -> sRS Retransmitted Response (8.1.3. SHOULD NOT) + * sPO -> sIG Response to an ignored Request or late retransmit + * sOP -> sIG Ignore, might be response to ignored Request + * sCR -> sIG Ignore, might be response to ignored Request + * sCG -> sIG Ignore, might be response to ignored Request + * sTW -> sIV Invalid, Request from client in sTW moves to sRQ + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sRS, sRS, sIG, sIG, sIG, sIG, sIV + }, + [DCCP_PKT_ACK] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sOP Enter OPEN state (8.1.5.) + * sOP -> sOP Regular Ack in OPEN state + * sCR -> sIV Waiting for Close from client + * sCG -> sCG Ack in CLOSING MAY be processed (8.3.) + * sTW -> sIV + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV + }, + [DCCP_PKT_DATA] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sOP Enter OPEN state (8.1.5.) + * sOP -> sOP Regular Data packet in OPEN state + * sCR -> sIV Waiting for Close from client + * sCG -> sCG Data in CLOSING MAY be processed (8.3.) + * sTW -> sIV + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV + }, + [DCCP_PKT_DATAACK] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sOP Enter OPEN state (8.1.5.) + * sOP -> sOP Regular DataAck in OPEN state + * sCR -> sIV Waiting for Close from client + * sCG -> sCG Data in CLOSING MAY be processed (8.3.) + * sTW -> sIV + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sOP, sOP, sIV, sCG, sIV + }, + [DCCP_PKT_CLOSEREQ] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sOP -> sCR Move directly to CLOSEREQ (8.1.5.) + * sOP -> sCR CloseReq in OPEN state + * sCR -> sCR Retransmit + * sCG -> sCR Simultaneous close, client sends another Close + * sTW -> sIV Already closed + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sCR, sCR, sCR, sCR, sIV + }, + [DCCP_PKT_CLOSE] = { + /* + * sNO -> sIV No connection + * sRQ -> sIV No connection + * sRS -> sIV No connection + * sPO -> sOP -> sCG Move direcly to CLOSING + * sOP -> sCG Move to CLOSING + * sCR -> sIV Close after CloseReq is invalid + * sCG -> sCG Retransmit + * sTW -> sIV Already closed + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIV, sIV, sIV, sCG, sCG, sIV, sCG, sIV + }, + [DCCP_PKT_RESET] = { + /* + * sNO -> sIV No connection + * sRQ -> sTW Reset in response to Request + * sRS -> sTW Timeout, SHOULD send Reset (8.1.3.) + * sPO -> sTW Timeout, SHOULD send Reset (8.1.3.) + * sOP -> sTW + * sCR -> sTW + * sCG -> sTW + * sTW -> sIG Ignore (don't refresh timer) + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW, sTW */ + sIV, sTW, sTW, sTW, sTW, sTW, sTW, sTW, sIG + }, + [DCCP_PKT_SYNC] = { + /* + * We currently ignore Sync packets + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, + }, + [DCCP_PKT_SYNCACK] = { + /* + * We currently ignore SyncAck packets + * + * sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */ + sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG, + }, + }, +}; + +static int dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, + struct nf_conntrack_tuple *tuple) +{ + struct dccp_hdr _hdr, *dh; + + dh = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); + if (dh == NULL) + return 0; + + tuple->src.u.dccp.port = dh->dccph_sport; + tuple->dst.u.dccp.port = dh->dccph_dport; + return 1; +} + +static int dccp_invert_tuple(struct nf_conntrack_tuple *inv, + const struct nf_conntrack_tuple *tuple) +{ + inv->src.u.dccp.port = tuple->dst.u.dccp.port; + inv->dst.u.dccp.port = tuple->src.u.dccp.port; + return 1; +} + +static int dccp_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff) +{ + int pf = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + struct dccp_hdr _dh, *dh; + const char *msg; + u_int8_t state; + + dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); + BUG_ON(dh == NULL); + + state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; + switch (state) { + default: + if (nf_ct_dccp_loose == 0) { + msg = "nf_ct_dccp: not picking up existing connection "; + goto out_invalid; + } + case CT_DCCP_REQUEST: + break; + case CT_DCCP_INVALID: + msg = "nf_ct_dccp: invalid state transition "; + goto out_invalid; + } + + ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT; + ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER; + ct->proto.dccp.state = CT_DCCP_NONE; + return 1; + +out_invalid: + if (LOG_INVALID(IPPROTO_DCCP)) + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, msg); + return 0; +} + +static u64 dccp_ack_seq(const struct dccp_hdr *dh) +{ + const struct dccp_hdr_ack_bits *dhack; + + dhack = (void *)dh + __dccp_basic_hdr_len(dh); + return ((u64)ntohs(dhack->dccph_ack_nr_high) << 32) + + ntohl(dhack->dccph_ack_nr_low); +} + +static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff, enum ip_conntrack_info ctinfo, + int pf, unsigned int hooknum) +{ + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + struct dccp_hdr _dh, *dh; + u_int8_t type, old_state, new_state; + enum ct_dccp_roles role; + + dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); + BUG_ON(dh == NULL); + type = dh->dccph_type; + + if (type == DCCP_PKT_RESET && + !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { + /* Tear down connection immediately if only reply is a RESET */ + if (del_timer(&ct->timeout)) + ct->timeout.function((unsigned long)ct); + return NF_ACCEPT; + } + + write_lock_bh(&dccp_lock); + + role = ct->proto.dccp.role[dir]; + old_state = ct->proto.dccp.state; + new_state = dccp_state_table[role][type][old_state]; + + switch (new_state) { + case CT_DCCP_REQUEST: + if (old_state == CT_DCCP_TIMEWAIT && + role == CT_DCCP_ROLE_SERVER) { + /* Reincarnation in the reverse direction: reopen and + * reverse client/server roles. */ + ct->proto.dccp.role[dir] = CT_DCCP_ROLE_CLIENT; + ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_SERVER; + } + break; + case CT_DCCP_RESPOND: + if (old_state == CT_DCCP_REQUEST) + ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh); + break; + case CT_DCCP_PARTOPEN: + if (old_state == CT_DCCP_RESPOND && + type == DCCP_PKT_ACK && + dccp_ack_seq(dh) == ct->proto.dccp.handshake_seq) + set_bit(IPS_ASSURED_BIT, &ct->status); + break; + case CT_DCCP_IGNORE: + /* + * Connection tracking might be out of sync, so we ignore + * packets that might establish a new connection and resync + * if the server responds with a valid Response. + */ + if (ct->proto.dccp.last_dir == !dir && + ct->proto.dccp.last_pkt == DCCP_PKT_REQUEST && + type == DCCP_PKT_RESPONSE) { + ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_CLIENT; + ct->proto.dccp.role[dir] = CT_DCCP_ROLE_SERVER; + ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh); + new_state = CT_DCCP_RESPOND; + break; + } + ct->proto.dccp.last_dir = dir; + ct->proto.dccp.last_pkt = type; + + write_unlock_bh(&dccp_lock); + if (LOG_INVALID(IPPROTO_DCCP)) + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, + "nf_ct_dccp: invalid packet ignored "); + return NF_ACCEPT; + case CT_DCCP_INVALID: + write_unlock_bh(&dccp_lock); + if (LOG_INVALID(IPPROTO_DCCP)) + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, + "nf_ct_dccp: invalid state transition "); + return -NF_ACCEPT; + } + + ct->proto.dccp.last_dir = dir; + ct->proto.dccp.last_pkt = type; + ct->proto.dccp.state = new_state; + write_unlock_bh(&dccp_lock); + nf_ct_refresh_acct(ct, ctinfo, skb, dccp_timeout[new_state]); + + return NF_ACCEPT; +} + +static int dccp_error(struct sk_buff *skb, unsigned int dataoff, + enum ip_conntrack_info *ctinfo, int pf, + unsigned int hooknum) +{ + struct dccp_hdr _dh, *dh; + unsigned int dccp_len = skb->len - dataoff; + unsigned int cscov; + const char *msg; + + dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh); + if (dh == NULL) { + msg = "nf_ct_dccp: short packet "; + goto out_invalid; + } + + if (dh->dccph_doff * 4 < sizeof(struct dccp_hdr) || + dh->dccph_doff * 4 > dccp_len) { + msg = "nf_ct_dccp: truncated/malformed packet "; + goto out_invalid; + } + + cscov = dccp_len; + if (dh->dccph_cscov) { + cscov = (dh->dccph_cscov - 1) * 4; + if (cscov > dccp_len) { + msg = "nf_ct_dccp: bad checksum coverage "; + goto out_invalid; + } + } + + if (nf_conntrack_checksum && hooknum == NF_INET_PRE_ROUTING && + nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_DCCP, + pf)) { + msg = "nf_ct_dccp: bad checksum "; + goto out_invalid; + } + + if (dh->dccph_type >= DCCP_PKT_INVALID) { + msg = "nf_ct_dccp: reserved packet type "; + goto out_invalid; + } + + return NF_ACCEPT; + +out_invalid: + if (LOG_INVALID(IPPROTO_DCCP)) + nf_log_packet(pf, 0, skb, NULL, NULL, NULL, msg); + return -NF_ACCEPT; +} + +static int dccp_print_tuple(struct seq_file *s, + const struct nf_conntrack_tuple *tuple) +{ + return seq_printf(s, "sport=%hu dport=%hu ", + ntohs(tuple->src.u.dccp.port), + ntohs(tuple->dst.u.dccp.port)); +} + +static int dccp_print_conntrack(struct seq_file *s, const struct nf_conn *ct) +{ + return seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]); +} + +#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) +static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla, + const struct nf_conn *ct) +{ + struct nlattr *nest_parms; + + read_lock_bh(&dccp_lock); + nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; + NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state); + nla_nest_end(skb, nest_parms); + read_unlock_bh(&dccp_lock); + return 0; + +nla_put_failure: + read_unlock_bh(&dccp_lock); + return -1; +} + +static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = { + [CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 }, +}; + +static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) +{ + struct nlattr *attr = cda[CTA_PROTOINFO_DCCP]; + struct nlattr *tb[CTA_PROTOINFO_DCCP_MAX + 1]; + int err; + + if (!attr) + return 0; + + err = nla_parse_nested(tb, CTA_PROTOINFO_DCCP_MAX, attr, + dccp_nla_policy); + if (err < 0) + return err; + + if (!tb[CTA_PROTOINFO_DCCP_STATE] || + nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) + return -EINVAL; + + write_lock_bh(&dccp_lock); + ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]); + write_unlock_bh(&dccp_lock); + return 0; +} +#endif + +#ifdef CONFIG_SYSCTL +static unsigned int dccp_sysctl_table_users; +static struct ctl_table_header *dccp_sysctl_header; +static ctl_table dccp_sysctl_table[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_request", + .data = &dccp_timeout[CT_DCCP_REQUEST], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_respond", + .data = &dccp_timeout[CT_DCCP_RESPOND], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_partopen", + .data = &dccp_timeout[CT_DCCP_PARTOPEN], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_open", + .data = &dccp_timeout[CT_DCCP_OPEN], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_closereq", + .data = &dccp_timeout[CT_DCCP_CLOSEREQ], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_closing", + .data = &dccp_timeout[CT_DCCP_CLOSING], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_timeout_timewait", + .data = &dccp_timeout[CT_DCCP_TIMEWAIT], + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = proc_dointvec_jiffies, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "nf_conntrack_dccp_loose", + .data = &nf_ct_dccp_loose, + .maxlen = sizeof(nf_ct_dccp_loose), + .mode = 0644, + .proc_handler = proc_dointvec, + }, + { + .ctl_name = 0, + } +}; +#endif /* CONFIG_SYSCTL */ + +static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { + .l3proto = AF_INET, + .l4proto = IPPROTO_DCCP, + .name = "dccp", + .pkt_to_tuple = dccp_pkt_to_tuple, + .invert_tuple = dccp_invert_tuple, + .new = dccp_new, + .packet = dccp_packet, + .error = dccp_error, + .print_tuple = dccp_print_tuple, + .print_conntrack = dccp_print_conntrack, +#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) + .to_nlattr = dccp_to_nlattr, + .from_nlattr = nlattr_to_dccp, + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, + .nla_policy = nf_ct_port_nla_policy, +#endif +#ifdef CONFIG_SYSCTL + .ctl_table_users = &dccp_sysctl_table_users, + .ctl_table_header = &dccp_sysctl_header, + .ctl_table = dccp_sysctl_table, +#endif +}; + +static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { + .l3proto = AF_INET6, + .l4proto = IPPROTO_DCCP, + .name = "dccp", + .pkt_to_tuple = dccp_pkt_to_tuple, + .invert_tuple = dccp_invert_tuple, + .new = dccp_new, + .packet = dccp_packet, + .error = dccp_error, + .print_tuple = dccp_print_tuple, + .print_conntrack = dccp_print_conntrack, +#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) + .to_nlattr = dccp_to_nlattr, + .from_nlattr = nlattr_to_dccp, + .tuple_to_nlattr = nf_ct_port_tuple_to_nlattr, + .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, + .nla_policy = nf_ct_port_nla_policy, +#endif +#ifdef CONFIG_SYSCTL + .ctl_table_users = &dccp_sysctl_table_users, + .ctl_table_header = &dccp_sysctl_header, + .ctl_table = dccp_sysctl_table, +#endif +}; + +static int __init nf_conntrack_proto_dccp_init(void) +{ + int err; + + err = nf_conntrack_l4proto_register(&dccp_proto4); + if (err < 0) + goto err1; + + err = nf_conntrack_l4proto_register(&dccp_proto6); + if (err < 0) + goto err2; + return 0; + +err2: + nf_conntrack_l4proto_unregister(&dccp_proto4); +err1: + return err; +} + +static void __exit nf_conntrack_proto_dccp_fini(void) +{ + nf_conntrack_l4proto_unregister(&dccp_proto6); + nf_conntrack_l4proto_unregister(&dccp_proto4); +} + +module_init(nf_conntrack_proto_dccp_init); +module_exit(nf_conntrack_proto_dccp_fini); + +MODULE_AUTHOR("Patrick McHardy "); +MODULE_DESCRIPTION("DCCP connection tracking protocol helper"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 4910a087996e637adc50f955eccf114307f8fab7 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 20 Mar 2008 15:15:57 +0100 Subject: [NETFILTER]: nf_nat: add DCCP protocol support Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/Kconfig | 5 ++ net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_proto_dccp.c | 108 +++++++++++++++++++++++++++++++++ net/ipv4/netfilter/nf_nat_standalone.c | 6 +- 4 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 net/ipv4/netfilter/nf_nat_proto_dccp.c (limited to 'net') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index c5bd2840663b..fde3eacd196d 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -241,6 +241,11 @@ config NF_NAT_SNMP_BASIC # '&&' (6) # # (6) Returns the result of min(/expr/, /expr/). +config NF_NAT_PROTO_DCCP + tristate + depends on NF_NAT && NF_CT_PROTO_DCCP + default NF_NAT && NF_CT_PROTO_DCCP + config NF_NAT_PROTO_GRE tristate depends on NF_NAT && NF_CT_PROTO_GRE diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 332f46fbc756..74d8dbdc1120 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_NF_NAT_SNMP_BASIC) += nf_nat_snmp_basic.o obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o # NAT protocols (nf_nat) +obj-$(CONFIG_NF_NAT_PROTO_DCCP) += nf_nat_proto_dccp.o obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o obj-$(CONFIG_NF_NAT_PROTO_UDPLITE) += nf_nat_proto_udplite.o diff --git a/net/ipv4/netfilter/nf_nat_proto_dccp.c b/net/ipv4/netfilter/nf_nat_proto_dccp.c new file mode 100644 index 000000000000..12b51b38442e --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_dccp.c @@ -0,0 +1,108 @@ +/* + * DCCP NAT protocol helper + * + * Copyright (c) 2005, 2006. 2008 Patrick McHardy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static u_int16_t dccp_port_rover; + +static int +dccp_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, + &dccp_port_rover); +} + +static int +dccp_manip_pkt(struct sk_buff *skb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff); + struct dccp_hdr *hdr; + unsigned int hdroff = iphdroff + iph->ihl * 4; + __be32 oldip, newip; + __be16 *portptr, oldport, newport; + int hdrsize = 8; /* DCCP connection tracking guarantees this much */ + + if (skb->len >= hdroff + sizeof(struct dccp_hdr)) + hdrsize = sizeof(struct dccp_hdr); + + if (!skb_make_writable(skb, hdroff + hdrsize)) + return 0; + + iph = (struct iphdr *)(skb->data + iphdroff); + hdr = (struct dccp_hdr *)(skb->data + hdroff); + + if (maniptype == IP_NAT_MANIP_SRC) { + oldip = iph->saddr; + newip = tuple->src.u3.ip; + newport = tuple->src.u.dccp.port; + portptr = &hdr->dccph_sport; + } else { + oldip = iph->daddr; + newip = tuple->dst.u3.ip; + newport = tuple->dst.u.dccp.port; + portptr = &hdr->dccph_dport; + } + + oldport = *portptr; + *portptr = newport; + + if (hdrsize < sizeof(*hdr)) + return 1; + + inet_proto_csum_replace4(&hdr->dccph_checksum, skb, oldip, newip, 1); + inet_proto_csum_replace2(&hdr->dccph_checksum, skb, oldport, newport, + 0); + return 1; +} + +static const struct nf_nat_protocol nf_nat_protocol_dccp = { + .protonum = IPPROTO_DCCP, + .me = THIS_MODULE, + .manip_pkt = dccp_manip_pkt, + .in_range = nf_nat_proto_in_range, + .unique_tuple = dccp_unique_tuple, +#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) + .range_to_nlattr = nf_nat_proto_range_to_nlattr, + .nlattr_to_range = nf_nat_proto_nlattr_to_range, +#endif +}; + +static int __init nf_nat_proto_dccp_init(void) +{ + return nf_nat_protocol_register(&nf_nat_protocol_dccp); +} + +static void __exit nf_nat_proto_dccp_fini(void) +{ + nf_nat_protocol_unregister(&nf_nat_protocol_dccp); +} + +module_init(nf_nat_proto_dccp_init); +module_exit(nf_nat_proto_dccp_fini); + +MODULE_AUTHOR("Patrick McHardy "); +MODULE_DESCRIPTION("DCCP NAT protocol helper"); +MODULE_LICENSE("GPL"); diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index dc316b9f9b1d..b759ffa1098d 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -51,7 +51,8 @@ static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) fl->fl4_dst = t->dst.u3.ip; if (t->dst.protonum == IPPROTO_TCP || t->dst.protonum == IPPROTO_UDP || - t->dst.protonum == IPPROTO_UDPLITE) + t->dst.protonum == IPPROTO_UDPLITE || + t->dst.protonum == IPPROTO_DCCP) fl->fl_ip_dport = t->dst.u.tcp.port; } @@ -61,7 +62,8 @@ static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) fl->fl4_src = t->src.u3.ip; if (t->dst.protonum == IPPROTO_TCP || t->dst.protonum == IPPROTO_UDP || - t->dst.protonum == IPPROTO_UDPLITE) + t->dst.protonum == IPPROTO_UDPLITE || + t->dst.protonum == IPPROTO_DCCP) fl->fl_ip_sport = t->src.u.tcp.port; } } -- cgit v1.2.3-59-g8ed1b From 9d908a69a32e0171eb5eeac93f2f46ffa4190573 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:15:50 +0200 Subject: [NETFILTER]: nf_nat: add SCTP protocol support Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/Kconfig | 5 ++ net/ipv4/netfilter/Makefile | 1 + net/ipv4/netfilter/nf_nat_proto_sctp.c | 96 ++++++++++++++++++++++++++++++++++ net/ipv4/netfilter/nf_nat_standalone.c | 6 ++- 4 files changed, 106 insertions(+), 2 deletions(-) create mode 100644 net/ipv4/netfilter/nf_nat_proto_sctp.c (limited to 'net') diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index fde3eacd196d..0c95cd5872f3 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -255,6 +255,11 @@ config NF_NAT_PROTO_UDPLITE depends on NF_NAT && NF_CT_PROTO_UDPLITE default NF_NAT && NF_CT_PROTO_UDPLITE +config NF_NAT_PROTO_SCTP + tristate + default NF_NAT && NF_CT_PROTO_SCTP + depends on NF_NAT && NF_CT_PROTO_SCTP + config NF_NAT_FTP tristate depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 74d8dbdc1120..d9b92fbf5579 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_NF_NAT_TFTP) += nf_nat_tftp.o obj-$(CONFIG_NF_NAT_PROTO_DCCP) += nf_nat_proto_dccp.o obj-$(CONFIG_NF_NAT_PROTO_GRE) += nf_nat_proto_gre.o obj-$(CONFIG_NF_NAT_PROTO_UDPLITE) += nf_nat_proto_udplite.o +obj-$(CONFIG_NF_NAT_PROTO_SCTP) += nf_nat_proto_sctp.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/ipv4/netfilter/nf_nat_proto_sctp.c new file mode 100644 index 000000000000..3d3faa9d5f6d --- /dev/null +++ b/net/ipv4/netfilter/nf_nat_proto_sctp.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2008 Patrick McHardy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include + +#include + +static u_int16_t nf_sctp_port_rover; + +static int +sctp_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) +{ + return nf_nat_proto_unique_tuple(tuple, range, maniptype, ct, + &nf_sctp_port_rover); +} + +static int +sctp_manip_pkt(struct sk_buff *skb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype) +{ + const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff); + sctp_sctphdr_t *hdr; + unsigned int hdroff = iphdroff + iph->ihl*4; + __be32 oldip, newip; + u32 crc32; + + if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) + return 0; + + iph = (struct iphdr *)(skb->data + iphdroff); + hdr = (struct sctphdr *)(skb->data + hdroff); + + if (maniptype == IP_NAT_MANIP_SRC) { + /* Get rid of src ip and src pt */ + oldip = iph->saddr; + newip = tuple->src.u3.ip; + hdr->source = tuple->src.u.sctp.port; + } else { + /* Get rid of dst ip and dst pt */ + oldip = iph->daddr; + newip = tuple->dst.u3.ip; + hdr->dest = tuple->dst.u.sctp.port; + } + + crc32 = sctp_start_cksum((u8 *)hdr, skb_headlen(skb) - hdroff); + for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next) + crc32 = sctp_update_cksum((u8 *)skb->data, skb_headlen(skb), + crc32); + crc32 = sctp_end_cksum(crc32); + hdr->checksum = htonl(crc32); + + return 1; +} + +static const struct nf_nat_protocol nf_nat_protocol_sctp = { + .protonum = IPPROTO_SCTP, + .me = THIS_MODULE, + .manip_pkt = sctp_manip_pkt, + .in_range = nf_nat_proto_in_range, + .unique_tuple = sctp_unique_tuple, +#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) + .range_to_nlattr = nf_nat_proto_range_to_nlattr, + .nlattr_to_range = nf_nat_proto_nlattr_to_range, +#endif +}; + +static int __init nf_nat_proto_sctp_init(void) +{ + return nf_nat_protocol_register(&nf_nat_protocol_sctp); +} + +static void __exit nf_nat_proto_sctp_exit(void) +{ + nf_nat_protocol_unregister(&nf_nat_protocol_sctp); +} + +module_init(nf_nat_proto_sctp_init); +module_exit(nf_nat_proto_sctp_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SCTP NAT protocol helper"); +MODULE_AUTHOR("Patrick McHardy "); diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index b759ffa1098d..4a3e0f85db97 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -52,7 +52,8 @@ static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) if (t->dst.protonum == IPPROTO_TCP || t->dst.protonum == IPPROTO_UDP || t->dst.protonum == IPPROTO_UDPLITE || - t->dst.protonum == IPPROTO_DCCP) + t->dst.protonum == IPPROTO_DCCP || + t->dst.protonum == IPPROTO_SCTP) fl->fl_ip_dport = t->dst.u.tcp.port; } @@ -63,7 +64,8 @@ static void nat_decode_session(struct sk_buff *skb, struct flowi *fl) if (t->dst.protonum == IPPROTO_TCP || t->dst.protonum == IPPROTO_UDP || t->dst.protonum == IPPROTO_UDPLITE || - t->dst.protonum == IPPROTO_DCCP) + t->dst.protonum == IPPROTO_DCCP || + t->dst.protonum == IPPROTO_SCTP) fl->fl_ip_sport = t->src.u.tcp.port; } } -- cgit v1.2.3-59-g8ed1b From 42cf800c240fa845e9c154429d70d62750e65b64 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:15:50 +0200 Subject: [NETFILTER]: nf_nat: remove obsolete check for ICMP redirects Locally generated ICMP packets have a reference to the conntrack entry of the original packet manually attached by icmp_send(). Therefore the check for locally originated untracked ICMP redirects can never be true. Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/nf_nat_standalone.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index 4a3e0f85db97..c362f672755a 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -93,21 +93,8 @@ nf_nat_fn(unsigned int hooknum, have dropped it. Hence it's the user's responsibilty to packet filter it out, or implement conntrack/NAT for that protocol. 8) --RR */ - if (!ct) { - /* Exception: ICMP redirect to new connection (not in - hash table yet). We must not let this through, in - case we're doing NAT to the same network. */ - if (ip_hdr(skb)->protocol == IPPROTO_ICMP) { - struct icmphdr _hdr, *hp; - - hp = skb_header_pointer(skb, ip_hdrlen(skb), - sizeof(_hdr), &_hdr); - if (hp != NULL && - hp->type == ICMP_REDIRECT) - return NF_DROP; - } + if (!ct) return NF_ACCEPT; - } /* Don't try to NAT if this packet is not conntracked */ if (ct == &nf_conntrack_untracked) -- cgit v1.2.3-59-g8ed1b From 8c87238b726e543f8af4bdb4296020a328df4744 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:15:51 +0200 Subject: [NETFILTER]: nf_nat: don't add NAT extension for confirmed conntracks Adding extensions to confirmed conntracks is not allowed to avoid races on reallocation. Don't setup NAT for confirmed conntracks in case NAT module is loaded late. The has one side-effect, the connections existing before the NAT module was loaded won't enter the bysource hash. The only case where this actually makes a difference is in case of SNAT to a multirange where the IP before NAT is also part of the range. Since old connections don't enter the bysource hash the first new connection from the IP will have a new address selected. This shouldn't matter at all. Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_nat_rule.h | 3 --- net/ipv4/netfilter/nf_nat_rule.c | 19 ------------------- net/ipv4/netfilter/nf_nat_standalone.c | 8 ++++---- 3 files changed, 4 insertions(+), 26 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_nat_rule.h b/include/net/netfilter/nf_nat_rule.h index 75d1825031d7..e4a18ae361c6 100644 --- a/include/net/netfilter/nf_nat_rule.h +++ b/include/net/netfilter/nf_nat_rule.h @@ -14,7 +14,4 @@ extern int nf_nat_rule_find(struct sk_buff *skb, extern unsigned int alloc_null_binding(struct nf_conn *ct, unsigned int hooknum); - -extern unsigned int -alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum); #endif /* _NF_NAT_RULE_H */ diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c index ebe0c7903ae9..e8b4d0d4439e 100644 --- a/net/ipv4/netfilter/nf_nat_rule.c +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -188,25 +188,6 @@ alloc_null_binding(struct nf_conn *ct, unsigned int hooknum) return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum)); } -unsigned int -alloc_null_binding_confirmed(struct nf_conn *ct, unsigned int hooknum) -{ - __be32 ip - = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC - ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip - : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip); - __be16 all - = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC - ? ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.all - : ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u.all); - struct nf_nat_range range - = { IP_NAT_RANGE_MAP_IPS, ip, ip, { all }, { all } }; - - pr_debug("Allocating NULL binding for confirmed %p (%u.%u.%u.%u)\n", - ct, NIPQUAD(ip)); - return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum)); -} - int nf_nat_rule_find(struct sk_buff *skb, unsigned int hooknum, const struct net_device *in, diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index c362f672755a..a366b5865b9c 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -102,6 +102,9 @@ nf_nat_fn(unsigned int hooknum, nat = nfct_nat(ct); if (!nat) { + /* NAT module was loaded late. */ + if (nf_ct_is_confirmed(ct)) + return NF_ACCEPT; nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); if (nat == NULL) { pr_debug("failed to add NAT extension\n"); @@ -127,10 +130,7 @@ nf_nat_fn(unsigned int hooknum, if (!nf_nat_initialized(ct, maniptype)) { unsigned int ret; - if (unlikely(nf_ct_is_confirmed(ct))) - /* NAT module was loaded late */ - ret = alloc_null_binding_confirmed(ct, hooknum); - else if (hooknum == NF_INET_LOCAL_IN) + if (hooknum == NF_INET_LOCAL_IN) /* LOCAL_IN hook doesn't have a chain! */ ret = alloc_null_binding(ct, hooknum); else -- cgit v1.2.3-59-g8ed1b From 55871d04793d9c069ee277b1e98794b88d92ed80 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:15:51 +0200 Subject: [NETFILTER]: nf_conntrack_extend: warn on confirmed conntracks New extensions may only be added to unconfirmed conntracks to avoid races when reallocating the storage. Also change NF_CT_ASSERT to use WARN_ON to get backtraces. Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_conntrack.h | 9 +-------- net/netfilter/nf_conntrack_extend.c | 3 +++ 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index bb9fc852e973..4a0496aa32d5 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -65,14 +65,7 @@ union nf_conntrack_help { #include #ifdef CONFIG_NETFILTER_DEBUG -#define NF_CT_ASSERT(x) \ -do { \ - if (!(x)) \ - /* Wooah! I'm tripping my conntrack in a frenzy of \ - netplay... */ \ - printk("NF_CT_ASSERT: %s:%i(%s)\n", \ - __FILE__, __LINE__, __FUNCTION__); \ -} while(0) +#define NF_CT_ASSERT(x) WARN_ON(!(x)) #else #define NF_CT_ASSERT(x) #endif diff --git a/net/netfilter/nf_conntrack_extend.c b/net/netfilter/nf_conntrack_extend.c index 2bd9963b5b3e..bcc19fa4ed1e 100644 --- a/net/netfilter/nf_conntrack_extend.c +++ b/net/netfilter/nf_conntrack_extend.c @@ -71,6 +71,9 @@ void *__nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp) int i, newlen, newoff; struct nf_ct_ext_type *t; + /* Conntrack must not be confirmed to avoid races on reallocation. */ + NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); + if (!ct->ext) return nf_ct_ext_create(&ct->ext, id, gfp); -- cgit v1.2.3-59-g8ed1b From dd13b010368f85dfa59364ba87bfe8ae930b2832 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:15:52 +0200 Subject: [NETFILTER]: nf_nat: kill helper and seq_adjust hooks Connection tracking helpers (specifically FTP) need to be called before NAT sequence numbers adjustments are performed to be able to compare them against previously seen ones. We've introduced two new hooks around 2.6.11 to maintain this ordering when NAT modules were changed to get called from conntrack helpers directly. The cost of netfilter hooks is quite high and sequence number adjustments are only rarely needed however. Add a RCU-protected sequence number adjustment function pointer and call it from IPv4 conntrack after calling the helper. Signed-off-by: Patrick McHardy --- include/linux/netfilter_ipv4.h | 2 - include/net/netfilter/nf_nat_helper.h | 3 ++ net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 56 +++++++++++++------------- net/ipv4/netfilter/nf_nat_core.c | 5 +++ net/ipv4/netfilter/nf_nat_helper.c | 1 - net/ipv4/netfilter/nf_nat_standalone.c | 35 ---------------- 6 files changed, 35 insertions(+), 67 deletions(-) (limited to 'net') diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h index 9a10092e358c..650318b0c405 100644 --- a/include/linux/netfilter_ipv4.h +++ b/include/linux/netfilter_ipv4.h @@ -62,8 +62,6 @@ enum nf_ip_hook_priorities { NF_IP_PRI_FILTER = 0, NF_IP_PRI_NAT_SRC = 100, NF_IP_PRI_SELINUX_LAST = 225, - NF_IP_PRI_CONNTRACK_HELPER = INT_MAX - 2, - NF_IP_PRI_NAT_SEQ_ADJUST = INT_MAX - 1, NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX, NF_IP_PRI_LAST = INT_MAX, }; diff --git a/include/net/netfilter/nf_nat_helper.h b/include/net/netfilter/nf_nat_helper.h index 58dd22687949..237a961f40e1 100644 --- a/include/net/netfilter/nf_nat_helper.h +++ b/include/net/netfilter/nf_nat_helper.h @@ -24,6 +24,9 @@ extern int nf_nat_mangle_udp_packet(struct sk_buff *skb, extern int nf_nat_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo); +extern int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo); /* Setup NAT on this expected conntrack so it follows master, but goes * to port ct->master->saved_proto. */ diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index a65b845c5f15..41e79613eb0a 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -23,6 +23,12 @@ #include #include #include +#include + +int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo); +EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook); static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, struct nf_conntrack_tuple *tuple) @@ -100,36 +106,42 @@ static unsigned int ipv4_confirm(unsigned int hooknum, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) -{ - /* We've seen it coming out the other side: confirm it */ - return nf_conntrack_confirm(skb); -} - -static unsigned int ipv4_conntrack_help(unsigned int hooknum, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) { struct nf_conn *ct; enum ip_conntrack_info ctinfo; const struct nf_conn_help *help; const struct nf_conntrack_helper *helper; + unsigned int ret; /* This is where we call the helper: as the packet goes out. */ ct = nf_ct_get(skb, &ctinfo); if (!ct || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY) - return NF_ACCEPT; + goto out; help = nfct_help(ct); if (!help) - return NF_ACCEPT; + goto out; + /* rcu_read_lock()ed by nf_hook_slow */ helper = rcu_dereference(help->helper); if (!helper) - return NF_ACCEPT; - return helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), - ct, ctinfo); + goto out; + + ret = helper->help(skb, skb_network_offset(skb) + ip_hdrlen(skb), + ct, ctinfo); + if (ret != NF_ACCEPT) + return ret; + + if (test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { + typeof(nf_nat_seq_adjust_hook) seq_adjust; + + seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); + if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) + return NF_DROP; + } +out: + /* We've seen it coming out the other side: confirm it */ + return nf_conntrack_confirm(skb); } static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, @@ -210,20 +222,6 @@ static struct nf_hook_ops ipv4_conntrack_ops[] __read_mostly = { .hooknum = NF_INET_LOCAL_OUT, .priority = NF_IP_PRI_CONNTRACK, }, - { - .hook = ipv4_conntrack_help, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_INET_POST_ROUTING, - .priority = NF_IP_PRI_CONNTRACK_HELPER, - }, - { - .hook = ipv4_conntrack_help, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_INET_LOCAL_IN, - .priority = NF_IP_PRI_CONNTRACK_HELPER, - }, { .hook = ipv4_confirm, .owner = THIS_MODULE, diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 9320c7ac5729..25c3efe4207e 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -618,6 +618,9 @@ static int __init nf_nat_init(void) nf_conntrack_untracked.status |= IPS_NAT_DONE_MASK; l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); + + BUG_ON(nf_nat_seq_adjust_hook != NULL); + rcu_assign_pointer(nf_nat_seq_adjust_hook, nf_nat_seq_adjust); return 0; cleanup_extend: @@ -644,6 +647,8 @@ static void __exit nf_nat_cleanup(void) nf_ct_free_hashtable(bysource, nf_nat_vmalloced, nf_nat_htable_size); nf_ct_l3proto_put(l3proto); nf_ct_extend_unregister(&nat_extend); + rcu_assign_pointer(nf_nat_seq_adjust_hook, NULL); + synchronize_net(); } MODULE_LICENSE("GPL"); diff --git a/net/ipv4/netfilter/nf_nat_helper.c b/net/ipv4/netfilter/nf_nat_helper.c index 2fca727aa8ba..11976ea29884 100644 --- a/net/ipv4/netfilter/nf_nat_helper.c +++ b/net/ipv4/netfilter/nf_nat_helper.c @@ -416,7 +416,6 @@ nf_nat_seq_adjust(struct sk_buff *skb, return 1; } -EXPORT_SYMBOL(nf_nat_seq_adjust); /* Setup NAT on this expected conntrack so it follows master. */ /* If we fail to get a free NAT slot, we'll get dropped on confirm */ diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index a366b5865b9c..b7dd695691a0 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c @@ -245,25 +245,6 @@ nf_nat_local_fn(unsigned int hooknum, return ret; } -static unsigned int -nf_nat_adjust(unsigned int hooknum, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - struct nf_conn *ct; - enum ip_conntrack_info ctinfo; - - ct = nf_ct_get(skb, &ctinfo); - if (ct && test_bit(IPS_SEQ_ADJUST_BIT, &ct->status)) { - pr_debug("nf_nat_standalone: adjusting sequence number\n"); - if (!nf_nat_seq_adjust(skb, ct, ctinfo)) - return NF_DROP; - } - return NF_ACCEPT; -} - /* We must be after connection tracking and before packet filtering. */ static struct nf_hook_ops nf_nat_ops[] __read_mostly = { @@ -283,14 +264,6 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = { .hooknum = NF_INET_POST_ROUTING, .priority = NF_IP_PRI_NAT_SRC, }, - /* After conntrack, adjust sequence number */ - { - .hook = nf_nat_adjust, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_INET_POST_ROUTING, - .priority = NF_IP_PRI_NAT_SEQ_ADJUST, - }, /* Before packet filtering, change destination */ { .hook = nf_nat_local_fn, @@ -307,14 +280,6 @@ static struct nf_hook_ops nf_nat_ops[] __read_mostly = { .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP_PRI_NAT_SRC, }, - /* After conntrack, adjust sequence number */ - { - .hook = nf_nat_adjust, - .owner = THIS_MODULE, - .pf = PF_INET, - .hooknum = NF_INET_LOCAL_IN, - .priority = NF_IP_PRI_NAT_SEQ_ADJUST, - }, }; static int __init nf_nat_standalone_init(void) -- cgit v1.2.3-59-g8ed1b From 5f7da4d26d421f3bdf10c3bbdb86ffc3a12a84f2 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:15:52 +0200 Subject: [NETFILTER]: nf_conntrack_tcp: catch invalid state updates over ctnetlink Invalid states can cause out-of-bound memory accesses of the state table. Also don't insist on having a new state contained in the netlink message. Signed-off-by: Patrick McHardy --- net/netfilter/nf_conntrack_proto_tcp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 62567959b66e..57831c75fa9f 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -1129,11 +1129,13 @@ static int nlattr_to_tcp(struct nlattr *cda[], struct nf_conn *ct) if (err < 0) return err; - if (!tb[CTA_PROTOINFO_TCP_STATE]) + if (tb[CTA_PROTOINFO_TCP_STATE] && + nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]) >= TCP_CONNTRACK_MAX) return -EINVAL; write_lock_bh(&tcp_lock); - ct->proto.tcp.state = nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]); + if (tb[CTA_PROTOINFO_TCP_STATE]) + ct->proto.tcp.state = nla_get_u8(tb[CTA_PROTOINFO_TCP_STATE]); if (tb[CTA_PROTOINFO_TCP_FLAGS_ORIGINAL]) { struct nf_ct_tcp_flags *attr = -- cgit v1.2.3-59-g8ed1b From 5e8fbe2ac8a3f1e34e7004c5750ef59bf9304f82 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:15:52 +0200 Subject: [NETFILTER]: nf_conntrack: add tuplehash l3num/protonum accessors Add accessors for l3num and protonum and get rid of some overly long expressions. Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_conntrack.h | 10 ++++++ .../netfilter/nf_conntrack_l3proto_ipv4_compat.c | 13 +++----- net/netfilter/nf_conntrack_amanda.c | 4 +-- net/netfilter/nf_conntrack_core.c | 3 +- net/netfilter/nf_conntrack_ftp.c | 4 +-- net/netfilter/nf_conntrack_h323_main.c | 39 ++++++++-------------- net/netfilter/nf_conntrack_netlink.c | 19 ++++------- net/netfilter/nf_conntrack_pptp.c | 4 +-- net/netfilter/nf_conntrack_proto.c | 9 ++--- net/netfilter/nf_conntrack_proto_dccp.c | 3 +- net/netfilter/nf_conntrack_sane.c | 3 +- net/netfilter/nf_conntrack_sip.c | 20 +++++------ net/netfilter/nf_conntrack_standalone.c | 15 +++------ net/netfilter/nf_conntrack_tftp.c | 4 +-- net/netfilter/xt_connlimit.c | 4 +-- net/netfilter/xt_conntrack.c | 4 +-- 16 files changed, 64 insertions(+), 94 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 4a0496aa32d5..26e6a6e2b5a2 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -140,6 +140,16 @@ nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash) tuplehash[hash->tuple.dst.dir]); } +static inline u_int16_t nf_ct_l3num(const struct nf_conn *ct) +{ + return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; +} + +static inline u_int8_t nf_ct_protonum(const struct nf_conn *ct) +{ + return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; +} + /* get master conntrack via master expectation */ #define master_ct(conntr) (conntr->master) diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c index e60b885d2dcd..40a46d482490 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c @@ -106,21 +106,16 @@ static int ct_seq_show(struct seq_file *s, void *v) /* we only want to print DIR_ORIGINAL */ if (NF_CT_DIRECTION(hash)) return 0; - if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num != AF_INET) + if (nf_ct_l3num(ct) != AF_INET) return 0; - l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL] - .tuple.src.l3num); + l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); NF_CT_ASSERT(l3proto); - l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL] - .tuple.src.l3num, - ct->tuplehash[IP_CT_DIR_ORIGINAL] - .tuple.dst.protonum); + l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); NF_CT_ASSERT(l4proto); if (seq_printf(s, "%-8s %u %ld ", - l4proto->name, - ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum, + l4proto->name, nf_ct_protonum(ct), timer_pending(&ct->timeout) ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) return -ENOSPC; diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c index ddfac99cbe63..38aedeeaf4e1 100644 --- a/net/netfilter/nf_conntrack_amanda.c +++ b/net/netfilter/nf_conntrack_amanda.c @@ -91,7 +91,6 @@ static int amanda_help(struct sk_buff *skb, char pbuf[sizeof("65535")], *tmp; u_int16_t len; __be16 port; - int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; int ret = NF_ACCEPT; typeof(nf_nat_amanda_hook) nf_nat_amanda; @@ -148,7 +147,8 @@ static int amanda_help(struct sk_buff *skb, goto out; } tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; - nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, + nf_ct_l3num(ct), &tuple->src.u3, &tuple->dst.u3, IPPROTO_TCP, NULL, &port); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index b77eb56a87e3..21ab0c3846ac 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -194,8 +194,7 @@ destroy_conntrack(struct nf_conntrack *nfct) * destroy_conntrack() MUST NOT be called with a write lock * to nf_conntrack_lock!!! -HW */ rcu_read_lock(); - l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num, - ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); + l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); if (l4proto && l4proto->destroy) l4proto->destroy(ct); diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 87ca39b353bb..bb20672fe036 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -406,7 +406,7 @@ static int help(struct sk_buff *skb, /* Initialize IP/IPv6 addr to expected address (it's not mentioned in EPSV responses) */ - cmd.l3num = ct->tuplehash[dir].tuple.src.l3num; + cmd.l3num = nf_ct_l3num(ct); memcpy(cmd.u3.all, &ct->tuplehash[dir].tuple.src.u3.all, sizeof(cmd.u3.all)); @@ -453,7 +453,7 @@ static int help(struct sk_buff *skb, daddr = &ct->tuplehash[!dir].tuple.dst.u3; /* Update the ftp info */ - if ((cmd.l3num == ct->tuplehash[dir].tuple.src.l3num) && + if ((cmd.l3num == nf_ct_l3num(ct)) && memcmp(&cmd.u3.all, &ct->tuplehash[dir].tuple.src.u3.all, sizeof(cmd.u3.all))) { /* Enrico Scholz's passive FTP to partially RNAT'd ftp diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c index 505052d495cf..c3f87094de43 100644 --- a/net/netfilter/nf_conntrack_h323_main.c +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -218,7 +218,6 @@ static int get_h245_addr(struct nf_conn *ct, const unsigned char *data, union nf_inet_addr *addr, __be16 *port) { const unsigned char *p; - int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; int len; if (taddr->choice != eH245_TransportAddress_unicastAddress) @@ -226,13 +225,13 @@ static int get_h245_addr(struct nf_conn *ct, const unsigned char *data, switch (taddr->unicastAddress.choice) { case eUnicastAddress_iPAddress: - if (family != AF_INET) + if (nf_ct_l3num(ct) != AF_INET) return 0; p = data + taddr->unicastAddress.iPAddress.network; len = 4; break; case eUnicastAddress_iP6Address: - if (family != AF_INET6) + if (nf_ct_l3num(ct) != AF_INET6) return 0; p = data + taddr->unicastAddress.iP6Address.network; len = 16; @@ -277,8 +276,7 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct, /* Create expect for RTP */ if ((rtp_exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(rtp_exp, NF_CT_EXPECT_CLASS_DEFAULT, - ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(rtp_exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, IPPROTO_UDP, NULL, &rtp_port); @@ -288,8 +286,7 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct, nf_ct_expect_put(rtp_exp); return -1; } - nf_ct_expect_init(rtcp_exp, NF_CT_EXPECT_CLASS_DEFAULT, - ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(rtcp_exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, IPPROTO_UDP, NULL, &rtcp_port); @@ -346,8 +343,7 @@ static int expect_t120(struct sk_buff *skb, /* Create expect for T.120 connections */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, - ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, IPPROTO_TCP, NULL, &port); @@ -634,18 +630,17 @@ int get_h225_addr(struct nf_conn *ct, unsigned char *data, union nf_inet_addr *addr, __be16 *port) { const unsigned char *p; - int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; int len; switch (taddr->choice) { case eTransportAddress_ipAddress: - if (family != AF_INET) + if (nf_ct_l3num(ct) != AF_INET) return 0; p = data + taddr->ipAddress.ip; len = 4; break; case eTransportAddress_ip6Address: - if (family != AF_INET6) + if (nf_ct_l3num(ct) != AF_INET6) return 0; p = data + taddr->ip6Address.ip; len = 16; @@ -683,8 +678,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct, /* Create expect for h245 connection */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, - ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, IPPROTO_TCP, NULL, &port); @@ -792,7 +786,7 @@ static int expect_callforwarding(struct sk_buff *skb, * we don't need to track the second call */ if (callforward_filter && callforward_do_filter(&addr, &ct->tuplehash[!dir].tuple.src.u3, - ct->tuplehash[!dir].tuple.src.l3num)) { + nf_ct_l3num(ct))) { pr_debug("nf_ct_q931: Call Forwarding not tracked\n"); return 0; } @@ -800,8 +794,7 @@ static int expect_callforwarding(struct sk_buff *skb, /* Create expect for the second call leg */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, - ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), &ct->tuplehash[!dir].tuple.src.u3, &addr, IPPROTO_TCP, NULL, &port); exp->helper = nf_conntrack_helper_q931; @@ -1272,8 +1265,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct, /* Create expect for Q.931 */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, - ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), gkrouted_only ? /* only accept calls from GK? */ &ct->tuplehash[!dir].tuple.src.u3 : NULL, &ct->tuplehash[!dir].tuple.dst.u3, @@ -1344,8 +1336,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct, /* Need new expect */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, - ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), &ct->tuplehash[!dir].tuple.src.u3, &addr, IPPROTO_UDP, NULL, &port); exp->helper = nf_conntrack_helper_ras; @@ -1549,8 +1540,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct, /* Need new expect */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, - ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), &ct->tuplehash[!dir].tuple.src.u3, &addr, IPPROTO_TCP, NULL, &port); exp->flags = NF_CT_EXPECT_PERMANENT; @@ -1603,8 +1593,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct, /* Need new expect for call signal */ if ((exp = nf_ct_expect_alloc(ct)) == NULL) return -1; - nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, - ct->tuplehash[!dir].tuple.src.l3num, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), &ct->tuplehash[!dir].tuple.src.u3, &addr, IPPROTO_TCP, NULL, &port); exp->flags = NF_CT_EXPECT_PERMANENT; diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 79d5ecde0ddc..16774ecd1c4e 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -145,10 +145,11 @@ nla_put_failure: static inline int ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct) { - struct nf_conntrack_l4proto *l4proto = nf_ct_l4proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); + struct nf_conntrack_l4proto *l4proto; struct nlattr *nest_proto; int ret; + l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct)); if (!l4proto->to_nlattr) { nf_ct_l4proto_put(l4proto); return 0; @@ -368,8 +369,7 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, nfmsg = NLMSG_DATA(nlh); nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; - nfmsg->nfgen_family = - ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + nfmsg->nfgen_family = nf_ct_l3num(ct); nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; @@ -454,7 +454,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, nfmsg = NLMSG_DATA(nlh); nlh->nlmsg_flags = flags; - nfmsg->nfgen_family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; + nfmsg->nfgen_family = nf_ct_l3num(ct); nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; @@ -535,8 +535,6 @@ static int ctnetlink_done(struct netlink_callback *cb) return 0; } -#define L3PROTO(ct) (ct)->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num - static int ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) { @@ -558,7 +556,7 @@ restart: /* Dump entries of a given L3 protocol number. * If it is not specified, ie. l3proto == 0, * then dump everything. */ - if (l3proto && L3PROTO(ct) != l3proto) + if (l3proto && nf_ct_l3num(ct) != l3proto) continue; if (cb->args[1]) { if (ct != last) @@ -704,7 +702,7 @@ static int nfnetlink_parse_nat_proto(struct nlattr *attr, if (err < 0) return err; - npt = nf_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); + npt = nf_nat_proto_find_get(nf_ct_protonum(ct)); if (npt->nlattr_to_range) err = npt->nlattr_to_range(tb, range); nf_nat_proto_put(npt); @@ -1001,14 +999,11 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[]) { struct nlattr *tb[CTA_PROTOINFO_MAX+1], *attr = cda[CTA_PROTOINFO]; struct nf_conntrack_l4proto *l4proto; - u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; - u_int16_t l3num = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; int err = 0; nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, NULL); - l4proto = nf_ct_l4proto_find_get(l3num, npt); - + l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct)); if (l4proto->from_nlattr) err = l4proto->from_nlattr(tb, ct); nf_ct_l4proto_put(l4proto); diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c index 8fd83470d1b3..4793cc078789 100644 --- a/net/netfilter/nf_conntrack_pptp.c +++ b/net/netfilter/nf_conntrack_pptp.c @@ -209,7 +209,7 @@ static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid) /* original direction, PNS->PAC */ dir = IP_CT_DIR_ORIGINAL; nf_ct_expect_init(exp_orig, NF_CT_EXPECT_CLASS_DEFAULT, - ct->tuplehash[dir].tuple.src.l3num, + nf_ct_l3num(ct), &ct->tuplehash[dir].tuple.src.u3, &ct->tuplehash[dir].tuple.dst.u3, IPPROTO_GRE, &peer_callid, &callid); @@ -218,7 +218,7 @@ static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid) /* reply direction, PAC->PNS */ dir = IP_CT_DIR_REPLY; nf_ct_expect_init(exp_reply, NF_CT_EXPECT_CLASS_DEFAULT, - ct->tuplehash[dir].tuple.src.l3num, + nf_ct_l3num(ct), &ct->tuplehash[dir].tuple.src.u3, &ct->tuplehash[dir].tuple.dst.u3, IPPROTO_GRE, &callid, &peer_callid); diff --git a/net/netfilter/nf_conntrack_proto.c b/net/netfilter/nf_conntrack_proto.c index 8595b5946acf..a49fc932629b 100644 --- a/net/netfilter/nf_conntrack_proto.c +++ b/net/netfilter/nf_conntrack_proto.c @@ -146,18 +146,15 @@ EXPORT_SYMBOL_GPL(nf_ct_l3proto_module_put); static int kill_l3proto(struct nf_conn *i, void *data) { - return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num == - ((struct nf_conntrack_l3proto *)data)->l3proto); + return nf_ct_l3num(i) == ((struct nf_conntrack_l3proto *)data)->l3proto; } static int kill_l4proto(struct nf_conn *i, void *data) { struct nf_conntrack_l4proto *l4proto; l4proto = (struct nf_conntrack_l4proto *)data; - return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == - l4proto->l4proto) && - (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num == - l4proto->l3proto); + return nf_ct_protonum(i) == l4proto->l4proto && + nf_ct_l3num(i) == l4proto->l3proto; } static int nf_ct_l3proto_register_sysctl(struct nf_conntrack_l3proto *l3proto) diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index db88c5bcc5fd..9376dcd394bd 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -418,7 +418,6 @@ static int dccp_invert_tuple(struct nf_conntrack_tuple *inv, static int dccp_new(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff) { - int pf = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; struct dccp_hdr _dh, *dh; const char *msg; u_int8_t state; @@ -447,7 +446,7 @@ static int dccp_new(struct nf_conn *ct, const struct sk_buff *skb, out_invalid: if (LOG_INVALID(IPPROTO_DCCP)) - nf_log_packet(pf, 0, skb, NULL, NULL, NULL, msg); + nf_log_packet(nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL, msg); return 0; } diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c index 7542e25eede3..c3d5e84dcc9b 100644 --- a/net/netfilter/nf_conntrack_sane.c +++ b/net/netfilter/nf_conntrack_sane.c @@ -72,7 +72,6 @@ static int help(struct sk_buff *skb, struct nf_conntrack_tuple *tuple; struct sane_request *req; struct sane_reply_net_start *reply; - int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; ct_sane_info = &nfct_help(ct)->help.ct_sane_info; /* Until there's been traffic both ways, don't look in packets. */ @@ -143,7 +142,7 @@ static int help(struct sk_buff *skb, } tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; - nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), &tuple->src.u3, &tuple->dst.u3, IPPROTO_TCP, NULL, &reply->port); diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index f3915f8724f9..65b3ba57a3b7 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -142,11 +142,10 @@ static int parse_addr(const struct nf_conn *ct, const char *cp, const char *limit) { const char *end; - int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; int ret = 0; memset(addr, 0, sizeof(*addr)); - switch (family) { + switch (nf_ct_l3num(ct)) { case AF_INET: ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); break; @@ -740,7 +739,6 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); union nf_inet_addr *saddr; struct nf_conntrack_tuple tuple; - int family = ct->tuplehash[!dir].tuple.src.l3num; int direct_rtp = 0, skip_expect = 0, ret = NF_DROP; u_int16_t base_port; __be16 rtp_port, rtcp_port; @@ -770,7 +768,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, memset(&tuple, 0, sizeof(tuple)); if (saddr) tuple.src.u3 = *saddr; - tuple.src.l3num = family; + tuple.src.l3num = nf_ct_l3num(ct); tuple.dst.protonum = IPPROTO_UDP; tuple.dst.u3 = *daddr; tuple.dst.u.udp.port = port; @@ -815,13 +813,13 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, rtp_exp = nf_ct_expect_alloc(ct); if (rtp_exp == NULL) goto err1; - nf_ct_expect_init(rtp_exp, class, family, saddr, daddr, + nf_ct_expect_init(rtp_exp, class, nf_ct_l3num(ct), saddr, daddr, IPPROTO_UDP, NULL, &rtp_port); rtcp_exp = nf_ct_expect_alloc(ct); if (rtcp_exp == NULL) goto err2; - nf_ct_expect_init(rtcp_exp, class, family, saddr, daddr, + nf_ct_expect_init(rtcp_exp, class, nf_ct_l3num(ct), saddr, daddr, IPPROTO_UDP, NULL, &rtcp_port); nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); @@ -871,7 +869,6 @@ static int process_sdp(struct sk_buff *skb, { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); - int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; unsigned int matchoff, matchlen; unsigned int mediaoff, medialen; unsigned int sdpoff; @@ -886,8 +883,8 @@ static int process_sdp(struct sk_buff *skb, typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session; nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook); - c_hdr = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : - SDP_HDR_CONNECTION_IP6; + c_hdr = nf_ct_l3num(ct) == AF_INET ? SDP_HDR_CONNECTION_IP4 : + SDP_HDR_CONNECTION_IP6; /* Find beginning of session description */ if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, @@ -1034,7 +1031,6 @@ static int process_register_request(struct sk_buff *skb, struct nf_conn *ct = nf_ct_get(skb, &ctinfo); struct nf_conn_help *help = nfct_help(ct); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; unsigned int matchoff, matchlen; struct nf_conntrack_expect *exp; union nf_inet_addr *saddr, daddr; @@ -1089,8 +1085,8 @@ static int process_register_request(struct sk_buff *skb, if (sip_direct_signalling) saddr = &ct->tuplehash[!dir].tuple.src.u3; - nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, family, saddr, &daddr, - IPPROTO_UDP, NULL, &port); + nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), + saddr, &daddr, IPPROTO_UDP, NULL, &port); exp->timeout.expires = sip_timeout * HZ; exp->helper = nfct_help(ct)->helper; exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 01d1f7e178f3..b59871f6bdda 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -127,21 +127,14 @@ static int ct_seq_show(struct seq_file *s, void *v) if (NF_CT_DIRECTION(hash)) return 0; - l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL] - .tuple.src.l3num); - + l3proto = __nf_ct_l3proto_find(nf_ct_l3num(ct)); NF_CT_ASSERT(l3proto); - l4proto = __nf_ct_l4proto_find(ct->tuplehash[IP_CT_DIR_ORIGINAL] - .tuple.src.l3num, - ct->tuplehash[IP_CT_DIR_ORIGINAL] - .tuple.dst.protonum); + l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); NF_CT_ASSERT(l4proto); if (seq_printf(s, "%-8s %u %-8s %u %ld ", - l3proto->name, - ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num, - l4proto->name, - ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum, + l3proto->name, nf_ct_l3num(ct), + l4proto->name, nf_ct_protonum(ct), timer_pending(&ct->timeout) ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0) return -ENOSPC; diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c index a28341b30f21..ea5ff49d77bc 100644 --- a/net/netfilter/nf_conntrack_tftp.c +++ b/net/netfilter/nf_conntrack_tftp.c @@ -44,7 +44,6 @@ static int tftp_help(struct sk_buff *skb, struct nf_conntrack_expect *exp; struct nf_conntrack_tuple *tuple; unsigned int ret = NF_ACCEPT; - int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; typeof(nf_nat_tftp_hook) nf_nat_tftp; tfh = skb_header_pointer(skb, protoff + sizeof(struct udphdr), @@ -63,7 +62,8 @@ static int tftp_help(struct sk_buff *skb, if (exp == NULL) return NF_DROP; tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; - nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family, + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, + nf_ct_l3num(ct), &tuple->src.u3, &tuple->dst.u3, IPPROTO_UDP, NULL, &tuple->dst.u.udp.port); diff --git a/net/netfilter/xt_connlimit.c b/net/netfilter/xt_connlimit.c index 0ca9fe9da203..2e89a00df92c 100644 --- a/net/netfilter/xt_connlimit.c +++ b/net/netfilter/xt_connlimit.c @@ -72,9 +72,7 @@ connlimit_iphash6(const union nf_inet_addr *addr, static inline bool already_closed(const struct nf_conn *conn) { - u_int16_t proto = conn->tuplehash[0].tuple.dst.protonum; - - if (proto == IPPROTO_TCP) + if (nf_ct_protonum(conn) == IPPROTO_TCP) return conn->proto.tcp.state == TCP_CONNTRACK_TIME_WAIT; else return 0; diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index 0c50b2894055..d61412f58ef7 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c @@ -65,7 +65,7 @@ conntrack_mt_v0(const struct sk_buff *skb, const struct net_device *in, } if (sinfo->flags & XT_CONNTRACK_PROTO && - FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != + FWINV(nf_ct_protonum(ct) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, XT_CONNTRACK_PROTO)) return false; @@ -174,7 +174,7 @@ ct_proto_port_check(const struct xt_conntrack_mtinfo1 *info, tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; if ((info->match_flags & XT_CONNTRACK_PROTO) && - (tuple->dst.protonum == info->l4proto) ^ + (nf_ct_protonum(ct) == info->l4proto) ^ !(info->invert_flags & XT_CONNTRACK_PROTO)) return false; -- cgit v1.2.3-59-g8ed1b From 8ce8439a31f723f3aa28adf27fe8797a5678dde1 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:52 +0200 Subject: [NETFILTER]: nf_conntrack: use bool type in struct nf_conntrack_l3proto Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_conntrack_l3proto.h | 8 ++++---- net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | 14 +++++++------- net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 14 +++++++------- net/netfilter/nf_conntrack_l3proto_generic.c | 12 ++++++------ 4 files changed, 24 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h index db0825803b16..0378676c3dd8 100644 --- a/include/net/netfilter/nf_conntrack_l3proto.h +++ b/include/net/netfilter/nf_conntrack_l3proto.h @@ -28,15 +28,15 @@ struct nf_conntrack_l3proto * Try to fill in the third arg: nhoff is offset of l3 proto * hdr. Return true if possible. */ - int (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int nhoff, - struct nf_conntrack_tuple *tuple); + bool (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int nhoff, + struct nf_conntrack_tuple *tuple); /* * Invert the per-proto part of the tuple: ie. turn xmit into reply. * Some packets can't be inverted: return 0 in that case. */ - int (*invert_tuple)(struct nf_conntrack_tuple *inverse, - const struct nf_conntrack_tuple *orig); + bool (*invert_tuple)(struct nf_conntrack_tuple *inverse, + const struct nf_conntrack_tuple *orig); /* Print out the per-protocol part of the tuple. */ int (*print_tuple)(struct seq_file *s, diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 41e79613eb0a..cacb9cb27dab 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -30,29 +30,29 @@ int (*nf_nat_seq_adjust_hook)(struct sk_buff *skb, enum ip_conntrack_info ctinfo); EXPORT_SYMBOL_GPL(nf_nat_seq_adjust_hook); -static int ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, - struct nf_conntrack_tuple *tuple) +static bool ipv4_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, + struct nf_conntrack_tuple *tuple) { const __be32 *ap; __be32 _addrs[2]; ap = skb_header_pointer(skb, nhoff + offsetof(struct iphdr, saddr), sizeof(u_int32_t) * 2, _addrs); if (ap == NULL) - return 0; + return false; tuple->src.u3.ip = ap[0]; tuple->dst.u3.ip = ap[1]; - return 1; + return true; } -static int ipv4_invert_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_tuple *orig) +static bool ipv4_invert_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig) { tuple->src.u3.ip = orig->dst.u3.ip; tuple->dst.u3.ip = orig->src.u3.ip; - return 1; + return true; } static int ipv4_print_tuple(struct seq_file *s, diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 3717bdf34f6e..85050c072abd 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -27,8 +27,8 @@ #include #include -static int ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, - struct nf_conntrack_tuple *tuple) +static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, + struct nf_conntrack_tuple *tuple) { const u_int32_t *ap; u_int32_t _addrs[8]; @@ -36,21 +36,21 @@ static int ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, ap = skb_header_pointer(skb, nhoff + offsetof(struct ipv6hdr, saddr), sizeof(_addrs), _addrs); if (ap == NULL) - return 0; + return false; memcpy(tuple->src.u3.ip6, ap, sizeof(tuple->src.u3.ip6)); memcpy(tuple->dst.u3.ip6, ap + 4, sizeof(tuple->dst.u3.ip6)); - return 1; + return true; } -static int ipv6_invert_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_tuple *orig) +static bool ipv6_invert_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig) { memcpy(tuple->src.u3.ip6, orig->dst.u3.ip6, sizeof(tuple->src.u3.ip6)); memcpy(tuple->dst.u3.ip6, orig->src.u3.ip6, sizeof(tuple->dst.u3.ip6)); - return 1; + return true; } static int ipv6_print_tuple(struct seq_file *s, diff --git a/net/netfilter/nf_conntrack_l3proto_generic.c b/net/netfilter/nf_conntrack_l3proto_generic.c index 8e914e5ffea8..e7eb807fe07d 100644 --- a/net/netfilter/nf_conntrack_l3proto_generic.c +++ b/net/netfilter/nf_conntrack_l3proto_generic.c @@ -31,22 +31,22 @@ #include #include -static int generic_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, - struct nf_conntrack_tuple *tuple) +static bool generic_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, + struct nf_conntrack_tuple *tuple) { memset(&tuple->src.u3, 0, sizeof(tuple->src.u3)); memset(&tuple->dst.u3, 0, sizeof(tuple->dst.u3)); - return 1; + return true; } -static int generic_invert_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_tuple *orig) +static bool generic_invert_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig) { memset(&tuple->src.u3, 0, sizeof(tuple->src.u3)); memset(&tuple->dst.u3, 0, sizeof(tuple->dst.u3)); - return 1; + return true; } static int generic_print_tuple(struct seq_file *s, -- cgit v1.2.3-59-g8ed1b From 09f263cd39751cada63dec2dccc71e67c00bc38c Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:53 +0200 Subject: [NETFILTER]: nf_conntrack: use bool type in struct nf_conntrack_l4proto Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_conntrack_l4proto.h | 13 +++---- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 25 ++++++------- net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 27 +++++++------ net/netfilter/nf_conntrack_proto_dccp.c | 22 +++++------ net/netfilter/nf_conntrack_proto_generic.c | 20 +++++----- net/netfilter/nf_conntrack_proto_gre.c | 25 ++++++------- net/netfilter/nf_conntrack_proto_sctp.c | 33 ++++++++-------- net/netfilter/nf_conntrack_proto_tcp.c | 52 +++++++++++++------------- net/netfilter/nf_conntrack_proto_udp.c | 18 ++++----- net/netfilter/nf_conntrack_proto_udplite.c | 22 +++++------ 10 files changed, 125 insertions(+), 132 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index efc16eccddb1..723df9d1cc35 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -25,15 +25,14 @@ struct nf_conntrack_l4proto /* Try to fill in the third arg: dataoff is offset past network protocol hdr. Return true if possible. */ - int (*pkt_to_tuple)(const struct sk_buff *skb, - unsigned int dataoff, - struct nf_conntrack_tuple *tuple); + bool (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int dataoff, + struct nf_conntrack_tuple *tuple); /* Invert the per-proto part of the tuple: ie. turn xmit into reply. * Some packets can't be inverted: return 0 in that case. */ - int (*invert_tuple)(struct nf_conntrack_tuple *inverse, - const struct nf_conntrack_tuple *orig); + bool (*invert_tuple)(struct nf_conntrack_tuple *inverse, + const struct nf_conntrack_tuple *orig); /* Returns verdict for packet, or -1 for invalid. */ int (*packet)(struct nf_conn *ct, @@ -45,8 +44,8 @@ struct nf_conntrack_l4proto /* Called when a new connection for this protocol found; * returns TRUE if it's OK. If so, packet() called next. */ - int (*new)(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff); + bool (*new)(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff); /* Called when a conntrack entry is destroyed */ void (*destroy)(struct nf_conn *ct); diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 6873fddb3529..193a845fe7f8 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -22,22 +22,21 @@ static unsigned long nf_ct_icmp_timeout __read_mostly = 30*HZ; -static int icmp_pkt_to_tuple(const struct sk_buff *skb, - unsigned int dataoff, - struct nf_conntrack_tuple *tuple) +static bool icmp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, + struct nf_conntrack_tuple *tuple) { const struct icmphdr *hp; struct icmphdr _hdr; hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); if (hp == NULL) - return 0; + return false; tuple->dst.u.icmp.type = hp->type; tuple->src.u.icmp.id = hp->un.echo.id; tuple->dst.u.icmp.code = hp->code; - return 1; + return true; } /* Add 1; spaces filled with 0. */ @@ -52,17 +51,17 @@ static const u_int8_t invmap[] = { [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1 }; -static int icmp_invert_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_tuple *orig) +static bool icmp_invert_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig) { if (orig->dst.u.icmp.type >= sizeof(invmap) || !invmap[orig->dst.u.icmp.type]) - return 0; + return false; tuple->src.u.icmp.id = orig->src.u.icmp.id; tuple->dst.u.icmp.type = invmap[orig->dst.u.icmp.type] - 1; tuple->dst.u.icmp.code = orig->dst.u.icmp.code; - return 1; + return true; } /* Print out the per-protocol part of the tuple. */ @@ -101,8 +100,8 @@ static int icmp_packet(struct nf_conn *ct, } /* Called when a new connection for this protocol found. */ -static int icmp_new(struct nf_conn *ct, - const struct sk_buff *skb, unsigned int dataoff) +static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff) { static const u_int8_t valid_new[] = { [ICMP_ECHO] = 1, @@ -117,10 +116,10 @@ static int icmp_new(struct nf_conn *ct, pr_debug("icmp: can't create new conn with type %u\n", ct->tuplehash[0].tuple.dst.u.icmp.type); NF_CT_DUMP_TUPLE(&ct->tuplehash[0].tuple); - return 0; + return false; } atomic_set(&ct->proto.icmp.count, 0); - return 1; + return true; } /* Returns conntrack if it dealt with ICMP, and filled in skb fields */ diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 0897d0f4c4a2..9ad40e0e17fc 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -28,21 +28,21 @@ static unsigned long nf_ct_icmpv6_timeout __read_mostly = 30*HZ; -static int icmpv6_pkt_to_tuple(const struct sk_buff *skb, - unsigned int dataoff, - struct nf_conntrack_tuple *tuple) +static bool icmpv6_pkt_to_tuple(const struct sk_buff *skb, + unsigned int dataoff, + struct nf_conntrack_tuple *tuple) { const struct icmp6hdr *hp; struct icmp6hdr _hdr; hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); if (hp == NULL) - return 0; + return false; tuple->dst.u.icmp.type = hp->icmp6_type; tuple->src.u.icmp.id = hp->icmp6_identifier; tuple->dst.u.icmp.code = hp->icmp6_code; - return 1; + return true; } /* Add 1; spaces filled with 0. */ @@ -53,17 +53,17 @@ static const u_int8_t invmap[] = { [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1 }; -static int icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_tuple *orig) +static bool icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig) { int type = orig->dst.u.icmp.type - 128; if (type < 0 || type >= sizeof(invmap) || !invmap[type]) - return 0; + return false; tuple->src.u.icmp.id = orig->src.u.icmp.id; tuple->dst.u.icmp.type = invmap[type] - 1; tuple->dst.u.icmp.code = orig->dst.u.icmp.code; - return 1; + return true; } /* Print out the per-protocol part of the tuple. */ @@ -102,9 +102,8 @@ static int icmpv6_packet(struct nf_conn *ct, } /* Called when a new connection for this protocol found. */ -static int icmpv6_new(struct nf_conn *ct, - const struct sk_buff *skb, - unsigned int dataoff) +static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff) { static const u_int8_t valid_new[] = { [ICMPV6_ECHO_REQUEST - 128] = 1, @@ -117,10 +116,10 @@ static int icmpv6_new(struct nf_conn *ct, pr_debug("icmpv6: can't create new conn with type %u\n", type + 128); NF_CT_DUMP_TUPLE(&ct->tuplehash[0].tuple); - return 0; + return false; } atomic_set(&ct->proto.icmp.count, 0); - return 1; + return true; } static int diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c index 9376dcd394bd..afb4a1861d2c 100644 --- a/net/netfilter/nf_conntrack_proto_dccp.c +++ b/net/netfilter/nf_conntrack_proto_dccp.c @@ -393,30 +393,30 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = }, }; -static int dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, - struct nf_conntrack_tuple *tuple) +static bool dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, + struct nf_conntrack_tuple *tuple) { struct dccp_hdr _hdr, *dh; dh = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); if (dh == NULL) - return 0; + return false; tuple->src.u.dccp.port = dh->dccph_sport; tuple->dst.u.dccp.port = dh->dccph_dport; - return 1; + return true; } -static int dccp_invert_tuple(struct nf_conntrack_tuple *inv, - const struct nf_conntrack_tuple *tuple) +static bool dccp_invert_tuple(struct nf_conntrack_tuple *inv, + const struct nf_conntrack_tuple *tuple) { inv->src.u.dccp.port = tuple->dst.u.dccp.port; inv->dst.u.dccp.port = tuple->src.u.dccp.port; - return 1; + return true; } -static int dccp_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) +static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff) { struct dccp_hdr _dh, *dh; const char *msg; @@ -442,12 +442,12 @@ static int dccp_new(struct nf_conn *ct, const struct sk_buff *skb, ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT; ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER; ct->proto.dccp.state = CT_DCCP_NONE; - return 1; + return true; out_invalid: if (LOG_INVALID(IPPROTO_DCCP)) nf_log_packet(nf_ct_l3num(ct), 0, skb, NULL, NULL, NULL, msg); - return 0; + return false; } static u64 dccp_ack_seq(const struct dccp_hdr *dh) diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index 55458915575f..e31b0e7bd0b1 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c @@ -14,23 +14,23 @@ static unsigned int nf_ct_generic_timeout __read_mostly = 600*HZ; -static int generic_pkt_to_tuple(const struct sk_buff *skb, - unsigned int dataoff, - struct nf_conntrack_tuple *tuple) +static bool generic_pkt_to_tuple(const struct sk_buff *skb, + unsigned int dataoff, + struct nf_conntrack_tuple *tuple) { tuple->src.u.all = 0; tuple->dst.u.all = 0; - return 1; + return true; } -static int generic_invert_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_tuple *orig) +static bool generic_invert_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig) { tuple->src.u.all = 0; tuple->dst.u.all = 0; - return 1; + return true; } /* Print out the per-protocol part of the tuple. */ @@ -53,10 +53,10 @@ static int packet(struct nf_conn *ct, } /* Called when a new connection for this protocol found. */ -static int new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) +static bool new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff) { - return 1; + return true; } #ifdef CONFIG_SYSCTL diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index e10024a1b666..7d37a2ea67b2 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -148,18 +148,17 @@ EXPORT_SYMBOL_GPL(nf_ct_gre_keymap_destroy); /* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ /* invert gre part of tuple */ -static int gre_invert_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_tuple *orig) +static bool gre_invert_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig) { tuple->dst.u.gre.key = orig->src.u.gre.key; tuple->src.u.gre.key = orig->dst.u.gre.key; - return 1; + return true; } /* gre hdr info to tuple */ -static int gre_pkt_to_tuple(const struct sk_buff *skb, - unsigned int dataoff, - struct nf_conntrack_tuple *tuple) +static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, + struct nf_conntrack_tuple *tuple) { const struct gre_hdr_pptp *pgrehdr; struct gre_hdr_pptp _pgrehdr; @@ -173,24 +172,24 @@ static int gre_pkt_to_tuple(const struct sk_buff *skb, /* try to behave like "nf_conntrack_proto_generic" */ tuple->src.u.all = 0; tuple->dst.u.all = 0; - return 1; + return true; } /* PPTP header is variable length, only need up to the call_id field */ pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr); if (!pgrehdr) - return 1; + return true; if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) { pr_debug("GRE_VERSION_PPTP but unknown proto\n"); - return 0; + return false; } tuple->dst.u.gre.key = pgrehdr->call_id; srckey = gre_keymap_lookup(tuple); tuple->src.u.gre.key = srckey; - return 1; + return true; } /* print gre part of tuple */ @@ -235,8 +234,8 @@ static int gre_packet(struct nf_conn *ct, } /* Called when a new connection for this protocol found. */ -static int gre_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) +static bool gre_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff) { pr_debug(": "); NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); @@ -246,7 +245,7 @@ static int gre_new(struct nf_conn *ct, const struct sk_buff *skb, ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; ct->proto.gre.timeout = GRE_TIMEOUT; - return 1; + return true; } /* Called when a conntrack entry has already been removed from the hashes diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index f9a08370dbb3..2d47351f70dc 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -130,28 +130,27 @@ static const u8 sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = { } }; -static int sctp_pkt_to_tuple(const struct sk_buff *skb, - unsigned int dataoff, - struct nf_conntrack_tuple *tuple) +static bool sctp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, + struct nf_conntrack_tuple *tuple) { sctp_sctphdr_t _hdr, *hp; /* Actually only need first 8 bytes. */ hp = skb_header_pointer(skb, dataoff, 8, &_hdr); if (hp == NULL) - return 0; + return false; tuple->src.u.sctp.port = hp->source; tuple->dst.u.sctp.port = hp->dest; - return 1; + return true; } -static int sctp_invert_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_tuple *orig) +static bool sctp_invert_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig) { tuple->src.u.sctp.port = orig->dst.u.sctp.port; tuple->dst.u.sctp.port = orig->src.u.sctp.port; - return 1; + return true; } /* Print out the per-protocol part of the tuple. */ @@ -390,8 +389,8 @@ out: } /* Called when a new connection for this protocol found. */ -static int sctp_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) +static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff) { enum sctp_conntrack new_state; sctp_sctphdr_t _sctph, *sh; @@ -401,16 +400,16 @@ static int sctp_new(struct nf_conn *ct, const struct sk_buff *skb, sh = skb_header_pointer(skb, dataoff, sizeof(_sctph), &_sctph); if (sh == NULL) - return 0; + return false; if (do_basic_checks(ct, skb, dataoff, map) != 0) - return 0; + return false; /* If an OOTB packet has any of these chunks discard (Sec 8.4) */ if (test_bit(SCTP_CID_ABORT, map) || test_bit(SCTP_CID_SHUTDOWN_COMPLETE, map) || test_bit(SCTP_CID_COOKIE_ACK, map)) - return 0; + return false; new_state = SCTP_CONNTRACK_MAX; for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { @@ -422,7 +421,7 @@ static int sctp_new(struct nf_conn *ct, const struct sk_buff *skb, if (new_state == SCTP_CONNTRACK_NONE || new_state == SCTP_CONNTRACK_MAX) { pr_debug("nf_conntrack_sctp: invalid new deleting.\n"); - return 0; + return false; } /* Copy the vtag into the state info */ @@ -433,7 +432,7 @@ static int sctp_new(struct nf_conn *ct, const struct sk_buff *skb, ih = skb_header_pointer(skb, offset + sizeof(sctp_chunkhdr_t), sizeof(_inithdr), &_inithdr); if (ih == NULL) - return 0; + return false; pr_debug("Setting vtag %x for new conn\n", ih->init_tag); @@ -442,7 +441,7 @@ static int sctp_new(struct nf_conn *ct, const struct sk_buff *skb, ih->init_tag; } else { /* Sec 8.5.1 (A) */ - return 0; + return false; } } /* If it is a shutdown ack OOTB packet, we expect a return @@ -456,7 +455,7 @@ static int sctp_new(struct nf_conn *ct, const struct sk_buff *skb, ct->proto.sctp.state = new_state; } - return 1; + return true; } #ifdef CONFIG_SYSCTL diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 57831c75fa9f..73a8b32db7be 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -257,9 +257,8 @@ static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { } }; -static int tcp_pkt_to_tuple(const struct sk_buff *skb, - unsigned int dataoff, - struct nf_conntrack_tuple *tuple) +static bool tcp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, + struct nf_conntrack_tuple *tuple) { const struct tcphdr *hp; struct tcphdr _hdr; @@ -267,20 +266,20 @@ static int tcp_pkt_to_tuple(const struct sk_buff *skb, /* Actually only need first 8 bytes. */ hp = skb_header_pointer(skb, dataoff, 8, &_hdr); if (hp == NULL) - return 0; + return false; tuple->src.u.tcp.port = hp->source; tuple->dst.u.tcp.port = hp->dest; - return 1; + return true; } -static int tcp_invert_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_tuple *orig) +static bool tcp_invert_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig) { tuple->src.u.tcp.port = orig->dst.u.tcp.port; tuple->dst.u.tcp.port = orig->src.u.tcp.port; - return 1; + return true; } /* Print out the per-protocol part of the tuple. */ @@ -478,20 +477,20 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff, } } -static int tcp_in_window(const struct nf_conn *ct, - struct ip_ct_tcp *state, - enum ip_conntrack_dir dir, - unsigned int index, - const struct sk_buff *skb, - unsigned int dataoff, - const struct tcphdr *tcph, - int pf) +static bool tcp_in_window(const struct nf_conn *ct, + struct ip_ct_tcp *state, + enum ip_conntrack_dir dir, + unsigned int index, + const struct sk_buff *skb, + unsigned int dataoff, + const struct tcphdr *tcph, + int pf) { struct ip_ct_tcp_state *sender = &state->seen[dir]; struct ip_ct_tcp_state *receiver = &state->seen[!dir]; const struct nf_conntrack_tuple *tuple = &ct->tuplehash[dir].tuple; __u32 seq, ack, sack, end, win, swin; - int res; + bool res; /* * Get the required data from the packet. @@ -657,12 +656,12 @@ static int tcp_in_window(const struct nf_conn *ct, state->retrans = 0; } } - res = 1; + res = true; } else { - res = 0; + res = false; if (sender->flags & IP_CT_TCP_FLAG_BE_LIBERAL || nf_ct_tcp_be_liberal) - res = 1; + res = true; if (!res && LOG_INVALID(IPPROTO_TCP)) nf_log_packet(pf, 0, skb, NULL, NULL, NULL, "nf_ct_tcp: %s ", @@ -676,7 +675,7 @@ static int tcp_in_window(const struct nf_conn *ct, : "SEQ is over the upper bound (over the window of the receiver)"); } - pr_debug("tcp_in_window: res=%i sender end=%u maxend=%u maxwin=%u " + pr_debug("tcp_in_window: res=%u sender end=%u maxend=%u maxwin=%u " "receiver end=%u maxend=%u maxwin=%u\n", res, sender->td_end, sender->td_maxend, sender->td_maxwin, receiver->td_end, receiver->td_maxend, receiver->td_maxwin); @@ -982,9 +981,8 @@ static int tcp_packet(struct nf_conn *ct, } /* Called when a new connection for this protocol found. */ -static int tcp_new(struct nf_conn *ct, - const struct sk_buff *skb, - unsigned int dataoff) +static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff) { enum tcp_conntrack new_state; const struct tcphdr *th; @@ -1003,7 +1001,7 @@ static int tcp_new(struct nf_conn *ct, /* Invalid: delete conntrack */ if (new_state >= TCP_CONNTRACK_MAX) { pr_debug("nf_ct_tcp: invalid new deleting.\n"); - return 0; + return false; } if (new_state == TCP_CONNTRACK_SYN_SENT) { @@ -1021,7 +1019,7 @@ static int tcp_new(struct nf_conn *ct, ct->proto.tcp.seen[1].flags = 0; } else if (nf_ct_tcp_loose == 0) { /* Don't try to pick up connections. */ - return 0; + return false; } else { /* * We are in the middle of a connection, @@ -1061,7 +1059,7 @@ static int tcp_new(struct nf_conn *ct, sender->td_scale, receiver->td_end, receiver->td_maxend, receiver->td_maxwin, receiver->td_scale); - return 1; + return true; } #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index b8a35cc06416..8b21762e65de 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -26,7 +26,7 @@ static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ; static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ; -static int udp_pkt_to_tuple(const struct sk_buff *skb, +static bool udp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, struct nf_conntrack_tuple *tuple) { @@ -36,20 +36,20 @@ static int udp_pkt_to_tuple(const struct sk_buff *skb, /* Actually only need first 8 bytes. */ hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); if (hp == NULL) - return 0; + return false; tuple->src.u.udp.port = hp->source; tuple->dst.u.udp.port = hp->dest; - return 1; + return true; } -static int udp_invert_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_tuple *orig) +static bool udp_invert_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig) { tuple->src.u.udp.port = orig->dst.u.udp.port; tuple->dst.u.udp.port = orig->src.u.udp.port; - return 1; + return true; } /* Print out the per-protocol part of the tuple. */ @@ -83,10 +83,10 @@ static int udp_packet(struct nf_conn *ct, } /* Called when a new connection for this protocol found. */ -static int udp_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) +static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff) { - return 1; + return true; } static int udp_error(struct sk_buff *skb, unsigned int dataoff, diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index c3eaee6afffd..1fa62f3c24f1 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c @@ -27,28 +27,28 @@ static unsigned int nf_ct_udplite_timeout __read_mostly = 30*HZ; static unsigned int nf_ct_udplite_timeout_stream __read_mostly = 180*HZ; -static int udplite_pkt_to_tuple(const struct sk_buff *skb, - unsigned int dataoff, - struct nf_conntrack_tuple *tuple) +static bool udplite_pkt_to_tuple(const struct sk_buff *skb, + unsigned int dataoff, + struct nf_conntrack_tuple *tuple) { const struct udphdr *hp; struct udphdr _hdr; hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); if (hp == NULL) - return 0; + return false; tuple->src.u.udp.port = hp->source; tuple->dst.u.udp.port = hp->dest; - return 1; + return true; } -static int udplite_invert_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_tuple *orig) +static bool udplite_invert_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple *orig) { tuple->src.u.udp.port = orig->dst.u.udp.port; tuple->dst.u.udp.port = orig->src.u.udp.port; - return 1; + return true; } /* Print out the per-protocol part of the tuple. */ @@ -83,10 +83,10 @@ static int udplite_packet(struct nf_conn *ct, } /* Called when a new connection for this protocol found. */ -static int udplite_new(struct nf_conn *ct, const struct sk_buff *skb, - unsigned int dataoff) +static bool udplite_new(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff) { - return 1; + return true; } static int udplite_error(struct sk_buff *skb, unsigned int dataoff, -- cgit v1.2.3-59-g8ed1b From 5f2b4c9006fc667c4614f0b079efab3721f68316 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:53 +0200 Subject: [NETFILTER]: nf_conntrack: use bool type in struct nf_conntrack_tuple.h Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_conntrack.h | 11 ++++----- include/net/netfilter/nf_conntrack_core.h | 4 +-- include/net/netfilter/nf_conntrack_tuple.h | 39 ++++++++++++++++-------------- net/netfilter/nf_conntrack_core.c | 22 ++++++++--------- 4 files changed, 38 insertions(+), 38 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 26e6a6e2b5a2..2dbd6c015b94 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -194,12 +194,11 @@ extern void nf_conntrack_hash_insert(struct nf_conn *ct); extern void nf_conntrack_flush(void); -extern int nf_ct_get_tuplepr(const struct sk_buff *skb, - unsigned int nhoff, - u_int16_t l3num, - struct nf_conntrack_tuple *tuple); -extern int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, - const struct nf_conntrack_tuple *orig); +extern bool nf_ct_get_tuplepr(const struct sk_buff *skb, + unsigned int nhoff, u_int16_t l3num, + struct nf_conntrack_tuple *tuple); +extern bool nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, + const struct nf_conntrack_tuple *orig); extern void __nf_ct_refresh_acct(struct nf_conn *ct, enum ip_conntrack_info ctinfo, diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h index 9ee26469c759..a81771210934 100644 --- a/include/net/netfilter/nf_conntrack_core.h +++ b/include/net/netfilter/nf_conntrack_core.h @@ -30,7 +30,7 @@ extern void nf_conntrack_cleanup(void); extern int nf_conntrack_proto_init(void); extern void nf_conntrack_proto_fini(void); -extern int +extern bool nf_ct_get_tuple(const struct sk_buff *skb, unsigned int nhoff, unsigned int dataoff, @@ -40,7 +40,7 @@ nf_ct_get_tuple(const struct sk_buff *skb, const struct nf_conntrack_l3proto *l3proto, const struct nf_conntrack_l4proto *l4proto); -extern int +extern bool nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, const struct nf_conntrack_tuple *orig, const struct nf_conntrack_l3proto *l3proto, diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h index bdeec3461384..2722b13ecd6c 100644 --- a/include/net/netfilter/nf_conntrack_tuple.h +++ b/include/net/netfilter/nf_conntrack_tuple.h @@ -166,61 +166,64 @@ struct nf_conntrack_tuple_hash #endif /* __KERNEL__ */ -static inline int __nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1, - const struct nf_conntrack_tuple *t2) +static inline bool __nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1, + const struct nf_conntrack_tuple *t2) { return (nf_inet_addr_cmp(&t1->src.u3, &t2->src.u3) && t1->src.u.all == t2->src.u.all && t1->src.l3num == t2->src.l3num); } -static inline int __nf_ct_tuple_dst_equal(const struct nf_conntrack_tuple *t1, - const struct nf_conntrack_tuple *t2) +static inline bool __nf_ct_tuple_dst_equal(const struct nf_conntrack_tuple *t1, + const struct nf_conntrack_tuple *t2) { return (nf_inet_addr_cmp(&t1->dst.u3, &t2->dst.u3) && t1->dst.u.all == t2->dst.u.all && t1->dst.protonum == t2->dst.protonum); } -static inline int nf_ct_tuple_equal(const struct nf_conntrack_tuple *t1, - const struct nf_conntrack_tuple *t2) +static inline bool nf_ct_tuple_equal(const struct nf_conntrack_tuple *t1, + const struct nf_conntrack_tuple *t2) { return __nf_ct_tuple_src_equal(t1, t2) && __nf_ct_tuple_dst_equal(t1, t2); } -static inline int nf_ct_tuple_mask_equal(const struct nf_conntrack_tuple_mask *m1, - const struct nf_conntrack_tuple_mask *m2) +static inline bool +nf_ct_tuple_mask_equal(const struct nf_conntrack_tuple_mask *m1, + const struct nf_conntrack_tuple_mask *m2) { return (nf_inet_addr_cmp(&m1->src.u3, &m2->src.u3) && m1->src.u.all == m2->src.u.all); } -static inline int nf_ct_tuple_src_mask_cmp(const struct nf_conntrack_tuple *t1, - const struct nf_conntrack_tuple *t2, - const struct nf_conntrack_tuple_mask *mask) +static inline bool +nf_ct_tuple_src_mask_cmp(const struct nf_conntrack_tuple *t1, + const struct nf_conntrack_tuple *t2, + const struct nf_conntrack_tuple_mask *mask) { int count; for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++) { if ((t1->src.u3.all[count] ^ t2->src.u3.all[count]) & mask->src.u3.all[count]) - return 0; + return false; } if ((t1->src.u.all ^ t2->src.u.all) & mask->src.u.all) - return 0; + return false; if (t1->src.l3num != t2->src.l3num || t1->dst.protonum != t2->dst.protonum) - return 0; + return false; - return 1; + return true; } -static inline int nf_ct_tuple_mask_cmp(const struct nf_conntrack_tuple *t, - const struct nf_conntrack_tuple *tuple, - const struct nf_conntrack_tuple_mask *mask) +static inline bool +nf_ct_tuple_mask_cmp(const struct nf_conntrack_tuple *t, + const struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple_mask *mask) { return nf_ct_tuple_src_mask_cmp(t, tuple, mask) && __nf_ct_tuple_dst_equal(t, tuple); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 21ab0c3846ac..a3fe9db412d3 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -94,7 +94,7 @@ static inline u_int32_t hash_conntrack(const struct nf_conntrack_tuple *tuple) nf_conntrack_hash_rnd); } -int +bool nf_ct_get_tuple(const struct sk_buff *skb, unsigned int nhoff, unsigned int dataoff, @@ -108,7 +108,7 @@ nf_ct_get_tuple(const struct sk_buff *skb, tuple->src.l3num = l3num; if (l3proto->pkt_to_tuple(skb, nhoff, tuple) == 0) - return 0; + return false; tuple->dst.protonum = protonum; tuple->dst.dir = IP_CT_DIR_ORIGINAL; @@ -117,10 +117,8 @@ nf_ct_get_tuple(const struct sk_buff *skb, } EXPORT_SYMBOL_GPL(nf_ct_get_tuple); -int nf_ct_get_tuplepr(const struct sk_buff *skb, - unsigned int nhoff, - u_int16_t l3num, - struct nf_conntrack_tuple *tuple) +bool nf_ct_get_tuplepr(const struct sk_buff *skb, unsigned int nhoff, + u_int16_t l3num, struct nf_conntrack_tuple *tuple) { struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; @@ -134,7 +132,7 @@ int nf_ct_get_tuplepr(const struct sk_buff *skb, ret = l3proto->get_l4proto(skb, nhoff, &protoff, &protonum); if (ret != NF_ACCEPT) { rcu_read_unlock(); - return 0; + return false; } l4proto = __nf_ct_l4proto_find(l3num, protonum); @@ -147,7 +145,7 @@ int nf_ct_get_tuplepr(const struct sk_buff *skb, } EXPORT_SYMBOL_GPL(nf_ct_get_tuplepr); -int +bool nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, const struct nf_conntrack_tuple *orig, const struct nf_conntrack_l3proto *l3proto, @@ -157,7 +155,7 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, inverse->src.l3num = orig->src.l3num; if (l3proto->invert_tuple(inverse, orig) == 0) - return 0; + return false; inverse->dst.dir = !orig->dst.dir; @@ -738,10 +736,10 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(nf_conntrack_in); -int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, - const struct nf_conntrack_tuple *orig) +bool nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, + const struct nf_conntrack_tuple *orig) { - int ret; + bool ret; rcu_read_lock(); ret = nf_ct_invert_tuple(inverse, orig, -- cgit v1.2.3-59-g8ed1b From f2ea825f483d5d78754ae813b6db63f8b74e9343 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:53 +0200 Subject: [NETFILTER]: nf_nat: use bool type in nf_nat_proto Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_nat_protocol.h | 42 +++++++++++++++---------------- net/ipv4/netfilter/nf_nat_core.c | 8 +++--- net/ipv4/netfilter/nf_nat_proto_common.c | 24 +++++++++--------- net/ipv4/netfilter/nf_nat_proto_dccp.c | 10 ++++---- net/ipv4/netfilter/nf_nat_proto_gre.c | 18 ++++++------- net/ipv4/netfilter/nf_nat_proto_icmp.c | 14 +++++------ net/ipv4/netfilter/nf_nat_proto_sctp.c | 8 +++--- net/ipv4/netfilter/nf_nat_proto_tcp.c | 10 ++++---- net/ipv4/netfilter/nf_nat_proto_udp.c | 8 +++--- net/ipv4/netfilter/nf_nat_proto_udplite.c | 8 +++--- net/ipv4/netfilter/nf_nat_proto_unknown.c | 24 +++++++++--------- 11 files changed, 87 insertions(+), 87 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_nat_protocol.h b/include/net/netfilter/nf_nat_protocol.h index fba94a2028d5..f3662c4394ef 100644 --- a/include/net/netfilter/nf_nat_protocol.h +++ b/include/net/netfilter/nf_nat_protocol.h @@ -15,25 +15,25 @@ struct nf_nat_protocol /* Translate a packet to the target according to manip type. Return true if succeeded. */ - int (*manip_pkt)(struct sk_buff *skb, - unsigned int iphdroff, - const struct nf_conntrack_tuple *tuple, - enum nf_nat_manip_type maniptype); + bool (*manip_pkt)(struct sk_buff *skb, + unsigned int iphdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype); /* Is the manipable part of the tuple between min and max incl? */ - int (*in_range)(const struct nf_conntrack_tuple *tuple, - enum nf_nat_manip_type maniptype, - const union nf_conntrack_man_proto *min, - const union nf_conntrack_man_proto *max); + bool (*in_range)(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max); /* Alter the per-proto part of the tuple (depending on maniptype), to give a unique tuple in the given range if possible; return false if not. Per-protocol part of tuple is initialized to the incoming packet. */ - int (*unique_tuple)(struct nf_conntrack_tuple *tuple, - const struct nf_nat_range *range, - enum nf_nat_manip_type maniptype, - const struct nf_conn *ct); + bool (*unique_tuple)(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct); int (*range_to_nlattr)(struct sk_buff *skb, const struct nf_nat_range *range); @@ -59,16 +59,16 @@ extern int init_protocols(void) __init; extern void cleanup_protocols(void); extern const struct nf_nat_protocol *find_nat_proto(u_int16_t protonum); -extern int nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple, - enum nf_nat_manip_type maniptype, - const union nf_conntrack_man_proto *min, - const union nf_conntrack_man_proto *max); +extern bool nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max); -extern int nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_nat_range *range, - enum nf_nat_manip_type maniptype, - const struct nf_conn *ct, - u_int16_t *rover); +extern bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct, + u_int16_t *rover); extern int nf_nat_proto_range_to_nlattr(struct sk_buff *skb, const struct nf_nat_range *range); diff --git a/net/ipv4/netfilter/nf_nat_core.c b/net/ipv4/netfilter/nf_nat_core.c index 25c3efe4207e..07a2fbc59622 100644 --- a/net/ipv4/netfilter/nf_nat_core.c +++ b/net/ipv4/netfilter/nf_nat_core.c @@ -349,7 +349,7 @@ nf_nat_setup_info(struct nf_conn *ct, EXPORT_SYMBOL(nf_nat_setup_info); /* Returns true if succeeded. */ -static int +static bool manip_pkt(u_int16_t proto, struct sk_buff *skb, unsigned int iphdroff, @@ -360,7 +360,7 @@ manip_pkt(u_int16_t proto, const struct nf_nat_protocol *p; if (!skb_make_writable(skb, iphdroff + sizeof(*iph))) - return 0; + return false; iph = (void *)skb->data + iphdroff; @@ -369,7 +369,7 @@ manip_pkt(u_int16_t proto, /* rcu_read_lock()ed by nf_hook_slow */ p = __nf_nat_proto_find(proto); if (!p->manip_pkt(skb, iphdroff, target, maniptype)) - return 0; + return false; iph = (void *)skb->data + iphdroff; @@ -380,7 +380,7 @@ manip_pkt(u_int16_t proto, csum_replace4(&iph->check, iph->daddr, target->dst.u3.ip); iph->daddr = target->dst.u3.ip; } - return 1; + return true; } /* Do packet manipulations according to nf_nat_setup_info. */ diff --git a/net/ipv4/netfilter/nf_nat_proto_common.c b/net/ipv4/netfilter/nf_nat_proto_common.c index 4904b86265e1..91537f11273f 100644 --- a/net/ipv4/netfilter/nf_nat_proto_common.c +++ b/net/ipv4/netfilter/nf_nat_proto_common.c @@ -17,10 +17,10 @@ #include #include -int nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple, - enum nf_nat_manip_type maniptype, - const union nf_conntrack_man_proto *min, - const union nf_conntrack_man_proto *max) +bool nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) { __be16 port; @@ -34,11 +34,11 @@ int nf_nat_proto_in_range(const struct nf_conntrack_tuple *tuple, } EXPORT_SYMBOL_GPL(nf_nat_proto_in_range); -int nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_nat_range *range, - enum nf_nat_manip_type maniptype, - const struct nf_conn *ct, - u_int16_t *rover) +bool nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct, + u_int16_t *rover) { unsigned int range_size, min, i; __be16 *portptr; @@ -53,7 +53,7 @@ int nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { /* If it's dst rewrite, can't change port */ if (maniptype == IP_NAT_MANIP_DST) - return 0; + return false; if (ntohs(*portptr) < 1024) { /* Loose convention: >> 512 is credential passing */ @@ -83,9 +83,9 @@ int nf_nat_proto_unique_tuple(struct nf_conntrack_tuple *tuple, continue; if (!(range->flags & IP_NAT_RANGE_PROTO_RANDOM)) *rover = off; - return 1; + return true; } - return 0; + return false; } EXPORT_SYMBOL_GPL(nf_nat_proto_unique_tuple); diff --git a/net/ipv4/netfilter/nf_nat_proto_dccp.c b/net/ipv4/netfilter/nf_nat_proto_dccp.c index 12b51b38442e..f78eb26e9a20 100644 --- a/net/ipv4/netfilter/nf_nat_proto_dccp.c +++ b/net/ipv4/netfilter/nf_nat_proto_dccp.c @@ -22,7 +22,7 @@ static u_int16_t dccp_port_rover; -static int +static bool dccp_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, @@ -32,7 +32,7 @@ dccp_unique_tuple(struct nf_conntrack_tuple *tuple, &dccp_port_rover); } -static int +static bool dccp_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, const struct nf_conntrack_tuple *tuple, @@ -49,7 +49,7 @@ dccp_manip_pkt(struct sk_buff *skb, hdrsize = sizeof(struct dccp_hdr); if (!skb_make_writable(skb, hdroff + hdrsize)) - return 0; + return false; iph = (struct iphdr *)(skb->data + iphdroff); hdr = (struct dccp_hdr *)(skb->data + hdroff); @@ -70,12 +70,12 @@ dccp_manip_pkt(struct sk_buff *skb, *portptr = newport; if (hdrsize < sizeof(*hdr)) - return 1; + return true; inet_proto_csum_replace4(&hdr->dccph_checksum, skb, oldip, newip, 1); inet_proto_csum_replace2(&hdr->dccph_checksum, skb, oldport, newport, 0); - return 1; + return true; } static const struct nf_nat_protocol nf_nat_protocol_dccp = { diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c index 84bb7854137a..4c4af5a6d6c8 100644 --- a/net/ipv4/netfilter/nf_nat_proto_gre.c +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c @@ -37,7 +37,7 @@ MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); /* generate unique tuple ... */ -static int +static bool gre_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, @@ -50,7 +50,7 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple, /* If there is no master conntrack we are not PPTP, do not change tuples */ if (!ct->master) - return 0; + return false; if (maniptype == IP_NAT_MANIP_SRC) keyptr = &tuple->src.u.gre.key; @@ -71,15 +71,15 @@ gre_unique_tuple(struct nf_conntrack_tuple *tuple, for (i = 0; i < range_size; i++, key++) { *keyptr = htons(min + key % range_size); if (!nf_nat_used_tuple(tuple, ct)) - return 1; + return true; } pr_debug("%p: no NAT mapping\n", ct); - return 0; + return false; } /* manipulate a GRE packet according to maniptype */ -static int +static bool gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, const struct nf_conntrack_tuple *tuple, enum nf_nat_manip_type maniptype) @@ -92,7 +92,7 @@ gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, /* pgreh includes two optional 32bit fields which are not required * to be there. That's where the magic '8' comes from */ if (!skb_make_writable(skb, hdroff + sizeof(*pgreh) - 8)) - return 0; + return false; greh = (void *)skb->data + hdroff; pgreh = (struct gre_hdr_pptp *)greh; @@ -100,7 +100,7 @@ gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, /* we only have destination manip of a packet, since 'source key' * is not present in the packet itself */ if (maniptype != IP_NAT_MANIP_DST) - return 1; + return true; switch (greh->version) { case GRE_VERSION_1701: /* We do not currently NAT any GREv0 packets. @@ -112,9 +112,9 @@ gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, break; default: pr_debug("can't nat unknown GRE version\n"); - return 0; + return false; } - return 1; + return true; } static const struct nf_nat_protocol gre = { diff --git a/net/ipv4/netfilter/nf_nat_proto_icmp.c b/net/ipv4/netfilter/nf_nat_proto_icmp.c index ab3a0ec2a2d1..19a8b0b07d8e 100644 --- a/net/ipv4/netfilter/nf_nat_proto_icmp.c +++ b/net/ipv4/netfilter/nf_nat_proto_icmp.c @@ -17,7 +17,7 @@ #include #include -static int +static bool icmp_in_range(const struct nf_conntrack_tuple *tuple, enum nf_nat_manip_type maniptype, const union nf_conntrack_man_proto *min, @@ -27,7 +27,7 @@ icmp_in_range(const struct nf_conntrack_tuple *tuple, ntohs(tuple->src.u.icmp.id) <= ntohs(max->icmp.id); } -static int +static bool icmp_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, @@ -46,12 +46,12 @@ icmp_unique_tuple(struct nf_conntrack_tuple *tuple, tuple->src.u.icmp.id = htons(ntohs(range->min.icmp.id) + (id % range_size)); if (!nf_nat_used_tuple(tuple, ct)) - return 1; + return true; } - return 0; + return false; } -static int +static bool icmp_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, const struct nf_conntrack_tuple *tuple, @@ -62,13 +62,13 @@ icmp_manip_pkt(struct sk_buff *skb, unsigned int hdroff = iphdroff + iph->ihl*4; if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) - return 0; + return false; hdr = (struct icmphdr *)(skb->data + hdroff); inet_proto_csum_replace2(&hdr->checksum, skb, hdr->un.echo.id, tuple->src.u.icmp.id, 0); hdr->un.echo.id = tuple->src.u.icmp.id; - return 1; + return true; } const struct nf_nat_protocol nf_nat_protocol_icmp = { diff --git a/net/ipv4/netfilter/nf_nat_proto_sctp.c b/net/ipv4/netfilter/nf_nat_proto_sctp.c index 3d3faa9d5f6d..82e4c0e286b8 100644 --- a/net/ipv4/netfilter/nf_nat_proto_sctp.c +++ b/net/ipv4/netfilter/nf_nat_proto_sctp.c @@ -16,7 +16,7 @@ static u_int16_t nf_sctp_port_rover; -static int +static bool sctp_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, @@ -26,7 +26,7 @@ sctp_unique_tuple(struct nf_conntrack_tuple *tuple, &nf_sctp_port_rover); } -static int +static bool sctp_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, const struct nf_conntrack_tuple *tuple, @@ -39,7 +39,7 @@ sctp_manip_pkt(struct sk_buff *skb, u32 crc32; if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) - return 0; + return false; iph = (struct iphdr *)(skb->data + iphdroff); hdr = (struct sctphdr *)(skb->data + hdroff); @@ -63,7 +63,7 @@ sctp_manip_pkt(struct sk_buff *skb, crc32 = sctp_end_cksum(crc32); hdr->checksum = htonl(crc32); - return 1; + return true; } static const struct nf_nat_protocol nf_nat_protocol_sctp = { diff --git a/net/ipv4/netfilter/nf_nat_proto_tcp.c b/net/ipv4/netfilter/nf_nat_proto_tcp.c index 5d4c8a0e89c0..399e2cfa263b 100644 --- a/net/ipv4/netfilter/nf_nat_proto_tcp.c +++ b/net/ipv4/netfilter/nf_nat_proto_tcp.c @@ -20,7 +20,7 @@ static u_int16_t tcp_port_rover; -static int +static bool tcp_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, @@ -30,7 +30,7 @@ tcp_unique_tuple(struct nf_conntrack_tuple *tuple, &tcp_port_rover); } -static int +static bool tcp_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, const struct nf_conntrack_tuple *tuple, @@ -50,7 +50,7 @@ tcp_manip_pkt(struct sk_buff *skb, hdrsize = sizeof(struct tcphdr); if (!skb_make_writable(skb, hdroff + hdrsize)) - return 0; + return false; iph = (struct iphdr *)(skb->data + iphdroff); hdr = (struct tcphdr *)(skb->data + hdroff); @@ -73,11 +73,11 @@ tcp_manip_pkt(struct sk_buff *skb, *portptr = newport; if (hdrsize < sizeof(*hdr)) - return 1; + return true; inet_proto_csum_replace4(&hdr->check, skb, oldip, newip, 1); inet_proto_csum_replace2(&hdr->check, skb, oldport, newport, 0); - return 1; + return true; } const struct nf_nat_protocol nf_nat_protocol_tcp = { diff --git a/net/ipv4/netfilter/nf_nat_proto_udp.c b/net/ipv4/netfilter/nf_nat_proto_udp.c index 74a7e7b63465..9e61c79492e4 100644 --- a/net/ipv4/netfilter/nf_nat_proto_udp.c +++ b/net/ipv4/netfilter/nf_nat_proto_udp.c @@ -19,7 +19,7 @@ static u_int16_t udp_port_rover; -static int +static bool udp_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, @@ -29,7 +29,7 @@ udp_unique_tuple(struct nf_conntrack_tuple *tuple, &udp_port_rover); } -static int +static bool udp_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, const struct nf_conntrack_tuple *tuple, @@ -42,7 +42,7 @@ udp_manip_pkt(struct sk_buff *skb, __be16 *portptr, newport; if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) - return 0; + return false; iph = (struct iphdr *)(skb->data + iphdroff); hdr = (struct udphdr *)(skb->data + hdroff); @@ -68,7 +68,7 @@ udp_manip_pkt(struct sk_buff *skb, hdr->check = CSUM_MANGLED_0; } *portptr = newport; - return 1; + return true; } const struct nf_nat_protocol nf_nat_protocol_udp = { diff --git a/net/ipv4/netfilter/nf_nat_proto_udplite.c b/net/ipv4/netfilter/nf_nat_proto_udplite.c index b29346d0e7ab..440a229bbd87 100644 --- a/net/ipv4/netfilter/nf_nat_proto_udplite.c +++ b/net/ipv4/netfilter/nf_nat_proto_udplite.c @@ -18,7 +18,7 @@ static u_int16_t udplite_port_rover; -static int +static bool udplite_unique_tuple(struct nf_conntrack_tuple *tuple, const struct nf_nat_range *range, enum nf_nat_manip_type maniptype, @@ -28,7 +28,7 @@ udplite_unique_tuple(struct nf_conntrack_tuple *tuple, &udplite_port_rover); } -static int +static bool udplite_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, const struct nf_conntrack_tuple *tuple, @@ -41,7 +41,7 @@ udplite_manip_pkt(struct sk_buff *skb, __be16 *portptr, newport; if (!skb_make_writable(skb, hdroff + sizeof(*hdr))) - return 0; + return false; iph = (struct iphdr *)(skb->data + iphdroff); hdr = (struct udphdr *)(skb->data + hdroff); @@ -66,7 +66,7 @@ udplite_manip_pkt(struct sk_buff *skb, hdr->check = CSUM_MANGLED_0; *portptr = newport; - return 1; + return true; } static const struct nf_nat_protocol nf_nat_protocol_udplite = { diff --git a/net/ipv4/netfilter/nf_nat_proto_unknown.c b/net/ipv4/netfilter/nf_nat_proto_unknown.c index cda21ff0e4cf..14381c62acea 100644 --- a/net/ipv4/netfilter/nf_nat_proto_unknown.c +++ b/net/ipv4/netfilter/nf_nat_proto_unknown.c @@ -18,31 +18,31 @@ #include #include -static int unknown_in_range(const struct nf_conntrack_tuple *tuple, - enum nf_nat_manip_type manip_type, - const union nf_conntrack_man_proto *min, - const union nf_conntrack_man_proto *max) +static bool unknown_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type manip_type, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max) { - return 1; + return true; } -static int unknown_unique_tuple(struct nf_conntrack_tuple *tuple, - const struct nf_nat_range *range, - enum nf_nat_manip_type maniptype, - const struct nf_conn *ct) +static bool unknown_unique_tuple(struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct) { /* Sorry: we can't help you; if it's not unique, we can't frob anything. */ - return 0; + return false; } -static int +static bool unknown_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, const struct nf_conntrack_tuple *tuple, enum nf_nat_manip_type maniptype) { - return 1; + return true; } const struct nf_nat_protocol nf_nat_unknown_protocol = { -- cgit v1.2.3-59-g8ed1b From 12c33aa20e1e248ac199d58076fcd4522acbff17 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:54 +0200 Subject: [NETFILTER]: nf_conntrack: const annotations in nf_conntrack_sctp, nf_nat_proto_gre Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- net/ipv4/netfilter/nf_nat_proto_dccp.c | 2 +- net/ipv4/netfilter/nf_nat_proto_gre.c | 2 +- net/netfilter/nf_conntrack_proto_sctp.c | 17 +++++++++++------ 3 files changed, 13 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv4/netfilter/nf_nat_proto_dccp.c b/net/ipv4/netfilter/nf_nat_proto_dccp.c index f78eb26e9a20..22485ce306d4 100644 --- a/net/ipv4/netfilter/nf_nat_proto_dccp.c +++ b/net/ipv4/netfilter/nf_nat_proto_dccp.c @@ -38,7 +38,7 @@ dccp_manip_pkt(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple, enum nf_nat_manip_type maniptype) { - struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff); + const struct iphdr *iph = (const void *)(skb->data + iphdroff); struct dccp_hdr *hdr; unsigned int hdroff = iphdroff + iph->ihl * 4; __be32 oldip, newip; diff --git a/net/ipv4/netfilter/nf_nat_proto_gre.c b/net/ipv4/netfilter/nf_nat_proto_gre.c index 4c4af5a6d6c8..d7e89201351e 100644 --- a/net/ipv4/netfilter/nf_nat_proto_gre.c +++ b/net/ipv4/netfilter/nf_nat_proto_gre.c @@ -84,7 +84,7 @@ gre_manip_pkt(struct sk_buff *skb, unsigned int iphdroff, const struct nf_conntrack_tuple *tuple, enum nf_nat_manip_type maniptype) { - struct gre_hdr *greh; + const struct gre_hdr *greh; struct gre_hdr_pptp *pgreh; const struct iphdr *iph = (struct iphdr *)(skb->data + iphdroff); unsigned int hdroff = iphdroff + iph->ihl * 4; diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index 2d47351f70dc..cbf2e27a22b2 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -33,7 +33,7 @@ static DEFINE_RWLOCK(sctp_lock); And so for me for SCTP :D -Kiran */ -static const char *sctp_conntrack_names[] = { +static const char *const sctp_conntrack_names[] = { "NONE", "CLOSED", "COOKIE_WAIT", @@ -133,7 +133,8 @@ static const u8 sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = { static bool sctp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, struct nf_conntrack_tuple *tuple) { - sctp_sctphdr_t _hdr, *hp; + const struct sctphdr *hp; + struct sctphdr _hdr; /* Actually only need first 8 bytes. */ hp = skb_header_pointer(skb, dataoff, 8, &_hdr); @@ -291,8 +292,10 @@ static int sctp_packet(struct nf_conn *ct, { enum sctp_conntrack new_state, old_state; enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); - sctp_sctphdr_t _sctph, *sh; - sctp_chunkhdr_t _sch, *sch; + const struct sctphdr *sh; + struct sctphdr _sctph; + const struct sctp_chunkhdr *sch; + struct sctp_chunkhdr _sch; u_int32_t offset, count; unsigned long map[256 / sizeof(unsigned long)] = { 0 }; @@ -393,8 +396,10 @@ static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff) { enum sctp_conntrack new_state; - sctp_sctphdr_t _sctph, *sh; - sctp_chunkhdr_t _sch, *sch; + const struct sctphdr *sh; + struct sctphdr _sctph; + const struct sctp_chunkhdr *sch; + struct sctp_chunkhdr _sch; u_int32_t offset, count; unsigned long map[256 / sizeof(unsigned long)] = { 0 }; -- cgit v1.2.3-59-g8ed1b From 3c9fba656a185cf56872a325e5594d9b4d4168ec Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Mon, 14 Apr 2008 11:15:54 +0200 Subject: [NETFILTER]: nf_conntrack: replace NF_CT_DUMP_TUPLE macro indrection by function call Directly call IPv4 and IPv6 variants where the address family is easily known. Signed-off-by: Jan Engelhardt Signed-off-by: Patrick McHardy --- include/net/netfilter/nf_conntrack_tuple.h | 2 -- net/ipv4/netfilter/ipt_CLUSTERIP.c | 2 +- net/ipv4/netfilter/nf_conntrack_proto_icmp.c | 2 +- net/ipv4/netfilter/nf_nat_pptp.c | 2 +- net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | 2 +- net/netfilter/nf_conntrack_core.c | 2 +- net/netfilter/nf_conntrack_h323_main.c | 26 +++++++++++++------------- net/netfilter/nf_conntrack_pptp.c | 4 ++-- net/netfilter/nf_conntrack_proto_gre.c | 6 +++--- net/netfilter/nf_conntrack_proto_tcp.c | 6 +++--- net/netfilter/nf_conntrack_sane.c | 2 +- net/netfilter/nf_conntrack_tftp.c | 6 +++--- 12 files changed, 30 insertions(+), 32 deletions(-) (limited to 'net') diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h index 2722b13ecd6c..1bb7087833d3 100644 --- a/include/net/netfilter/nf_conntrack_tuple.h +++ b/include/net/netfilter/nf_conntrack_tuple.h @@ -151,8 +151,6 @@ static inline void nf_ct_dump_tuple(const struct nf_conntrack_tuple *t) } } -#define NF_CT_DUMP_TUPLE(tp) nf_ct_dump_tuple(tp) - /* If we're the first tuple, it's the original dir. */ #define NF_CT_DIRECTION(h) \ ((enum ip_conntrack_dir)(h)->tuple.dst.dir) diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 2510d4fcdb54..c1f970cb7221 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -331,7 +331,7 @@ clusterip_tg(struct sk_buff *skb, const struct net_device *in, } #ifdef DEBUG - NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + nf_ct_dump_tuple_ip(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); #endif pr_debug("hash=%u ct_hash=%u ", hash, ct->mark); if (!clusterip_responsible(cipinfo->config, hash)) { diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 193a845fe7f8..78ab19accace 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -115,7 +115,7 @@ static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb, /* Can't create a new ICMP `conn' with this. */ pr_debug("icmp: can't create new conn with type %u\n", ct->tuplehash[0].tuple.dst.u.icmp.type); - NF_CT_DUMP_TUPLE(&ct->tuplehash[0].tuple); + nf_ct_dump_tuple_ip(&ct->tuplehash[0].tuple); return false; } atomic_set(&ct->proto.icmp.count, 0); diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c index 3a1e6d6afc0a..da3d91a5ef5c 100644 --- a/net/ipv4/netfilter/nf_nat_pptp.c +++ b/net/ipv4/netfilter/nf_nat_pptp.c @@ -72,7 +72,7 @@ static void pptp_nat_expected(struct nf_conn *ct, } pr_debug("trying to unexpect other dir: "); - NF_CT_DUMP_TUPLE(&t); + nf_ct_dump_tuple_ip(&t); other_exp = nf_ct_expect_find_get(&t); if (other_exp) { nf_ct_unexpect_related(other_exp); diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 9ad40e0e17fc..ee713b03e9ec 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -115,7 +115,7 @@ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, /* Can't create a new ICMPv6 `conn' with this. */ pr_debug("icmpv6: can't create new conn with type %u\n", type + 128); - NF_CT_DUMP_TUPLE(&ct->tuplehash[0].tuple); + nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple); return false; } atomic_set(&ct->proto.icmp.count, 0); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index a3fe9db412d3..351237399e27 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -763,7 +763,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct, NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); pr_debug("Altering reply tuple of %p to ", ct); - NF_CT_DUMP_TUPLE(newreply); + nf_ct_dump_tuple(newreply); ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; if (ct->master || (help && help->expecting != 0)) diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c index c3f87094de43..95da1a24aab7 100644 --- a/net/netfilter/nf_conntrack_h323_main.c +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -303,9 +303,9 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct, if (nf_ct_expect_related(rtp_exp) == 0) { if (nf_ct_expect_related(rtcp_exp) == 0) { pr_debug("nf_ct_h323: expect RTP "); - NF_CT_DUMP_TUPLE(&rtp_exp->tuple); + nf_ct_dump_tuple(&rtp_exp->tuple); pr_debug("nf_ct_h323: expect RTCP "); - NF_CT_DUMP_TUPLE(&rtcp_exp->tuple); + nf_ct_dump_tuple(&rtcp_exp->tuple); } else { nf_ct_unexpect_related(rtp_exp); ret = -1; @@ -360,7 +360,7 @@ static int expect_t120(struct sk_buff *skb, } else { /* Conntrack only */ if (nf_ct_expect_related(exp) == 0) { pr_debug("nf_ct_h323: expect T.120 "); - NF_CT_DUMP_TUPLE(&exp->tuple); + nf_ct_dump_tuple(&exp->tuple); } else ret = -1; } @@ -582,7 +582,7 @@ static int h245_help(struct sk_buff *skb, unsigned int protoff, while (get_tpkt_data(skb, protoff, ct, ctinfo, &data, &datalen, &dataoff)) { pr_debug("nf_ct_h245: TPKT len=%d ", datalen); - NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple); + nf_ct_dump_tuple(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple); /* Decode H.245 signal */ ret = DecodeMultimediaSystemControlMessage(data, datalen, @@ -695,7 +695,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct, } else { /* Conntrack only */ if (nf_ct_expect_related(exp) == 0) { pr_debug("nf_ct_q931: expect H.245 "); - NF_CT_DUMP_TUPLE(&exp->tuple); + nf_ct_dump_tuple(&exp->tuple); } else ret = -1; } @@ -810,7 +810,7 @@ static int expect_callforwarding(struct sk_buff *skb, } else { /* Conntrack only */ if (nf_ct_expect_related(exp) == 0) { pr_debug("nf_ct_q931: expect Call Forwarding "); - NF_CT_DUMP_TUPLE(&exp->tuple); + nf_ct_dump_tuple(&exp->tuple); } else ret = -1; } @@ -1130,7 +1130,7 @@ static int q931_help(struct sk_buff *skb, unsigned int protoff, while (get_tpkt_data(skb, protoff, ct, ctinfo, &data, &datalen, &dataoff)) { pr_debug("nf_ct_q931: TPKT len=%d ", datalen); - NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple); + nf_ct_dump_tuple(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple); /* Decode Q.931 signal */ ret = DecodeQ931(data, datalen, &q931); @@ -1279,7 +1279,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct, } else { /* Conntrack only */ if (nf_ct_expect_related(exp) == 0) { pr_debug("nf_ct_ras: expect Q.931 "); - NF_CT_DUMP_TUPLE(&exp->tuple); + nf_ct_dump_tuple(&exp->tuple); /* Save port for looking up expect in processing RCF */ info->sig_port[dir] = port; @@ -1343,7 +1343,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct, if (nf_ct_expect_related(exp) == 0) { pr_debug("nf_ct_ras: expect RAS "); - NF_CT_DUMP_TUPLE(&exp->tuple); + nf_ct_dump_tuple(&exp->tuple); } else ret = -1; @@ -1427,7 +1427,7 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct, pr_debug("nf_ct_ras: set Q.931 expect " "timeout to %u seconds for", info->timeout); - NF_CT_DUMP_TUPLE(&exp->tuple); + nf_ct_dump_tuple(&exp->tuple); set_expect_timeout(exp, info->timeout); } spin_unlock_bh(&nf_conntrack_lock); @@ -1548,7 +1548,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct, if (nf_ct_expect_related(exp) == 0) { pr_debug("nf_ct_ras: expect Q.931 "); - NF_CT_DUMP_TUPLE(&exp->tuple); + nf_ct_dump_tuple(&exp->tuple); } else ret = -1; @@ -1601,7 +1601,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct, if (nf_ct_expect_related(exp) == 0) { pr_debug("nf_ct_ras: expect Q.931 "); - NF_CT_DUMP_TUPLE(&exp->tuple); + nf_ct_dump_tuple(&exp->tuple); } else ret = -1; @@ -1705,7 +1705,7 @@ static int ras_help(struct sk_buff *skb, unsigned int protoff, if (data == NULL) goto accept; pr_debug("nf_ct_ras: RAS message len=%d ", datalen); - NF_CT_DUMP_TUPLE(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple); + nf_ct_dump_tuple(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple); /* Decode RAS message */ ret = DecodeRasMessage(data, datalen, &ras); diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c index 4793cc078789..97e54b0e43a3 100644 --- a/net/netfilter/nf_conntrack_pptp.c +++ b/net/netfilter/nf_conntrack_pptp.c @@ -119,7 +119,7 @@ static void pptp_expectfn(struct nf_conn *ct, /* obviously this tuple inversion only works until you do NAT */ nf_ct_invert_tuplepr(&inv_t, &exp->tuple); pr_debug("trying to unexpect other dir: "); - NF_CT_DUMP_TUPLE(&inv_t); + nf_ct_dump_tuple(&inv_t); exp_other = nf_ct_expect_find_get(&inv_t); if (exp_other) { @@ -141,7 +141,7 @@ static int destroy_sibling_or_exp(const struct nf_conntrack_tuple *t) struct nf_conn *sibling; pr_debug("trying to timeout ct or exp for tuple "); - NF_CT_DUMP_TUPLE(t); + nf_ct_dump_tuple(t); h = nf_conntrack_find_get(t); if (h) { diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 7d37a2ea67b2..654a4f7f12c6 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -82,7 +82,7 @@ static __be16 gre_keymap_lookup(struct nf_conntrack_tuple *t) read_unlock_bh(&nf_ct_gre_lock); pr_debug("lookup src key 0x%x for ", key); - NF_CT_DUMP_TUPLE(t); + nf_ct_dump_tuple(t); return key; } @@ -113,7 +113,7 @@ int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir, *kmp = km; pr_debug("adding new entry %p: ", km); - NF_CT_DUMP_TUPLE(&km->tuple); + nf_ct_dump_tuple(&km->tuple); write_lock_bh(&nf_ct_gre_lock); list_add_tail(&km->list, &gre_keymap_list); @@ -238,7 +238,7 @@ static bool gre_new(struct nf_conn *ct, const struct sk_buff *skb, unsigned int dataoff) { pr_debug(": "); - NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); /* initialize to sane value. Ideally a conntrack helper * (e.g. in case of pptp) is increasing them */ diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 73a8b32db7be..ba94004fe323 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -505,7 +505,7 @@ static bool tcp_in_window(const struct nf_conn *ct, pr_debug("tcp_in_window: START\n"); pr_debug("tcp_in_window: "); - NF_CT_DUMP_TUPLE(tuple); + nf_ct_dump_tuple(tuple); pr_debug("seq=%u ack=%u sack=%u win=%u end=%u\n", seq, ack, sack, win, end); pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " @@ -592,7 +592,7 @@ static bool tcp_in_window(const struct nf_conn *ct, seq = end = sender->td_end; pr_debug("tcp_in_window: "); - NF_CT_DUMP_TUPLE(tuple); + nf_ct_dump_tuple(tuple); pr_debug("seq=%u ack=%u sack =%u win=%u end=%u\n", seq, ack, sack, win, end); pr_debug("tcp_in_window: sender end=%u maxend=%u maxwin=%u scale=%i " @@ -936,7 +936,7 @@ static int tcp_packet(struct nf_conn *ct, ct->proto.tcp.last_dir = dir; pr_debug("tcp_conntracks: "); - NF_CT_DUMP_TUPLE(tuple); + nf_ct_dump_tuple(tuple); pr_debug("syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n", (th->syn ? 1 : 0), (th->ack ? 1 : 0), (th->fin ? 1 : 0), (th->rst ? 1 : 0), diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c index c3d5e84dcc9b..a94294b2b23c 100644 --- a/net/netfilter/nf_conntrack_sane.c +++ b/net/netfilter/nf_conntrack_sane.c @@ -147,7 +147,7 @@ static int help(struct sk_buff *skb, IPPROTO_TCP, NULL, &reply->port); pr_debug("nf_ct_sane: expect: "); - NF_CT_DUMP_TUPLE(&exp->tuple); + nf_ct_dump_tuple(&exp->tuple); /* Can't expect this? Best to drop packet now. */ if (nf_ct_expect_related(exp) != 0) diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c index ea5ff49d77bc..f57f6e7a71ee 100644 --- a/net/netfilter/nf_conntrack_tftp.c +++ b/net/netfilter/nf_conntrack_tftp.c @@ -55,8 +55,8 @@ static int tftp_help(struct sk_buff *skb, case TFTP_OPCODE_READ: case TFTP_OPCODE_WRITE: /* RRQ and WRQ works the same way */ - NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); - NF_CT_DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); + nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); exp = nf_ct_expect_alloc(ct); if (exp == NULL) @@ -68,7 +68,7 @@ static int tftp_help(struct sk_buff *skb, IPPROTO_UDP, NULL, &tuple->dst.u.udp.port); pr_debug("expect: "); - NF_CT_DUMP_TUPLE(&exp->tuple); + nf_ct_dump_tuple(&exp->tuple); nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook); if (nf_nat_tftp && ct->status & IPS_NAT_MASK) -- cgit v1.2.3-59-g8ed1b From e7bfd0a1a6c8f82977253dab19be9d9979c1ec1b Mon Sep 17 00:00:00 2001 From: Peter Warasin Date: Mon, 14 Apr 2008 11:15:54 +0200 Subject: [NETFILTER]: bridge: add ebt_nflog watcher This patch adds the ebtables nflog watcher to the kernel in order to allow ebtables log through the nfnetlink_log backend. Signed-off-by: Peter Warasin Signed-off-by: Patrick McHardy --- include/linux/netfilter_bridge/ebt_nflog.h | 21 +++++++++ net/bridge/netfilter/Kconfig | 14 ++++++ net/bridge/netfilter/Makefile | 1 + net/bridge/netfilter/ebt_nflog.c | 74 ++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+) create mode 100644 include/linux/netfilter_bridge/ebt_nflog.h create mode 100644 net/bridge/netfilter/ebt_nflog.c (limited to 'net') diff --git a/include/linux/netfilter_bridge/ebt_nflog.h b/include/linux/netfilter_bridge/ebt_nflog.h new file mode 100644 index 000000000000..052817849b83 --- /dev/null +++ b/include/linux/netfilter_bridge/ebt_nflog.h @@ -0,0 +1,21 @@ +#ifndef __LINUX_BRIDGE_EBT_NFLOG_H +#define __LINUX_BRIDGE_EBT_NFLOG_H + +#define EBT_NFLOG_MASK 0x0 + +#define EBT_NFLOG_PREFIX_SIZE 64 +#define EBT_NFLOG_WATCHER "nflog" + +#define EBT_NFLOG_DEFAULT_GROUP 0x1 +#define EBT_NFLOG_DEFAULT_THRESHOLD 1 + +struct ebt_nflog_info { + u_int32_t len; + u_int16_t group; + u_int16_t threshold; + u_int16_t flags; + u_int16_t pad; + char prefix[EBT_NFLOG_PREFIX_SIZE]; +}; + +#endif /* __LINUX_BRIDGE_EBT_NFLOG_H */ diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig index 4a3e2bf892c7..7beeefa0f9c0 100644 --- a/net/bridge/netfilter/Kconfig +++ b/net/bridge/netfilter/Kconfig @@ -212,4 +212,18 @@ config BRIDGE_EBT_ULOG To compile it as a module, choose M here. If unsure, say N. +config BRIDGE_EBT_NFLOG + tristate "ebt: nflog support" + depends on BRIDGE_NF_EBTABLES + help + This option enables the nflog watcher, which allows to LOG + messages through the netfilter logging API, which can use + either the old LOG target, the old ULOG target or nfnetlink_log + as backend. + + This option adds the ulog watcher, that you can use in any rule + in any ebtables table. + + To compile it as a module, choose M here. If unsure, say N. + endmenu diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile index 905087e0d485..83715d73a503 100644 --- a/net/bridge/netfilter/Makefile +++ b/net/bridge/netfilter/Makefile @@ -30,3 +30,4 @@ obj-$(CONFIG_BRIDGE_EBT_SNAT) += ebt_snat.o # watchers obj-$(CONFIG_BRIDGE_EBT_LOG) += ebt_log.o obj-$(CONFIG_BRIDGE_EBT_ULOG) += ebt_ulog.o +obj-$(CONFIG_BRIDGE_EBT_NFLOG) += ebt_nflog.o diff --git a/net/bridge/netfilter/ebt_nflog.c b/net/bridge/netfilter/ebt_nflog.c new file mode 100644 index 000000000000..8e799aa9e560 --- /dev/null +++ b/net/bridge/netfilter/ebt_nflog.c @@ -0,0 +1,74 @@ +/* + * ebt_nflog + * + * Author: + * Peter Warasin + * + * February, 2008 + * + * Based on: + * xt_NFLOG.c, (C) 2006 by Patrick McHardy + * ebt_ulog.c, (C) 2004 by Bart De Schuymer + * + */ + +#include +#include +#include +#include +#include + +static void ebt_nflog(const struct sk_buff *skb, + unsigned int hooknr, + const struct net_device *in, + const struct net_device *out, + const void *data, unsigned int datalen) +{ + struct ebt_nflog_info *info = (struct ebt_nflog_info *)data; + struct nf_loginfo li; + + li.type = NF_LOG_TYPE_ULOG; + li.u.ulog.copy_len = info->len; + li.u.ulog.group = info->group; + li.u.ulog.qthreshold = info->threshold; + + nf_log_packet(PF_BRIDGE, hooknr, skb, in, out, &li, "%s", info->prefix); +} + +static int ebt_nflog_check(const char *tablename, + unsigned int hookmask, + const struct ebt_entry *e, + void *data, unsigned int datalen) +{ + struct ebt_nflog_info *info = (struct ebt_nflog_info *)data; + + if (datalen != EBT_ALIGN(sizeof(struct ebt_nflog_info))) + return -EINVAL; + if (info->flags & ~EBT_NFLOG_MASK) + return -EINVAL; + info->prefix[EBT_NFLOG_PREFIX_SIZE - 1] = '\0'; + return 0; +} + +static struct ebt_watcher nflog __read_mostly = { + .name = EBT_NFLOG_WATCHER, + .watcher = ebt_nflog, + .check = ebt_nflog_check, + .me = THIS_MODULE, +}; + +static int __init ebt_nflog_init(void) +{ + return ebt_register_watcher(&nflog); +} + +static void __exit ebt_nflog_fini(void) +{ + ebt_unregister_watcher(&nflog); +} + +module_init(ebt_nflog_init); +module_exit(ebt_nflog_fini); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Peter Warasin "); +MODULE_DESCRIPTION("ebtables NFLOG netfilter logging module"); -- cgit v1.2.3-59-g8ed1b From ef1a5a50bbd509b8697dcd4d13017e9e0053867b Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 14 Apr 2008 11:21:01 +0200 Subject: [NETFILTER]: nf_conntrack: fix incorrect check for expectations The expectation classes changed help->expectations to an array, fix use as scalar value. Signed-off-by: Patrick McHardy --- net/netfilter/nf_conntrack_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 351237399e27..4eac65c74ed0 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -766,7 +766,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct, nf_ct_dump_tuple(newreply); ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; - if (ct->master || (help && help->expecting != 0)) + if (ct->master || (help && !hlist_empty(&help->expectations))) return; rcu_read_lock(); -- cgit v1.2.3-59-g8ed1b From 13f51d82acb003918d71ce4639ae77fceaa58cad Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 14 Apr 2008 02:38:45 -0700 Subject: [DCCP]: Fix comment about control sockets. These sockets now have a bit other names and are no longer global. Shame on me, I haven't provided a good comment for this when sending DCCP netnsization patches. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/dccp/ipv4.c | 2 +- net/dccp/ipv6.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index baa268d02e24..b348dd70c685 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -32,7 +32,7 @@ #include "feat.h" /* - * The dccp_ctl_sk is the global socket data structure used for responding to + * The per-net dccp.v4_ctl_sk socket is used for responding to * the Out-of-the-blue (OOTB) packets. A control sock will be created * for this socket at the initialization time. */ diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 94e0c9495b2c..f8371c7e5e80 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -33,7 +33,7 @@ #include "ipv6.h" #include "feat.h" -/* dccp_v6_ctl_sk is used for sending RSTs and ACKs */ +/* The per-net dccp.v6_ctl_sk is used for sending RSTs and ACKs */ static struct inet_connection_sock_af_ops dccp_ipv6_mapped; static struct inet_connection_sock_af_ops dccp_ipv6_af_ops; -- cgit v1.2.3-59-g8ed1b From 7477fd2e6b676fcd15861c2a96a7172f71afe0a5 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 14 Apr 2008 02:42:27 -0700 Subject: [SOCK]: Add some notes about per-bind-bucket sock lookup. I was asked about "why don't we perform a sk_net filtering in bind_conflict calls, like we do in other sock lookup places" for a couple of times. Can we please add a comment about why we do not need one? Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/inet_connection_sock.c | 7 +++++++ net/ipv6/inet6_connection_sock.c | 4 ++++ 2 files changed, 11 insertions(+) (limited to 'net') diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index 8d70cfbacb78..828ea211ff21 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -55,6 +55,13 @@ int inet_csk_bind_conflict(const struct sock *sk, struct hlist_node *node; int reuse = sk->sk_reuse; + /* + * Unlike other sk lookup places we do not check + * for sk_net here, since _all_ the socks listed + * in tb->owners list belong to the same net - the + * one this bucket belongs to. + */ + sk_for_each_bound(sk2, node, &tb->owners) { if (sk != sk2 && !inet_v6_ipv6only(sk2) && diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 78de42ada844..87801cc1b2f8 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -33,6 +33,10 @@ int inet6_csk_bind_conflict(const struct sock *sk, const struct hlist_node *node; /* We must walk the whole port owner list in this case. -DaveM */ + /* + * See comment in inet_csk_bind_conflict about sock lookup + * vs net namespaces issues. + */ sk_for_each_bound(sk2, node, &tb->owners) { if (sk != sk2 && (!sk->sk_bound_dev_if || -- cgit v1.2.3-59-g8ed1b From a7d632b6b4ad1c92746ed409e41f9dc571ec04e2 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Mon, 14 Apr 2008 04:09:00 -0700 Subject: [IPV4]: Use NIPQUAD_FMT to format ipv4 addresses. And use %u to format port. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 2 +- net/ipv4/arp.c | 4 ++-- net/ipv4/fib_trie.c | 4 ++-- net/ipv4/icmp.c | 12 ++++++------ net/ipv4/ip_fragment.c | 2 +- net/ipv4/ip_input.c | 2 +- net/ipv4/ipcomp.c | 2 +- net/ipv4/ipconfig.c | 28 ++++++++++++++-------------- net/ipv4/route.c | 26 +++++++++++++------------- net/ipv4/tcp_input.c | 2 +- net/ipv4/tcp_ipv4.c | 2 +- net/ipv4/tcp_probe.c | 2 +- net/ipv4/tcp_timer.c | 2 +- net/ipv4/udp.c | 4 ++-- 14 files changed, 47 insertions(+), 47 deletions(-) (limited to 'net') diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 72ae8ed5a3d7..f2b5270efdaa 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1077,7 +1077,7 @@ static int inet_sk_reselect_saddr(struct sock *sk) if (sysctl_ip_dynaddr > 1) { printk(KERN_INFO "%s(): shifting inet->" - "saddr from %d.%d.%d.%d to %d.%d.%d.%d\n", + "saddr from " NIPQUAD_FMT " to " NIPQUAD_FMT "\n", __func__, NIPQUAD(old_saddr), NIPQUAD(new_saddr)); diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 3ce2e137e7bc..68b72a7a1806 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1310,7 +1310,7 @@ static void arp_format_neigh_entry(struct seq_file *seq, #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) } #endif - sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->primary_key)); + sprintf(tbuf, NIPQUAD_FMT, NIPQUAD(*(u32*)n->primary_key)); seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", tbuf, hatype, arp_state_to_flags(n), hbuffer, dev->name); read_unlock(&n->lock); @@ -1323,7 +1323,7 @@ static void arp_format_pneigh_entry(struct seq_file *seq, int hatype = dev ? dev->type : 0; char tbuf[16]; - sprintf(tbuf, "%u.%u.%u.%u", NIPQUAD(*(u32*)n->key)); + sprintf(tbuf, NIPQUAD_FMT, NIPQUAD(*(u32*)n->key)); seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", tbuf, hatype, ATF_PUBL | ATF_PERM, "00:00:00:00:00:00", dev ? dev->name : "*"); diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 1ada5a6b03ea..ea294fffb9ce 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2424,7 +2424,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v) __be32 prf = htonl(mask_pfx(tn->key, tn->pos)); seq_indent(seq, iter->depth-1); - seq_printf(seq, " +-- %d.%d.%d.%d/%d %d %d %d\n", + seq_printf(seq, " +-- " NIPQUAD_FMT "/%d %d %d %d\n", NIPQUAD(prf), tn->pos, tn->bits, tn->full_children, tn->empty_children); @@ -2435,7 +2435,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v) __be32 val = htonl(l->key); seq_indent(seq, iter->depth); - seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val)); + seq_printf(seq, " |-- " NIPQUAD_FMT "\n", NIPQUAD(val)); hlist_for_each_entry_rcu(li, node, &l->list, hlist) { struct fib_alias *fa; diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 3e14d9cd29b3..f064031f2031 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -685,7 +685,7 @@ static void icmp_unreach(struct sk_buff *skb) break; case ICMP_FRAG_NEEDED: if (ipv4_config.no_pmtu_disc) { - LIMIT_NETDEBUG(KERN_INFO "ICMP: %u.%u.%u.%u: " + LIMIT_NETDEBUG(KERN_INFO "ICMP: " NIPQUAD_FMT ": " "fragmentation needed " "and DF set.\n", NIPQUAD(iph->daddr)); @@ -697,7 +697,7 @@ static void icmp_unreach(struct sk_buff *skb) } break; case ICMP_SR_FAILED: - LIMIT_NETDEBUG(KERN_INFO "ICMP: %u.%u.%u.%u: Source " + LIMIT_NETDEBUG(KERN_INFO "ICMP: " NIPQUAD_FMT ": Source " "Route Failed.\n", NIPQUAD(iph->daddr)); break; @@ -730,9 +730,9 @@ static void icmp_unreach(struct sk_buff *skb) if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses && inet_addr_type(net, iph->daddr) == RTN_BROADCAST) { if (net_ratelimit()) - printk(KERN_WARNING "%u.%u.%u.%u sent an invalid ICMP " + printk(KERN_WARNING NIPQUAD_FMT " sent an invalid ICMP " "type %u, code %u " - "error to a broadcast: %u.%u.%u.%u on %s\n", + "error to a broadcast: " NIPQUAD_FMT " on %s\n", NIPQUAD(ip_hdr(skb)->saddr), icmph->type, icmph->code, NIPQUAD(iph->daddr), @@ -953,8 +953,8 @@ static void icmp_address_reply(struct sk_buff *skb) break; } if (!ifa && net_ratelimit()) { - printk(KERN_INFO "Wrong address mask %u.%u.%u.%u from " - "%s/%u.%u.%u.%u\n", + printk(KERN_INFO "Wrong address mask " NIPQUAD_FMT " from " + "%s/" NIPQUAD_FMT "\n", NIPQUAD(*mp), dev->name, NIPQUAD(rt->rt_src)); } } diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 02ae470fe60c..cd6ce6ac6358 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -557,7 +557,7 @@ out_nomem: out_oversize: if (net_ratelimit()) printk(KERN_INFO - "Oversized IP packet from %d.%d.%d.%d.\n", + "Oversized IP packet from " NIPQUAD_FMT ".\n", NIPQUAD(qp->saddr)); out_fail: IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS); diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 4be00959b748..7b4bad6d572f 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -303,7 +303,7 @@ static inline int ip_rcv_options(struct sk_buff *skb) if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) printk(KERN_INFO "source route option " - "%u.%u.%u.%u -> %u.%u.%u.%u\n", + NIPQUAD_FMT " -> " NIPQUAD_FMT "\n", NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); in_dev_put(in_dev); diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 58b60b2fb011..fb53ddfea5b5 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -179,7 +179,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info) spi, IPPROTO_COMP, AF_INET); if (!x) return; - NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%u.%u.%u.%u\n", + NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/" NIPQUAD_FMT "\n", spi, NIPQUAD(iph->daddr)); xfrm_state_put(x); } diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 08e8fb60d315..0b859d46ea74 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -376,7 +376,7 @@ static int __init ic_defaults(void) */ if (!ic_host_name_set) - sprintf(init_utsname()->nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr)); + sprintf(init_utsname()->nodename, NIPQUAD_FMT, NIPQUAD(ic_myaddr)); if (root_server_addr == NONE) root_server_addr = ic_servaddr; @@ -389,11 +389,11 @@ static int __init ic_defaults(void) else if (IN_CLASSC(ntohl(ic_myaddr))) ic_netmask = htonl(IN_CLASSC_NET); else { - printk(KERN_ERR "IP-Config: Unable to guess netmask for address %u.%u.%u.%u\n", + printk(KERN_ERR "IP-Config: Unable to guess netmask for address " NIPQUAD_FMT "\n", NIPQUAD(ic_myaddr)); return -1; } - printk("IP-Config: Guessing netmask %u.%u.%u.%u\n", NIPQUAD(ic_netmask)); + printk("IP-Config: Guessing netmask " NIPQUAD_FMT "\n", NIPQUAD(ic_netmask)); } return 0; @@ -981,9 +981,9 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str ic_myaddr = b->your_ip; ic_servaddr = server_id; #ifdef IPCONFIG_DEBUG - printk("DHCP: Offered address %u.%u.%u.%u", + printk("DHCP: Offered address " NIPQUAD_FMT, NIPQUAD(ic_myaddr)); - printk(" by server %u.%u.%u.%u\n", + printk(" by server " NIPQUAD_FMT "\n", NIPQUAD(ic_servaddr)); #endif /* The DHCP indicated server address takes @@ -1179,11 +1179,11 @@ static int __init ic_dynamic(void) return -1; } - printk("IP-Config: Got %s answer from %u.%u.%u.%u, ", + printk("IP-Config: Got %s answer from " NIPQUAD_FMT ", ", ((ic_got_reply & IC_RARP) ? "RARP" : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"), NIPQUAD(ic_servaddr)); - printk("my address is %u.%u.%u.%u\n", NIPQUAD(ic_myaddr)); + printk("my address is " NIPQUAD_FMT "\n", NIPQUAD(ic_myaddr)); return 0; } @@ -1209,12 +1209,12 @@ static int pnp_seq_show(struct seq_file *seq, void *v) for (i = 0; i < CONF_NAMESERVERS_MAX; i++) { if (ic_nameservers[i] != NONE) seq_printf(seq, - "nameserver %u.%u.%u.%u\n", + "nameserver " NIPQUAD_FMT "\n", NIPQUAD(ic_nameservers[i])); } if (ic_servaddr != NONE) seq_printf(seq, - "bootserver %u.%u.%u.%u\n", + "bootserver " NIPQUAD_FMT "\n", NIPQUAD(ic_servaddr)); return 0; } @@ -1389,13 +1389,13 @@ static int __init ip_auto_config(void) */ printk("IP-Config: Complete:"); printk("\n device=%s", ic_dev->name); - printk(", addr=%u.%u.%u.%u", NIPQUAD(ic_myaddr)); - printk(", mask=%u.%u.%u.%u", NIPQUAD(ic_netmask)); - printk(", gw=%u.%u.%u.%u", NIPQUAD(ic_gateway)); + printk(", addr=" NIPQUAD_FMT, NIPQUAD(ic_myaddr)); + printk(", mask=" NIPQUAD_FMT, NIPQUAD(ic_netmask)); + printk(", gw=" NIPQUAD_FMT, NIPQUAD(ic_gateway)); printk(",\n host=%s, domain=%s, nis-domain=%s", utsname()->nodename, ic_domain, utsname()->domainname); - printk(",\n bootserver=%u.%u.%u.%u", NIPQUAD(ic_servaddr)); - printk(", rootserver=%u.%u.%u.%u", NIPQUAD(root_server_addr)); + printk(",\n bootserver=" NIPQUAD_FMT, NIPQUAD(ic_servaddr)); + printk(", rootserver=" NIPQUAD_FMT, NIPQUAD(root_server_addr)); printk(", rootpath=%s", root_server_path); printk("\n"); #endif /* !SILENT */ diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 139799f8a8a1..780e9484c825 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1059,10 +1059,10 @@ restart: #if RT_CACHE_DEBUG >= 2 if (rt->u.dst.rt_next) { struct rtable *trt; - printk(KERN_DEBUG "rt_cache @%02x: %u.%u.%u.%u", hash, + printk(KERN_DEBUG "rt_cache @%02x: " NIPQUAD_FMT, hash, NIPQUAD(rt->rt_dst)); for (trt = rt->u.dst.rt_next; trt; trt = trt->u.dst.rt_next) - printk(" . %u.%u.%u.%u", NIPQUAD(trt->rt_dst)); + printk(" . " NIPQUAD_FMT, NIPQUAD(trt->rt_dst)); printk("\n"); } #endif @@ -1275,9 +1275,9 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, reject_redirect: #ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) - printk(KERN_INFO "Redirect from %u.%u.%u.%u on %s about " - "%u.%u.%u.%u ignored.\n" - " Advised path = %u.%u.%u.%u -> %u.%u.%u.%u\n", + printk(KERN_INFO "Redirect from " NIPQUAD_FMT " on %s about " + NIPQUAD_FMT " ignored.\n" + " Advised path = " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n", NIPQUAD(old_gw), dev->name, NIPQUAD(new_gw), NIPQUAD(saddr), NIPQUAD(daddr)); #endif @@ -1299,7 +1299,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) rt->fl.oif); #if RT_CACHE_DEBUG >= 1 printk(KERN_DEBUG "ipv4_negative_advice: redirect to " - "%u.%u.%u.%u/%02x dropped\n", + NIPQUAD_FMT "/%02x dropped\n", NIPQUAD(rt->rt_dst), rt->fl.fl4_tos); #endif rt_del(hash, rt); @@ -1364,8 +1364,8 @@ void ip_rt_send_redirect(struct sk_buff *skb) if (IN_DEV_LOG_MARTIANS(in_dev) && rt->u.dst.rate_tokens == ip_rt_redirect_number && net_ratelimit()) - printk(KERN_WARNING "host %u.%u.%u.%u/if%d ignores " - "redirects for %u.%u.%u.%u to %u.%u.%u.%u.\n", + printk(KERN_WARNING "host " NIPQUAD_FMT "/if%d ignores " + "redirects for " NIPQUAD_FMT " to " NIPQUAD_FMT ".\n", NIPQUAD(rt->rt_src), rt->rt_iif, NIPQUAD(rt->rt_dst), NIPQUAD(rt->rt_gateway)); #endif @@ -1552,7 +1552,7 @@ static void ipv4_link_failure(struct sk_buff *skb) static int ip_rt_bug(struct sk_buff *skb) { - printk(KERN_DEBUG "ip_rt_bug: %u.%u.%u.%u -> %u.%u.%u.%u, %s\n", + printk(KERN_DEBUG "ip_rt_bug: " NIPQUAD_FMT " -> " NIPQUAD_FMT ", %s\n", NIPQUAD(ip_hdr(skb)->saddr), NIPQUAD(ip_hdr(skb)->daddr), skb->dev ? skb->dev->name : "?"); kfree_skb(skb); @@ -1730,8 +1730,8 @@ static void ip_handle_martian_source(struct net_device *dev, * RFC1812 recommendation, if source is martian, * the only hint is MAC header. */ - printk(KERN_WARNING "martian source %u.%u.%u.%u from " - "%u.%u.%u.%u, on dev %s\n", + printk(KERN_WARNING "martian source " NIPQUAD_FMT " from " + NIPQUAD_FMT", on dev %s\n", NIPQUAD(daddr), NIPQUAD(saddr), dev->name); if (dev->hard_header_len && skb_mac_header_was_set(skb)) { int i; @@ -2040,8 +2040,8 @@ martian_destination: RT_CACHE_STAT_INC(in_martian_dst); #ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) - printk(KERN_WARNING "martian destination %u.%u.%u.%u from " - "%u.%u.%u.%u, dev %s\n", + printk(KERN_WARNING "martian destination " NIPQUAD_FMT " from " + NIPQUAD_FMT ", dev %s\n", NIPQUAD(daddr), NIPQUAD(saddr), dev->name); #endif diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index bd0ee8ca8b21..3c6c7d7a7b0a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2309,7 +2309,7 @@ static void DBGUNDO(struct sock *sk, const char *msg) struct tcp_sock *tp = tcp_sk(sk); struct inet_sock *inet = inet_sk(sk); - printk(KERN_DEBUG "Undo %s %u.%u.%u.%u/%u c%u l%u ss%u/%u p%u\n", + printk(KERN_DEBUG "Undo %s " NIPQUAD_FMT "/%u c%u l%u ss%u/%u p%u\n", msg, NIPQUAD(inet->daddr), ntohs(inet->dport), tp->snd_cwnd, tcp_left_out(tp), diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 02519730e0d5..776615180b93 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1369,7 +1369,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) * to the moment of synflood. */ LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open " - "request from %u.%u.%u.%u/%u\n", + "request from " NIPQUAD_FMT "/%u\n", NIPQUAD(saddr), ntohs(tcp_hdr(skb)->source)); goto drop_and_release; diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index 87dd5bff315f..1c509592574a 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c @@ -153,7 +153,7 @@ static int tcpprobe_sprint(char *tbuf, int n) = ktime_to_timespec(ktime_sub(p->tstamp, tcp_probe.start)); return snprintf(tbuf, n, - "%lu.%09lu %d.%d.%d.%d:%u %d.%d.%d.%d:%u" + "%lu.%09lu " NIPQUAD_FMT ":%u " NIPQUAD_FMT ":%u" " %d %#x %#x %u %u %u %u\n", (unsigned long) tv.tv_sec, (unsigned long) tv.tv_nsec, diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 160d16f9f4fc..e588d6dc2a81 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -301,7 +301,7 @@ static void tcp_retransmit_timer(struct sock *sk) #ifdef TCP_DEBUG if (1) { struct inet_sock *inet = inet_sk(sk); - LIMIT_NETDEBUG(KERN_DEBUG "TCP: Treason uncloaked! Peer %u.%u.%u.%u:%u/%u shrinks window %u:%u. Repaired.\n", + LIMIT_NETDEBUG(KERN_DEBUG "TCP: Treason uncloaked! Peer " NIPQUAD_FMT ":%u/%u shrinks window %u:%u. Repaired.\n", NIPQUAD(inet->daddr), ntohs(inet->dport), inet->num, tp->snd_una, tp->snd_nxt); } diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 7b7fcacec4a0..b053ac795275 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1221,7 +1221,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], return 0; short_packet: - LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %u.%u.%u.%u:%u %d/%d to %u.%u.%u.%u:%u\n", + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From " NIPQUAD_FMT ":%u %d/%d to " NIPQUAD_FMT ":%u\n", proto == IPPROTO_UDPLITE ? "-Lite" : "", NIPQUAD(saddr), ntohs(uh->source), @@ -1236,7 +1236,7 @@ csum_error: * RFC1122: OK. Discards the bad packet silently (as far as * the network is concerned, anyway) as per 4.1.3.4 (MUST). */ - LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %d.%d.%d.%d:%d to %d.%d.%d.%d:%d ulen %d\n", + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From " NIPQUAD_FMT ":%u to " NIPQUAD_FMT ":%u ulen %d\n", proto == IPPROTO_UDPLITE ? "-Lite" : "", NIPQUAD(saddr), ntohs(uh->source), -- cgit v1.2.3-59-g8ed1b From 569508c964a8b5235e00998523bc3acd3f6aff01 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Mon, 14 Apr 2008 04:09:36 -0700 Subject: [TCP]: Format addresses appropriately in debug messages. Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 25 +++++++++++++++++++------ net/ipv4/tcp_timer.c | 12 ++++++++++-- 2 files changed, 29 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 3c6c7d7a7b0a..1bdb1bd22134 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2309,12 +2309,25 @@ static void DBGUNDO(struct sock *sk, const char *msg) struct tcp_sock *tp = tcp_sk(sk); struct inet_sock *inet = inet_sk(sk); - printk(KERN_DEBUG "Undo %s " NIPQUAD_FMT "/%u c%u l%u ss%u/%u p%u\n", - msg, - NIPQUAD(inet->daddr), ntohs(inet->dport), - tp->snd_cwnd, tcp_left_out(tp), - tp->snd_ssthresh, tp->prior_ssthresh, - tp->packets_out); + if (sk->sk_family == AF_INET) { + printk(KERN_DEBUG "Undo %s " NIPQUAD_FMT "/%u c%u l%u ss%u/%u p%u\n", + msg, + NIPQUAD(inet->daddr), ntohs(inet->dport), + tp->snd_cwnd, tcp_left_out(tp), + tp->snd_ssthresh, tp->prior_ssthresh, + tp->packets_out); + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (sk->sk_family == AF_INET6) { + struct ipv6_pinfo *np = inet6_sk(sk); + printk(KERN_DEBUG "Undo %s " NIP6_FMT "/%u c%u l%u ss%u/%u p%u\n", + msg, + NIP6(np->daddr), ntohs(inet->dport), + tp->snd_cwnd, tcp_left_out(tp), + tp->snd_ssthresh, tp->prior_ssthresh, + tp->packets_out); + } +#endif } #else #define DBGUNDO(x...) do { } while (0) diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index e588d6dc2a81..4de68cf5f2aa 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -299,12 +299,20 @@ static void tcp_retransmit_timer(struct sock *sk) * we cannot allow such beasts to hang infinitely. */ #ifdef TCP_DEBUG - if (1) { - struct inet_sock *inet = inet_sk(sk); + struct inet_sock *inet = inet_sk(sk); + if (sk->sk_family == AF_INET) { LIMIT_NETDEBUG(KERN_DEBUG "TCP: Treason uncloaked! Peer " NIPQUAD_FMT ":%u/%u shrinks window %u:%u. Repaired.\n", NIPQUAD(inet->daddr), ntohs(inet->dport), inet->num, tp->snd_una, tp->snd_nxt); } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + else if (sk->sk_family == AF_INET6) { + struct ipv6_pinfo *np = inet6_sk(sk); + LIMIT_NETDEBUG(KERN_DEBUG "TCP: Treason uncloaked! Peer " NIP6_FMT ":%u/%u shrinks window %u:%u. Repaired.\n", + NIP6(np->daddr), ntohs(inet->dport), + inet->num, tp->snd_una, tp->snd_nxt); + } +#endif #endif if (tcp_time_stamp - tp->rcv_tstamp > TCP_RTO_MAX) { tcp_write_err(sk); -- cgit v1.2.3-59-g8ed1b From 2c8dd11636e3a5f14a7fb765331b7043f01fe937 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Mon, 14 Apr 2008 14:47:48 -0700 Subject: [XFRM]: Compilation warnings in xfrm_user.c. When CONFIG_SECURITY_NETWORK_XFRM is undefined the following warnings appears: net/xfrm/xfrm_user.c: In function 'xfrm_add_pol_expire': net/xfrm/xfrm_user.c:1576: warning: 'ctx' may be used uninitialized in this function net/xfrm/xfrm_user.c: In function 'xfrm_get_policy': net/xfrm/xfrm_user.c:1340: warning: 'ctx' may be used uninitialized in this function (security_xfrm_policy_alloc is noop for the case). It seems that they are result of the commit 03e1ad7b5d871d4189b1da3125c2f12d1b5f7d0b ("LSM: Make the Labeled IPsec hooks more stack friendly") Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'net') diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index b822b56e5b8e..1810f5645bb5 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1343,14 +1343,14 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, if (err) return err; + ctx = NULL; if (rt) { struct xfrm_user_sec_ctx *uctx = nla_data(rt); err = security_xfrm_policy_alloc(&ctx, uctx); if (err) return err; - } else - ctx = NULL; + } xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx, delete, &err); security_xfrm_policy_free(ctx); @@ -1579,14 +1579,14 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, if (err) return err; + ctx = NULL; if (rt) { struct xfrm_user_sec_ctx *uctx = nla_data(rt); err = security_xfrm_policy_alloc(&ctx, uctx); if (err) return err; - } else - ctx = NULL; + } xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx, 0, &err); security_xfrm_policy_free(ctx); } -- cgit v1.2.3-59-g8ed1b From 990098068fe963f956c14f681bd88d90dcb14584 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 15 Apr 2008 00:06:12 -0700 Subject: [TIPC]: Skip connection flow control in connectionless sockets This patch optimizes the receive path for SOCK_DGRAM and SOCK_RDM messages by skipping over code that handles connection-based flow control. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/socket.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index ca6f52f392a9..91aa2dc51771 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -919,7 +919,8 @@ restart: /* Consume received message (optional) */ if (likely(!(flags & MSG_PEEK))) { - if (unlikely(++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) + if ((sock->state != SS_READY) && + (++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) tipc_acknowledge(tsock->p->ref, tsock->p->conn_unacked); advance_queue(tsock); } -- cgit v1.2.3-59-g8ed1b From a198d3a200313bca8261e30e6daaad790937fd7e Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 15 Apr 2008 00:07:15 -0700 Subject: [TIPC]: Allow stream receive to read from multiple TIPC messages This patch allows a stream socket to receive data from multiple TIPC messages in its receive queue, without requiring the use of the MSG_WAITALL flag. Acknowledgements to Florian Westphal for identifying this issue and suggesting how to correct it. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/socket.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 91aa2dc51771..c1a199c0fa6d 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1065,7 +1065,9 @@ restart: /* Loop around if more data is required */ if ((sz_copied < buf_len) /* didn't get all requested data */ - && (flags & MSG_WAITALL) /* ... and need to wait for more */ + && (!skb_queue_empty(&sock->sk->sk_receive_queue) || + (flags & MSG_WAITALL)) + /* ... and more is ready or required */ && (!(flags & MSG_PEEK)) /* ... and aren't just peeking at data */ && (!err) /* ... and haven't reached a FIN */ ) -- cgit v1.2.3-59-g8ed1b From 7a8036c2b93c8301afce8f75ac099c347bad569d Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 15 Apr 2008 00:15:15 -0700 Subject: [TIPC]: Ignore message padding when receiving stream data This patch ensures that padding bytes appearing at the end of an incoming TIPC message are not returned as valid stream data. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index c1a199c0fa6d..ead22e5eed32 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1027,7 +1027,7 @@ restart: if (!err) { buf_crs = (unsigned char *)(TIPC_SKB_CB(buf)->handle); - sz = skb_tail_pointer(buf) - buf_crs; + sz = (unsigned char *)msg + msg_size(msg) - buf_crs; needed = (buf_len - sz_copied); sz_to_copy = (sz <= needed) ? sz : needed; -- cgit v1.2.3-59-g8ed1b From 1819b83718dc3fe0aea0a2c3cd48d617e2003606 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 15 Apr 2008 00:15:50 -0700 Subject: [TIPC]: Correct "off by 1" error in socket queue limit enforcement This patch fixes a bug that allowed TIPC to queue 1 more message than allowed by the socket receive queue threshold limits. The patch also improves the threshold code's logic and naming to help prevent this sort of error from recurring in the future. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/socket.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index ead22e5eed32..4c83aba575c5 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1079,15 +1079,15 @@ exit: } /** - * queue_overloaded - test if queue overload condition exists + * rx_queue_full - determine if receive queue can accept another message + * @msg: message to be added to queue * @queue_size: current size of queue * @base: nominal maximum size of queue - * @msg: message to be added to queue * - * Returns 1 if queue is currently overloaded, 0 otherwise + * Returns 1 if queue is unable to accept message, 0 otherwise */ -static int queue_overloaded(u32 queue_size, u32 base, struct tipc_msg *msg) +static int rx_queue_full(struct tipc_msg *msg, u32 queue_size, u32 base) { u32 threshold; u32 imp = msg_importance(msg); @@ -1104,7 +1104,7 @@ static int queue_overloaded(u32 queue_size, u32 base, struct tipc_msg *msg) if (msg_connected(msg)) threshold *= 4; - return (queue_size > threshold); + return (queue_size >= threshold); } /** @@ -1189,16 +1189,14 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf) /* Reject message if there isn't room to queue it */ - if (unlikely((u32)atomic_read(&tipc_queue_size) > - OVERLOAD_LIMIT_BASE)) { - if (queue_overloaded(atomic_read(&tipc_queue_size), - OVERLOAD_LIMIT_BASE, msg)) + recv_q_len = (u32)atomic_read(&tipc_queue_size); + if (unlikely(recv_q_len >= OVERLOAD_LIMIT_BASE)) { + if (rx_queue_full(msg, recv_q_len, OVERLOAD_LIMIT_BASE)) return TIPC_ERR_OVERLOAD; } recv_q_len = skb_queue_len(&tsock->sk.sk_receive_queue); - if (unlikely(recv_q_len > (OVERLOAD_LIMIT_BASE / 2))) { - if (queue_overloaded(recv_q_len, - OVERLOAD_LIMIT_BASE / 2, msg)) + if (unlikely(recv_q_len >= (OVERLOAD_LIMIT_BASE / 2))) { + if (rx_queue_full(msg, recv_q_len, OVERLOAD_LIMIT_BASE / 2)) return TIPC_ERR_OVERLOAD; } -- cgit v1.2.3-59-g8ed1b From 4934c69a384ede7d0c3009098184554da2063de6 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 15 Apr 2008 00:16:19 -0700 Subject: [TIPC]: Add error check to detect non-blocking form of connect() This patch causes TIPC to return an error indication if the non- blocking form of connect() is requested (which TIPC does not yet support). Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/socket.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 4c83aba575c5..348e4ff881ab 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1260,6 +1260,11 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, if (sock->state == SS_READY) return -EOPNOTSUPP; + /* For now, TIPC does not support the non-blocking form of connect() */ + + if (flags & O_NONBLOCK) + return -EWOULDBLOCK; + /* Issue Posix-compliant error code if socket is in the wrong state */ if (sock->state == SS_LISTENING) -- cgit v1.2.3-59-g8ed1b From b89741a0cc162511b4341c07e17e1bd4c8b4621d Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 15 Apr 2008 00:20:37 -0700 Subject: [TIPC]: Cosmetic changes to TIPC connect() code This patch fixes TIPC's connect routine to conform to Linux kernel style norms of indentation, line length, etc. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/socket.c | 143 +++++++++++++++++++++++++++--------------------------- 1 file changed, 72 insertions(+), 71 deletions(-) (limited to 'net') diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 348e4ff881ab..df1960384364 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1248,77 +1248,78 @@ static void wakeupdispatch(struct tipc_port *tport) static int connect(struct socket *sock, struct sockaddr *dest, int destlen, int flags) { - struct tipc_sock *tsock = tipc_sk(sock->sk); - struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; - struct msghdr m = {NULL,}; - struct sk_buff *buf; - struct tipc_msg *msg; - int res; - - /* For now, TIPC does not allow use of connect() with DGRAM or RDM types */ - - if (sock->state == SS_READY) - return -EOPNOTSUPP; - - /* For now, TIPC does not support the non-blocking form of connect() */ - - if (flags & O_NONBLOCK) - return -EWOULDBLOCK; - - /* Issue Posix-compliant error code if socket is in the wrong state */ - - if (sock->state == SS_LISTENING) - return -EOPNOTSUPP; - if (sock->state == SS_CONNECTING) - return -EALREADY; - if (sock->state != SS_UNCONNECTED) - return -EISCONN; - - /* - * Reject connection attempt using multicast address - * - * Note: send_msg() validates the rest of the address fields, - * so there's no need to do it here - */ - - if (dst->addrtype == TIPC_ADDR_MCAST) - return -EINVAL; - - /* Send a 'SYN-' to destination */ - - m.msg_name = dest; - m.msg_namelen = destlen; - if ((res = send_msg(NULL, sock, &m, 0)) < 0) { - sock->state = SS_DISCONNECTING; - return res; - } - - if (mutex_lock_interruptible(&tsock->lock)) - return -ERESTARTSYS; - - /* Wait for destination's 'ACK' response */ - - res = wait_event_interruptible_timeout(*sock->sk->sk_sleep, - skb_queue_len(&sock->sk->sk_receive_queue), - sock->sk->sk_rcvtimeo); - buf = skb_peek(&sock->sk->sk_receive_queue); - if (res > 0) { - msg = buf_msg(buf); - res = auto_connect(sock, tsock, msg); - if (!res) { - if (!msg_data_sz(msg)) - advance_queue(tsock); - } - } else { - if (res == 0) { - res = -ETIMEDOUT; - } else - { /* leave "res" unchanged */ } - sock->state = SS_DISCONNECTING; - } - - mutex_unlock(&tsock->lock); - return res; + struct tipc_sock *tsock = tipc_sk(sock->sk); + struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; + struct msghdr m = {NULL,}; + struct sk_buff *buf; + struct tipc_msg *msg; + int res; + + /* For now, TIPC does not allow use of connect() with DGRAM/RDM types */ + + if (sock->state == SS_READY) + return -EOPNOTSUPP; + + /* For now, TIPC does not support the non-blocking form of connect() */ + + if (flags & O_NONBLOCK) + return -EWOULDBLOCK; + + /* Issue Posix-compliant error code if socket is in the wrong state */ + + if (sock->state == SS_LISTENING) + return -EOPNOTSUPP; + if (sock->state == SS_CONNECTING) + return -EALREADY; + if (sock->state != SS_UNCONNECTED) + return -EISCONN; + + /* + * Reject connection attempt using multicast address + * + * Note: send_msg() validates the rest of the address fields, + * so there's no need to do it here + */ + + if (dst->addrtype == TIPC_ADDR_MCAST) + return -EINVAL; + + /* Send a 'SYN-' to destination */ + + m.msg_name = dest; + m.msg_namelen = destlen; + res = send_msg(NULL, sock, &m, 0); + if (res < 0) { + sock->state = SS_DISCONNECTING; + return res; + } + + if (mutex_lock_interruptible(&tsock->lock)) + return -ERESTARTSYS; + + /* Wait for destination's 'ACK' response */ + + res = wait_event_interruptible_timeout(*sock->sk->sk_sleep, + skb_queue_len(&sock->sk->sk_receive_queue), + sock->sk->sk_rcvtimeo); + buf = skb_peek(&sock->sk->sk_receive_queue); + if (res > 0) { + msg = buf_msg(buf); + res = auto_connect(sock, tsock, msg); + if (!res) { + if (!msg_data_sz(msg)) + advance_queue(tsock); + } + } else { + if (res == 0) + res = -ETIMEDOUT; + else + ; /* leave "res" unchanged */ + sock->state = SS_DISCONNECTING; + } + + mutex_unlock(&tsock->lock); + return res; } /** -- cgit v1.2.3-59-g8ed1b From 0c3141e910eaaa0b617e2f26c69b266d1cd1f035 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 15 Apr 2008 00:22:02 -0700 Subject: [TIPC]: Overhaul of socket locking logic This patch modifies TIPC's socket code to follow the same approach used by other protocols. This change eliminates the need for a mutex in the TIPC-specific portion of the socket protocol data structure -- in its place, the standard Linux socket backlog queue and associated locking routines are utilized. These changes fix a long-standing receive queue bug on SMP systems, and also enable individual read and write threads to utilize a socket without unnecessarily interfering with each other. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- include/net/tipc/tipc_port.h | 6 + net/tipc/port.c | 31 +- net/tipc/socket.c | 1002 ++++++++++++++++++++++++------------------ 3 files changed, 608 insertions(+), 431 deletions(-) (limited to 'net') diff --git a/include/net/tipc/tipc_port.h b/include/net/tipc/tipc_port.h index c9b36b77a0b9..11105bcc4457 100644 --- a/include/net/tipc/tipc_port.h +++ b/include/net/tipc/tipc_port.h @@ -96,6 +96,12 @@ struct tipc_port *tipc_get_port(const u32 ref); void *tipc_get_handle(const u32 ref); +/* + * The following routines require that the port be locked on entry + */ + +int tipc_disconnect_port(struct tipc_port *tp_ptr); + #endif diff --git a/net/tipc/port.c b/net/tipc/port.c index e2646a96935d..2f5806410c64 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c @@ -1240,6 +1240,28 @@ exit: return res; } +/** + * tipc_disconnect_port - disconnect port from peer + * + * Port must be locked. + */ + +int tipc_disconnect_port(struct tipc_port *tp_ptr) +{ + int res; + + if (tp_ptr->connected) { + tp_ptr->connected = 0; + /* let timer expire on it's own to avoid deadlock! */ + tipc_nodesub_unsubscribe( + &((struct port *)tp_ptr)->subscription); + res = TIPC_OK; + } else { + res = -ENOTCONN; + } + return res; +} + /* * tipc_disconnect(): Disconnect port form peer. * This is a node local operation. @@ -1248,17 +1270,12 @@ exit: int tipc_disconnect(u32 ref) { struct port *p_ptr; - int res = -ENOTCONN; + int res; p_ptr = tipc_port_lock(ref); if (!p_ptr) return -EINVAL; - if (p_ptr->publ.connected) { - p_ptr->publ.connected = 0; - /* let timer expire on it's own to avoid deadlock! */ - tipc_nodesub_unsubscribe(&p_ptr->subscription); - res = TIPC_OK; - } + res = tipc_disconnect_port((struct tipc_port *)p_ptr); tipc_port_unlock(p_ptr); return res; } diff --git a/net/tipc/socket.c b/net/tipc/socket.c index df1960384364..05853159536a 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include @@ -64,11 +63,12 @@ struct tipc_sock { struct sock sk; struct tipc_port *p; - struct mutex lock; }; -#define tipc_sk(sk) ((struct tipc_sock*)sk) +#define tipc_sk(sk) ((struct tipc_sock *)(sk)) +#define tipc_sk_port(sk) ((struct tipc_port *)(tipc_sk(sk)->p)) +static int backlog_rcv(struct sock *sk, struct sk_buff *skb); static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf); static void wakeupdispatch(struct tipc_port *tport); @@ -82,55 +82,115 @@ static int sockets_enabled = 0; static atomic_t tipc_queue_size = ATOMIC_INIT(0); - /* - * sock_lock(): Lock a port/socket pair. lock_sock() can - * not be used here, since the same lock must protect ports - * with non-socket interfaces. - * See net.c for description of locking policy. + * Revised TIPC socket locking policy: + * + * Most socket operations take the standard socket lock when they start + * and hold it until they finish (or until they need to sleep). Acquiring + * this lock grants the owner exclusive access to the fields of the socket + * data structures, with the exception of the backlog queue. A few socket + * operations can be done without taking the socket lock because they only + * read socket information that never changes during the life of the socket. + * + * Socket operations may acquire the lock for the associated TIPC port if they + * need to perform an operation on the port. If any routine needs to acquire + * both the socket lock and the port lock it must take the socket lock first + * to avoid the risk of deadlock. + * + * The dispatcher handling incoming messages cannot grab the socket lock in + * the standard fashion, since invoked it runs at the BH level and cannot block. + * Instead, it checks to see if the socket lock is currently owned by someone, + * and either handles the message itself or adds it to the socket's backlog + * queue; in the latter case the queued message is processed once the process + * owning the socket lock releases it. + * + * NOTE: Releasing the socket lock while an operation is sleeping overcomes + * the problem of a blocked socket operation preventing any other operations + * from occurring. However, applications must be careful if they have + * multiple threads trying to send (or receive) on the same socket, as these + * operations might interfere with each other. For example, doing a connect + * and a receive at the same time might allow the receive to consume the + * ACK message meant for the connect. While additional work could be done + * to try and overcome this, it doesn't seem to be worthwhile at the present. + * + * NOTE: Releasing the socket lock while an operation is sleeping also ensures + * that another operation that must be performed in a non-blocking manner is + * not delayed for very long because the lock has already been taken. + * + * NOTE: This code assumes that certain fields of a port/socket pair are + * constant over its lifetime; such fields can be examined without taking + * the socket lock and/or port lock, and do not need to be re-read even + * after resuming processing after waiting. These fields include: + * - socket type + * - pointer to socket sk structure (aka tipc_sock structure) + * - pointer to port structure + * - port reference + */ + +/** + * advance_rx_queue - discard first buffer in socket receive queue + * + * Caller must hold socket lock */ -static void sock_lock(struct tipc_sock* tsock) + +static void advance_rx_queue(struct sock *sk) { - spin_lock_bh(tsock->p->lock); + buf_discard(__skb_dequeue(&sk->sk_receive_queue)); + atomic_dec(&tipc_queue_size); } -/* - * sock_unlock(): Unlock a port/socket pair +/** + * discard_rx_queue - discard all buffers in socket receive queue + * + * Caller must hold socket lock */ -static void sock_unlock(struct tipc_sock* tsock) + +static void discard_rx_queue(struct sock *sk) { - spin_unlock_bh(tsock->p->lock); + struct sk_buff *buf; + + while ((buf = __skb_dequeue(&sk->sk_receive_queue))) { + atomic_dec(&tipc_queue_size); + buf_discard(buf); + } } /** - * advance_queue - discard first buffer in queue - * @tsock: TIPC socket + * reject_rx_queue - reject all buffers in socket receive queue + * + * Caller must hold socket lock */ -static void advance_queue(struct tipc_sock *tsock) +static void reject_rx_queue(struct sock *sk) { - sock_lock(tsock); - buf_discard(skb_dequeue(&tsock->sk.sk_receive_queue)); - sock_unlock(tsock); - atomic_dec(&tipc_queue_size); + struct sk_buff *buf; + + while ((buf = __skb_dequeue(&sk->sk_receive_queue))) { + tipc_reject_msg(buf, TIPC_ERR_NO_PORT); + atomic_dec(&tipc_queue_size); + } } /** * tipc_create - create a TIPC socket + * @net: network namespace (must be default network) * @sock: pre-allocated socket structure * @protocol: protocol indicator (must be 0) * - * This routine creates and attaches a 'struct sock' to the 'struct socket', - * then create and attaches a TIPC port to the 'struct sock' part. + * This routine creates additional data structures used by the TIPC socket, + * initializes them, and links them together. * * Returns 0 on success, errno otherwise */ + static int tipc_create(struct net *net, struct socket *sock, int protocol) { - struct tipc_sock *tsock; - struct tipc_port *port; + const struct proto_ops *ops; + socket_state state; struct sock *sk; - u32 ref; + u32 portref; + + /* Validate arguments */ if (net != &init_net) return -EAFNOSUPPORT; @@ -138,53 +198,56 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol) if (unlikely(protocol != 0)) return -EPROTONOSUPPORT; - ref = tipc_createport_raw(NULL, &dispatch, &wakeupdispatch, TIPC_LOW_IMPORTANCE); - if (unlikely(!ref)) - return -ENOMEM; - - sock->state = SS_UNCONNECTED; - switch (sock->type) { case SOCK_STREAM: - sock->ops = &stream_ops; + ops = &stream_ops; + state = SS_UNCONNECTED; break; case SOCK_SEQPACKET: - sock->ops = &packet_ops; + ops = &packet_ops; + state = SS_UNCONNECTED; break; case SOCK_DGRAM: - tipc_set_portunreliable(ref, 1); - /* fall through */ case SOCK_RDM: - tipc_set_portunreturnable(ref, 1); - sock->ops = &msg_ops; - sock->state = SS_READY; + ops = &msg_ops; + state = SS_READY; break; default: - tipc_deleteport(ref); return -EPROTOTYPE; } + /* Allocate socket's protocol area */ + sk = sk_alloc(net, AF_TIPC, GFP_KERNEL, &tipc_proto); - if (!sk) { - tipc_deleteport(ref); + if (sk == NULL) return -ENOMEM; - } - sock_init_data(sock, sk); - sk->sk_rcvtimeo = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT); + /* Allocate TIPC port for socket to use */ - tsock = tipc_sk(sk); - port = tipc_get_port(ref); + portref = tipc_createport_raw(sk, &dispatch, &wakeupdispatch, + TIPC_LOW_IMPORTANCE); + if (unlikely(portref == 0)) { + sk_free(sk); + return -ENOMEM; + } - tsock->p = port; - port->usr_handle = tsock; + /* Finish initializing socket data structures */ - mutex_init(&tsock->lock); + sock->ops = ops; + sock->state = state; - dbg("sock_create: %x\n",tsock); + sock_init_data(sock, sk); + sk->sk_rcvtimeo = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT); + sk->sk_backlog_rcv = backlog_rcv; + tipc_sk(sk)->p = tipc_get_port(portref); - atomic_inc(&tipc_user_count); + if (sock->state == SS_READY) { + tipc_set_portunreturnable(portref, 1); + if (sock->type == SOCK_DGRAM) + tipc_set_portunreliable(portref, 1); + } + atomic_inc(&tipc_user_count); return 0; } @@ -207,52 +270,62 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol) static int release(struct socket *sock) { - struct tipc_sock *tsock = tipc_sk(sock->sk); struct sock *sk = sock->sk; - int res = TIPC_OK; + struct tipc_port *tport; struct sk_buff *buf; + int res; - dbg("sock_delete: %x\n",tsock); - if (!tsock) - return 0; - mutex_lock(&tsock->lock); - if (!sock->sk) { - mutex_unlock(&tsock->lock); + /* + * Exit if socket isn't fully initialized (occurs when a failed accept() + * releases a pre-allocated child socket that was never used) + */ + + if (sk == NULL) return 0; - } - /* Reject unreceived messages, unless no longer connected */ + tport = tipc_sk_port(sk); + lock_sock(sk); + + /* + * Reject all unreceived messages, except on an active connection + * (which disconnects locally & sends a 'FIN+' to peer) + */ while (sock->state != SS_DISCONNECTING) { - sock_lock(tsock); - buf = skb_dequeue(&sk->sk_receive_queue); - if (!buf) - tsock->p->usr_handle = NULL; - sock_unlock(tsock); - if (!buf) + buf = __skb_dequeue(&sk->sk_receive_queue); + if (buf == NULL) break; + atomic_dec(&tipc_queue_size); if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) buf_discard(buf); - else + else { + if ((sock->state == SS_CONNECTING) || + (sock->state == SS_CONNECTED)) { + sock->state = SS_DISCONNECTING; + tipc_disconnect(tport->ref); + } tipc_reject_msg(buf, TIPC_ERR_NO_PORT); - atomic_dec(&tipc_queue_size); + } } - /* Delete TIPC port */ + /* + * Delete TIPC port; this ensures no more messages are queued + * (also disconnects an active connection & sends a 'FIN-' to peer) + */ - res = tipc_deleteport(tsock->p->ref); - sock->sk = NULL; + res = tipc_deleteport(tport->ref); - /* Discard any remaining messages */ + /* Discard any remaining (connection-based) messages in receive queue */ - while ((buf = skb_dequeue(&sk->sk_receive_queue))) { - buf_discard(buf); - atomic_dec(&tipc_queue_size); - } + discard_rx_queue(sk); - mutex_unlock(&tsock->lock); + /* Reject any messages that accumulated in backlog queue */ + + sock->state = SS_DISCONNECTING; + release_sock(sk); sock_put(sk); + sock->sk = NULL; atomic_dec(&tipc_user_count); return res; @@ -269,47 +342,32 @@ static int release(struct socket *sock) * (i.e. a socket address length of 0) unbinds all names from the socket. * * Returns 0 on success, errno otherwise + * + * NOTE: This routine doesn't need to take the socket lock since it doesn't + * access any non-constant socket information. */ static int bind(struct socket *sock, struct sockaddr *uaddr, int uaddr_len) { - struct tipc_sock *tsock = tipc_sk(sock->sk); struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; - int res; + u32 portref = tipc_sk_port(sock->sk)->ref; - if (mutex_lock_interruptible(&tsock->lock)) - return -ERESTARTSYS; + if (unlikely(!uaddr_len)) + return tipc_withdraw(portref, 0, NULL); - if (unlikely(!uaddr_len)) { - res = tipc_withdraw(tsock->p->ref, 0, NULL); - goto exit; - } - - if (uaddr_len < sizeof(struct sockaddr_tipc)) { - res = -EINVAL; - goto exit; - } + if (uaddr_len < sizeof(struct sockaddr_tipc)) + return -EINVAL; + if (addr->family != AF_TIPC) + return -EAFNOSUPPORT; - if (addr->family != AF_TIPC) { - res = -EAFNOSUPPORT; - goto exit; - } if (addr->addrtype == TIPC_ADDR_NAME) addr->addr.nameseq.upper = addr->addr.nameseq.lower; - else if (addr->addrtype != TIPC_ADDR_NAMESEQ) { - res = -EAFNOSUPPORT; - goto exit; - } + else if (addr->addrtype != TIPC_ADDR_NAMESEQ) + return -EAFNOSUPPORT; - if (addr->scope > 0) - res = tipc_publish(tsock->p->ref, addr->scope, - &addr->addr.nameseq); - else - res = tipc_withdraw(tsock->p->ref, -addr->scope, - &addr->addr.nameseq); -exit: - mutex_unlock(&tsock->lock); - return res; + return (addr->scope > 0) ? + tipc_publish(portref, addr->scope, &addr->addr.nameseq) : + tipc_withdraw(portref, -addr->scope, &addr->addr.nameseq); } /** @@ -320,30 +378,33 @@ exit: * @peer: 0 to obtain socket name, 1 to obtain peer socket name * * Returns 0 on success, errno otherwise + * + * NOTE: This routine doesn't need to take the socket lock since it doesn't + * access any non-constant socket information. */ static int get_name(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { - struct tipc_sock *tsock = tipc_sk(sock->sk); struct sockaddr_tipc *addr = (struct sockaddr_tipc *)uaddr; + u32 portref = tipc_sk_port(sock->sk)->ref; u32 res; - if (mutex_lock_interruptible(&tsock->lock)) - return -ERESTARTSYS; + if (peer) { + res = tipc_peer(portref, &addr->addr.id); + if (res) + return res; + } else { + tipc_ownidentity(portref, &addr->addr.id); + } *uaddr_len = sizeof(*addr); addr->addrtype = TIPC_ADDR_ID; addr->family = AF_TIPC; addr->scope = 0; - if (peer) - res = tipc_peer(tsock->p->ref, &addr->addr.id); - else - res = tipc_ownidentity(tsock->p->ref, &addr->addr.id); addr->addr.name.domain = 0; - mutex_unlock(&tsock->lock); - return res; + return 0; } /** @@ -414,7 +475,6 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) return 0; if (likely(dest->addr.name.name.type == TIPC_TOP_SRV)) return 0; - if (likely(dest->addr.name.name.type != TIPC_CFG_SRV)) return -EACCES; @@ -428,7 +488,7 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) /** * send_msg - send message in connectionless manner - * @iocb: (unused) + * @iocb: if NULL, indicates that socket lock is already held * @sock: socket structure * @m: message to send * @total_len: length of message @@ -444,9 +504,9 @@ static int dest_name_check(struct sockaddr_tipc *dest, struct msghdr *m) static int send_msg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) { - struct tipc_sock *tsock = tipc_sk(sock->sk); + struct sock *sk = sock->sk; + struct tipc_port *tport = tipc_sk_port(sk); struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; - struct sk_buff *buf; int needs_conn; int res = -EINVAL; @@ -456,48 +516,46 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, (dest->family != AF_TIPC))) return -EINVAL; + if (iocb) + lock_sock(sk); + needs_conn = (sock->state != SS_READY); if (unlikely(needs_conn)) { - if (sock->state == SS_LISTENING) - return -EPIPE; - if (sock->state != SS_UNCONNECTED) - return -EISCONN; - if ((tsock->p->published) || - ((sock->type == SOCK_STREAM) && (total_len != 0))) - return -EOPNOTSUPP; + if (sock->state == SS_LISTENING) { + res = -EPIPE; + goto exit; + } + if (sock->state != SS_UNCONNECTED) { + res = -EISCONN; + goto exit; + } + if ((tport->published) || + ((sock->type == SOCK_STREAM) && (total_len != 0))) { + res = -EOPNOTSUPP; + goto exit; + } if (dest->addrtype == TIPC_ADDR_NAME) { - tsock->p->conn_type = dest->addr.name.name.type; - tsock->p->conn_instance = dest->addr.name.name.instance; + tport->conn_type = dest->addr.name.name.type; + tport->conn_instance = dest->addr.name.name.instance; } - } - - if (mutex_lock_interruptible(&tsock->lock)) - return -ERESTARTSYS; - - if (needs_conn) { /* Abort any pending connection attempts (very unlikely) */ - while ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) { - tipc_reject_msg(buf, TIPC_ERR_NO_PORT); - atomic_dec(&tipc_queue_size); - } - - sock->state = SS_CONNECTING; + reject_rx_queue(sk); } do { if (dest->addrtype == TIPC_ADDR_NAME) { if ((res = dest_name_check(dest, m))) - goto exit; - res = tipc_send2name(tsock->p->ref, + break; + res = tipc_send2name(tport->ref, &dest->addr.name.name, dest->addr.name.domain, m->msg_iovlen, m->msg_iov); } else if (dest->addrtype == TIPC_ADDR_ID) { - res = tipc_send2port(tsock->p->ref, + res = tipc_send2port(tport->ref, &dest->addr.id, m->msg_iovlen, m->msg_iov); @@ -505,36 +563,43 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, else if (dest->addrtype == TIPC_ADDR_MCAST) { if (needs_conn) { res = -EOPNOTSUPP; - goto exit; + break; } if ((res = dest_name_check(dest, m))) - goto exit; - res = tipc_multicast(tsock->p->ref, + break; + res = tipc_multicast(tport->ref, &dest->addr.nameseq, 0, m->msg_iovlen, m->msg_iov); } if (likely(res != -ELINKCONG)) { -exit: - mutex_unlock(&tsock->lock); - return res; + if (needs_conn && (res >= 0)) { + sock->state = SS_CONNECTING; + } + break; } if (m->msg_flags & MSG_DONTWAIT) { res = -EWOULDBLOCK; - goto exit; - } - if (wait_event_interruptible(*sock->sk->sk_sleep, - !tsock->p->congested)) { - res = -ERESTARTSYS; - goto exit; + break; } + release_sock(sk); + res = wait_event_interruptible(*sk->sk_sleep, + !tport->congested); + lock_sock(sk); + if (res) + break; } while (1); + +exit: + if (iocb) + release_sock(sk); + return res; } /** * send_packet - send a connection-oriented message - * @iocb: (unused) + * @iocb: if NULL, indicates that socket lock is already held * @sock: socket structure * @m: message to send * @total_len: length of message @@ -547,7 +612,8 @@ exit: static int send_packet(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) { - struct tipc_sock *tsock = tipc_sk(sock->sk); + struct sock *sk = sock->sk; + struct tipc_port *tport = tipc_sk_port(sk); struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; int res; @@ -556,9 +622,8 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, if (unlikely(dest)) return send_msg(iocb, sock, m, total_len); - if (mutex_lock_interruptible(&tsock->lock)) { - return -ERESTARTSYS; - } + if (iocb) + lock_sock(sk); do { if (unlikely(sock->state != SS_CONNECTED)) { @@ -566,25 +631,28 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, res = -EPIPE; else res = -ENOTCONN; - goto exit; + break; } - res = tipc_send(tsock->p->ref, m->msg_iovlen, m->msg_iov); + res = tipc_send(tport->ref, m->msg_iovlen, m->msg_iov); if (likely(res != -ELINKCONG)) { -exit: - mutex_unlock(&tsock->lock); - return res; + break; } if (m->msg_flags & MSG_DONTWAIT) { res = -EWOULDBLOCK; - goto exit; - } - if (wait_event_interruptible(*sock->sk->sk_sleep, - !tsock->p->congested)) { - res = -ERESTARTSYS; - goto exit; + break; } + release_sock(sk); + res = wait_event_interruptible(*sk->sk_sleep, + (!tport->congested || !tport->connected)); + lock_sock(sk); + if (res) + break; } while (1); + + if (iocb) + release_sock(sk); + return res; } /** @@ -600,11 +668,11 @@ exit: * or errno if no data sent */ - static int send_stream(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len) { - struct tipc_port *tport; + struct sock *sk = sock->sk; + struct tipc_port *tport = tipc_sk_port(sk); struct msghdr my_msg; struct iovec my_iov; struct iovec *curr_iov; @@ -616,19 +684,27 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, int bytes_sent; int res; + lock_sock(sk); + /* Handle special cases where there is no connection */ if (unlikely(sock->state != SS_CONNECTED)) { - if (sock->state == SS_UNCONNECTED) - return send_packet(iocb, sock, m, total_len); - else if (sock->state == SS_DISCONNECTING) - return -EPIPE; - else - return -ENOTCONN; + if (sock->state == SS_UNCONNECTED) { + res = send_packet(NULL, sock, m, total_len); + goto exit; + } else if (sock->state == SS_DISCONNECTING) { + res = -EPIPE; + goto exit; + } else { + res = -ENOTCONN; + goto exit; + } } - if (unlikely(m->msg_name)) - return -EISCONN; + if (unlikely(m->msg_name)) { + res = -EISCONN; + goto exit; + } /* * Send each iovec entry using one or more messages @@ -646,7 +722,6 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, my_msg.msg_name = NULL; bytes_sent = 0; - tport = tipc_sk(sock->sk)->p; hdr_size = msg_hdr_sz(&tport->phdr); while (curr_iovlen--) { @@ -661,10 +736,10 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, bytes_to_send = curr_left; my_iov.iov_base = curr_start; my_iov.iov_len = bytes_to_send; - if ((res = send_packet(iocb, sock, &my_msg, 0)) < 0) { - if (bytes_sent != 0) + if ((res = send_packet(NULL, sock, &my_msg, 0)) < 0) { + if (bytes_sent) res = bytes_sent; - return res; + goto exit; } curr_left -= bytes_to_send; curr_start += bytes_to_send; @@ -673,22 +748,23 @@ static int send_stream(struct kiocb *iocb, struct socket *sock, curr_iov++; } - - return bytes_sent; + res = bytes_sent; +exit: + release_sock(sk); + return res; } /** * auto_connect - complete connection setup to a remote port * @sock: socket structure - * @tsock: TIPC-specific socket structure * @msg: peer's response message * * Returns 0 on success, errno otherwise */ -static int auto_connect(struct socket *sock, struct tipc_sock *tsock, - struct tipc_msg *msg) +static int auto_connect(struct socket *sock, struct tipc_msg *msg) { + struct tipc_port *tport = tipc_sk_port(sock->sk); struct tipc_portid peer; if (msg_errcode(msg)) { @@ -698,8 +774,8 @@ static int auto_connect(struct socket *sock, struct tipc_sock *tsock, peer.ref = msg_origport(msg); peer.node = msg_orignode(msg); - tipc_connect2port(tsock->p->ref, &peer); - tipc_set_portimportance(tsock->p->ref, msg_importance(msg)); + tipc_connect2port(tport->ref, &peer); + tipc_set_portimportance(tport->ref, msg_importance(msg)); sock->state = SS_CONNECTED; return 0; } @@ -812,62 +888,54 @@ static int anc_data_recv(struct msghdr *m, struct tipc_msg *msg, static int recv_msg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t buf_len, int flags) { - struct tipc_sock *tsock = tipc_sk(sock->sk); + struct sock *sk = sock->sk; + struct tipc_port *tport = tipc_sk_port(sk); struct sk_buff *buf; struct tipc_msg *msg; - unsigned int q_len; unsigned int sz; u32 err; int res; - /* Currently doesn't support receiving into multiple iovec entries */ + /* Catch invalid receive requests */ if (m->msg_iovlen != 1) - return -EOPNOTSUPP; - - /* Catch invalid receive attempts */ + return -EOPNOTSUPP; /* Don't do multiple iovec entries yet */ if (unlikely(!buf_len)) return -EINVAL; - if (sock->type == SOCK_SEQPACKET) { - if (unlikely(sock->state == SS_UNCONNECTED)) - return -ENOTCONN; - if (unlikely((sock->state == SS_DISCONNECTING) && - (skb_queue_len(&sock->sk->sk_receive_queue) == 0))) - return -ENOTCONN; - } + lock_sock(sk); - /* Look for a message in receive queue; wait if necessary */ - - if (unlikely(mutex_lock_interruptible(&tsock->lock))) - return -ERESTARTSYS; - -restart: - if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) && - (flags & MSG_DONTWAIT))) { - res = -EWOULDBLOCK; + if (unlikely(sock->state == SS_UNCONNECTED)) { + res = -ENOTCONN; goto exit; } - if ((res = wait_event_interruptible( - *sock->sk->sk_sleep, - ((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) || - (sock->state == SS_DISCONNECTING))) )) { - goto exit; - } +restart: - /* Catch attempt to receive on an already terminated connection */ - /* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */ + /* Look for a message in receive queue; wait if necessary */ - if (!q_len) { - res = -ENOTCONN; - goto exit; + while (skb_queue_empty(&sk->sk_receive_queue)) { + if (sock->state == SS_DISCONNECTING) { + res = -ENOTCONN; + goto exit; + } + if (flags & MSG_DONTWAIT) { + res = -EWOULDBLOCK; + goto exit; + } + release_sock(sk); + res = wait_event_interruptible(*sk->sk_sleep, + (!skb_queue_empty(&sk->sk_receive_queue) || + (sock->state == SS_DISCONNECTING))); + lock_sock(sk); + if (res) + goto exit; } - /* Get access to first message in receive queue */ + /* Look at first message in receive queue */ - buf = skb_peek(&sock->sk->sk_receive_queue); + buf = skb_peek(&sk->sk_receive_queue); msg = buf_msg(buf); sz = msg_data_sz(msg); err = msg_errcode(msg); @@ -875,14 +943,15 @@ restart: /* Complete connection setup for an implied connect */ if (unlikely(sock->state == SS_CONNECTING)) { - if ((res = auto_connect(sock, tsock, msg))) + res = auto_connect(sock, msg); + if (res) goto exit; } /* Discard an empty non-errored message & try again */ if ((!sz) && (!err)) { - advance_queue(tsock); + advance_rx_queue(sk); goto restart; } @@ -892,7 +961,8 @@ restart: /* Capture ancillary data (optional) */ - if ((res = anc_data_recv(m, msg, tsock->p))) + res = anc_data_recv(m, msg, tport); + if (res) goto exit; /* Capture message data (if valid) & compute return value (always) */ @@ -920,12 +990,12 @@ restart: if (likely(!(flags & MSG_PEEK))) { if ((sock->state != SS_READY) && - (++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) - tipc_acknowledge(tsock->p->ref, tsock->p->conn_unacked); - advance_queue(tsock); + (++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) + tipc_acknowledge(tport->ref, tport->conn_unacked); + advance_rx_queue(sk); } exit: - mutex_unlock(&tsock->lock); + release_sock(sk); return res; } @@ -945,10 +1015,10 @@ exit: static int recv_stream(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t buf_len, int flags) { - struct tipc_sock *tsock = tipc_sk(sock->sk); + struct sock *sk = sock->sk; + struct tipc_port *tport = tipc_sk_port(sk); struct sk_buff *buf; struct tipc_msg *msg; - unsigned int q_len; unsigned int sz; int sz_to_copy; int sz_copied = 0; @@ -956,54 +1026,49 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock, char __user *crs = m->msg_iov->iov_base; unsigned char *buf_crs; u32 err; - int res; + int res = 0; - /* Currently doesn't support receiving into multiple iovec entries */ + /* Catch invalid receive attempts */ if (m->msg_iovlen != 1) - return -EOPNOTSUPP; - - /* Catch invalid receive attempts */ + return -EOPNOTSUPP; /* Don't do multiple iovec entries yet */ if (unlikely(!buf_len)) return -EINVAL; - if (unlikely(sock->state == SS_DISCONNECTING)) { - if (skb_queue_len(&sock->sk->sk_receive_queue) == 0) - return -ENOTCONN; - } else if (unlikely(sock->state != SS_CONNECTED)) - return -ENOTCONN; - - /* Look for a message in receive queue; wait if necessary */ - - if (unlikely(mutex_lock_interruptible(&tsock->lock))) - return -ERESTARTSYS; + lock_sock(sk); -restart: - if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) && - (flags & MSG_DONTWAIT))) { - res = -EWOULDBLOCK; + if (unlikely((sock->state == SS_UNCONNECTED) || + (sock->state == SS_CONNECTING))) { + res = -ENOTCONN; goto exit; } - if ((res = wait_event_interruptible( - *sock->sk->sk_sleep, - ((q_len = skb_queue_len(&sock->sk->sk_receive_queue)) || - (sock->state == SS_DISCONNECTING))) )) { - goto exit; - } +restart: - /* Catch attempt to receive on an already terminated connection */ - /* [THIS CHECK MAY OVERLAP WITH AN EARLIER CHECK] */ + /* Look for a message in receive queue; wait if necessary */ - if (!q_len) { - res = -ENOTCONN; - goto exit; + while (skb_queue_empty(&sk->sk_receive_queue)) { + if (sock->state == SS_DISCONNECTING) { + res = -ENOTCONN; + goto exit; + } + if (flags & MSG_DONTWAIT) { + res = -EWOULDBLOCK; + goto exit; + } + release_sock(sk); + res = wait_event_interruptible(*sk->sk_sleep, + (!skb_queue_empty(&sk->sk_receive_queue) || + (sock->state == SS_DISCONNECTING))); + lock_sock(sk); + if (res) + goto exit; } - /* Get access to first message in receive queue */ + /* Look at first message in receive queue */ - buf = skb_peek(&sock->sk->sk_receive_queue); + buf = skb_peek(&sk->sk_receive_queue); msg = buf_msg(buf); sz = msg_data_sz(msg); err = msg_errcode(msg); @@ -1011,7 +1076,7 @@ restart: /* Discard an empty non-errored message & try again */ if ((!sz) && (!err)) { - advance_queue(tsock); + advance_rx_queue(sk); goto restart; } @@ -1019,7 +1084,8 @@ restart: if (sz_copied == 0) { set_orig_addr(m, msg); - if ((res = anc_data_recv(m, msg, tsock->p))) + res = anc_data_recv(m, msg, tport); + if (res) goto exit; } @@ -1057,9 +1123,9 @@ restart: /* Consume received message (optional) */ if (likely(!(flags & MSG_PEEK))) { - if (unlikely(++tsock->p->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) - tipc_acknowledge(tsock->p->ref, tsock->p->conn_unacked); - advance_queue(tsock); + if (unlikely(++tport->conn_unacked >= TIPC_FLOW_CONTROL_WIN)) + tipc_acknowledge(tport->ref, tport->conn_unacked); + advance_rx_queue(sk); } /* Loop around if more data is required */ @@ -1074,7 +1140,7 @@ restart: goto restart; exit: - mutex_unlock(&tsock->lock); + release_sock(sk); return sz_copied ? sz_copied : res; } @@ -1108,37 +1174,24 @@ static int rx_queue_full(struct tipc_msg *msg, u32 queue_size, u32 base) } /** - * async_disconnect - wrapper function used to disconnect port - * @portref: TIPC port reference (passed as pointer-sized value) - */ - -static void async_disconnect(unsigned long portref) -{ - tipc_disconnect((u32)portref); -} - -/** - * dispatch - handle arriving message - * @tport: TIPC port that received message + * filter_rcv - validate incoming message + * @sk: socket * @buf: message * - * Called with port locked. Must not take socket lock to avoid deadlock risk. + * Enqueues message on receive queue if acceptable; optionally handles + * disconnect indication for a connected socket. + * + * Called with socket lock already taken; port lock may also be taken. * * Returns TIPC error status code (TIPC_OK if message is not to be rejected) */ -static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf) +static u32 filter_rcv(struct sock *sk, struct sk_buff *buf) { + struct socket *sock = sk->sk_socket; struct tipc_msg *msg = buf_msg(buf); - struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle; - struct socket *sock; u32 recv_q_len; - /* Reject message if socket is closing */ - - if (!tsock) - return TIPC_ERR_NO_PORT; - /* Reject message if it is wrong sort of message for socket */ /* @@ -1146,7 +1199,7 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf) * "NO PORT" ISN'T REALLY THE RIGHT ERROR CODE, AND THERE MAY * BE SECURITY IMPLICATIONS INHERENT IN REJECTING INVALID TRAFFIC */ - sock = tsock->sk.sk_socket; + if (sock->state == SS_READY) { if (msg_connected(msg)) { msg_dbg(msg, "dispatch filter 1\n"); @@ -1194,45 +1247,98 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf) if (rx_queue_full(msg, recv_q_len, OVERLOAD_LIMIT_BASE)) return TIPC_ERR_OVERLOAD; } - recv_q_len = skb_queue_len(&tsock->sk.sk_receive_queue); + recv_q_len = skb_queue_len(&sk->sk_receive_queue); if (unlikely(recv_q_len >= (OVERLOAD_LIMIT_BASE / 2))) { if (rx_queue_full(msg, recv_q_len, OVERLOAD_LIMIT_BASE / 2)) return TIPC_ERR_OVERLOAD; } + /* Enqueue message (finally!) */ + + msg_dbg(msg, "handle = msg_data(msg); + atomic_inc(&tipc_queue_size); + __skb_queue_tail(&sk->sk_receive_queue, buf); + /* Initiate connection termination for an incoming 'FIN' */ if (unlikely(msg_errcode(msg) && (sock->state == SS_CONNECTED))) { sock->state = SS_DISCONNECTING; - /* Note: Use signal since port lock is already taken! */ - tipc_k_signal((Handler)async_disconnect, tport->ref); + tipc_disconnect_port(tipc_sk_port(sk)); } - /* Enqueue message (finally!) */ + if (waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); + return TIPC_OK; +} - msg_dbg(msg,"handle = msg_data(msg); - atomic_inc(&tipc_queue_size); - skb_queue_tail(&sock->sk->sk_receive_queue, buf); +/** + * backlog_rcv - handle incoming message from backlog queue + * @sk: socket + * @buf: message + * + * Caller must hold socket lock, but not port lock. + * + * Returns 0 + */ - if (waitqueue_active(sock->sk->sk_sleep)) - wake_up_interruptible(sock->sk->sk_sleep); - return TIPC_OK; +static int backlog_rcv(struct sock *sk, struct sk_buff *buf) +{ + u32 res; + + res = filter_rcv(sk, buf); + if (res) + tipc_reject_msg(buf, res); + return 0; +} + +/** + * dispatch - handle incoming message + * @tport: TIPC port that received message + * @buf: message + * + * Called with port lock already taken. + * + * Returns TIPC error status code (TIPC_OK if message is not to be rejected) + */ + +static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf) +{ + struct sock *sk = (struct sock *)tport->usr_handle; + u32 res; + + /* + * Process message if socket is unlocked; otherwise add to backlog queue + * + * This code is based on sk_receive_skb(), but must be distinct from it + * since a TIPC-specific filter/reject mechanism is utilized + */ + + bh_lock_sock(sk); + if (!sock_owned_by_user(sk)) { + res = filter_rcv(sk, buf); + } else { + sk_add_backlog(sk, buf); + res = TIPC_OK; + } + bh_unlock_sock(sk); + + return res; } /** * wakeupdispatch - wake up port after congestion * @tport: port to wakeup * - * Called with port lock on. + * Called with port lock already taken. */ static void wakeupdispatch(struct tipc_port *tport) { - struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle; + struct sock *sk = (struct sock *)tport->usr_handle; - if (waitqueue_active(tsock->sk.sk_sleep)) - wake_up_interruptible(tsock->sk.sk_sleep); + if (waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); } /** @@ -1240,7 +1346,7 @@ static void wakeupdispatch(struct tipc_port *tport) * @sock: socket structure * @dest: socket address for destination port * @destlen: size of socket address data structure - * @flags: (unused) + * @flags: file-related flags associated with socket * * Returns 0 on success, errno otherwise */ @@ -1248,31 +1354,43 @@ static void wakeupdispatch(struct tipc_port *tport) static int connect(struct socket *sock, struct sockaddr *dest, int destlen, int flags) { - struct tipc_sock *tsock = tipc_sk(sock->sk); + struct sock *sk = sock->sk; struct sockaddr_tipc *dst = (struct sockaddr_tipc *)dest; struct msghdr m = {NULL,}; struct sk_buff *buf; struct tipc_msg *msg; int res; + lock_sock(sk); + /* For now, TIPC does not allow use of connect() with DGRAM/RDM types */ - if (sock->state == SS_READY) - return -EOPNOTSUPP; + if (sock->state == SS_READY) { + res = -EOPNOTSUPP; + goto exit; + } /* For now, TIPC does not support the non-blocking form of connect() */ - if (flags & O_NONBLOCK) - return -EWOULDBLOCK; + if (flags & O_NONBLOCK) { + res = -EWOULDBLOCK; + goto exit; + } /* Issue Posix-compliant error code if socket is in the wrong state */ - if (sock->state == SS_LISTENING) - return -EOPNOTSUPP; - if (sock->state == SS_CONNECTING) - return -EALREADY; - if (sock->state != SS_UNCONNECTED) - return -EISCONN; + if (sock->state == SS_LISTENING) { + res = -EOPNOTSUPP; + goto exit; + } + if (sock->state == SS_CONNECTING) { + res = -EALREADY; + goto exit; + } + if (sock->state != SS_UNCONNECTED) { + res = -EISCONN; + goto exit; + } /* * Reject connection attempt using multicast address @@ -1281,8 +1399,14 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, * so there's no need to do it here */ - if (dst->addrtype == TIPC_ADDR_MCAST) - return -EINVAL; + if (dst->addrtype == TIPC_ADDR_MCAST) { + res = -EINVAL; + goto exit; + } + + /* Reject any messages already in receive queue (very unlikely) */ + + reject_rx_queue(sk); /* Send a 'SYN-' to destination */ @@ -1290,25 +1414,33 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, m.msg_namelen = destlen; res = send_msg(NULL, sock, &m, 0); if (res < 0) { - sock->state = SS_DISCONNECTING; - return res; + goto exit; } - if (mutex_lock_interruptible(&tsock->lock)) - return -ERESTARTSYS; + /* Wait until an 'ACK' or 'RST' arrives, or a timeout occurs */ - /* Wait for destination's 'ACK' response */ + release_sock(sk); + res = wait_event_interruptible_timeout(*sk->sk_sleep, + (!skb_queue_empty(&sk->sk_receive_queue) || + (sock->state != SS_CONNECTING)), + sk->sk_rcvtimeo); + lock_sock(sk); - res = wait_event_interruptible_timeout(*sock->sk->sk_sleep, - skb_queue_len(&sock->sk->sk_receive_queue), - sock->sk->sk_rcvtimeo); - buf = skb_peek(&sock->sk->sk_receive_queue); if (res > 0) { - msg = buf_msg(buf); - res = auto_connect(sock, tsock, msg); - if (!res) { - if (!msg_data_sz(msg)) - advance_queue(tsock); + buf = skb_peek(&sk->sk_receive_queue); + if (buf != NULL) { + msg = buf_msg(buf); + res = auto_connect(sock, msg); + if (!res) { + if (!msg_data_sz(msg)) + advance_rx_queue(sk); + } + } else { + if (sock->state == SS_CONNECTED) { + res = -EISCONN; + } else { + res = -ECONNREFUSED; + } } } else { if (res == 0) @@ -1318,7 +1450,8 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, sock->state = SS_DISCONNECTING; } - mutex_unlock(&tsock->lock); +exit: + release_sock(sk); return res; } @@ -1332,14 +1465,22 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, static int listen(struct socket *sock, int len) { - /* REQUIRES SOCKET LOCKING OF SOME SORT? */ + struct sock *sk = sock->sk; + int res; + + lock_sock(sk); if (sock->state == SS_READY) - return -EOPNOTSUPP; - if (sock->state != SS_UNCONNECTED) - return -EINVAL; - sock->state = SS_LISTENING; - return 0; + res = -EOPNOTSUPP; + else if (sock->state != SS_UNCONNECTED) + res = -EINVAL; + else { + sock->state = SS_LISTENING; + res = 0; + } + + release_sock(sk); + return res; } /** @@ -1351,50 +1492,69 @@ static int listen(struct socket *sock, int len) * Returns 0 on success, errno otherwise */ -static int accept(struct socket *sock, struct socket *newsock, int flags) +static int accept(struct socket *sock, struct socket *new_sock, int flags) { - struct tipc_sock *tsock = tipc_sk(sock->sk); + struct sock *sk = sock->sk; struct sk_buff *buf; - int res = -EFAULT; - - if (sock->state == SS_READY) - return -EOPNOTSUPP; - if (sock->state != SS_LISTENING) - return -EINVAL; - - if (unlikely((skb_queue_len(&sock->sk->sk_receive_queue) == 0) && - (flags & O_NONBLOCK))) - return -EWOULDBLOCK; + int res; - if (mutex_lock_interruptible(&tsock->lock)) - return -ERESTARTSYS; + lock_sock(sk); - if (wait_event_interruptible(*sock->sk->sk_sleep, - skb_queue_len(&sock->sk->sk_receive_queue))) { - res = -ERESTARTSYS; + if (sock->state == SS_READY) { + res = -EOPNOTSUPP; + goto exit; + } + if (sock->state != SS_LISTENING) { + res = -EINVAL; goto exit; } - buf = skb_peek(&sock->sk->sk_receive_queue); - res = tipc_create(sock_net(sock->sk), newsock, 0); + while (skb_queue_empty(&sk->sk_receive_queue)) { + if (flags & O_NONBLOCK) { + res = -EWOULDBLOCK; + goto exit; + } + release_sock(sk); + res = wait_event_interruptible(*sk->sk_sleep, + (!skb_queue_empty(&sk->sk_receive_queue))); + lock_sock(sk); + if (res) + goto exit; + } + + buf = skb_peek(&sk->sk_receive_queue); + + res = tipc_create(sock_net(sock->sk), new_sock, 0); if (!res) { - struct tipc_sock *new_tsock = tipc_sk(newsock->sk); + struct sock *new_sk = new_sock->sk; + struct tipc_port *new_tport = tipc_sk_port(new_sk); + u32 new_ref = new_tport->ref; struct tipc_portid id; struct tipc_msg *msg = buf_msg(buf); - u32 new_ref = new_tsock->p->ref; + + lock_sock(new_sk); + + /* + * Reject any stray messages received by new socket + * before the socket lock was taken (very, very unlikely) + */ + + reject_rx_queue(new_sk); + + /* Connect new socket to it's peer */ id.ref = msg_origport(msg); id.node = msg_orignode(msg); tipc_connect2port(new_ref, &id); - newsock->state = SS_CONNECTED; + new_sock->state = SS_CONNECTED; tipc_set_portimportance(new_ref, msg_importance(msg)); if (msg_named(msg)) { - new_tsock->p->conn_type = msg_nametype(msg); - new_tsock->p->conn_instance = msg_nameinst(msg); + new_tport->conn_type = msg_nametype(msg); + new_tport->conn_instance = msg_nameinst(msg); } - /* + /* * Respond to 'SYN-' by discarding it & returning 'ACK'-. * Respond to 'SYN+' by queuing it on new socket. */ @@ -1403,17 +1563,16 @@ static int accept(struct socket *sock, struct socket *newsock, int flags) if (!msg_data_sz(msg)) { struct msghdr m = {NULL,}; - send_packet(NULL, newsock, &m, 0); - advance_queue(tsock); + advance_rx_queue(sk); + send_packet(NULL, new_sock, &m, 0); } else { - sock_lock(tsock); - skb_dequeue(&sock->sk->sk_receive_queue); - sock_unlock(tsock); - skb_queue_head(&newsock->sk->sk_receive_queue, buf); + __skb_dequeue(&sk->sk_receive_queue); + __skb_queue_head(&new_sk->sk_receive_queue, buf); } + release_sock(new_sk); } exit: - mutex_unlock(&tsock->lock); + release_sock(sk); return res; } @@ -1429,54 +1588,46 @@ exit: static int shutdown(struct socket *sock, int how) { - struct tipc_sock* tsock = tipc_sk(sock->sk); + struct sock *sk = sock->sk; + struct tipc_port *tport = tipc_sk_port(sk); struct sk_buff *buf; int res; if (how != SHUT_RDWR) return -EINVAL; - if (mutex_lock_interruptible(&tsock->lock)) - return -ERESTARTSYS; - - sock_lock(tsock); + lock_sock(sk); switch (sock->state) { + case SS_CONNECTING: case SS_CONNECTED: - /* Send 'FIN+' or 'FIN-' message to peer */ - - sock_unlock(tsock); + /* Disconnect and send a 'FIN+' or 'FIN-' message to peer */ restart: - if ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) { + buf = __skb_dequeue(&sk->sk_receive_queue); + if (buf) { atomic_dec(&tipc_queue_size); if (TIPC_SKB_CB(buf)->handle != msg_data(buf_msg(buf))) { buf_discard(buf); goto restart; } + tipc_disconnect(tport->ref); tipc_reject_msg(buf, TIPC_CONN_SHUTDOWN); + } else { + tipc_shutdown(tport->ref); } - else { - tipc_shutdown(tsock->p->ref); - } - sock_lock(tsock); + + sock->state = SS_DISCONNECTING; /* fall through */ case SS_DISCONNECTING: - /* Discard any unreceived messages */ - - while ((buf = skb_dequeue(&sock->sk->sk_receive_queue))) { - atomic_dec(&tipc_queue_size); - buf_discard(buf); - } - tsock->p->conn_unacked = 0; + /* Discard any unreceived messages; wake up sleeping tasks */ - /* fall through */ - - case SS_CONNECTING: - sock->state = SS_DISCONNECTING; + discard_rx_queue(sk); + if (waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); res = 0; break; @@ -1484,9 +1635,7 @@ restart: res = -ENOTCONN; } - sock_unlock(tsock); - - mutex_unlock(&tsock->lock); + release_sock(sk); return res; } @@ -1507,7 +1656,8 @@ restart: static int setsockopt(struct socket *sock, int lvl, int opt, char __user *ov, int ol) { - struct tipc_sock *tsock = tipc_sk(sock->sk); + struct sock *sk = sock->sk; + struct tipc_port *tport = tipc_sk_port(sk); u32 value; int res; @@ -1520,30 +1670,31 @@ static int setsockopt(struct socket *sock, if ((res = get_user(value, (u32 __user *)ov))) return res; - if (mutex_lock_interruptible(&tsock->lock)) - return -ERESTARTSYS; + lock_sock(sk); switch (opt) { case TIPC_IMPORTANCE: - res = tipc_set_portimportance(tsock->p->ref, value); + res = tipc_set_portimportance(tport->ref, value); break; case TIPC_SRC_DROPPABLE: if (sock->type != SOCK_STREAM) - res = tipc_set_portunreliable(tsock->p->ref, value); + res = tipc_set_portunreliable(tport->ref, value); else res = -ENOPROTOOPT; break; case TIPC_DEST_DROPPABLE: - res = tipc_set_portunreturnable(tsock->p->ref, value); + res = tipc_set_portunreturnable(tport->ref, value); break; case TIPC_CONN_TIMEOUT: - sock->sk->sk_rcvtimeo = msecs_to_jiffies(value); + sk->sk_rcvtimeo = msecs_to_jiffies(value); + /* no need to set "res", since already 0 at this point */ break; default: res = -EINVAL; } - mutex_unlock(&tsock->lock); + release_sock(sk); + return res; } @@ -1564,7 +1715,8 @@ static int setsockopt(struct socket *sock, static int getsockopt(struct socket *sock, int lvl, int opt, char __user *ov, int __user *ol) { - struct tipc_sock *tsock = tipc_sk(sock->sk); + struct sock *sk = sock->sk; + struct tipc_port *tport = tipc_sk_port(sk); int len; u32 value; int res; @@ -1576,26 +1728,28 @@ static int getsockopt(struct socket *sock, if ((res = get_user(len, ol))) return res; - if (mutex_lock_interruptible(&tsock->lock)) - return -ERESTARTSYS; + lock_sock(sk); switch (opt) { case TIPC_IMPORTANCE: - res = tipc_portimportance(tsock->p->ref, &value); + res = tipc_portimportance(tport->ref, &value); break; case TIPC_SRC_DROPPABLE: - res = tipc_portunreliable(tsock->p->ref, &value); + res = tipc_portunreliable(tport->ref, &value); break; case TIPC_DEST_DROPPABLE: - res = tipc_portunreturnable(tsock->p->ref, &value); + res = tipc_portunreturnable(tport->ref, &value); break; case TIPC_CONN_TIMEOUT: - value = jiffies_to_msecs(sock->sk->sk_rcvtimeo); + value = jiffies_to_msecs(sk->sk_rcvtimeo); + /* no need to set "res", since already 0 at this point */ break; default: res = -EINVAL; } + release_sock(sk); + if (res) { /* "get" failed */ } @@ -1609,7 +1763,6 @@ static int getsockopt(struct socket *sock, res = put_user(sizeof(value), ol); } - mutex_unlock(&tsock->lock); return res; } @@ -1722,6 +1875,7 @@ int tipc_socket_init(void) /** * tipc_socket_stop - stop TIPC socket interface */ + void tipc_socket_stop(void) { if (!sockets_enabled) -- cgit v1.2.3-59-g8ed1b From 7ef3abd2104232a35f259dad6a213310edc7c9fe Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Tue, 15 Apr 2008 00:29:24 -0700 Subject: [IRDA]: Remove irlan_eth_send_gratuitous_arp() Even kernel 2.2.26 (sic) already contains the #undef CONFIG_IRLAN_SEND_GRATUITOUS_ARP with the comment "but for some reason the machine crashes if you use DHCP". Either someone finally looks into this or it's simply time to remove this dead code. Reported-by: Robert P. J. Day Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- include/net/irda/irlan_eth.h | 1 - net/irda/irlan/irlan_common.c | 10 ---------- net/irda/irlan/irlan_eth.c | 33 --------------------------------- 3 files changed, 44 deletions(-) (limited to 'net') diff --git a/include/net/irda/irlan_eth.h b/include/net/irda/irlan_eth.h index 0062347600b9..de5c81691f33 100644 --- a/include/net/irda/irlan_eth.h +++ b/include/net/irda/irlan_eth.h @@ -29,5 +29,4 @@ struct net_device *alloc_irlandev(const char *name); int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb); void irlan_eth_flow_indication( void *instance, void *sap, LOCAL_FLOW flow); -void irlan_eth_send_gratuitous_arp(struct net_device *dev); #endif diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c index 75bb6a9dcaaa..9a1cd87e7142 100644 --- a/net/irda/irlan/irlan_common.c +++ b/net/irda/irlan/irlan_common.c @@ -54,13 +54,6 @@ #include -/* - * Send gratuitous ARP when connected to a new AP or not. May be a clever - * thing to do, but for some reason the machine crashes if you use DHCP. So - * lets not use it by default. - */ -#undef CONFIG_IRLAN_SEND_GRATUITOUS_ARP - /* extern char sysctl_devname[]; */ /* @@ -393,9 +386,6 @@ static void irlan_connect_confirm(void *instance, void *sap, /* Ready to transfer Ethernet frames */ netif_start_queue(self->dev); self->disconnect_reason = 0; /* Clear reason */ -#ifdef CONFIG_IRLAN_SEND_GRATUITOUS_ARP - irlan_eth_send_gratuitous_arp(&self->dev); -#endif wake_up_interruptible(&self->open_wait); } diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index 7a6b14ab1e7f..05112be99569 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -288,39 +288,6 @@ void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) } } -/* - * Function irlan_etc_send_gratuitous_arp (dev) - * - * Send gratuitous ARP to announce that we have changed - * hardware address, so that all peers updates their ARP tables - */ -void irlan_eth_send_gratuitous_arp(struct net_device *dev) -{ -#ifdef CONFIG_INET - struct in_device *in_dev; - - /* - * When we get a new MAC address do a gratuitous ARP. This - * is useful if we have changed access points on the same - * subnet. - */ - IRDA_DEBUG(4, "IrLAN: Sending gratuitous ARP\n"); - rcu_read_lock(); - in_dev = __in_dev_get_rcu(dev); - if (in_dev == NULL) - goto out; - if (in_dev->ifa_list) - - arp_send(ARPOP_REQUEST, ETH_P_ARP, - in_dev->ifa_list->ifa_address, - dev, - in_dev->ifa_list->ifa_address, - NULL, dev->dev_addr, NULL); -out: - rcu_read_unlock(); -#endif /* CONFIG_INET */ -} - /* * Function set_multicast_list (dev) * -- cgit v1.2.3-59-g8ed1b From c93cf61fd1d5378134f9b06703f7078067542e00 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 15 Apr 2008 00:35:23 -0700 Subject: [NETNS]: The net-subsys IDs generator. To make some per-net generic pointers, we need some way to address them, i.e. - IDs. This is simple IDA-based IDs generator for pernet subsystems. Addressing questions about potential checkpoint/restart problems: these IDs are "lite-offsets" within the net structure and are by no means supposed to be exported to the userspace. Since it will be used in the nearest future by devices only (tun, vlan, tunnels, bridge, etc), I make it resemble the functionality of register_pernet_device(). The new ids is stored in the *id pointer _before_ calling the init callback to make this id available in this callback. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/net/net_namespace.h | 2 ++ net/core/net_namespace.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) (limited to 'net') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index e2aee2689abe..72fad1a0956b 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -185,6 +185,8 @@ extern int register_pernet_subsys(struct pernet_operations *); extern void unregister_pernet_subsys(struct pernet_operations *); extern int register_pernet_device(struct pernet_operations *); extern void unregister_pernet_device(struct pernet_operations *); +extern int register_pernet_gen_device(int *id, struct pernet_operations *); +extern void unregister_pernet_gen_device(int id, struct pernet_operations *); struct ctl_path; struct ctl_table; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 7b660834a4c2..2197d51aef3b 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -5,6 +5,7 @@ #include #include #include +#include #include /* @@ -253,6 +254,8 @@ static void unregister_pernet_operations(struct pernet_operations *ops) } #endif +static DEFINE_IDA(net_generic_ids); + /** * register_pernet_subsys - register a network namespace subsystem * @ops: pernet operations structure for the subsystem @@ -330,6 +333,30 @@ int register_pernet_device(struct pernet_operations *ops) } EXPORT_SYMBOL_GPL(register_pernet_device); +int register_pernet_gen_device(int *id, struct pernet_operations *ops) +{ + int error; + mutex_lock(&net_mutex); +again: + error = ida_get_new_above(&net_generic_ids, 1, id); + if (error) { + if (error == -EAGAIN) { + ida_pre_get(&net_generic_ids, GFP_KERNEL); + goto again; + } + goto out; + } + error = register_pernet_operations(&pernet_list, ops); + if (error) + ida_remove(&net_generic_ids, *id); + else if (first_device == &pernet_list) + first_device = &ops->list; +out: + mutex_unlock(&net_mutex); + return error; +} +EXPORT_SYMBOL_GPL(register_pernet_gen_device); + /** * unregister_pernet_device - unregister a network namespace netdevice * @ops: pernet operations structure to manipulate @@ -348,3 +375,14 @@ void unregister_pernet_device(struct pernet_operations *ops) mutex_unlock(&net_mutex); } EXPORT_SYMBOL_GPL(unregister_pernet_device); + +void unregister_pernet_gen_device(int id, struct pernet_operations *ops) +{ + mutex_lock(&net_mutex); + if (&ops->list == first_device) + first_device = first_device->next; + unregister_pernet_operations(ops); + ida_remove(&net_generic_ids, id); + mutex_unlock(&net_mutex); +} +EXPORT_SYMBOL_GPL(unregister_pernet_gen_device); -- cgit v1.2.3-59-g8ed1b From dec827d174d7f76c457238800183ca864a639365 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Tue, 15 Apr 2008 00:36:08 -0700 Subject: [NETNS]: The generic per-net pointers. Add the elastic array of void * pointer to the struct net. The access rules are simple: 1. register the ops with register_pernet_gen_device to get the id of your private pointer 2. call net_assign_generic() to put the private data on the struct net (most preferably this should be done in the ->init callback of the ops registered) 3. do not store any private reference on the net_generic array; 4. do not change this pointer while the net is alive; 5. use the net_generic() to get the pointer. When adding a new pointer, I copy the old array, replace it with a new one and schedule the old for kfree after an RCU grace period. Since the net_generic explores the net->gen array inside rcu read section and once set the net->gen->ptr[x] pointer never changes, this grants us a safe access to generic pointers. Quoting Paul: "... RCU is protecting -only- the net_generic structure that net_generic() is traversing, and the [pointer] returned by net_generic() is protected by a reference counter in the upper-level struct net." Signed-off-by: Pavel Emelyanov Acked-by: Paul E. McKenney Signed-off-by: David S. Miller --- include/net/net_namespace.h | 2 ++ include/net/netns/generic.h | 49 +++++++++++++++++++++++++++++++++++ net/core/net_namespace.c | 62 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 include/net/netns/generic.h (limited to 'net') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 72fad1a0956b..f880b0f9f107 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -20,6 +20,7 @@ struct proc_dir_entry; struct net_device; struct sock; struct ctl_table_header; +struct net_generic; struct net { atomic_t count; /* To decided when the network @@ -61,6 +62,7 @@ struct net { #ifdef CONFIG_NETFILTER struct netns_xt xt; #endif + struct net_generic *gen; }; diff --git a/include/net/netns/generic.h b/include/net/netns/generic.h new file mode 100644 index 000000000000..0c04fd2a700b --- /dev/null +++ b/include/net/netns/generic.h @@ -0,0 +1,49 @@ +/* + * generic net pointers + */ + +#ifndef __NET_GENERIC_H__ +#define __NET_GENERIC_H__ + +#include + +/* + * Generic net pointers are to be used by modules to put some private + * stuff on the struct net without explicit struct net modification + * + * The rules are simple: + * 1. register the ops with register_pernet_gen_device to get the id + * of your private pointer; + * 2. call net_assign_generic() to put the private data on the struct + * net (most preferably this should be done in the ->init callback + * of the ops registered); + * 3. do not change this pointer while the net is alive; + * 4. do not try to have any private reference on the net_generic object. + * + * After accomplishing all of the above, the private pointer can be + * accessed with the net_generic() call. + */ + +struct net_generic { + unsigned int len; + struct rcu_head rcu; + + void *ptr[0]; +}; + +static inline void *net_generic(struct net *net, int id) +{ + struct net_generic *ng; + void *ptr; + + rcu_read_lock(); + ng = rcu_dereference(net->gen); + BUG_ON(id == 0 || id > ng->len); + ptr = ng->ptr[id - 1]; + rcu_read_unlock(); + + return ptr; +} + +extern int net_assign_generic(struct net *net, int id, void *data); +#endif diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 2197d51aef3b..763674e1e593 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -7,6 +7,7 @@ #include #include #include +#include /* * Our network namespace constructor/destructor lists @@ -21,6 +22,8 @@ LIST_HEAD(net_namespace_list); struct net init_net; EXPORT_SYMBOL(init_net); +#define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ + /* * setup_net runs the initializers for the network namespace object. */ @@ -29,10 +32,21 @@ static __net_init int setup_net(struct net *net) /* Must be called with net_mutex held */ struct pernet_operations *ops; int error; + struct net_generic *ng; atomic_set(&net->count, 1); atomic_set(&net->use_count, 0); + error = -ENOMEM; + ng = kzalloc(sizeof(struct net_generic) + + INITIAL_NET_GEN_PTRS * sizeof(void *), GFP_KERNEL); + if (ng == NULL) + goto out; + + ng->len = INITIAL_NET_GEN_PTRS; + INIT_RCU_HEAD(&ng->rcu); + rcu_assign_pointer(net->gen, ng); + error = 0; list_for_each_entry(ops, &pernet_list, list) { if (ops->init) { @@ -54,6 +68,7 @@ out_undo: } rcu_barrier(); + kfree(ng); goto out; } @@ -386,3 +401,50 @@ void unregister_pernet_gen_device(int id, struct pernet_operations *ops) mutex_unlock(&net_mutex); } EXPORT_SYMBOL_GPL(unregister_pernet_gen_device); + +static void net_generic_release(struct rcu_head *rcu) +{ + struct net_generic *ng; + + ng = container_of(rcu, struct net_generic, rcu); + kfree(ng); +} + +int net_assign_generic(struct net *net, int id, void *data) +{ + struct net_generic *ng, *old_ng; + + BUG_ON(!mutex_is_locked(&net_mutex)); + BUG_ON(id == 0); + + ng = old_ng = net->gen; + if (old_ng->len >= id) + goto assign; + + ng = kzalloc(sizeof(struct net_generic) + + id * sizeof(void *), GFP_KERNEL); + if (ng == NULL) + return -ENOMEM; + + /* + * Some synchronisation notes: + * + * The net_generic explores the net->gen array inside rcu + * read section. Besides once set the net->gen->ptr[x] + * pointer never changes (see rules in netns/generic.h). + * + * That said, we simply duplicate this array and schedule + * the old copy for kfree after a grace period. + */ + + ng->len = id; + INIT_RCU_HEAD(&ng->rcu); + memcpy(&ng->ptr, &old_ng->ptr, old_ng->len); + + rcu_assign_pointer(net->gen, ng); + call_rcu(&old_ng->rcu, net_generic_release); +assign: + ng->ptr[id - 1] = data; + return 0; +} +EXPORT_SYMBOL_GPL(net_assign_generic); -- cgit v1.2.3-59-g8ed1b From 11ecede7874efb9c31184b49090fc6d9bb17f9f6 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 15 Apr 2008 19:01:43 -0700 Subject: [TIPC]: Remove redundant NULL check when discarding buffers This patch eliminates a null pointer check when discarding a TIPC message buffer, since kfree_skb() already handles this situation. Acknowledgements to Florian Westphal (fw@strlen.de> for suggesting this enhancement. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/core.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net') diff --git a/net/tipc/core.h b/net/tipc/core.h index 3fe9b70331d9..3229d29e352a 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -334,8 +334,7 @@ static inline struct sk_buff *buf_acquire(u32 size) static inline void buf_discard(struct sk_buff *skb) { - if (likely(skb != NULL)) - kfree_skb(skb); + kfree_skb(skb); } #endif -- cgit v1.2.3-59-g8ed1b From bdc82bee43d11c093ff0378acef2a9550891cbb9 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 15 Apr 2008 19:02:30 -0700 Subject: [TIPC]: Use fast buffer cloning to improve performance This patch causes TIPC to allocate fast clonable sk_buffs, rather than standard ones. This speeds up the cloning operation done by the link code each time a message is sent off-node. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/tipc/core.h b/net/tipc/core.h index 3229d29e352a..b3c9df385bbc 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -316,7 +316,7 @@ static inline struct sk_buff *buf_acquire(u32 size) struct sk_buff *skb; unsigned int buf_size = (BUF_HEADROOM + size + 3) & ~3u; - skb = alloc_skb(buf_size, GFP_ATOMIC); + skb = alloc_skb_fclone(buf_size, GFP_ATOMIC); if (skb) { skb_reserve(skb, BUF_HEADROOM); skb_put(skb, size); -- cgit v1.2.3-59-g8ed1b From fe13dda2d24eca2ee8a6bb8a0af88ab84d589fd6 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 15 Apr 2008 19:03:23 -0700 Subject: [TIPC]: Force linearization of non-linear sk_buffs This patch allows TIPC to process incoming messages that are stored in a fragmented sk_buff, by forcing the linearization of any such messages it receives. Note: This is an interim solution to allow TIPC to operate with Ethernet devices that generate non-linear buffers (such as the gianfar driver), until such time as the rest of TIPC is enhanced to handle sk_buffs with multiple data areas. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/core.h | 12 ++++++++++++ net/tipc/link.c | 6 ++++++ 2 files changed, 18 insertions(+) (limited to 'net') diff --git a/net/tipc/core.h b/net/tipc/core.h index b3c9df385bbc..325404fd4eb5 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -337,4 +337,16 @@ static inline void buf_discard(struct sk_buff *skb) kfree_skb(skb); } +/** + * buf_linearize - convert a TIPC message buffer into a single contiguous piece + * @skb: message buffer + * + * Returns 0 on success. + */ + +static inline int buf_linearize(struct sk_buff *skb) +{ + return skb_linearize(skb); +} + #endif diff --git a/net/tipc/link.c b/net/tipc/link.c index a42f43430101..087379366d3c 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1811,6 +1811,12 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) #endif msg_dbg(msg," Date: Tue, 15 Apr 2008 19:04:54 -0700 Subject: [TIPC]: Enhance validation of format on incoming messages This patch ensures that TIPC properly handles incoming messages that have incorrect or unexpected formats. Most significantly, it now ensures that each sl_buff has at least as much data as the message header indicates it should, and that the entire message header is stored contiguously; this prevents TIPC from accidentally accessing memory that is not part of the sk_buff. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/link.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 77 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/tipc/link.c b/net/tipc/link.c index 087379366d3c..2a26a16e269f 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1785,6 +1785,56 @@ static struct sk_buff *link_insert_deferred_queue(struct link *l_ptr, return buf; } +/** + * link_recv_buf_validate - validate basic format of received message + * + * This routine ensures a TIPC message has an acceptable header, and at least + * as much data as the header indicates it should. The routine also ensures + * that the entire message header is stored in the main fragment of the message + * buffer, to simplify future access to message header fields. + * + * Note: Having extra info present in the message header or data areas is OK. + * TIPC will ignore the excess, under the assumption that it is optional info + * introduced by a later release of the protocol. + */ + +static int link_recv_buf_validate(struct sk_buff *buf) +{ + static u32 min_data_hdr_size[8] = { + SHORT_H_SIZE, MCAST_H_SIZE, LONG_H_SIZE, DIR_MSG_H_SIZE, + MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE, MAX_H_SIZE + }; + + struct tipc_msg *msg; + u32 tipc_hdr[2]; + u32 size; + u32 hdr_size; + u32 min_hdr_size; + + if (unlikely(buf->len < MIN_H_SIZE)) + return 0; + + msg = skb_header_pointer(buf, 0, sizeof(tipc_hdr), tipc_hdr); + if (msg == NULL) + return 0; + + if (unlikely(msg_version(msg) != TIPC_VERSION)) + return 0; + + size = msg_size(msg); + hdr_size = msg_hdr_sz(msg); + min_hdr_size = msg_isdata(msg) ? + min_data_hdr_size[msg_type(msg)] : INT_H_SIZE; + + if (unlikely((hdr_size < min_hdr_size) || + (size < hdr_size) || + (buf->len < size) || + (size - hdr_size > TIPC_MAX_USER_MSG_SIZE))) + return 0; + + return pskb_may_pull(buf, hdr_size); +} + void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) { read_lock_bh(&tipc_net_lock); @@ -1794,9 +1844,9 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) struct link *l_ptr; struct sk_buff *crs; struct sk_buff *buf = head; - struct tipc_msg *msg = buf_msg(buf); - u32 seq_no = msg_seqno(msg); - u32 ackd = msg_ack(msg); + struct tipc_msg *msg; + u32 seq_no; + u32 ackd; u32 released = 0; int type; @@ -1804,12 +1854,11 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) TIPC_SKB_CB(buf)->handle = b_ptr; head = head->next; - if (unlikely(msg_version(msg) != TIPC_VERSION)) + + /* Ensure message is well-formed */ + + if (unlikely(!link_recv_buf_validate(buf))) goto cont; -#if 0 - if (msg_user(msg) != LINK_PROTOCOL) -#endif - msg_dbg(msg,"links[b_ptr->identity]; if (unlikely(!l_ptr)) { tipc_node_unlock(n_ptr); goto cont; } - /* - * Release acked messages - */ + + /* Validate message sequence number info */ + + seq_no = msg_seqno(msg); + ackd = msg_ack(msg); + + /* Release acked messages */ + if (less(n_ptr->bclink.acked, msg_bcast_ack(msg))) { if (tipc_node_is_up(n_ptr) && n_ptr->bclink.supported) tipc_bclink_acknowledge(n_ptr, msg_bcast_ack(msg)); @@ -1857,6 +1917,9 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) l_ptr->first_out = crs; l_ptr->out_queue_size -= released; } + + /* Try sending any messages link endpoint has pending */ + if (unlikely(l_ptr->next_out)) tipc_link_push_queue(l_ptr); if (unlikely(!list_empty(&l_ptr->waiting_ports))) @@ -1866,6 +1929,8 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *tb_ptr) tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); } + /* Now (finally!) process the incoming message */ + protocol_check: if (likely(link_working_working(l_ptr))) { if (likely(seq_no == mod(l_ptr->next_in_no))) { -- cgit v1.2.3-59-g8ed1b From 73e87e02ec484ac459c4be262ab76960b89dc019 Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Tue, 15 Apr 2008 19:29:14 -0700 Subject: CAN: use hrtimers in can-bcm protocol Make use of hrtimers to support high resolution capabilities, when provided by the system clocksource. The conversion to hrtimers additionally discovered and solved an unlikely race condition that has been reproduced under (unrealistic) massive receive load, which can only be produced on vcan software devices. [ Fix printf format warnings on 64-bit -DaveM ] Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller --- net/can/bcm.c | 251 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 130 insertions(+), 121 deletions(-) (limited to 'net') diff --git a/net/can/bcm.c b/net/can/bcm.c index e9f99b2c6bc9..74fd2d33aff4 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -43,6 +43,7 @@ #include #include +#include #include #include #include @@ -66,7 +67,7 @@ #define REGMASK(id) ((id & CAN_RTR_FLAG) | ((id & CAN_EFF_FLAG) ? \ (CAN_EFF_MASK | CAN_EFF_FLAG) : CAN_SFF_MASK)) -#define CAN_BCM_VERSION CAN_VERSION +#define CAN_BCM_VERSION "20080415" static __initdata const char banner[] = KERN_INFO "can: broadcast manager protocol (rev " CAN_BCM_VERSION ")\n"; @@ -85,11 +86,10 @@ struct bcm_op { int ifindex; canid_t can_id; int flags; - unsigned long j_ival1, j_ival2, j_lastmsg; unsigned long frames_abs, frames_filtered; - struct timer_list timer, thrtimer; struct timeval ival1, ival2; - ktime_t rx_stamp; + struct hrtimer timer, thrtimer; + ktime_t rx_stamp, kt_ival1, kt_ival2, kt_lastmsg; int rx_ifindex; int count; int nframes; @@ -125,39 +125,6 @@ static inline struct bcm_sock *bcm_sk(const struct sock *sk) #define OPSIZ sizeof(struct bcm_op) #define MHSIZ sizeof(struct bcm_msg_head) -/* - * rounded_tv2jif - calculate jiffies from timeval including optional up - * @tv: pointer to timeval - * - * Description: - * Unlike timeval_to_jiffies() provided in include/linux/jiffies.h, this - * function is intentionally more relaxed on precise timer ticks to get - * exact one jiffy for requested 1000us on a 1000HZ machine. - * This code is to be removed when upgrading to kernel hrtimer. - * - * Return: - * calculated jiffies (max: ULONG_MAX) - */ -static unsigned long rounded_tv2jif(const struct timeval *tv) -{ - unsigned long sec = tv->tv_sec; - unsigned long usec = tv->tv_usec; - unsigned long jif; - - if (sec > ULONG_MAX / HZ) - return ULONG_MAX; - - /* round up to get at least the requested time */ - usec += 1000000 / HZ - 1; - - jif = usec / (1000000 / HZ); - - if (sec * HZ > ULONG_MAX - jif) - return ULONG_MAX; - - return jif + sec * HZ; -} - /* * procfs functions */ @@ -208,13 +175,17 @@ static int bcm_read_proc(char *page, char **start, off_t off, len += snprintf(page + len, PAGE_SIZE - len, "[%d]%c ", op->nframes, (op->flags & RX_CHECK_DLC)?'d':' '); - if (op->j_ival1) + if (op->kt_ival1.tv64) len += snprintf(page + len, PAGE_SIZE - len, - "timeo=%ld ", op->j_ival1); + "timeo=%lld ", + (long long) + ktime_to_us(op->kt_ival1)); - if (op->j_ival2) + if (op->kt_ival2.tv64) len += snprintf(page + len, PAGE_SIZE - len, - "thr=%ld ", op->j_ival2); + "thr=%lld ", + (long long) + ktime_to_us(op->kt_ival2)); len += snprintf(page + len, PAGE_SIZE - len, "# recv %ld (%ld) => reduction: ", @@ -238,13 +209,14 @@ static int bcm_read_proc(char *page, char **start, off_t off, "tx_op: %03X %s [%d] ", op->can_id, bcm_proc_getifname(op->ifindex), op->nframes); - if (op->j_ival1) - len += snprintf(page + len, PAGE_SIZE - len, "t1=%ld ", - op->j_ival1); - if (op->j_ival2) - len += snprintf(page + len, PAGE_SIZE - len, "t2=%ld ", - op->j_ival2); + if (op->kt_ival1.tv64) + len += snprintf(page + len, PAGE_SIZE - len, "t1=%lld ", + (long long) ktime_to_us(op->kt_ival1)); + + if (op->kt_ival2.tv64) + len += snprintf(page + len, PAGE_SIZE - len, "t2=%lld ", + (long long) ktime_to_us(op->kt_ival2)); len += snprintf(page + len, PAGE_SIZE - len, "# sent %ld\n", op->frames_abs); @@ -371,11 +343,12 @@ static void bcm_send_to_user(struct bcm_op *op, struct bcm_msg_head *head, /* * bcm_tx_timeout_handler - performes cyclic CAN frame transmissions */ -static void bcm_tx_timeout_handler(unsigned long data) +static enum hrtimer_restart bcm_tx_timeout_handler(struct hrtimer *hrtimer) { - struct bcm_op *op = (struct bcm_op *)data; + struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer); + enum hrtimer_restart ret = HRTIMER_NORESTART; - if (op->j_ival1 && (op->count > 0)) { + if (op->kt_ival1.tv64 && (op->count > 0)) { op->count--; if (!op->count && (op->flags & TX_COUNTEVT)) { @@ -394,22 +367,24 @@ static void bcm_tx_timeout_handler(unsigned long data) } } - if (op->j_ival1 && (op->count > 0)) { + if (op->kt_ival1.tv64 && (op->count > 0)) { /* send (next) frame */ bcm_can_tx(op); - mod_timer(&op->timer, jiffies + op->j_ival1); + hrtimer_forward(hrtimer, ktime_get(), op->kt_ival1); + ret = HRTIMER_RESTART; } else { - if (op->j_ival2) { + if (op->kt_ival2.tv64) { /* send (next) frame */ bcm_can_tx(op); - mod_timer(&op->timer, jiffies + op->j_ival2); + hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2); + ret = HRTIMER_RESTART; } } - return; + return ret; } /* @@ -419,8 +394,6 @@ static void bcm_rx_changed(struct bcm_op *op, struct can_frame *data) { struct bcm_msg_head head; - op->j_lastmsg = jiffies; - /* update statistics */ op->frames_filtered++; @@ -439,6 +412,12 @@ static void bcm_rx_changed(struct bcm_op *op, struct can_frame *data) bcm_send_to_user(op, &head, data, 1); } +/* TODO: move to linux/hrtimer.h */ +static inline int hrtimer_callback_running(struct hrtimer *timer) +{ + return timer->state & HRTIMER_STATE_CALLBACK; +} + /* * bcm_rx_update_and_send - process a detected relevant receive content change * 1. update the last received data @@ -448,30 +427,44 @@ static void bcm_rx_update_and_send(struct bcm_op *op, struct can_frame *lastdata, struct can_frame *rxdata) { - unsigned long nexttx = op->j_lastmsg + op->j_ival2; - memcpy(lastdata, rxdata, CFSIZ); /* mark as used */ lastdata->can_dlc |= RX_RECV; - /* throttle bcm_rx_changed ? */ - if ((op->thrtimer.expires) || - ((op->j_ival2) && (nexttx > jiffies))) { - /* we are already waiting OR we have to start waiting */ + /* throtteling mode inactive OR data update already on the run ? */ + if (!op->kt_ival2.tv64 || hrtimer_callback_running(&op->thrtimer)) { + /* send RX_CHANGED to the user immediately */ + bcm_rx_changed(op, rxdata); + return; + } + if (hrtimer_active(&op->thrtimer)) { /* mark as 'throttled' */ lastdata->can_dlc |= RX_THR; + return; + } - if (!(op->thrtimer.expires)) { - /* start the timer only the first time */ - mod_timer(&op->thrtimer, nexttx); - } - - } else { - /* send RX_CHANGED to the user immediately */ + if (!op->kt_lastmsg.tv64) { + /* send first RX_CHANGED to the user immediately */ bcm_rx_changed(op, rxdata); + op->kt_lastmsg = ktime_get(); + return; + } + + if (ktime_us_delta(ktime_get(), op->kt_lastmsg) < + ktime_to_us(op->kt_ival2)) { + /* mark as 'throttled' and start timer */ + lastdata->can_dlc |= RX_THR; + hrtimer_start(&op->thrtimer, + ktime_add(op->kt_lastmsg, op->kt_ival2), + HRTIMER_MODE_ABS); + return; } + + /* the gap was that big, that throttling was not needed here */ + bcm_rx_changed(op, rxdata); + op->kt_lastmsg = ktime_get(); } /* @@ -519,16 +512,16 @@ static void bcm_rx_starttimer(struct bcm_op *op) if (op->flags & RX_NO_AUTOTIMER) return; - if (op->j_ival1) - mod_timer(&op->timer, jiffies + op->j_ival1); + if (op->kt_ival1.tv64) + hrtimer_start(&op->timer, op->kt_ival1, HRTIMER_MODE_REL); } /* * bcm_rx_timeout_handler - when the (cyclic) CAN frame receiption timed out */ -static void bcm_rx_timeout_handler(unsigned long data) +static enum hrtimer_restart bcm_rx_timeout_handler(struct hrtimer *hrtimer) { - struct bcm_op *op = (struct bcm_op *)data; + struct bcm_op *op = container_of(hrtimer, struct bcm_op, timer); struct bcm_msg_head msg_head; msg_head.opcode = RX_TIMEOUT; @@ -548,27 +541,27 @@ static void bcm_rx_timeout_handler(unsigned long data) /* clear received can_frames to indicate 'nothing received' */ memset(op->last_frames, 0, op->nframes * CFSIZ); } + + return HRTIMER_NORESTART; } /* - * bcm_rx_thr_handler - the time for blocked content updates is over now: - * Check for throttled data and send it to the userspace + * bcm_rx_thr_flush - Check for throttled data and send it to the userspace */ -static void bcm_rx_thr_handler(unsigned long data) +static int bcm_rx_thr_flush(struct bcm_op *op) { - struct bcm_op *op = (struct bcm_op *)data; - int i = 0; - - /* mark disabled / consumed timer */ - op->thrtimer.expires = 0; + int updated = 0; if (op->nframes > 1) { + int i; + /* for MUX filter we start at index 1 */ for (i = 1; i < op->nframes; i++) { if ((op->last_frames) && (op->last_frames[i].can_dlc & RX_THR)) { op->last_frames[i].can_dlc &= ~RX_THR; bcm_rx_changed(op, &op->last_frames[i]); + updated++; } } @@ -577,8 +570,29 @@ static void bcm_rx_thr_handler(unsigned long data) if (op->last_frames && (op->last_frames[0].can_dlc & RX_THR)) { op->last_frames[0].can_dlc &= ~RX_THR; bcm_rx_changed(op, &op->last_frames[0]); + updated++; } } + + return updated; +} + +/* + * bcm_rx_thr_handler - the time for blocked content updates is over now: + * Check for throttled data and send it to the userspace + */ +static enum hrtimer_restart bcm_rx_thr_handler(struct hrtimer *hrtimer) +{ + struct bcm_op *op = container_of(hrtimer, struct bcm_op, thrtimer); + + if (bcm_rx_thr_flush(op)) { + hrtimer_forward(hrtimer, ktime_get(), op->kt_ival2); + return HRTIMER_RESTART; + } else { + /* rearm throttle handling */ + op->kt_lastmsg = ktime_set(0, 0); + return HRTIMER_NORESTART; + } } /* @@ -591,7 +605,7 @@ static void bcm_rx_handler(struct sk_buff *skb, void *data) int i; /* disable timeout */ - del_timer(&op->timer); + hrtimer_cancel(&op->timer); if (skb->len == sizeof(rxframe)) { memcpy(&rxframe, skb->data, sizeof(rxframe)); @@ -669,8 +683,8 @@ static struct bcm_op *bcm_find_op(struct list_head *ops, canid_t can_id, static void bcm_remove_op(struct bcm_op *op) { - del_timer(&op->timer); - del_timer(&op->thrtimer); + hrtimer_cancel(&op->timer); + hrtimer_cancel(&op->thrtimer); if ((op->frames) && (op->frames != &op->sframe)) kfree(op->frames); @@ -871,11 +885,11 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, op->ifindex = ifindex; /* initialize uninitialized (kzalloc) structure */ - setup_timer(&op->timer, bcm_tx_timeout_handler, - (unsigned long)op); + hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + op->timer.function = bcm_tx_timeout_handler; /* currently unused in tx_ops */ - init_timer(&op->thrtimer); + hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); /* add this bcm_op to the list of the tx_ops */ list_add(&op->list, &bo->tx_ops); @@ -902,25 +916,27 @@ static int bcm_tx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, op->count = msg_head->count; op->ival1 = msg_head->ival1; op->ival2 = msg_head->ival2; - op->j_ival1 = rounded_tv2jif(&msg_head->ival1); - op->j_ival2 = rounded_tv2jif(&msg_head->ival2); + op->kt_ival1 = timeval_to_ktime(msg_head->ival1); + op->kt_ival2 = timeval_to_ktime(msg_head->ival2); /* disable an active timer due to zero values? */ - if (!op->j_ival1 && !op->j_ival2) - del_timer(&op->timer); + if (!op->kt_ival1.tv64 && !op->kt_ival2.tv64) + hrtimer_cancel(&op->timer); } if ((op->flags & STARTTIMER) && - ((op->j_ival1 && op->count) || op->j_ival2)) { + ((op->kt_ival1.tv64 && op->count) || op->kt_ival2.tv64)) { /* spec: send can_frame when starting timer */ op->flags |= TX_ANNOUNCE; - if (op->j_ival1 && (op->count > 0)) { + if (op->kt_ival1.tv64 && (op->count > 0)) { /* op->count-- is done in bcm_tx_timeout_handler */ - mod_timer(&op->timer, jiffies + op->j_ival1); + hrtimer_start(&op->timer, op->kt_ival1, + HRTIMER_MODE_REL); } else - mod_timer(&op->timer, jiffies + op->j_ival2); + hrtimer_start(&op->timer, op->kt_ival2, + HRTIMER_MODE_REL); } if (op->flags & TX_ANNOUNCE) @@ -1032,15 +1048,11 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, op->ifindex = ifindex; /* initialize uninitialized (kzalloc) structure */ - setup_timer(&op->timer, bcm_rx_timeout_handler, - (unsigned long)op); + hrtimer_init(&op->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + op->timer.function = bcm_rx_timeout_handler; - /* init throttle timer for RX_CHANGED */ - setup_timer(&op->thrtimer, bcm_rx_thr_handler, - (unsigned long)op); - - /* mark disabled timer */ - op->thrtimer.expires = 0; + hrtimer_init(&op->thrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + op->thrtimer.function = bcm_rx_thr_handler; /* add this bcm_op to the list of the rx_ops */ list_add(&op->list, &bo->rx_ops); @@ -1056,8 +1068,8 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, if (op->flags & RX_RTR_FRAME) { /* no timers in RTR-mode */ - del_timer(&op->thrtimer); - del_timer(&op->timer); + hrtimer_cancel(&op->thrtimer); + hrtimer_cancel(&op->timer); /* * funny feature in RX(!)_SETUP only for RTR-mode: @@ -1074,28 +1086,25 @@ static int bcm_rx_setup(struct bcm_msg_head *msg_head, struct msghdr *msg, /* set timer value */ op->ival1 = msg_head->ival1; op->ival2 = msg_head->ival2; - op->j_ival1 = rounded_tv2jif(&msg_head->ival1); - op->j_ival2 = rounded_tv2jif(&msg_head->ival2); + op->kt_ival1 = timeval_to_ktime(msg_head->ival1); + op->kt_ival2 = timeval_to_ktime(msg_head->ival2); /* disable an active timer due to zero value? */ - if (!op->j_ival1) - del_timer(&op->timer); - - /* free currently blocked msgs ? */ - if (op->thrtimer.expires) { - /* send blocked msgs hereafter */ - mod_timer(&op->thrtimer, jiffies + 2); - } + if (!op->kt_ival1.tv64) + hrtimer_cancel(&op->timer); /* - * if (op->j_ival2) is zero, no (new) throttling - * will happen. For details see functions - * bcm_rx_update_and_send() and bcm_rx_thr_handler() + * In any case cancel the throttle timer, flush + * potentially blocked msgs and reset throttle handling */ + op->kt_lastmsg = ktime_set(0, 0); + hrtimer_cancel(&op->thrtimer); + bcm_rx_thr_flush(op); } - if ((op->flags & STARTTIMER) && op->j_ival1) - mod_timer(&op->timer, jiffies + op->j_ival1); + if ((op->flags & STARTTIMER) && op->kt_ival1.tv64) + hrtimer_start(&op->timer, op->kt_ival1, + HRTIMER_MODE_REL); } /* now we can register for can_ids, if we added a new bcm_op */ -- cgit v1.2.3-59-g8ed1b From b131dd5d659aaf287a3809473130c3ff5eddb71b Mon Sep 17 00:00:00 2001 From: Mandeep Singh Baines Date: Tue, 15 Apr 2008 19:24:17 -0700 Subject: [ETHTOOL]: Add support for large eeproms Currently, it is not possible to read/write to an eeprom larger than 128k in size because the buffer used for temporarily storing the eeprom contents is allocated using kmalloc. kmalloc can only allocate a maximum of 128k depending on architecture. Modified ethtool_get/set_eeprom to only allocate a page of memory and then copy the eeprom a page at a time. Updated original patch as per suggestions from Joe Perches. Signed-off-by: Mandeep Singh Baines Signed-off-by: David S. Miller --- net/core/ethtool.c | 64 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 36 insertions(+), 28 deletions(-) (limited to 'net') diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 1163eb2256d0..a29b43d0b450 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -284,8 +284,10 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr) { struct ethtool_eeprom eeprom; const struct ethtool_ops *ops = dev->ethtool_ops; + void __user *userbuf = useraddr + sizeof(eeprom); + u32 bytes_remaining; u8 *data; - int ret; + int ret = 0; if (!ops->get_eeprom || !ops->get_eeprom_len) return -EOPNOTSUPP; @@ -301,26 +303,26 @@ static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr) if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) return -EINVAL; - data = kmalloc(eeprom.len, GFP_USER); + data = kmalloc(PAGE_SIZE, GFP_USER); if (!data) return -ENOMEM; - ret = -EFAULT; - if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len)) - goto out; - - ret = ops->get_eeprom(dev, &eeprom, data); - if (ret) - goto out; + bytes_remaining = eeprom.len; + while (bytes_remaining > 0) { + eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE); - ret = -EFAULT; - if (copy_to_user(useraddr, &eeprom, sizeof(eeprom))) - goto out; - if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len)) - goto out; - ret = 0; + ret = ops->get_eeprom(dev, &eeprom, data); + if (ret) + break; + if (copy_to_user(userbuf, data, eeprom.len)) { + ret = -EFAULT; + break; + } + userbuf += eeprom.len; + eeprom.offset += eeprom.len; + bytes_remaining -= eeprom.len; + } - out: kfree(data); return ret; } @@ -329,8 +331,10 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr) { struct ethtool_eeprom eeprom; const struct ethtool_ops *ops = dev->ethtool_ops; + void __user *userbuf = useraddr + sizeof(eeprom); + u32 bytes_remaining; u8 *data; - int ret; + int ret = 0; if (!ops->set_eeprom || !ops->get_eeprom_len) return -EOPNOTSUPP; @@ -346,22 +350,26 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr) if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) return -EINVAL; - data = kmalloc(eeprom.len, GFP_USER); + data = kmalloc(PAGE_SIZE, GFP_USER); if (!data) return -ENOMEM; - ret = -EFAULT; - if (copy_from_user(data, useraddr + sizeof(eeprom), eeprom.len)) - goto out; - - ret = ops->set_eeprom(dev, &eeprom, data); - if (ret) - goto out; + bytes_remaining = eeprom.len; + while (bytes_remaining > 0) { + eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE); - if (copy_to_user(useraddr + sizeof(eeprom), data, eeprom.len)) - ret = -EFAULT; + if (copy_from_user(data, userbuf, eeprom.len)) { + ret = -EFAULT; + break; + } + ret = ops->set_eeprom(dev, &eeprom, data); + if (ret) + break; + userbuf += eeprom.len; + eeprom.offset += eeprom.len; + bytes_remaining -= eeprom.len; + } - out: kfree(data); return ret; } -- cgit v1.2.3-59-g8ed1b From 17515408a15fa51c553e67c415502e785145cd7f Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Tue, 15 Apr 2008 20:36:55 -0700 Subject: [TCP]: Remove superflushious skb == write_queue_tail() check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed can only be more strict than what was checked by the earlier common case check for non-tail skbs, thus cwnd_len <= needed will never match in that case anyway. Signed-off-by: Ilpo Järvinen Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 90270cbdf42c..debf23581606 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1057,7 +1057,7 @@ static unsigned int tcp_mss_split_point(struct sock *sk, struct sk_buff *skb, needed = min(skb->len, window); - if (skb == tcp_write_queue_tail(sk) && cwnd_len <= needed) + if (cwnd_len <= needed) return cwnd_len; return needed - needed % mss_now; -- cgit v1.2.3-59-g8ed1b From 3a931a80cb25f905da377d1bb0ba9b1641aa579a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 00:45:56 -0700 Subject: [RTNL]: Relax for_each_netdev_safe in __rtnl_link_unregister. Each potential list_del (happening from inside a ->dellink call) is followed by goto restart, so there's no need in _safe iteration. Signed-off-by: Pavel Emelyanov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- net/core/rtnetlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index da99ac0871bf..edc6dbfe48f2 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -277,12 +277,12 @@ EXPORT_SYMBOL_GPL(rtnl_link_register); */ void __rtnl_link_unregister(struct rtnl_link_ops *ops) { - struct net_device *dev, *n; + struct net_device *dev; struct net *net; for_each_net(net) { restart: - for_each_netdev_safe(net, dev, n) { + for_each_netdev(net, dev) { if (dev->rtnl_link_ops == ops) { ops->dellink(dev); goto restart; -- cgit v1.2.3-59-g8ed1b From 669f87baab90183e13b95480aecf8d7bac92ca3c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 00:46:52 -0700 Subject: [RTNL]: Introduce the rtnl_kill_links helper. This one is responsible for calling ->dellink on each net device found in net to help with vlan net_exit hook in the nearest future. Signed-off-by: Pavel Emelyanov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- include/net/rtnetlink.h | 1 + net/core/rtnetlink.c | 29 +++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 793863e09c69..3c1895e54b7f 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -74,6 +74,7 @@ struct rtnl_link_ops { extern int __rtnl_link_register(struct rtnl_link_ops *ops); extern void __rtnl_link_unregister(struct rtnl_link_ops *ops); +extern void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops); extern int rtnl_link_register(struct rtnl_link_ops *ops); extern void rtnl_link_unregister(struct rtnl_link_ops *ops); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index edc6dbfe48f2..bc39e417694a 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -269,6 +269,26 @@ int rtnl_link_register(struct rtnl_link_ops *ops) EXPORT_SYMBOL_GPL(rtnl_link_register); +static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) +{ + struct net_device *dev; +restart: + for_each_netdev(net, dev) { + if (dev->rtnl_link_ops == ops) { + ops->dellink(dev); + goto restart; + } + } +} + +void rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) +{ + rtnl_lock(); + __rtnl_kill_links(net, ops); + rtnl_unlock(); +} +EXPORT_SYMBOL_GPL(rtnl_kill_links); + /** * __rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink. * @ops: struct rtnl_link_ops * to unregister @@ -277,17 +297,10 @@ EXPORT_SYMBOL_GPL(rtnl_link_register); */ void __rtnl_link_unregister(struct rtnl_link_ops *ops) { - struct net_device *dev; struct net *net; for_each_net(net) { -restart: - for_each_netdev(net, dev) { - if (dev->rtnl_link_ops == ops) { - ops->dellink(dev); - goto restart; - } - } + __rtnl_kill_links(net, ops); } list_del(&ops->list); } -- cgit v1.2.3-59-g8ed1b From a9fde2607895667823e9d1172fc193087125ef68 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 00:48:04 -0700 Subject: [VLAN]: Tag vlan_group_device with net device, not ifindex. Currently vlan group is searched using one key - the ifindex. We'll have to lookup the vlan_group by two keys - ifindex and net. Turning the vlan_group lookup key to struct net_device pointer will make this process easier. Besides, this will eliminate one more place in the networking, that assumes that indexes are unique in the kernel. Signed-off-by: Pavel Emelyanov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/if_vlan.h | 4 +++- net/8021q/vlan.c | 22 +++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index edd55af7ebd6..15ace02b7b24 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -81,7 +81,9 @@ extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *)); #define VLAN_GROUP_ARRAY_PART_LEN (VLAN_GROUP_ARRAY_LEN/VLAN_GROUP_ARRAY_SPLIT_PARTS) struct vlan_group { - int real_dev_ifindex; /* The ifindex of the ethernet(like) device the vlan is attached to. */ + struct net_device *real_dev; /* The ethernet(like) device + * the vlan is attached to. + */ unsigned int nr_vlans; struct hlist_node hlist; /* linked list */ struct net_device **vlan_devices_arrays[VLAN_GROUP_ARRAY_SPLIT_PARTS]; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 5975ec3be7f3..cf8d810a130d 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -65,14 +65,14 @@ static inline unsigned int vlan_grp_hashfn(unsigned int idx) } /* Must be invoked with RCU read lock (no preempt) */ -static struct vlan_group *__vlan_find_group(int real_dev_ifindex) +static struct vlan_group *__vlan_find_group(struct net_device *real_dev) { struct vlan_group *grp; struct hlist_node *n; - int hash = vlan_grp_hashfn(real_dev_ifindex); + int hash = vlan_grp_hashfn(real_dev->ifindex); hlist_for_each_entry_rcu(grp, n, &vlan_group_hash[hash], hlist) { - if (grp->real_dev_ifindex == real_dev_ifindex) + if (grp->real_dev == real_dev) return grp; } @@ -86,7 +86,7 @@ static struct vlan_group *__vlan_find_group(int real_dev_ifindex) struct net_device *__find_vlan_dev(struct net_device *real_dev, unsigned short VID) { - struct vlan_group *grp = __vlan_find_group(real_dev->ifindex); + struct vlan_group *grp = __vlan_find_group(real_dev); if (grp) return vlan_group_get_device(grp, VID); @@ -103,7 +103,7 @@ static void vlan_group_free(struct vlan_group *grp) kfree(grp); } -static struct vlan_group *vlan_group_alloc(int ifindex) +static struct vlan_group *vlan_group_alloc(struct net_device *real_dev) { struct vlan_group *grp; @@ -111,9 +111,9 @@ static struct vlan_group *vlan_group_alloc(int ifindex) if (!grp) return NULL; - grp->real_dev_ifindex = ifindex; + grp->real_dev = real_dev; hlist_add_head_rcu(&grp->hlist, - &vlan_group_hash[vlan_grp_hashfn(ifindex)]); + &vlan_group_hash[vlan_grp_hashfn(real_dev->ifindex)]); return grp; } @@ -151,7 +151,7 @@ void unregister_vlan_dev(struct net_device *dev) ASSERT_RTNL(); - grp = __vlan_find_group(real_dev->ifindex); + grp = __vlan_find_group(real_dev); BUG_ON(!grp); vlan_proc_rem_dev(dev); @@ -246,9 +246,9 @@ int register_vlan_dev(struct net_device *dev) struct vlan_group *grp, *ngrp = NULL; int err; - grp = __vlan_find_group(real_dev->ifindex); + grp = __vlan_find_group(real_dev); if (!grp) { - ngrp = grp = vlan_group_alloc(real_dev->ifindex); + ngrp = grp = vlan_group_alloc(real_dev); if (!grp) return -ENOBUFS; } @@ -412,7 +412,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, goto out; } - grp = __vlan_find_group(dev->ifindex); + grp = __vlan_find_group(dev); if (!grp) goto out; -- cgit v1.2.3-59-g8ed1b From d9ed0f0e2dba45eec79ffbdd841757f87712349b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 00:49:09 -0700 Subject: [VLAN]: Introduce the vlan_net structure and init/exit net ops. Unlike TUN, it is empty from the very beginning, and will be eventually populated later. Signed-off-by: Pavel Emelyanov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- net/8021q/vlan.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ net/8021q/vlan.h | 5 +++++ 2 files changed, 51 insertions(+) (limited to 'net') diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index cf8d810a130d..92966016a221 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "vlan.h" @@ -41,6 +42,8 @@ /* Global VLAN variables */ +int vlan_net_id; + /* Our listing of VLAN group(s) */ static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE]; @@ -625,6 +628,41 @@ out: return err; } +static int vlan_init_net(struct net *net) +{ + int err; + struct vlan_net *vn; + + err = -ENOMEM; + vn = kzalloc(sizeof(struct vlan_net), GFP_KERNEL); + if (vn == NULL) + goto err_alloc; + + err = net_assign_generic(net, vlan_net_id, vn); + if (err < 0) + goto err_assign; + + return 0; + +err_assign: + kfree(vn); +err_alloc: + return err; +} + +static void vlan_exit_net(struct net *net) +{ + struct vlan_net *vn; + + vn = net_generic(net, vlan_net_id); + kfree(vn); +} + +static struct pernet_operations vlan_net_ops = { + .init = vlan_init_net, + .exit = vlan_exit_net, +}; + static int __init vlan_proto_init(void) { int err; @@ -632,6 +670,10 @@ static int __init vlan_proto_init(void) pr_info("%s v%s %s\n", vlan_fullname, vlan_version, vlan_copyright); pr_info("All bugs added by %s\n", vlan_buggyright); + err = register_pernet_gen_device(&vlan_net_id, &vlan_net_ops); + if (err < 0) + goto err0; + err = vlan_proc_init(); if (err < 0) goto err1; @@ -653,6 +695,8 @@ err3: err2: vlan_proc_cleanup(); err1: + unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); +err0: return err; } @@ -673,6 +717,8 @@ static void __exit vlan_cleanup_module(void) vlan_proc_cleanup(); + unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); + synchronize_net(); } diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 51271aea402b..f27d8d6f3625 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -50,4 +50,9 @@ static inline int is_vlan_dev(struct net_device *dev) return dev->priv_flags & IFF_802_1Q_VLAN; } +extern int vlan_net_id; + +struct vlan_net { +}; + #endif /* !(__BEN_VLAN_802_1Q_INC__) */ -- cgit v1.2.3-59-g8ed1b From cd1c701432fbf84ad5ea1d8012ddd398a560bccc Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 00:51:12 -0700 Subject: [VLAN]: Add a net argument to proc init and cleanup calls. All proc files will be created in each net, so prepare them for this change now, not to mess it with real creation patch. The net != &init_net checks in them are for git-bisect sanity, but I will drop them soon. Signed-off-by: Pavel Emelyanov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- net/8021q/vlan.c | 15 +++++++-------- net/8021q/vlanproc.c | 12 +++++++++--- net/8021q/vlanproc.h | 10 ++++++---- 3 files changed, 22 insertions(+), 15 deletions(-) (limited to 'net') diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 92966016a221..541542e2a2c1 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -642,8 +642,14 @@ static int vlan_init_net(struct net *net) if (err < 0) goto err_assign; + err = vlan_proc_init(net); + if (err < 0) + goto err_proc; + return 0; +err_proc: + /* nothing */ err_assign: kfree(vn); err_alloc: @@ -655,6 +661,7 @@ static void vlan_exit_net(struct net *net) struct vlan_net *vn; vn = net_generic(net, vlan_net_id); + vlan_proc_cleanup(net); kfree(vn); } @@ -674,10 +681,6 @@ static int __init vlan_proto_init(void) if (err < 0) goto err0; - err = vlan_proc_init(); - if (err < 0) - goto err1; - err = register_netdevice_notifier(&vlan_notifier_block); if (err < 0) goto err2; @@ -693,8 +696,6 @@ static int __init vlan_proto_init(void) err3: unregister_netdevice_notifier(&vlan_notifier_block); err2: - vlan_proc_cleanup(); -err1: unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); err0: return err; @@ -715,8 +716,6 @@ static void __exit vlan_cleanup_module(void) for (i = 0; i < VLAN_GRP_HASH_SIZE; i++) BUG_ON(!hlist_empty(&vlan_group_hash[i])); - vlan_proc_cleanup(); - unregister_pernet_gen_device(vlan_net_id, &vlan_net_ops); synchronize_net(); diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 24cd96ee8109..4d13aeb88584 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -138,8 +138,11 @@ static const char *vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = { * Clean up /proc/net/vlan entries */ -void vlan_proc_cleanup(void) +void vlan_proc_cleanup(struct net *net) { + if (net != &init_net) + return; + if (proc_vlan_conf) remove_proc_entry(name_conf, proc_vlan_dir); @@ -155,8 +158,11 @@ void vlan_proc_cleanup(void) * Create /proc/net/vlan entries */ -int __init vlan_proc_init(void) +int vlan_proc_init(struct net *net) { + if (net != &init_net) + return 0; + proc_vlan_dir = proc_mkdir(name_root, init_net.proc_net); if (!proc_vlan_dir) goto err; @@ -169,7 +175,7 @@ int __init vlan_proc_init(void) err: pr_err("%s: can't create entry in proc filesystem!\n", __func__); - vlan_proc_cleanup(); + vlan_proc_cleanup(net); return -ENOBUFS; } diff --git a/net/8021q/vlanproc.h b/net/8021q/vlanproc.h index da542cacc5a5..063f60a3d5cc 100644 --- a/net/8021q/vlanproc.h +++ b/net/8021q/vlanproc.h @@ -2,15 +2,17 @@ #define __BEN_VLAN_PROC_INC__ #ifdef CONFIG_PROC_FS -int vlan_proc_init(void); +struct net; + +int vlan_proc_init(struct net *net); int vlan_proc_rem_dev(struct net_device *vlandev); int vlan_proc_add_dev(struct net_device *vlandev); -void vlan_proc_cleanup(void); +void vlan_proc_cleanup(struct net *net); #else /* No CONFIG_PROC_FS */ -#define vlan_proc_init() (0) -#define vlan_proc_cleanup() do {} while (0) +#define vlan_proc_init(net) (0) +#define vlan_proc_cleanup(net) do {} while (0) #define vlan_proc_add_dev(dev) ({(void)(dev), 0; }) #define vlan_proc_rem_dev(dev) ({(void)(dev), 0; }) #endif -- cgit v1.2.3-59-g8ed1b From a59a8c1c865e6d231e1b5675f767ace006f08c21 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 00:51:51 -0700 Subject: [VLAN]: Create proc entries in the proper net. The proc_vlan_dir and proc_vlan_conf migrate on the struct vlan_net and their creation uses the struct net. The devices' entries use the corresponding device's net. Signed-off-by: Pavel Emelyanov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- net/8021q/vlan.h | 6 ++++++ net/8021q/vlanproc.c | 44 +++++++++++++++++--------------------------- 2 files changed, 23 insertions(+), 27 deletions(-) (limited to 'net') diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index f27d8d6f3625..7258357db847 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -52,7 +52,13 @@ static inline int is_vlan_dev(struct net_device *dev) extern int vlan_net_id; +struct proc_dir_entry; + struct vlan_net { + /* /proc/net/vlan */ + struct proc_dir_entry *proc_vlan_dir; + /* /proc/net/vlan/config */ + struct proc_dir_entry *proc_vlan_conf; }; #endif /* !(__BEN_VLAN_802_1Q_INC__) */ diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 4d13aeb88584..995544b89071 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "vlanproc.h" #include "vlan.h" @@ -111,18 +112,6 @@ static const struct file_operations vlandev_fops = { * Proc filesystem derectory entries. */ -/* - * /proc/net/vlan - */ - -static struct proc_dir_entry *proc_vlan_dir; - -/* - * /proc/net/vlan/config - */ - -static struct proc_dir_entry *proc_vlan_conf; - /* Strings */ static const char *vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = { [VLAN_NAME_TYPE_RAW_PLUS_VID] = "VLAN_NAME_TYPE_RAW_PLUS_VID", @@ -140,14 +129,13 @@ static const char *vlan_name_type_str[VLAN_NAME_TYPE_HIGHEST] = { void vlan_proc_cleanup(struct net *net) { - if (net != &init_net) - return; + struct vlan_net *vn = net_generic(net, vlan_net_id); - if (proc_vlan_conf) - remove_proc_entry(name_conf, proc_vlan_dir); + if (vn->proc_vlan_conf) + remove_proc_entry(name_conf, vn->proc_vlan_dir); - if (proc_vlan_dir) - proc_net_remove(&init_net, name_root); + if (vn->proc_vlan_dir) + proc_net_remove(net, name_root); /* Dynamically added entries should be cleaned up as their vlan_device * is removed, so we should not have to take care of it here... @@ -160,16 +148,15 @@ void vlan_proc_cleanup(struct net *net) int vlan_proc_init(struct net *net) { - if (net != &init_net) - return 0; + struct vlan_net *vn = net_generic(net, vlan_net_id); - proc_vlan_dir = proc_mkdir(name_root, init_net.proc_net); - if (!proc_vlan_dir) + vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net); + if (!vn->proc_vlan_dir) goto err; - proc_vlan_conf = proc_create(name_conf, S_IFREG|S_IRUSR|S_IWUSR, - proc_vlan_dir, &vlan_fops); - if (!proc_vlan_conf) + vn->proc_vlan_conf = proc_create(name_conf, S_IFREG|S_IRUSR|S_IWUSR, + vn->proc_vlan_dir, &vlan_fops); + if (!vn->proc_vlan_conf) goto err; return 0; @@ -186,9 +173,10 @@ err: int vlan_proc_add_dev(struct net_device *vlandev) { struct vlan_dev_info *dev_info = vlan_dev_info(vlandev); + struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id); dev_info->dent = proc_create(vlandev->name, S_IFREG|S_IRUSR|S_IWUSR, - proc_vlan_dir, &vlandev_fops); + vn->proc_vlan_dir, &vlandev_fops); if (!dev_info->dent) return -ENOBUFS; @@ -201,10 +189,12 @@ int vlan_proc_add_dev(struct net_device *vlandev) */ int vlan_proc_rem_dev(struct net_device *vlandev) { + struct vlan_net *vn = net_generic(dev_net(vlandev), vlan_net_id); + /** NOTE: This will consume the memory pointed to by dent, it seems. */ if (vlan_dev_info(vlandev)->dent) { remove_proc_entry(vlan_dev_info(vlandev)->dent->name, - proc_vlan_dir); + vn->proc_vlan_dir); vlan_dev_info(vlandev)->dent = NULL; } return 0; -- cgit v1.2.3-59-g8ed1b From 80de2d982156b5f6f50ff97175dc94ccfe3d093f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 00:52:24 -0700 Subject: [VLAN]: Make the /proc/net/vlan/conf file show per-net info. It is created in a proper net, so make is show info, related to this particular net. Signed-off-by: Pavel Emelyanov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- net/8021q/vlanproc.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index 995544b89071..cc17b722078a 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -80,7 +80,8 @@ static const struct seq_operations vlan_seq_ops = { static int vlan_seq_open(struct inode *inode, struct file *file) { - return seq_open(file, &vlan_seq_ops); + return seq_open_net(inode, file, &vlan_seq_ops, + sizeof(struct seq_net_private)); } static const struct file_operations vlan_fops = { @@ -88,7 +89,7 @@ static const struct file_operations vlan_fops = { .open = vlan_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_net, }; /* @@ -211,6 +212,7 @@ static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) __acquires(dev_base_lock) { struct net_device *dev; + struct net *net = seq_file_net(seq); loff_t i = 1; read_lock(&dev_base_lock); @@ -218,7 +220,7 @@ static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) if (*pos == 0) return SEQ_START_TOKEN; - for_each_netdev(&init_net, dev) { + for_each_netdev(net, dev) { if (!is_vlan_dev(dev)) continue; @@ -232,14 +234,15 @@ static void *vlan_seq_start(struct seq_file *seq, loff_t *pos) static void *vlan_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct net_device *dev; + struct net *net = seq_file_net(seq); ++*pos; dev = (struct net_device *)v; if (v == SEQ_START_TOKEN) - dev = net_device_entry(&init_net.dev_base_head); + dev = net_device_entry(&net->dev_base_head); - for_each_netdev_continue(&init_net, dev) { + for_each_netdev_continue(net, dev) { if (!is_vlan_dev(dev)) continue; -- cgit v1.2.3-59-g8ed1b From 7a17a2f79f54a988d08ffa33ec9e1038bffec42b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 00:54:39 -0700 Subject: [VLAN]: Make the vlan_name_type per-net. This includes moving one on the struct vlan_net and s/vlan_name_type/vn->name_type/ over the code. Signed-off-by: Pavel Emelyanov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- net/8021q/vlan.c | 14 +++++++++----- net/8021q/vlan.h | 4 ++-- net/8021q/vlanproc.c | 7 +++++-- 3 files changed, 16 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 541542e2a2c1..5cacad0671db 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -52,9 +52,6 @@ static char vlan_version[] = DRV_VERSION; static char vlan_copyright[] = "Ben Greear "; static char vlan_buggyright[] = "David S. Miller "; -/* Determines interface naming scheme. */ -unsigned short vlan_name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD; - static struct packet_type vlan_packet_type = { .type = __constant_htons(ETH_P_8021Q), .func = vlan_skb_recv, /* VLAN receive method */ @@ -299,6 +296,8 @@ static int register_vlan_device(struct net_device *real_dev, unsigned short VLAN_ID) { struct net_device *new_dev; + struct net *net = dev_net(real_dev); + struct vlan_net *vn = net_generic(net, vlan_net_id); char name[IFNAMSIZ]; int err; @@ -310,7 +309,7 @@ static int register_vlan_device(struct net_device *real_dev, return err; /* Gotta set up the fields for the device. */ - switch (vlan_name_type) { + switch (vn->name_type) { case VLAN_NAME_TYPE_RAW_PLUS_VID: /* name will look like: eth1.0005 */ snprintf(name, IFNAMSIZ, "%s.%.4i", real_dev->name, VLAN_ID); @@ -580,7 +579,10 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg) break; if ((args.u.name_type >= 0) && (args.u.name_type < VLAN_NAME_TYPE_HIGHEST)) { - vlan_name_type = args.u.name_type; + struct vlan_net *vn; + + vn = net_generic(net, vlan_net_id); + vn->name_type = args.u.name_type; err = 0; } else { err = -EINVAL; @@ -642,6 +644,8 @@ static int vlan_init_net(struct net *net) if (err < 0) goto err_assign; + vn->name_type = VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD; + err = vlan_proc_init(net); if (err < 0) goto err_proc; diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index 7258357db847..5229a72c7ea1 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -3,8 +3,6 @@ #include -extern unsigned short vlan_name_type; - #define VLAN_GRP_HASH_SHIFT 5 #define VLAN_GRP_HASH_SIZE (1 << VLAN_GRP_HASH_SHIFT) #define VLAN_GRP_HASH_MASK (VLAN_GRP_HASH_SIZE - 1) @@ -59,6 +57,8 @@ struct vlan_net { struct proc_dir_entry *proc_vlan_dir; /* /proc/net/vlan/config */ struct proc_dir_entry *proc_vlan_conf; + /* Determines interface naming scheme. */ + unsigned short name_type; }; #endif /* !(__BEN_VLAN_802_1Q_INC__) */ diff --git a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c index cc17b722078a..daad0064e2c2 100644 --- a/net/8021q/vlanproc.c +++ b/net/8021q/vlanproc.c @@ -260,13 +260,16 @@ static void vlan_seq_stop(struct seq_file *seq, void *v) static int vlan_seq_show(struct seq_file *seq, void *v) { + struct net *net = seq_file_net(seq); + struct vlan_net *vn = net_generic(net, vlan_net_id); + if (v == SEQ_START_TOKEN) { const char *nmtype = NULL; seq_puts(seq, "VLAN Dev name | VLAN ID\n"); - if (vlan_name_type < ARRAY_SIZE(vlan_name_type_str)) - nmtype = vlan_name_type_str[vlan_name_type]; + if (vn->name_type < ARRAY_SIZE(vlan_name_type_str)) + nmtype = vlan_name_type_str[vn->name_type]; seq_printf(seq, "Name-Type: %s\n", nmtype ? nmtype : "UNKNOWN"); -- cgit v1.2.3-59-g8ed1b From 65d292a2ef2df66fd1ab83447afee71ef3720ded Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 00:55:06 -0700 Subject: [VLAN]: Allow vlan devices registration in net namespaces. This one is similar to what I've done for TUN - set the proper net after device allocation and clean VLANs on net exit (use the rtnl_kill_links helper finally). Plus, drop explicit init_net usage and net != &init_net checks. Signed-off-by: Pavel Emelyanov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- net/8021q/vlan.c | 7 +++---- net/8021q/vlan_dev.c | 3 --- net/8021q/vlan_netlink.c | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 5cacad0671db..7e9d22ec7d45 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -340,6 +340,7 @@ static int register_vlan_device(struct net_device *real_dev, if (new_dev == NULL) return -ENOBUFS; + dev_net_set(new_dev, net); /* need 4 bytes for extra VLAN header info, * hope the underlying device can handle it. */ @@ -406,9 +407,6 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, int i, flgs; struct net_device *vlandev; - if (dev_net(dev) != &init_net) - return NOTIFY_DONE; - if (is_vlan_dev(dev)) { __vlan_device_event(dev, event); goto out; @@ -534,7 +532,7 @@ static int vlan_ioctl_handler(struct net *net, void __user *arg) case GET_VLAN_REALDEV_NAME_CMD: case GET_VLAN_VID_CMD: err = -ENODEV; - dev = __dev_get_by_name(&init_net, args.device1); + dev = __dev_get_by_name(net, args.device1); if (!dev) goto out; @@ -665,6 +663,7 @@ static void vlan_exit_net(struct net *net) struct vlan_net *vn; vn = net_generic(net, vlan_net_id); + rtnl_kill_links(net, &vlan_link_ops); vlan_proc_cleanup(net); kfree(vn); } diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 4ae0d7ef62c1..c961f0826005 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -153,9 +153,6 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, struct net_device_stats *stats; unsigned short vlan_TCI; - if (dev_net(dev) != &init_net) - goto err_free; - skb = skb_share_check(skb, GFP_ATOMIC); if (skb == NULL) goto err_free; diff --git a/net/8021q/vlan_netlink.c b/net/8021q/vlan_netlink.c index e32eeb37987e..c93e69ec28ed 100644 --- a/net/8021q/vlan_netlink.c +++ b/net/8021q/vlan_netlink.c @@ -113,7 +113,7 @@ static int vlan_newlink(struct net_device *dev, if (!tb[IFLA_LINK]) return -EINVAL; - real_dev = __dev_get_by_index(&init_net, nla_get_u32(tb[IFLA_LINK])); + real_dev = __dev_get_by_index(dev_net(dev), nla_get_u32(tb[IFLA_LINK])); if (!real_dev) return -ENODEV; -- cgit v1.2.3-59-g8ed1b From 30688a9a3e06d83d187658bd1c15f0e306bed38b Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 00:57:01 -0700 Subject: [VLAN]: Handle vlan devices net namespace changing. When van device is moved to another namespace proc files, related to this device, should also change one. Use the netdev REGISTER and UNREGISTER event handlers for this. Signed-off-by: Pavel Emelyanov Acked-by: Patrick McHardy Signed-off-by: David S. Miller --- net/8021q/vlan.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 7e9d22ec7d45..2a739adaa92b 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -154,8 +154,6 @@ void unregister_vlan_dev(struct net_device *dev) grp = __vlan_find_group(real_dev); BUG_ON(!grp); - vlan_proc_rem_dev(dev); - /* Take it out of our own structures, but be sure to interlock with * HW accelerating devices or SW vlan input packet processing. */ @@ -278,9 +276,6 @@ int register_vlan_dev(struct net_device *dev) if (real_dev->features & NETIF_F_HW_VLAN_FILTER) real_dev->vlan_rx_add_vid(real_dev, vlan_id); - if (vlan_proc_add_dev(dev) < 0) - pr_warning("8021q: failed to add proc entry for %s\n", - dev->name); return 0; out_free_group: @@ -396,6 +391,14 @@ static void __vlan_device_event(struct net_device *dev, unsigned long event) pr_warning("8021q: failed to change proc name for %s\n", dev->name); break; + case NETDEV_REGISTER: + if (vlan_proc_add_dev(dev) < 0) + pr_warning("8021q: failed to add proc entry for %s\n", + dev->name); + break; + case NETDEV_UNREGISTER: + vlan_proc_rem_dev(dev); + break; } } -- cgit v1.2.3-59-g8ed1b From 10dc4c7bb70533d16184aaaa69e137a7d2b9a3a8 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:03:13 -0700 Subject: [IPIP]: Introduce empty ipip_net structure and net init/exit ops. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'net') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 894bce96284a..e39a4c279a20 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -115,10 +115,16 @@ #include #include #include +#include +#include #define HASH_SIZE 16 #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) +static int ipip_net_id; +struct ipip_net { +}; + static int ipip_fb_tunnel_init(struct net_device *dev); static int ipip_tunnel_init(struct net_device *dev); static void ipip_tunnel_setup(struct net_device *dev); @@ -867,6 +873,41 @@ static struct xfrm_tunnel ipip_handler = { static char banner[] __initdata = KERN_INFO "IPv4 over IPv4 tunneling driver\n"; +static int ipip_init_net(struct net *net) +{ + int err; + struct ipip_net *ipn; + + err = -ENOMEM; + ipn = kmalloc(sizeof(struct ipip_net), GFP_KERNEL); + if (ipn == NULL) + goto err_alloc; + + err = net_assign_generic(net, ipip_net_id, ipn); + if (err < 0) + goto err_assign; + + return 0; + +err_assign: + kfree(ipn); +err_alloc: + return err; +} + +static void ipip_exit_net(struct net *net) +{ + struct ipip_net *ipn; + + ipn = net_generic(net, ipip_net_id); + kfree(ipn); +} + +static struct pernet_operations ipip_net_ops = { + .init = ipip_init_net, + .exit = ipip_exit_net, +}; + static int __init ipip_init(void) { int err; @@ -890,6 +931,10 @@ static int __init ipip_init(void) if ((err = register_netdev(ipip_fb_tunnel_dev))) goto err2; + + err = register_pernet_gen_device(&ipip_net_id, &ipip_net_ops); + if (err) + goto err3; out: return err; err2: @@ -897,6 +942,9 @@ static int __init ipip_init(void) err1: xfrm4_tunnel_deregister(&ipip_handler, AF_INET); goto out; +err3: + unregister_netdevice(ipip_fb_tunnel_dev); + goto err1; } static void __exit ipip_destroy_tunnels(void) @@ -922,6 +970,8 @@ static void __exit ipip_fini(void) ipip_destroy_tunnels(); unregister_netdevice(ipip_fb_tunnel_dev); rtnl_unlock(); + + unregister_pernet_gen_device(ipip_net_id, &ipip_net_ops); } module_init(ipip_init); -- cgit v1.2.3-59-g8ed1b From b9855c54dadc0768dcc3804df1972488783d2267 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:04:13 -0700 Subject: [IPIP]: Make the fallback tunnel device per-net. Create on in ipip_init_net(), use it all over the code (the proper place to get the net from already exists) and destroy in ipip_net_exit(). Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 67 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 35 insertions(+), 32 deletions(-) (limited to 'net') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index e39a4c279a20..e657a6605e08 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -123,14 +123,13 @@ static int ipip_net_id; struct ipip_net { + struct net_device *fb_tunnel_dev; }; static int ipip_fb_tunnel_init(struct net_device *dev); static int ipip_tunnel_init(struct net_device *dev); static void ipip_tunnel_setup(struct net_device *dev); -static struct net_device *ipip_fb_tunnel_dev; - static struct ip_tunnel *tunnels_r_l[HASH_SIZE]; static struct ip_tunnel *tunnels_r[HASH_SIZE]; static struct ip_tunnel *tunnels_l[HASH_SIZE]; @@ -257,7 +256,10 @@ failed_free: static void ipip_tunnel_uninit(struct net_device *dev) { - if (dev == ipip_fb_tunnel_dev) { + struct net *net = dev_net(dev); + struct ipip_net *ipn = net_generic(net, ipip_net_id); + + if (dev == ipn->fb_tunnel_dev) { write_lock_bh(&ipip_lock); tunnels_wc[0] = NULL; write_unlock_bh(&ipip_lock); @@ -693,11 +695,13 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) int err = 0; struct ip_tunnel_parm p; struct ip_tunnel *t; + struct net *net = dev_net(dev); + struct ipip_net *ipn = net_generic(net, ipip_net_id); switch (cmd) { case SIOCGETTUNNEL: t = NULL; - if (dev == ipip_fb_tunnel_dev) { + if (dev == ipn->fb_tunnel_dev) { if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { err = -EFAULT; break; @@ -730,7 +734,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) t = ipip_tunnel_locate(&p, cmd == SIOCADDTUNNEL); - if (dev != ipip_fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { + if (dev != ipn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { if (t != NULL) { if (t->dev != dev) { err = -EEXIST; @@ -776,7 +780,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (!capable(CAP_NET_ADMIN)) goto done; - if (dev == ipip_fb_tunnel_dev) { + if (dev == ipn->fb_tunnel_dev) { err = -EFAULT; if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) goto done; @@ -784,7 +788,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if ((t = ipip_tunnel_locate(&p, 0)) == NULL) goto done; err = -EPERM; - if (t->dev == ipip_fb_tunnel_dev) + if (t->dev == ipn->fb_tunnel_dev) goto done; dev = t->dev; } @@ -847,7 +851,7 @@ static int ipip_tunnel_init(struct net_device *dev) return 0; } -static int __init ipip_fb_tunnel_init(struct net_device *dev) +static int ipip_fb_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; @@ -887,8 +891,26 @@ static int ipip_init_net(struct net *net) if (err < 0) goto err_assign; + ipn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), + "tunl0", + ipip_tunnel_setup); + if (!ipn->fb_tunnel_dev) { + err = -ENOMEM; + goto err_alloc_dev; + } + + ipn->fb_tunnel_dev->init = ipip_fb_tunnel_init; + dev_net_set(ipn->fb_tunnel_dev, net); + + if ((err = register_netdev(ipn->fb_tunnel_dev))) + goto err_reg_dev; + return 0; +err_reg_dev: + free_netdev(ipn->fb_tunnel_dev); +err_alloc_dev: + /* nothing */ err_assign: kfree(ipn); err_alloc: @@ -900,6 +922,9 @@ static void ipip_exit_net(struct net *net) struct ipip_net *ipn; ipn = net_generic(net, ipip_net_id); + rtnl_lock(); + unregister_netdevice(ipn->fb_tunnel_dev); + rtnl_unlock(); kfree(ipn); } @@ -919,32 +944,11 @@ static int __init ipip_init(void) return -EAGAIN; } - ipip_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), - "tunl0", - ipip_tunnel_setup); - if (!ipip_fb_tunnel_dev) { - err = -ENOMEM; - goto err1; - } - - ipip_fb_tunnel_dev->init = ipip_fb_tunnel_init; - - if ((err = register_netdev(ipip_fb_tunnel_dev))) - goto err2; - err = register_pernet_gen_device(&ipip_net_id, &ipip_net_ops); if (err) - goto err3; - out: + xfrm4_tunnel_deregister(&ipip_handler, AF_INET); + return err; - err2: - free_netdev(ipip_fb_tunnel_dev); - err1: - xfrm4_tunnel_deregister(&ipip_handler, AF_INET); - goto out; -err3: - unregister_netdevice(ipip_fb_tunnel_dev); - goto err1; } static void __exit ipip_destroy_tunnels(void) @@ -968,7 +972,6 @@ static void __exit ipip_fini(void) rtnl_lock(); ipip_destroy_tunnels(); - unregister_netdevice(ipip_fb_tunnel_dev); rtnl_unlock(); unregister_pernet_gen_device(ipip_net_id, &ipip_net_ops); -- cgit v1.2.3-59-g8ed1b From b9fae5c9138086d27715a8a0f29d5b55239db35c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:04:35 -0700 Subject: [IPIP]: Add net/ipip_net argument to some functions. The hashes of tunnels will be per-net too, so prepare all the functions that uses them for this change by adding an argument. Use init_net temporarily in places, where the net does not exist explicitly yet. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index e657a6605e08..bc4d4cb89b01 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -138,7 +138,8 @@ static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunne static DEFINE_RWLOCK(ipip_lock); -static struct ip_tunnel * ipip_tunnel_lookup(__be32 remote, __be32 local) +static struct ip_tunnel * ipip_tunnel_lookup(struct net *net, + __be32 remote, __be32 local) { unsigned h0 = HASH(remote); unsigned h1 = HASH(local); @@ -162,7 +163,8 @@ static struct ip_tunnel * ipip_tunnel_lookup(__be32 remote, __be32 local) return NULL; } -static struct ip_tunnel **__ipip_bucket(struct ip_tunnel_parm *parms) +static struct ip_tunnel **__ipip_bucket(struct ipip_net *ipn, + struct ip_tunnel_parm *parms) { __be32 remote = parms->iph.daddr; __be32 local = parms->iph.saddr; @@ -180,16 +182,17 @@ static struct ip_tunnel **__ipip_bucket(struct ip_tunnel_parm *parms) return &tunnels[prio][h]; } -static inline struct ip_tunnel **ipip_bucket(struct ip_tunnel *t) +static inline struct ip_tunnel **ipip_bucket(struct ipip_net *ipn, + struct ip_tunnel *t) { - return __ipip_bucket(&t->parms); + return __ipip_bucket(ipn, &t->parms); } -static void ipip_tunnel_unlink(struct ip_tunnel *t) +static void ipip_tunnel_unlink(struct ipip_net *ipn, struct ip_tunnel *t) { struct ip_tunnel **tp; - for (tp = ipip_bucket(t); *tp; tp = &(*tp)->next) { + for (tp = ipip_bucket(ipn, t); *tp; tp = &(*tp)->next) { if (t == *tp) { write_lock_bh(&ipip_lock); *tp = t->next; @@ -199,9 +202,9 @@ static void ipip_tunnel_unlink(struct ip_tunnel *t) } } -static void ipip_tunnel_link(struct ip_tunnel *t) +static void ipip_tunnel_link(struct ipip_net *ipn, struct ip_tunnel *t) { - struct ip_tunnel **tp = ipip_bucket(t); + struct ip_tunnel **tp = ipip_bucket(ipn, t); t->next = *tp; write_lock_bh(&ipip_lock); @@ -209,15 +212,17 @@ static void ipip_tunnel_link(struct ip_tunnel *t) write_unlock_bh(&ipip_lock); } -static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int create) +static struct ip_tunnel * ipip_tunnel_locate(struct net *net, + struct ip_tunnel_parm *parms, int create) { __be32 remote = parms->iph.daddr; __be32 local = parms->iph.saddr; struct ip_tunnel *t, **tp, *nt; struct net_device *dev; char name[IFNAMSIZ]; + struct ipip_net *ipn = net_generic(net, ipip_net_id); - for (tp = __ipip_bucket(parms); (t = *tp) != NULL; tp = &t->next) { + for (tp = __ipip_bucket(ipn, parms); (t = *tp) != NULL; tp = &t->next) { if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) return t; } @@ -246,7 +251,7 @@ static struct ip_tunnel * ipip_tunnel_locate(struct ip_tunnel_parm *parms, int c goto failed_free; dev_hold(dev); - ipip_tunnel_link(nt); + ipip_tunnel_link(ipn, nt); return nt; failed_free: @@ -264,7 +269,7 @@ static void ipip_tunnel_uninit(struct net_device *dev) tunnels_wc[0] = NULL; write_unlock_bh(&ipip_lock); } else - ipip_tunnel_unlink(netdev_priv(dev)); + ipip_tunnel_unlink(ipn, netdev_priv(dev)); dev_put(dev); } @@ -313,7 +318,7 @@ static int ipip_err(struct sk_buff *skb, u32 info) err = -ENOENT; read_lock(&ipip_lock); - t = ipip_tunnel_lookup(iph->daddr, iph->saddr); + t = ipip_tunnel_lookup(&init_net, iph->daddr, iph->saddr); if (t == NULL || t->parms.iph.daddr == 0) goto out; @@ -473,7 +478,8 @@ static int ipip_rcv(struct sk_buff *skb) const struct iphdr *iph = ip_hdr(skb); read_lock(&ipip_lock); - if ((tunnel = ipip_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) { + if ((tunnel = ipip_tunnel_lookup(&init_net, + iph->saddr, iph->daddr)) != NULL) { if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { read_unlock(&ipip_lock); kfree_skb(skb); @@ -706,7 +712,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) err = -EFAULT; break; } - t = ipip_tunnel_locate(&p, 0); + t = ipip_tunnel_locate(net, &p, 0); } if (t == NULL) t = netdev_priv(dev); @@ -732,7 +738,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (p.iph.ttl) p.iph.frag_off |= htons(IP_DF); - t = ipip_tunnel_locate(&p, cmd == SIOCADDTUNNEL); + t = ipip_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL); if (dev != ipn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { if (t != NULL) { @@ -747,12 +753,12 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) break; } t = netdev_priv(dev); - ipip_tunnel_unlink(t); + ipip_tunnel_unlink(ipn, t); t->parms.iph.saddr = p.iph.saddr; t->parms.iph.daddr = p.iph.daddr; memcpy(dev->dev_addr, &p.iph.saddr, 4); memcpy(dev->broadcast, &p.iph.daddr, 4); - ipip_tunnel_link(t); + ipip_tunnel_link(ipn, t); netdev_state_change(dev); } } @@ -785,7 +791,7 @@ ipip_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) goto done; err = -ENOENT; - if ((t = ipip_tunnel_locate(&p, 0)) == NULL) + if ((t = ipip_tunnel_locate(net, &p, 0)) == NULL) goto done; err = -EPERM; if (t->dev == ipn->fb_tunnel_dev) -- cgit v1.2.3-59-g8ed1b From cec3ffae1a019f02cd6b5fa291f279c8e9f86157 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:05:03 -0700 Subject: [IPIP]: Use proper net in hash-lookup functions. This is the part#2 of the previous patch - get the proper net for these functions. I make it in a separate patch, so that this change does not get lost in a large previous patch. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index bc4d4cb89b01..da7147090a19 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -318,7 +318,7 @@ static int ipip_err(struct sk_buff *skb, u32 info) err = -ENOENT; read_lock(&ipip_lock); - t = ipip_tunnel_lookup(&init_net, iph->daddr, iph->saddr); + t = ipip_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); if (t == NULL || t->parms.iph.daddr == 0) goto out; @@ -478,7 +478,7 @@ static int ipip_rcv(struct sk_buff *skb) const struct iphdr *iph = ip_hdr(skb); read_lock(&ipip_lock); - if ((tunnel = ipip_tunnel_lookup(&init_net, + if ((tunnel = ipip_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr)) != NULL) { if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { read_unlock(&ipip_lock); -- cgit v1.2.3-59-g8ed1b From 44d3c299dcfee094f10e0c686ad6588fd36d4f8f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:05:32 -0700 Subject: [IPIP]: Make tunnels hashes per net. Either net or ipip_net already exists in all the required places, so just use one. Besides, tune net_init and net_exit calls to respectively initialize the hashes and destroy devices. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 68 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 32 deletions(-) (limited to 'net') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index da7147090a19..9c2939ba7b94 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -123,6 +123,12 @@ static int ipip_net_id; struct ipip_net { + struct ip_tunnel *tunnels_r_l[HASH_SIZE]; + struct ip_tunnel *tunnels_r[HASH_SIZE]; + struct ip_tunnel *tunnels_l[HASH_SIZE]; + struct ip_tunnel *tunnels_wc[1]; + struct ip_tunnel **tunnels[4]; + struct net_device *fb_tunnel_dev; }; @@ -130,12 +136,6 @@ static int ipip_fb_tunnel_init(struct net_device *dev); static int ipip_tunnel_init(struct net_device *dev); static void ipip_tunnel_setup(struct net_device *dev); -static struct ip_tunnel *tunnels_r_l[HASH_SIZE]; -static struct ip_tunnel *tunnels_r[HASH_SIZE]; -static struct ip_tunnel *tunnels_l[HASH_SIZE]; -static struct ip_tunnel *tunnels_wc[1]; -static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunnels_r_l }; - static DEFINE_RWLOCK(ipip_lock); static struct ip_tunnel * ipip_tunnel_lookup(struct net *net, @@ -144,21 +144,22 @@ static struct ip_tunnel * ipip_tunnel_lookup(struct net *net, unsigned h0 = HASH(remote); unsigned h1 = HASH(local); struct ip_tunnel *t; + struct ipip_net *ipn = net_generic(net, ipip_net_id); - for (t = tunnels_r_l[h0^h1]; t; t = t->next) { + for (t = ipn->tunnels_r_l[h0^h1]; t; t = t->next) { if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) return t; } - for (t = tunnels_r[h0]; t; t = t->next) { + for (t = ipn->tunnels_r[h0]; t; t = t->next) { if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) return t; } - for (t = tunnels_l[h1]; t; t = t->next) { + for (t = ipn->tunnels_l[h1]; t; t = t->next) { if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) return t; } - if ((t = tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) + if ((t = ipn->tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) return t; return NULL; } @@ -179,7 +180,7 @@ static struct ip_tunnel **__ipip_bucket(struct ipip_net *ipn, prio |= 1; h ^= HASH(local); } - return &tunnels[prio][h]; + return &ipn->tunnels[prio][h]; } static inline struct ip_tunnel **ipip_bucket(struct ipip_net *ipn, @@ -266,7 +267,7 @@ static void ipip_tunnel_uninit(struct net_device *dev) if (dev == ipn->fb_tunnel_dev) { write_lock_bh(&ipip_lock); - tunnels_wc[0] = NULL; + ipn->tunnels_wc[0] = NULL; write_unlock_bh(&ipip_lock); } else ipip_tunnel_unlink(ipn, netdev_priv(dev)); @@ -861,6 +862,7 @@ static int ipip_fb_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; + struct ipip_net *ipn = net_generic(dev_net(dev), ipip_net_id); tunnel->dev = dev; strcpy(tunnel->parms.name, dev->name); @@ -870,7 +872,7 @@ static int ipip_fb_tunnel_init(struct net_device *dev) iph->ihl = 5; dev_hold(dev); - tunnels_wc[0] = tunnel; + ipn->tunnels_wc[0] = tunnel; return 0; } @@ -883,13 +885,27 @@ static struct xfrm_tunnel ipip_handler = { static char banner[] __initdata = KERN_INFO "IPv4 over IPv4 tunneling driver\n"; +static void ipip_destroy_tunnels(struct ipip_net *ipn) +{ + int prio; + + for (prio = 1; prio < 4; prio++) { + int h; + for (h = 0; h < HASH_SIZE; h++) { + struct ip_tunnel *t; + while ((t = ipn->tunnels[prio][h]) != NULL) + unregister_netdevice(t->dev); + } + } +} + static int ipip_init_net(struct net *net) { int err; struct ipip_net *ipn; err = -ENOMEM; - ipn = kmalloc(sizeof(struct ipip_net), GFP_KERNEL); + ipn = kzalloc(sizeof(struct ipip_net), GFP_KERNEL); if (ipn == NULL) goto err_alloc; @@ -897,6 +913,11 @@ static int ipip_init_net(struct net *net) if (err < 0) goto err_assign; + ipn->tunnels[0] = ipn->tunnels_wc; + ipn->tunnels[1] = ipn->tunnels_l; + ipn->tunnels[2] = ipn->tunnels_r; + ipn->tunnels[3] = ipn->tunnels_r_l; + ipn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "tunl0", ipip_tunnel_setup); @@ -929,6 +950,7 @@ static void ipip_exit_net(struct net *net) ipn = net_generic(net, ipip_net_id); rtnl_lock(); + ipip_destroy_tunnels(ipn); unregister_netdevice(ipn->fb_tunnel_dev); rtnl_unlock(); kfree(ipn); @@ -957,29 +979,11 @@ static int __init ipip_init(void) return err; } -static void __exit ipip_destroy_tunnels(void) -{ - int prio; - - for (prio = 1; prio < 4; prio++) { - int h; - for (h = 0; h < HASH_SIZE; h++) { - struct ip_tunnel *t; - while ((t = tunnels[prio][h]) != NULL) - unregister_netdevice(t->dev); - } - } -} - static void __exit ipip_fini(void) { if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) printk(KERN_INFO "ipip close: can't deregister tunnel\n"); - rtnl_lock(); - ipip_destroy_tunnels(); - rtnl_unlock(); - unregister_pernet_gen_device(ipip_net_id, &ipip_net_ops); } -- cgit v1.2.3-59-g8ed1b From b99f0152e5f96dde31d2b9060b4f1029abc11078 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:05:57 -0700 Subject: [IPIP]: Use proper net in (mostly) routing calls. There are some ip_route_output_key() calls in there that require a proper net so give one to them. Besides - give a proper net to a single __get_dev_by_index call in ipip_tunnel_bind_dev(). Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 9c2939ba7b94..1de39e1dc432 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -415,7 +415,7 @@ out: fl.fl4_daddr = eiph->saddr; fl.fl4_tos = RT_TOS(eiph->tos); fl.proto = IPPROTO_IPIP; - if (ip_route_output_key(&init_net, &rt, &key)) { + if (ip_route_output_key(dev_net(skb->dev), &rt, &key)) { kfree_skb(skb2); return 0; } @@ -428,7 +428,7 @@ out: fl.fl4_daddr = eiph->daddr; fl.fl4_src = eiph->saddr; fl.fl4_tos = eiph->tos; - if (ip_route_output_key(&init_net, &rt, &fl) || + if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) || rt->u.dst.dev->type != ARPHRD_TUNNEL) { ip_rt_put(rt); kfree_skb(skb2); @@ -558,7 +558,7 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) .saddr = tiph->saddr, .tos = RT_TOS(tos) } }, .proto = IPPROTO_IPIP }; - if (ip_route_output_key(&init_net, &rt, &fl)) { + if (ip_route_output_key(dev_net(dev), &rt, &fl)) { tunnel->stat.tx_carrier_errors++; goto tx_error_icmp; } @@ -679,7 +679,7 @@ static void ipip_tunnel_bind_dev(struct net_device *dev) .tos = RT_TOS(iph->tos) } }, .proto = IPPROTO_IPIP }; struct rtable *rt; - if (!ip_route_output_key(&init_net, &rt, &fl)) { + if (!ip_route_output_key(dev_net(dev), &rt, &fl)) { tdev = rt->u.dst.dev; ip_rt_put(rt); } @@ -687,7 +687,7 @@ static void ipip_tunnel_bind_dev(struct net_device *dev) } if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(&init_net, tunnel->parms.link); + tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link); if (tdev) { dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); -- cgit v1.2.3-59-g8ed1b From 0a826406d4adf0c4b7cd47f116cb8e8ef65b92a3 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:06:18 -0700 Subject: [IPIP]: Allow to create IPIP tunnels in net namespaces. Set the proper net before calling register_netdev and disable the tunnel device netns changing. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ipip.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 1de39e1dc432..149111f08e8d 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -239,6 +239,8 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net, if (dev == NULL) return NULL; + dev_net_set(dev, net); + if (strchr(name, '%')) { if (dev_alloc_name(dev, name) < 0) goto failed_free; @@ -839,6 +841,7 @@ static void ipip_tunnel_setup(struct net_device *dev) dev->flags = IFF_NOARP; dev->iflink = 0; dev->addr_len = 4; + dev->features |= NETIF_F_NETNS_LOCAL; } static int ipip_tunnel_init(struct net_device *dev) -- cgit v1.2.3-59-g8ed1b From 4597a0ce0849eaa62fc9083c21943e0c434e4135 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:06:56 -0700 Subject: [IPIP]: Allow for IPPROTO_IPIP protocol in namespaces. This one was disabled by default for sanity. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/tunnel4.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c index 978b3fd61e65..cc4cd0e518cc 100644 --- a/net/ipv4/tunnel4.c +++ b/net/ipv4/tunnel4.c @@ -136,6 +136,7 @@ static struct net_protocol tunnel4_protocol = { .handler = tunnel4_rcv, .err_handler = tunnel4_err, .no_policy = 1, + .netns_ok = 1, }; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -- cgit v1.2.3-59-g8ed1b From 59a4c7594bcecef27f072a599e9fb3b18754fc60 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:08:53 -0700 Subject: [GRE]: Introduce empty ipgre_net structure and net init/exit ops. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 50972b397a9a..d729ca820931 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #ifdef CONFIG_IPV6 #include @@ -122,6 +124,10 @@ static void ipgre_tunnel_setup(struct net_device *dev); static int ipgre_fb_tunnel_init(struct net_device *dev); +static int ipgre_net_id; +struct ipgre_net { +}; + static struct net_device *ipgre_fb_tunnel_dev; /* Tunnel hash table */ @@ -1275,6 +1281,40 @@ static struct net_protocol ipgre_protocol = { .err_handler = ipgre_err, }; +static int ipgre_init_net(struct net *net) +{ + int err; + struct ipgre_net *ign; + + err = -ENOMEM; + ign = kmalloc(sizeof(struct ipgre_net), GFP_KERNEL); + if (ign == NULL) + goto err_alloc; + + err = net_assign_generic(net, ipgre_net_id, ign); + if (err < 0) + goto err_assign; + + return 0; + +err_assign: + kfree(ign); +err_alloc: + return err; +} + +static void ipgre_exit_net(struct net *net) +{ + struct ipgre_net *ign; + + ign = net_generic(net, ipgre_net_id); + kfree(ign); +} + +static struct pernet_operations ipgre_net_ops = { + .init = ipgre_init_net, + .exit = ipgre_exit_net, +}; /* * And now the modules code and kernel interface. @@ -1302,6 +1342,10 @@ static int __init ipgre_init(void) if ((err = register_netdev(ipgre_fb_tunnel_dev))) goto err2; + + err = register_pernet_gen_device(&ipgre_net_id, &ipgre_net_ops); + if (err < 0) + goto err3; out: return err; err2: @@ -1309,6 +1353,9 @@ err2: err1: inet_del_protocol(&ipgre_protocol, IPPROTO_GRE); goto out; +err3: + unregister_netdevice(ipgre_fb_tunnel_dev); + goto err1; } static void __exit ipgre_destroy_tunnels(void) @@ -1333,6 +1380,8 @@ static void __exit ipgre_fini(void) rtnl_lock(); ipgre_destroy_tunnels(); rtnl_unlock(); + + unregister_pernet_gen_device(ipgre_net_id, &ipgre_net_ops); } module_init(ipgre_init); -- cgit v1.2.3-59-g8ed1b From f57e7d5a7bd2a600a8a97e278e4c46904ceacf51 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:09:22 -0700 Subject: [GRE]: Add net/gre_net argument to some functions. The fallback device and hashes are to become per-net, but many code doesn't have anything to get the struct net pointer from. So pass the proper net there with an extra argument. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 51 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index d729ca820931..6209ab36cab7 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -162,7 +162,8 @@ static DEFINE_RWLOCK(ipgre_lock); /* Given src, dst and key, find appropriate for input tunnel. */ -static struct ip_tunnel * ipgre_tunnel_lookup(__be32 remote, __be32 local, __be32 key) +static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net, + __be32 remote, __be32 local, __be32 key) { unsigned h0 = HASH(remote); unsigned h1 = HASH(key); @@ -198,7 +199,8 @@ static struct ip_tunnel * ipgre_tunnel_lookup(__be32 remote, __be32 local, __be3 return NULL; } -static struct ip_tunnel **__ipgre_bucket(struct ip_tunnel_parm *parms) +static struct ip_tunnel **__ipgre_bucket(struct ipgre_net *ign, + struct ip_tunnel_parm *parms) { __be32 remote = parms->iph.daddr; __be32 local = parms->iph.saddr; @@ -216,14 +218,15 @@ static struct ip_tunnel **__ipgre_bucket(struct ip_tunnel_parm *parms) return &tunnels[prio][h]; } -static inline struct ip_tunnel **ipgre_bucket(struct ip_tunnel *t) +static inline struct ip_tunnel **ipgre_bucket(struct ipgre_net *ign, + struct ip_tunnel *t) { - return __ipgre_bucket(&t->parms); + return __ipgre_bucket(ign, &t->parms); } -static void ipgre_tunnel_link(struct ip_tunnel *t) +static void ipgre_tunnel_link(struct ipgre_net *ign, struct ip_tunnel *t) { - struct ip_tunnel **tp = ipgre_bucket(t); + struct ip_tunnel **tp = ipgre_bucket(ign, t); t->next = *tp; write_lock_bh(&ipgre_lock); @@ -231,11 +234,11 @@ static void ipgre_tunnel_link(struct ip_tunnel *t) write_unlock_bh(&ipgre_lock); } -static void ipgre_tunnel_unlink(struct ip_tunnel *t) +static void ipgre_tunnel_unlink(struct ipgre_net *ign, struct ip_tunnel *t) { struct ip_tunnel **tp; - for (tp = ipgre_bucket(t); *tp; tp = &(*tp)->next) { + for (tp = ipgre_bucket(ign, t); *tp; tp = &(*tp)->next) { if (t == *tp) { write_lock_bh(&ipgre_lock); *tp = t->next; @@ -245,7 +248,8 @@ static void ipgre_tunnel_unlink(struct ip_tunnel *t) } } -static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int create) +static struct ip_tunnel * ipgre_tunnel_locate(struct net *net, + struct ip_tunnel_parm *parms, int create) { __be32 remote = parms->iph.daddr; __be32 local = parms->iph.saddr; @@ -253,8 +257,9 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int struct ip_tunnel *t, **tp, *nt; struct net_device *dev; char name[IFNAMSIZ]; + struct ipgre_net *ign = net_generic(net, ipgre_net_id); - for (tp = __ipgre_bucket(parms); (t = *tp) != NULL; tp = &t->next) { + for (tp = __ipgre_bucket(ign, parms); (t = *tp) != NULL; tp = &t->next) { if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) { if (key == t->parms.i_key) return t; @@ -285,7 +290,7 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct ip_tunnel_parm *parms, int goto failed_free; dev_hold(dev); - ipgre_tunnel_link(nt); + ipgre_tunnel_link(ign, nt); return nt; failed_free: @@ -295,7 +300,10 @@ failed_free: static void ipgre_tunnel_uninit(struct net_device *dev) { - ipgre_tunnel_unlink(netdev_priv(dev)); + struct net *net = dev_net(dev); + struct ipgre_net *ign = net_generic(net, ipgre_net_id); + + ipgre_tunnel_unlink(ign, netdev_priv(dev)); dev_put(dev); } @@ -369,7 +377,9 @@ static void ipgre_err(struct sk_buff *skb, u32 info) } read_lock(&ipgre_lock); - t = ipgre_tunnel_lookup(iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((__be32*)p) + (grehlen>>2) - 1) : 0); + t = ipgre_tunnel_lookup(&init_net, iph->daddr, iph->saddr, + (flags&GRE_KEY) ? + *(((__be32*)p) + (grehlen>>2) - 1) : 0); if (t == NULL || t->parms.iph.daddr == 0 || ipv4_is_multicast(t->parms.iph.daddr)) goto out; @@ -602,7 +612,8 @@ static int ipgre_rcv(struct sk_buff *skb) } read_lock(&ipgre_lock); - if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) { + if ((tunnel = ipgre_tunnel_lookup(&init_net, + iph->saddr, iph->daddr, key)) != NULL) { secpath_reset(skb); skb->protocol = *(__be16*)(h + 2); @@ -960,6 +971,8 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) int err = 0; struct ip_tunnel_parm p; struct ip_tunnel *t; + struct net *net = dev_net(dev); + struct ipgre_net *ign = net_generic(net, ipgre_net_id); switch (cmd) { case SIOCGETTUNNEL: @@ -969,7 +982,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) err = -EFAULT; break; } - t = ipgre_tunnel_locate(&p, 0); + t = ipgre_tunnel_locate(net, &p, 0); } if (t == NULL) t = netdev_priv(dev); @@ -1001,7 +1014,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (!(p.o_flags&GRE_KEY)) p.o_key = 0; - t = ipgre_tunnel_locate(&p, cmd == SIOCADDTUNNEL); + t = ipgre_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL); if (dev != ipgre_fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { if (t != NULL) { @@ -1023,14 +1036,14 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) err = -EINVAL; break; } - ipgre_tunnel_unlink(t); + ipgre_tunnel_unlink(ign, t); t->parms.iph.saddr = p.iph.saddr; t->parms.iph.daddr = p.iph.daddr; t->parms.i_key = p.i_key; t->parms.o_key = p.o_key; memcpy(dev->dev_addr, &p.iph.saddr, 4); memcpy(dev->broadcast, &p.iph.daddr, 4); - ipgre_tunnel_link(t); + ipgre_tunnel_link(ign, t); netdev_state_change(dev); } } @@ -1063,7 +1076,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) goto done; err = -ENOENT; - if ((t = ipgre_tunnel_locate(&p, 0)) == NULL) + if ((t = ipgre_tunnel_locate(net, &p, 0)) == NULL) goto done; err = -EPERM; if (t == netdev_priv(ipgre_fb_tunnel_dev)) -- cgit v1.2.3-59-g8ed1b From 3b4667f3db4d7d0b6d8f35c2ca80333ea141629a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:09:44 -0700 Subject: [GRE]: Use proper net in hash-lookup functions. This is the part#2 of the patch #2 - get the proper net for these functions. This change in a separate patch in order not to get lost in a large previous patch. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 6209ab36cab7..1a17c5beffdc 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -377,7 +377,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info) } read_lock(&ipgre_lock); - t = ipgre_tunnel_lookup(&init_net, iph->daddr, iph->saddr, + t = ipgre_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr, (flags&GRE_KEY) ? *(((__be32*)p) + (grehlen>>2) - 1) : 0); if (t == NULL || t->parms.iph.daddr == 0 || @@ -612,7 +612,7 @@ static int ipgre_rcv(struct sk_buff *skb) } read_lock(&ipgre_lock); - if ((tunnel = ipgre_tunnel_lookup(&init_net, + if ((tunnel = ipgre_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr, key)) != NULL) { secpath_reset(skb); -- cgit v1.2.3-59-g8ed1b From 7daa0004895f0421bff41a3ac0464f2ff4d9cd41 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:10:05 -0700 Subject: [GRE]: Make the fallback tunnel device per-net. Everything is prepared for this change now. Create on in init callback, use it over the code and destroy on net exit. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 63 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 31 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 1a17c5beffdc..a8ec0904e5a6 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -126,10 +126,9 @@ static int ipgre_fb_tunnel_init(struct net_device *dev); static int ipgre_net_id; struct ipgre_net { + struct net_device *fb_tunnel_dev; }; -static struct net_device *ipgre_fb_tunnel_dev; - /* Tunnel hash table */ /* @@ -168,6 +167,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net, unsigned h0 = HASH(remote); unsigned h1 = HASH(key); struct ip_tunnel *t; + struct ipgre_net *ign = net_generic(net, ipgre_net_id); for (t = tunnels_r_l[h0^h1]; t; t = t->next) { if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) { @@ -194,8 +194,8 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net, return t; } - if (ipgre_fb_tunnel_dev->flags&IFF_UP) - return netdev_priv(ipgre_fb_tunnel_dev); + if (ign->fb_tunnel_dev->flags&IFF_UP) + return netdev_priv(ign->fb_tunnel_dev); return NULL; } @@ -977,7 +977,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) switch (cmd) { case SIOCGETTUNNEL: t = NULL; - if (dev == ipgre_fb_tunnel_dev) { + if (dev == ign->fb_tunnel_dev) { if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { err = -EFAULT; break; @@ -1016,7 +1016,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) t = ipgre_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL); - if (dev != ipgre_fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { + if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { if (t != NULL) { if (t->dev != dev) { err = -EEXIST; @@ -1071,7 +1071,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (!capable(CAP_NET_ADMIN)) goto done; - if (dev == ipgre_fb_tunnel_dev) { + if (dev == ign->fb_tunnel_dev) { err = -EFAULT; if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) goto done; @@ -1079,7 +1079,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if ((t = ipgre_tunnel_locate(net, &p, 0)) == NULL) goto done; err = -EPERM; - if (t == netdev_priv(ipgre_fb_tunnel_dev)) + if (t == netdev_priv(ign->fb_tunnel_dev)) goto done; dev = t->dev; } @@ -1270,7 +1270,7 @@ static int ipgre_tunnel_init(struct net_device *dev) return 0; } -static int __init ipgre_fb_tunnel_init(struct net_device *dev) +static int ipgre_fb_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; @@ -1308,8 +1308,25 @@ static int ipgre_init_net(struct net *net) if (err < 0) goto err_assign; + ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0", + ipgre_tunnel_setup); + if (!ign->fb_tunnel_dev) { + err = -ENOMEM; + goto err_alloc_dev; + } + + ign->fb_tunnel_dev->init = ipgre_fb_tunnel_init; + dev_net_set(ign->fb_tunnel_dev, net); + + if ((err = register_netdev(ign->fb_tunnel_dev))) + goto err_reg_dev; + return 0; +err_reg_dev: + free_netdev(ign->fb_tunnel_dev); +err_alloc_dev: + /* nothing */ err_assign: kfree(ign); err_alloc: @@ -1321,6 +1338,10 @@ static void ipgre_exit_net(struct net *net) struct ipgre_net *ign; ign = net_generic(net, ipgre_net_id); + rtnl_lock(); + if (net != &init_net) + unregister_netdevice(ign->fb_tunnel_dev); + rtnl_unlock(); kfree(ign); } @@ -1344,31 +1365,11 @@ static int __init ipgre_init(void) return -EAGAIN; } - ipgre_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "gre0", - ipgre_tunnel_setup); - if (!ipgre_fb_tunnel_dev) { - err = -ENOMEM; - goto err1; - } - - ipgre_fb_tunnel_dev->init = ipgre_fb_tunnel_init; - - if ((err = register_netdev(ipgre_fb_tunnel_dev))) - goto err2; - err = register_pernet_gen_device(&ipgre_net_id, &ipgre_net_ops); if (err < 0) - goto err3; -out: + inet_del_protocol(&ipgre_protocol, IPPROTO_GRE); + return err; -err2: - free_netdev(ipgre_fb_tunnel_dev); -err1: - inet_del_protocol(&ipgre_protocol, IPPROTO_GRE); - goto out; -err3: - unregister_netdevice(ipgre_fb_tunnel_dev); - goto err1; } static void __exit ipgre_destroy_tunnels(void) -- cgit v1.2.3-59-g8ed1b From eb8ce741a3c4d4ba5f345ff19689c7d2e4555668 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:10:26 -0700 Subject: [GRE]: Make tunnels hashes per-net. Very similar to what was done for the IPIP code. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 65 ++++++++++++++++++++++++++----------------------------- 1 file changed, 31 insertions(+), 34 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index a8ec0904e5a6..74d4c515772e 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -124,8 +124,12 @@ static void ipgre_tunnel_setup(struct net_device *dev); static int ipgre_fb_tunnel_init(struct net_device *dev); +#define HASH_SIZE 16 + static int ipgre_net_id; struct ipgre_net { + struct ip_tunnel *tunnels[4][HASH_SIZE]; + struct net_device *fb_tunnel_dev; }; @@ -147,15 +151,12 @@ struct ipgre_net { will match fallback tunnel. */ -#define HASH_SIZE 16 #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) -static struct ip_tunnel *tunnels[4][HASH_SIZE]; - -#define tunnels_r_l (tunnels[3]) -#define tunnels_r (tunnels[2]) -#define tunnels_l (tunnels[1]) -#define tunnels_wc (tunnels[0]) +#define tunnels_r_l tunnels[3] +#define tunnels_r tunnels[2] +#define tunnels_l tunnels[1] +#define tunnels_wc tunnels[0] static DEFINE_RWLOCK(ipgre_lock); @@ -169,19 +170,19 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net, struct ip_tunnel *t; struct ipgre_net *ign = net_generic(net, ipgre_net_id); - for (t = tunnels_r_l[h0^h1]; t; t = t->next) { + for (t = ign->tunnels_r_l[h0^h1]; t; t = t->next) { if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) { if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) return t; } } - for (t = tunnels_r[h0^h1]; t; t = t->next) { + for (t = ign->tunnels_r[h0^h1]; t; t = t->next) { if (remote == t->parms.iph.daddr) { if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) return t; } } - for (t = tunnels_l[h1]; t; t = t->next) { + for (t = ign->tunnels_l[h1]; t; t = t->next) { if (local == t->parms.iph.saddr || (local == t->parms.iph.daddr && ipv4_is_multicast(local))) { @@ -189,7 +190,7 @@ static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net, return t; } } - for (t = tunnels_wc[h1]; t; t = t->next) { + for (t = ign->tunnels_wc[h1]; t; t = t->next) { if (t->parms.i_key == key && (t->dev->flags&IFF_UP)) return t; } @@ -215,7 +216,7 @@ static struct ip_tunnel **__ipgre_bucket(struct ipgre_net *ign, h ^= HASH(remote); } - return &tunnels[prio][h]; + return &ign->tunnels[prio][h]; } static inline struct ip_tunnel **ipgre_bucket(struct ipgre_net *ign, @@ -1274,6 +1275,7 @@ static int ipgre_fb_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; + struct ipgre_net *ign = net_generic(dev_net(dev), ipgre_net_id); tunnel->dev = dev; strcpy(tunnel->parms.name, dev->name); @@ -1284,7 +1286,7 @@ static int ipgre_fb_tunnel_init(struct net_device *dev) tunnel->hlen = sizeof(struct iphdr) + 4; dev_hold(dev); - tunnels_wc[0] = tunnel; + ign->tunnels_wc[0] = tunnel; return 0; } @@ -1294,13 +1296,27 @@ static struct net_protocol ipgre_protocol = { .err_handler = ipgre_err, }; +static void ipgre_destroy_tunnels(struct ipgre_net *ign) +{ + int prio; + + for (prio = 0; prio < 4; prio++) { + int h; + for (h = 0; h < HASH_SIZE; h++) { + struct ip_tunnel *t; + while ((t = ign->tunnels[prio][h]) != NULL) + unregister_netdevice(t->dev); + } + } +} + static int ipgre_init_net(struct net *net) { int err; struct ipgre_net *ign; err = -ENOMEM; - ign = kmalloc(sizeof(struct ipgre_net), GFP_KERNEL); + ign = kzalloc(sizeof(struct ipgre_net), GFP_KERNEL); if (ign == NULL) goto err_alloc; @@ -1339,8 +1355,7 @@ static void ipgre_exit_net(struct net *net) ign = net_generic(net, ipgre_net_id); rtnl_lock(); - if (net != &init_net) - unregister_netdevice(ign->fb_tunnel_dev); + ipgre_destroy_tunnels(ign); rtnl_unlock(); kfree(ign); } @@ -1372,29 +1387,11 @@ static int __init ipgre_init(void) return err; } -static void __exit ipgre_destroy_tunnels(void) -{ - int prio; - - for (prio = 0; prio < 4; prio++) { - int h; - for (h = 0; h < HASH_SIZE; h++) { - struct ip_tunnel *t; - while ((t = tunnels[prio][h]) != NULL) - unregister_netdevice(t->dev); - } - } -} - static void __exit ipgre_fini(void) { if (inet_del_protocol(&ipgre_protocol, IPPROTO_GRE) < 0) printk(KERN_INFO "ipgre close: can't remove protocol\n"); - rtnl_lock(); - ipgre_destroy_tunnels(); - rtnl_unlock(); - unregister_pernet_gen_device(ipgre_net_id, &ipgre_net_ops); } -- cgit v1.2.3-59-g8ed1b From 96635522f7930025b8a56a7075db82c48a454a30 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:10:44 -0700 Subject: [GRE]: Use proper net in routing calls. As for the IPIP tunnel, there are some ip_route_output_key() calls in there that require a proper net so give one to them. And a proper net for the __get_dev_by_index hanging around. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 74d4c515772e..aa973812edc1 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -493,7 +493,7 @@ out: fl.fl4_dst = eiph->saddr; fl.fl4_tos = RT_TOS(eiph->tos); fl.proto = IPPROTO_GRE; - if (ip_route_output_key(&init_net, &rt, &fl)) { + if (ip_route_output_key(dev_net(skb->dev), &rt, &fl)) { kfree_skb(skb2); return; } @@ -506,7 +506,7 @@ out: fl.fl4_dst = eiph->daddr; fl.fl4_src = eiph->saddr; fl.fl4_tos = eiph->tos; - if (ip_route_output_key(&init_net, &rt, &fl) || + if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) || rt->u.dst.dev->type != ARPHRD_IPGRE) { ip_rt_put(rt); kfree_skb(skb2); @@ -762,7 +762,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) .saddr = tiph->saddr, .tos = RT_TOS(tos) } }, .proto = IPPROTO_GRE }; - if (ip_route_output_key(&init_net, &rt, &fl)) { + if (ip_route_output_key(dev_net(dev), &rt, &fl)) { tunnel->stat.tx_carrier_errors++; goto tx_error; } @@ -935,7 +935,7 @@ static void ipgre_tunnel_bind_dev(struct net_device *dev) .tos = RT_TOS(iph->tos) } }, .proto = IPPROTO_GRE }; struct rtable *rt; - if (!ip_route_output_key(&init_net, &rt, &fl)) { + if (!ip_route_output_key(dev_net(dev), &rt, &fl)) { tdev = rt->u.dst.dev; ip_rt_put(rt); } @@ -943,7 +943,7 @@ static void ipgre_tunnel_bind_dev(struct net_device *dev) } if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(&init_net, tunnel->parms.link); + tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link); if (tdev) { hlen = tdev->hard_header_len; @@ -1193,7 +1193,7 @@ static int ipgre_open(struct net_device *dev) .tos = RT_TOS(t->parms.iph.tos) } }, .proto = IPPROTO_GRE }; struct rtable *rt; - if (ip_route_output_key(&init_net, &rt, &fl)) + if (ip_route_output_key(dev_net(dev), &rt, &fl)) return -EADDRNOTAVAIL; dev = rt->u.dst.dev; ip_rt_put(rt); -- cgit v1.2.3-59-g8ed1b From 0b67eceb198b77045950011e12bf176a7c11ad98 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:11:13 -0700 Subject: [GRE]: Allow to create IPGRE tunnels in net namespaces. I.e. set the proper net and mark as NETNS_LOCAL. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index aa973812edc1..7ff52628a73f 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -278,6 +278,8 @@ static struct ip_tunnel * ipgre_tunnel_locate(struct net *net, if (!dev) return NULL; + dev_net_set(dev, net); + if (strchr(name, '%')) { if (dev_alloc_name(dev, name) < 0) goto failed_free; @@ -1236,6 +1238,7 @@ static void ipgre_tunnel_setup(struct net_device *dev) dev->flags = IFF_NOARP; dev->iflink = 0; dev->addr_len = 4; + dev->features |= NETIF_F_NETNS_LOCAL; } static int ipgre_tunnel_init(struct net_device *dev) -- cgit v1.2.3-59-g8ed1b From f96c148fd53a2a0dbb2d768895c7cf6951e35cc5 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:11:36 -0700 Subject: [GRE]: Allow for IPPROTO_GRE protocol in namespaces. This one was also disabled by default for sanity. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/ip_gre.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 7ff52628a73f..2ada033406de 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -1297,6 +1297,7 @@ static int ipgre_fb_tunnel_init(struct net_device *dev) static struct net_protocol ipgre_protocol = { .handler = ipgre_rcv, .err_handler = ipgre_err, + .netns_ok = 1, }; static void ipgre_destroy_tunnels(struct ipgre_net *ign) -- cgit v1.2.3-59-g8ed1b From 8190d9009a74e7862b31874cd347b394d390cc6e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:15:17 -0700 Subject: [SIT]: Introduce empty struct sit_net and init/exit net ops. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/sit.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 91e46fbe6ce2..aa6efc2ab55b 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -52,6 +52,8 @@ #include #include #include +#include +#include /* This version of net/ipv6/sit.c is cloned of net/ipv4/ip_gre.c @@ -66,6 +68,10 @@ static int ipip6_fb_tunnel_init(struct net_device *dev); static int ipip6_tunnel_init(struct net_device *dev); static void ipip6_tunnel_setup(struct net_device *dev); +static int sit_net_id; +struct sit_net { +}; + static struct net_device *ipip6_fb_tunnel_dev; static struct ip_tunnel *tunnels_r_l[HASH_SIZE]; @@ -1068,6 +1074,41 @@ static void __exit sit_destroy_tunnels(void) } } +static int sit_init_net(struct net *net) +{ + int err; + struct sit_net *sitn; + + err = -ENOMEM; + sitn = kmalloc(sizeof(struct sit_net), GFP_KERNEL); + if (sitn == NULL) + goto err_alloc; + + err = net_assign_generic(net, sit_net_id, sitn); + if (err < 0) + goto err_assign; + + return 0; + +err_assign: + kfree(sitn); +err_alloc: + return err; +} + +static void sit_exit_net(struct net *net) +{ + struct sit_net *sitn; + + sitn = net_generic(net, sit_net_id); + kfree(sitn); +} + +static struct pernet_operations sit_net_ops = { + .init = sit_init_net, + .exit = sit_exit_net, +}; + static void __exit sit_cleanup(void) { xfrm4_tunnel_deregister(&sit_handler, AF_INET6); @@ -1076,6 +1117,8 @@ static void __exit sit_cleanup(void) sit_destroy_tunnels(); unregister_netdevice(ipip6_fb_tunnel_dev); rtnl_unlock(); + + unregister_pernet_gen_device(sit_net_id, &sit_net_ops); } static int __init sit_init(void) @@ -1101,6 +1144,10 @@ static int __init sit_init(void) if ((err = register_netdev(ipip6_fb_tunnel_dev))) goto err2; + err = register_pernet_gen_device(&sit_net_id, &sit_net_ops); + if (err < 0) + goto err3; + out: return err; err2: @@ -1108,6 +1155,9 @@ static int __init sit_init(void) err1: xfrm4_tunnel_deregister(&sit_handler, AF_INET6); goto out; +err3: + unregister_netdevice(ipip6_fb_tunnel_dev); + goto err1; } module_init(sit_init); -- cgit v1.2.3-59-g8ed1b From ca8def1483a7621503247e28d1ca5dace9b945fe Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:15:39 -0700 Subject: [SIT]: Add net/sit_net argument to some functions. ... to make them prepared for future hashes and fallback device move on the struct sit_net. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/sit.c | 49 ++++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index aa6efc2ab55b..66cf0be4b679 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -82,7 +82,8 @@ static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunne static DEFINE_RWLOCK(ipip6_lock); -static struct ip_tunnel * ipip6_tunnel_lookup(__be32 remote, __be32 local) +static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, + __be32 remote, __be32 local) { unsigned h0 = HASH(remote); unsigned h1 = HASH(local); @@ -106,7 +107,8 @@ static struct ip_tunnel * ipip6_tunnel_lookup(__be32 remote, __be32 local) return NULL; } -static struct ip_tunnel **__ipip6_bucket(struct ip_tunnel_parm *parms) +static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn, + struct ip_tunnel_parm *parms) { __be32 remote = parms->iph.daddr; __be32 local = parms->iph.saddr; @@ -124,16 +126,17 @@ static struct ip_tunnel **__ipip6_bucket(struct ip_tunnel_parm *parms) return &tunnels[prio][h]; } -static inline struct ip_tunnel **ipip6_bucket(struct ip_tunnel *t) +static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn, + struct ip_tunnel *t) { - return __ipip6_bucket(&t->parms); + return __ipip6_bucket(sitn, &t->parms); } -static void ipip6_tunnel_unlink(struct ip_tunnel *t) +static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) { struct ip_tunnel **tp; - for (tp = ipip6_bucket(t); *tp; tp = &(*tp)->next) { + for (tp = ipip6_bucket(sitn, t); *tp; tp = &(*tp)->next) { if (t == *tp) { write_lock_bh(&ipip6_lock); *tp = t->next; @@ -143,9 +146,9 @@ static void ipip6_tunnel_unlink(struct ip_tunnel *t) } } -static void ipip6_tunnel_link(struct ip_tunnel *t) +static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) { - struct ip_tunnel **tp = ipip6_bucket(t); + struct ip_tunnel **tp = ipip6_bucket(sitn, t); t->next = *tp; write_lock_bh(&ipip6_lock); @@ -153,15 +156,17 @@ static void ipip6_tunnel_link(struct ip_tunnel *t) write_unlock_bh(&ipip6_lock); } -static struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int create) +static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, + struct ip_tunnel_parm *parms, int create) { __be32 remote = parms->iph.daddr; __be32 local = parms->iph.saddr; struct ip_tunnel *t, **tp, *nt; struct net_device *dev; char name[IFNAMSIZ]; + struct sit_net *sitn = net_generic(net, sit_net_id); - for (tp = __ipip6_bucket(parms); (t = *tp) != NULL; tp = &t->next) { + for (tp = __ipip6_bucket(sitn, parms); (t = *tp) != NULL; tp = &t->next) { if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) return t; } @@ -194,7 +199,7 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct ip_tunnel_parm *parms, int dev_hold(dev); - ipip6_tunnel_link(nt); + ipip6_tunnel_link(sitn, nt); return nt; failed_free: @@ -378,13 +383,16 @@ isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) static void ipip6_tunnel_uninit(struct net_device *dev) { + struct net *net = dev_net(dev); + struct sit_net *sitn = net_generic(net, sit_net_id); + if (dev == ipip6_fb_tunnel_dev) { write_lock_bh(&ipip6_lock); tunnels_wc[0] = NULL; write_unlock_bh(&ipip6_lock); dev_put(dev); } else { - ipip6_tunnel_unlink(netdev_priv(dev)); + ipip6_tunnel_unlink(sitn, netdev_priv(dev)); ipip6_tunnel_del_prl(netdev_priv(dev), NULL); dev_put(dev); } @@ -436,7 +444,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) err = -ENOENT; read_lock(&ipip6_lock); - t = ipip6_tunnel_lookup(iph->daddr, iph->saddr); + t = ipip6_tunnel_lookup(&init_net, iph->daddr, iph->saddr); if (t == NULL || t->parms.iph.daddr == 0) goto out; @@ -556,7 +564,8 @@ static int ipip6_rcv(struct sk_buff *skb) iph = ip_hdr(skb); read_lock(&ipip6_lock); - if ((tunnel = ipip6_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) { + if ((tunnel = ipip6_tunnel_lookup(&init_net, + iph->saddr, iph->daddr)) != NULL) { secpath_reset(skb); skb->mac_header = skb->network_header; skb_reset_network_header(skb); @@ -847,6 +856,8 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) struct ip_tunnel_parm p; struct ip_tunnel_prl prl; struct ip_tunnel *t; + struct net *net = dev_net(dev); + struct sit_net *sitn = net_generic(net, sit_net_id); switch (cmd) { case SIOCGETTUNNEL: @@ -856,7 +867,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) err = -EFAULT; break; } - t = ipip6_tunnel_locate(&p, 0); + t = ipip6_tunnel_locate(net, &p, 0); } if (t == NULL) t = netdev_priv(dev); @@ -882,7 +893,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (p.iph.ttl) p.iph.frag_off |= htons(IP_DF); - t = ipip6_tunnel_locate(&p, cmd == SIOCADDTUNNEL); + t = ipip6_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL); if (dev != ipip6_fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { if (t != NULL) { @@ -897,12 +908,12 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) break; } t = netdev_priv(dev); - ipip6_tunnel_unlink(t); + ipip6_tunnel_unlink(sitn, t); t->parms.iph.saddr = p.iph.saddr; t->parms.iph.daddr = p.iph.daddr; memcpy(dev->dev_addr, &p.iph.saddr, 4); memcpy(dev->broadcast, &p.iph.daddr, 4); - ipip6_tunnel_link(t); + ipip6_tunnel_link(sitn, t); netdev_state_change(dev); } } @@ -934,7 +945,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) goto done; err = -ENOENT; - if ((t = ipip6_tunnel_locate(&p, 0)) == NULL) + if ((t = ipip6_tunnel_locate(net, &p, 0)) == NULL) goto done; err = -EPERM; if (t == netdev_priv(ipip6_fb_tunnel_dev)) -- cgit v1.2.3-59-g8ed1b From fcee5ec9fdd2b27bce2a6ae8cd8161ad9a8899df Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:15:59 -0700 Subject: [SIT]: Use proper net in hash-lookup functions. Replace introduced in the previous patch init_net stubs with the proper net pointer. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/sit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 66cf0be4b679..e85ddcd763d0 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -444,7 +444,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info) err = -ENOENT; read_lock(&ipip6_lock); - t = ipip6_tunnel_lookup(&init_net, iph->daddr, iph->saddr); + t = ipip6_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr); if (t == NULL || t->parms.iph.daddr == 0) goto out; @@ -564,7 +564,7 @@ static int ipip6_rcv(struct sk_buff *skb) iph = ip_hdr(skb); read_lock(&ipip6_lock); - if ((tunnel = ipip6_tunnel_lookup(&init_net, + if ((tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), iph->saddr, iph->daddr)) != NULL) { secpath_reset(skb); skb->mac_header = skb->network_header; -- cgit v1.2.3-59-g8ed1b From cd3dbc194d6784624f21acbc622a75c92378ba5a Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:16:18 -0700 Subject: [SIT]: Make the fallback tunnel device per-net Allocate and register one in sit_init_net, use sitn->fb_tunnel_dev over the code and unregister one in sit_exit_net. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/sit.c | 61 ++++++++++++++++++++++++++++------------------------------ 1 file changed, 29 insertions(+), 32 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index e85ddcd763d0..d0c1f2db7f21 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -70,10 +70,9 @@ static void ipip6_tunnel_setup(struct net_device *dev); static int sit_net_id; struct sit_net { + struct net_device *fb_tunnel_dev; }; -static struct net_device *ipip6_fb_tunnel_dev; - static struct ip_tunnel *tunnels_r_l[HASH_SIZE]; static struct ip_tunnel *tunnels_r[HASH_SIZE]; static struct ip_tunnel *tunnels_l[HASH_SIZE]; @@ -386,7 +385,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev) struct net *net = dev_net(dev); struct sit_net *sitn = net_generic(net, sit_net_id); - if (dev == ipip6_fb_tunnel_dev) { + if (dev == sitn->fb_tunnel_dev) { write_lock_bh(&ipip6_lock); tunnels_wc[0] = NULL; write_unlock_bh(&ipip6_lock); @@ -862,7 +861,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) switch (cmd) { case SIOCGETTUNNEL: t = NULL; - if (dev == ipip6_fb_tunnel_dev) { + if (dev == sitn->fb_tunnel_dev) { if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { err = -EFAULT; break; @@ -895,7 +894,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) t = ipip6_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL); - if (dev != ipip6_fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { + if (dev != sitn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { if (t != NULL) { if (t->dev != dev) { err = -EEXIST; @@ -940,7 +939,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (!capable(CAP_NET_ADMIN)) goto done; - if (dev == ipip6_fb_tunnel_dev) { + if (dev == sitn->fb_tunnel_dev) { err = -EFAULT; if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) goto done; @@ -948,7 +947,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if ((t = ipip6_tunnel_locate(net, &p, 0)) == NULL) goto done; err = -EPERM; - if (t == netdev_priv(ipip6_fb_tunnel_dev)) + if (t == netdev_priv(sitn->fb_tunnel_dev)) goto done; dev = t->dev; } @@ -964,7 +963,7 @@ ipip6_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) if (cmd != SIOCGETPRL && !capable(CAP_NET_ADMIN)) goto done; err = -EINVAL; - if (dev == ipip6_fb_tunnel_dev) + if (dev == sitn->fb_tunnel_dev) goto done; err = -EFAULT; if (copy_from_user(&prl, ifr->ifr_ifru.ifru_data, sizeof(prl))) @@ -1047,7 +1046,7 @@ static int ipip6_tunnel_init(struct net_device *dev) return 0; } -static int __init ipip6_fb_tunnel_init(struct net_device *dev) +static int ipip6_fb_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; @@ -1099,8 +1098,25 @@ static int sit_init_net(struct net *net) if (err < 0) goto err_assign; + sitn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0", + ipip6_tunnel_setup); + if (!sitn->fb_tunnel_dev) { + err = -ENOMEM; + goto err_alloc_dev; + } + + sitn->fb_tunnel_dev->init = ipip6_fb_tunnel_init; + dev_net_set(sitn->fb_tunnel_dev, net); + + if ((err = register_netdev(sitn->fb_tunnel_dev))) + goto err_reg_dev; + return 0; +err_reg_dev: + free_netdev(sitn->fb_tunnel_dev); +err_alloc_dev: + /* nothing */ err_assign: kfree(sitn); err_alloc: @@ -1112,6 +1128,9 @@ static void sit_exit_net(struct net *net) struct sit_net *sitn; sitn = net_generic(net, sit_net_id); + rtnl_lock(); + unregister_netdevice(sitn->fb_tunnel_dev); + rtnl_unlock(); kfree(sitn); } @@ -1126,7 +1145,6 @@ static void __exit sit_cleanup(void) rtnl_lock(); sit_destroy_tunnels(); - unregister_netdevice(ipip6_fb_tunnel_dev); rtnl_unlock(); unregister_pernet_gen_device(sit_net_id, &sit_net_ops); @@ -1143,32 +1161,11 @@ static int __init sit_init(void) return -EAGAIN; } - ipip6_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0", - ipip6_tunnel_setup); - if (!ipip6_fb_tunnel_dev) { - err = -ENOMEM; - goto err1; - } - - ipip6_fb_tunnel_dev->init = ipip6_fb_tunnel_init; - - if ((err = register_netdev(ipip6_fb_tunnel_dev))) - goto err2; - err = register_pernet_gen_device(&sit_net_id, &sit_net_ops); if (err < 0) - goto err3; + xfrm4_tunnel_deregister(&sit_handler, AF_INET6); - out: return err; - err2: - free_netdev(ipip6_fb_tunnel_dev); - err1: - xfrm4_tunnel_deregister(&sit_handler, AF_INET6); - goto out; -err3: - unregister_netdevice(ipip6_fb_tunnel_dev); - goto err1; } module_init(sit_init); -- cgit v1.2.3-59-g8ed1b From 291821766b5ca90ffe3fb64531d49537c4ff7395 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:16:38 -0700 Subject: [SIT]: Make tunnels hashes per-net. Just move all the hashes on the sit_net structure and patch the rest of the code appropriately. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/sit.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index d0c1f2db7f21..f82494bc4c58 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -70,15 +70,15 @@ static void ipip6_tunnel_setup(struct net_device *dev); static int sit_net_id; struct sit_net { + struct ip_tunnel *tunnels_r_l[HASH_SIZE]; + struct ip_tunnel *tunnels_r[HASH_SIZE]; + struct ip_tunnel *tunnels_l[HASH_SIZE]; + struct ip_tunnel *tunnels_wc[1]; + struct ip_tunnel **tunnels[4]; + struct net_device *fb_tunnel_dev; }; -static struct ip_tunnel *tunnels_r_l[HASH_SIZE]; -static struct ip_tunnel *tunnels_r[HASH_SIZE]; -static struct ip_tunnel *tunnels_l[HASH_SIZE]; -static struct ip_tunnel *tunnels_wc[1]; -static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunnels_r_l }; - static DEFINE_RWLOCK(ipip6_lock); static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, @@ -87,21 +87,22 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net, unsigned h0 = HASH(remote); unsigned h1 = HASH(local); struct ip_tunnel *t; + struct sit_net *sitn = net_generic(net, sit_net_id); - for (t = tunnels_r_l[h0^h1]; t; t = t->next) { + for (t = sitn->tunnels_r_l[h0^h1]; t; t = t->next) { if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) return t; } - for (t = tunnels_r[h0]; t; t = t->next) { + for (t = sitn->tunnels_r[h0]; t; t = t->next) { if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP)) return t; } - for (t = tunnels_l[h1]; t; t = t->next) { + for (t = sitn->tunnels_l[h1]; t; t = t->next) { if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP)) return t; } - if ((t = tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) + if ((t = sitn->tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP)) return t; return NULL; } @@ -122,7 +123,7 @@ static struct ip_tunnel **__ipip6_bucket(struct sit_net *sitn, prio |= 1; h ^= HASH(local); } - return &tunnels[prio][h]; + return &sitn->tunnels[prio][h]; } static inline struct ip_tunnel **ipip6_bucket(struct sit_net *sitn, @@ -387,7 +388,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev) if (dev == sitn->fb_tunnel_dev) { write_lock_bh(&ipip6_lock); - tunnels_wc[0] = NULL; + sitn->tunnels_wc[0] = NULL; write_unlock_bh(&ipip6_lock); dev_put(dev); } else { @@ -1050,6 +1051,8 @@ static int ipip6_fb_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; + struct net *net = dev_net(dev); + struct sit_net *sitn = net_generic(net, sit_net_id); tunnel->dev = dev; strcpy(tunnel->parms.name, dev->name); @@ -1060,7 +1063,7 @@ static int ipip6_fb_tunnel_init(struct net_device *dev) iph->ttl = 64; dev_hold(dev); - tunnels_wc[0] = tunnel; + sitn->tunnels_wc[0] = tunnel; return 0; } @@ -1070,7 +1073,7 @@ static struct xfrm_tunnel sit_handler = { .priority = 1, }; -static void __exit sit_destroy_tunnels(void) +static void sit_destroy_tunnels(struct sit_net *sitn) { int prio; @@ -1078,7 +1081,7 @@ static void __exit sit_destroy_tunnels(void) int h; for (h = 0; h < HASH_SIZE; h++) { struct ip_tunnel *t; - while ((t = tunnels[prio][h]) != NULL) + while ((t = sitn->tunnels[prio][h]) != NULL) unregister_netdevice(t->dev); } } @@ -1090,7 +1093,7 @@ static int sit_init_net(struct net *net) struct sit_net *sitn; err = -ENOMEM; - sitn = kmalloc(sizeof(struct sit_net), GFP_KERNEL); + sitn = kzalloc(sizeof(struct sit_net), GFP_KERNEL); if (sitn == NULL) goto err_alloc; @@ -1098,6 +1101,11 @@ static int sit_init_net(struct net *net) if (err < 0) goto err_assign; + sitn->tunnels[0] = sitn->tunnels_wc; + sitn->tunnels[1] = sitn->tunnels_l; + sitn->tunnels[2] = sitn->tunnels_r; + sitn->tunnels[3] = sitn->tunnels_r_l; + sitn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0", ipip6_tunnel_setup); if (!sitn->fb_tunnel_dev) { @@ -1129,6 +1137,7 @@ static void sit_exit_net(struct net *net) sitn = net_generic(net, sit_net_id); rtnl_lock(); + sit_destroy_tunnels(sitn); unregister_netdevice(sitn->fb_tunnel_dev); rtnl_unlock(); kfree(sitn); @@ -1143,10 +1152,6 @@ static void __exit sit_cleanup(void) { xfrm4_tunnel_deregister(&sit_handler, AF_INET6); - rtnl_lock(); - sit_destroy_tunnels(); - rtnl_unlock(); - unregister_pernet_gen_device(sit_net_id, &sit_net_ops); } -- cgit v1.2.3-59-g8ed1b From 907a08c4023b54ffebf3fb966efcbcc1312abe32 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:16:58 -0700 Subject: [SIT]: Use proper net in routing calls. I.e. replace init_net stubs in ip_route_output_key() calls. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/sit.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index f82494bc4c58..7badac6c7416 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -527,11 +527,12 @@ out: skb_reset_network_header(skb2); /* Try to guess incoming interface */ - rt6i = rt6_lookup(&init_net, &iph6->saddr, NULL, NULL, 0); + rt6i = rt6_lookup(dev_net(skb->dev), &iph6->saddr, NULL, NULL, 0); if (rt6i && rt6i->rt6i_dev) { skb2->dev = rt6i->rt6i_dev; - rt6i = rt6_lookup(&init_net, &iph6->daddr, &iph6->saddr, NULL, 0); + rt6i = rt6_lookup(dev_net(skb->dev), + &iph6->daddr, &iph6->saddr, NULL, 0); if (rt6i && rt6i->rt6i_dev && rt6i->rt6i_dev->type == ARPHRD_SIT) { struct ip_tunnel *t = netdev_priv(rt6i->rt6i_dev); @@ -701,7 +702,7 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) .tos = RT_TOS(tos) } }, .oif = tunnel->parms.link, .proto = IPPROTO_IPV6 }; - if (ip_route_output_key(&init_net, &rt, &fl)) { + if (ip_route_output_key(dev_net(dev), &rt, &fl)) { tunnel->stat.tx_carrier_errors++; goto tx_error_icmp; } @@ -830,7 +831,7 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) .oif = tunnel->parms.link, .proto = IPPROTO_IPV6 }; struct rtable *rt; - if (!ip_route_output_key(&init_net, &rt, &fl)) { + if (!ip_route_output_key(dev_net(dev), &rt, &fl)) { tdev = rt->u.dst.dev; ip_rt_put(rt); } @@ -838,7 +839,7 @@ static void ipip6_tunnel_bind_dev(struct net_device *dev) } if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(&init_net, tunnel->parms.link); + tdev = __dev_get_by_index(dev_net(dev), tunnel->parms.link); if (tdev) { dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); -- cgit v1.2.3-59-g8ed1b From 7a97146cc6e8145f65abfee36e56de7b8061c34f Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:17:18 -0700 Subject: [SIT]: Allow to create SIT tunnels in net namespaces. Set proper net and mark a new device as NETNS_LOCAL before registering. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/sit.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 7badac6c7416..4b2f1033994e 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -182,6 +182,8 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, if (dev == NULL) return NULL; + dev_net_set(dev, net); + if (strchr(name, '%')) { if (dev_alloc_name(dev, name) < 0) goto failed_free; @@ -1029,6 +1031,7 @@ static void ipip6_tunnel_setup(struct net_device *dev) dev->flags = IFF_NOARP; dev->iflink = 0; dev->addr_len = 4; + dev->features |= NETIF_F_NETNS_LOCAL; } static int ipip6_tunnel_init(struct net_device *dev) -- cgit v1.2.3-59-g8ed1b From b0970c428b33ee6e0aa576f58f87dde74262a441 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:17:39 -0700 Subject: [SIT]: Allow for IPPROTO_IPV6 protocol in namespaces. This makes sit-generated traffic enter the namespace. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv4/tunnel4.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c index cc4cd0e518cc..d3b709a6f264 100644 --- a/net/ipv4/tunnel4.c +++ b/net/ipv4/tunnel4.c @@ -144,6 +144,7 @@ static struct net_protocol tunnel64_protocol = { .handler = tunnel64_rcv, .err_handler = tunnel64_err, .no_policy = 1, + .netns_ok = 1, }; #endif -- cgit v1.2.3-59-g8ed1b From 13eeb8e92c95ca8a1c044e3692246f884be826ee Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:22:02 -0700 Subject: [IP6TUNNEL]: Introduce empty ip6_tnl_net structure and net ops. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'net') diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 61517fe0c57c..2365eb0fb6a4 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -52,6 +52,8 @@ #include #include #include +#include +#include MODULE_AUTHOR("Ville Nuorvala"); MODULE_DESCRIPTION("IPv6 tunneling device"); @@ -78,6 +80,10 @@ static int ip6_fb_tnl_dev_init(struct net_device *dev); static int ip6_tnl_dev_init(struct net_device *dev); static void ip6_tnl_dev_setup(struct net_device *dev); +static int ip6_tnl_net_id; +struct ip6_tnl_net { +}; + /* the IPv6 tunnel fallback device */ static struct net_device *ip6_fb_tnl_dev; @@ -1384,6 +1390,41 @@ static struct xfrm6_tunnel ip6ip6_handler = { .priority = 1, }; +static int ip6_tnl_init_net(struct net *net) +{ + int err; + struct ip6_tnl_net *ip6n; + + err = -ENOMEM; + ip6n = kmalloc(sizeof(struct ip6_tnl_net), GFP_KERNEL); + if (ip6n == NULL) + goto err_alloc; + + err = net_assign_generic(net, ip6_tnl_net_id, ip6n); + if (err < 0) + goto err_assign; + + return 0; + +err_assign: + kfree(ip6n); +err_alloc: + return err; +} + +static void ip6_tnl_exit_net(struct net *net) +{ + struct ip6_tnl_net *ip6n; + + ip6n = net_generic(net, ip6_tnl_net_id); + kfree(ip6n); +} + +static struct pernet_operations ip6_tnl_net_ops = { + .init = ip6_tnl_init_net, + .exit = ip6_tnl_exit_net, +}; + /** * ip6_tunnel_init - register protocol and reserve needed resources * @@ -1418,7 +1459,13 @@ static int __init ip6_tunnel_init(void) free_netdev(ip6_fb_tnl_dev); goto fail; } + + err = register_pernet_gen_device(&ip6_tnl_net_id, &ip6_tnl_net_ops); + if (err < 0) + goto err_pernet; return 0; +err_pernet: + unregister_netdevice(ip6_fb_tnl_dev); fail: xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6); unreg_ip4ip6: @@ -1456,6 +1503,8 @@ static void __exit ip6_tunnel_cleanup(void) rtnl_lock(); ip6_tnl_destroy_tunnels(); rtnl_unlock(); + + unregister_pernet_gen_device(ip6_tnl_net_id, &ip6_tnl_net_ops); } module_init(ip6_tunnel_init); -- cgit v1.2.3-59-g8ed1b From 2dd02c897d798c6a00dca46c7a50ebc10eb3be0d Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:22:23 -0700 Subject: [IP6TUNNEL]: Add (ip6_tnl_)net argument to some calls. Hashes and fallback device used in them will be per-net. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 2365eb0fb6a4..fad1af8ae1cf 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -136,7 +136,7 @@ static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst) **/ static struct ip6_tnl * -ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local) +ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) { unsigned h0 = HASH(remote); unsigned h1 = HASH(local); @@ -166,7 +166,7 @@ ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local) **/ static struct ip6_tnl ** -ip6_tnl_bucket(struct ip6_tnl_parm *p) +ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p) { struct in6_addr *remote = &p->raddr; struct in6_addr *local = &p->laddr; @@ -186,9 +186,9 @@ ip6_tnl_bucket(struct ip6_tnl_parm *p) **/ static void -ip6_tnl_link(struct ip6_tnl *t) +ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) { - struct ip6_tnl **tp = ip6_tnl_bucket(&t->parms); + struct ip6_tnl **tp = ip6_tnl_bucket(ip6n, &t->parms); t->next = *tp; write_lock_bh(&ip6_tnl_lock); @@ -202,11 +202,11 @@ ip6_tnl_link(struct ip6_tnl *t) **/ static void -ip6_tnl_unlink(struct ip6_tnl *t) +ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) { struct ip6_tnl **tp; - for (tp = ip6_tnl_bucket(&t->parms); *tp; tp = &(*tp)->next) { + for (tp = ip6_tnl_bucket(ip6n, &t->parms); *tp; tp = &(*tp)->next) { if (t == *tp) { write_lock_bh(&ip6_tnl_lock); *tp = t->next; @@ -228,12 +228,13 @@ ip6_tnl_unlink(struct ip6_tnl *t) * created tunnel or NULL **/ -static struct ip6_tnl *ip6_tnl_create(struct ip6_tnl_parm *p) +static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p) { struct net_device *dev; struct ip6_tnl *t; char name[IFNAMSIZ]; int err; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); if (p->name[0]) strlcpy(name, p->name, IFNAMSIZ); @@ -257,7 +258,7 @@ static struct ip6_tnl *ip6_tnl_create(struct ip6_tnl_parm *p) goto failed_free; dev_hold(dev); - ip6_tnl_link(t); + ip6_tnl_link(ip6n, t); return t; failed_free: @@ -280,20 +281,22 @@ failed: * matching tunnel or NULL **/ -static struct ip6_tnl *ip6_tnl_locate(struct ip6_tnl_parm *p, int create) +static struct ip6_tnl *ip6_tnl_locate(struct net *net, + struct ip6_tnl_parm *p, int create) { struct in6_addr *remote = &p->raddr; struct in6_addr *local = &p->laddr; struct ip6_tnl *t; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); - for (t = *ip6_tnl_bucket(p); t; t = t->next) { + for (t = *ip6_tnl_bucket(ip6n, p); t; t = t->next) { if (ipv6_addr_equal(local, &t->parms.laddr) && ipv6_addr_equal(remote, &t->parms.raddr)) return t; } if (!create) return NULL; - return ip6_tnl_create(p); + return ip6_tnl_create(net, p); } /** @@ -308,13 +311,15 @@ static void ip6_tnl_dev_uninit(struct net_device *dev) { struct ip6_tnl *t = netdev_priv(dev); + struct net *net = dev_net(dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); if (dev == ip6_fb_tnl_dev) { write_lock_bh(&ip6_tnl_lock); tnls_wc[0] = NULL; write_unlock_bh(&ip6_tnl_lock); } else { - ip6_tnl_unlink(t); + ip6_tnl_unlink(ip6n, t); } ip6_tnl_dst_reset(t); dev_put(dev); @@ -407,7 +412,8 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, processing of the error. */ read_lock(&ip6_tnl_lock); - if ((t = ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL) + if ((t = ip6_tnl_lookup(&init_net, &ipv6h->daddr, + &ipv6h->saddr)) == NULL) goto out; if (t->parms.proto != ipproto && t->parms.proto != 0) @@ -690,7 +696,8 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, read_lock(&ip6_tnl_lock); - if ((t = ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) { + if ((t = ip6_tnl_lookup(&init_net, &ipv6h->saddr, + &ipv6h->daddr)) != NULL) { if (t->parms.proto != ipproto && t->parms.proto != 0) { read_unlock(&ip6_tnl_lock); goto discard; @@ -1197,6 +1204,8 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) int err = 0; struct ip6_tnl_parm p; struct ip6_tnl *t = NULL; + struct net *net = dev_net(dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); switch (cmd) { case SIOCGETTUNNEL: @@ -1205,7 +1214,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) err = -EFAULT; break; } - t = ip6_tnl_locate(&p, 0); + t = ip6_tnl_locate(net, &p, 0); } if (t == NULL) t = netdev_priv(dev); @@ -1226,7 +1235,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP && p.proto != 0) break; - t = ip6_tnl_locate(&p, cmd == SIOCADDTUNNEL); + t = ip6_tnl_locate(net, &p, cmd == SIOCADDTUNNEL); if (dev != ip6_fb_tnl_dev && cmd == SIOCCHGTUNNEL) { if (t != NULL) { if (t->dev != dev) { @@ -1236,9 +1245,9 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } else t = netdev_priv(dev); - ip6_tnl_unlink(t); + ip6_tnl_unlink(ip6n, t); err = ip6_tnl_change(t, &p); - ip6_tnl_link(t); + ip6_tnl_link(ip6n, t); netdev_state_change(dev); } if (t) { @@ -1259,7 +1268,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) break; err = -ENOENT; - if ((t = ip6_tnl_locate(&p, 0)) == NULL) + if ((t = ip6_tnl_locate(net, &p, 0)) == NULL) break; err = -EPERM; if (t->dev == ip6_fb_tnl_dev) -- cgit v1.2.3-59-g8ed1b From 8704ca7e916973c6583c0937e14b057d6c748651 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:22:43 -0700 Subject: [IP6TUNNEL]: Use proper net in hash-lookup functions. Calls to ip6_tnl_lookup were stubbed with init_net - give them a proper one. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index fad1af8ae1cf..72485a3ac9fd 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -412,7 +412,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt, processing of the error. */ read_lock(&ip6_tnl_lock); - if ((t = ip6_tnl_lookup(&init_net, &ipv6h->daddr, + if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->daddr, &ipv6h->saddr)) == NULL) goto out; @@ -696,7 +696,7 @@ static int ip6_tnl_rcv(struct sk_buff *skb, __u16 protocol, read_lock(&ip6_tnl_lock); - if ((t = ip6_tnl_lookup(&init_net, &ipv6h->saddr, + if ((t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr)) != NULL) { if (t->parms.proto != ipproto && t->parms.proto != 0) { read_unlock(&ip6_tnl_lock); -- cgit v1.2.3-59-g8ed1b From 15820e129013dd0771812001a2046ae37c9a2ba0 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:23:02 -0700 Subject: [IP6TUNNEL]: Make the fallback tunnel device per-net. All the code, that reference it already has the ip6_tnl_net pointer, so s/ip6_fb_tnl_dev/ip6n->fb_tnl_dev/ and move creation/releasing code into net init/exit ops. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 72485a3ac9fd..511a6c416887 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -82,12 +82,10 @@ static void ip6_tnl_dev_setup(struct net_device *dev); static int ip6_tnl_net_id; struct ip6_tnl_net { + /* the IPv6 tunnel fallback device */ + struct net_device *fb_tnl_dev; }; -/* the IPv6 tunnel fallback device */ -static struct net_device *ip6_fb_tnl_dev; - - /* lists for storing tunnels in use */ static struct ip6_tnl *tnls_r_l[HASH_SIZE]; static struct ip6_tnl *tnls_wc[1]; @@ -314,7 +312,7 @@ ip6_tnl_dev_uninit(struct net_device *dev) struct net *net = dev_net(dev); struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); - if (dev == ip6_fb_tnl_dev) { + if (dev == ip6n->fb_tnl_dev) { write_lock_bh(&ip6_tnl_lock); tnls_wc[0] = NULL; write_unlock_bh(&ip6_tnl_lock); @@ -1209,7 +1207,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) switch (cmd) { case SIOCGETTUNNEL: - if (dev == ip6_fb_tnl_dev) { + if (dev == ip6n->fb_tnl_dev) { if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) { err = -EFAULT; break; @@ -1236,7 +1234,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) p.proto != 0) break; t = ip6_tnl_locate(net, &p, cmd == SIOCADDTUNNEL); - if (dev != ip6_fb_tnl_dev && cmd == SIOCCHGTUNNEL) { + if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) { if (t != NULL) { if (t->dev != dev) { err = -EEXIST; @@ -1263,7 +1261,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!capable(CAP_NET_ADMIN)) break; - if (dev == ip6_fb_tnl_dev) { + if (dev == ip6n->fb_tnl_dev) { err = -EFAULT; if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) break; @@ -1271,7 +1269,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if ((t = ip6_tnl_locate(net, &p, 0)) == NULL) break; err = -EPERM; - if (t->dev == ip6_fb_tnl_dev) + if (t->dev == ip6n->fb_tnl_dev) break; dev = t->dev; } @@ -1413,8 +1411,25 @@ static int ip6_tnl_init_net(struct net *net) if (err < 0) goto err_assign; + err = -ENOMEM; + ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0", + ip6_tnl_dev_setup); + + if (!ip6n->fb_tnl_dev) + goto err_alloc_dev; + + ip6n->fb_tnl_dev->init = ip6_fb_tnl_dev_init; + dev_net_set(ip6n->fb_tnl_dev, net); + + err = register_netdev(ip6n->fb_tnl_dev); + if (err < 0) + goto err_register; return 0; +err_register: + free_netdev(ip6n->fb_tnl_dev); +err_alloc_dev: + /* nothing */ err_assign: kfree(ip6n); err_alloc: @@ -1455,27 +1470,12 @@ static int __init ip6_tunnel_init(void) err = -EAGAIN; goto unreg_ip4ip6; } - ip6_fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0", - ip6_tnl_dev_setup); - - if (!ip6_fb_tnl_dev) { - err = -ENOMEM; - goto fail; - } - ip6_fb_tnl_dev->init = ip6_fb_tnl_dev_init; - - if ((err = register_netdev(ip6_fb_tnl_dev))) { - free_netdev(ip6_fb_tnl_dev); - goto fail; - } err = register_pernet_gen_device(&ip6_tnl_net_id, &ip6_tnl_net_ops); if (err < 0) goto err_pernet; return 0; err_pernet: - unregister_netdevice(ip6_fb_tnl_dev); -fail: xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6); unreg_ip4ip6: xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET); -- cgit v1.2.3-59-g8ed1b From 3e6c9fb5f5a4cab0d2342b69d4e46e8f5a08b04e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:23:22 -0700 Subject: [IP6TUNNEL]: Make tunnels hashes per-net. Move hashes in the struct ip6_tnl_net, replace tnls_xxx[] with ip6n->tnlx_xxx[] and handle init and exit appropriately. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 63 +++++++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 29 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 511a6c416887..7d2aa6e772ac 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -84,13 +84,12 @@ static int ip6_tnl_net_id; struct ip6_tnl_net { /* the IPv6 tunnel fallback device */ struct net_device *fb_tnl_dev; + /* lists for storing tunnels in use */ + struct ip6_tnl *tnls_r_l[HASH_SIZE]; + struct ip6_tnl *tnls_wc[1]; + struct ip6_tnl **tnls[2]; }; -/* lists for storing tunnels in use */ -static struct ip6_tnl *tnls_r_l[HASH_SIZE]; -static struct ip6_tnl *tnls_wc[1]; -static struct ip6_tnl **tnls[2] = { tnls_wc, tnls_r_l }; - /* lock for the tunnel lists */ static DEFINE_RWLOCK(ip6_tnl_lock); @@ -139,14 +138,15 @@ ip6_tnl_lookup(struct net *net, struct in6_addr *remote, struct in6_addr *local) unsigned h0 = HASH(remote); unsigned h1 = HASH(local); struct ip6_tnl *t; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); - for (t = tnls_r_l[h0 ^ h1]; t; t = t->next) { + for (t = ip6n->tnls_r_l[h0 ^ h1]; t; t = t->next) { if (ipv6_addr_equal(local, &t->parms.laddr) && ipv6_addr_equal(remote, &t->parms.raddr) && (t->dev->flags & IFF_UP)) return t; } - if ((t = tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP)) + if ((t = ip6n->tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP)) return t; return NULL; @@ -175,7 +175,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n, struct ip6_tnl_parm *p) prio = 1; h = HASH(remote) ^ HASH(local); } - return &tnls[prio][h]; + return &ip6n->tnls[prio][h]; } /** @@ -314,7 +314,7 @@ ip6_tnl_dev_uninit(struct net_device *dev) if (dev == ip6n->fb_tnl_dev) { write_lock_bh(&ip6_tnl_lock); - tnls_wc[0] = NULL; + ip6n->tnls_wc[0] = NULL; write_unlock_bh(&ip6_tnl_lock); } else { ip6_tnl_unlink(ip6n, t); @@ -1378,10 +1378,13 @@ static int ip6_fb_tnl_dev_init(struct net_device *dev) { struct ip6_tnl *t = netdev_priv(dev); + struct net *net = dev_net(dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + ip6_tnl_dev_init_gen(dev); t->parms.proto = IPPROTO_IPV6; dev_hold(dev); - tnls_wc[0] = t; + ip6n->tnls_wc[0] = t; return 0; } @@ -1397,13 +1400,27 @@ static struct xfrm6_tunnel ip6ip6_handler = { .priority = 1, }; +static void ip6_tnl_destroy_tunnels(struct ip6_tnl_net *ip6n) +{ + int h; + struct ip6_tnl *t; + + for (h = 0; h < HASH_SIZE; h++) { + while ((t = ip6n->tnls_r_l[h]) != NULL) + unregister_netdevice(t->dev); + } + + t = ip6n->tnls_wc[0]; + unregister_netdevice(t->dev); +} + static int ip6_tnl_init_net(struct net *net) { int err; struct ip6_tnl_net *ip6n; err = -ENOMEM; - ip6n = kmalloc(sizeof(struct ip6_tnl_net), GFP_KERNEL); + ip6n = kzalloc(sizeof(struct ip6_tnl_net), GFP_KERNEL); if (ip6n == NULL) goto err_alloc; @@ -1411,6 +1428,9 @@ static int ip6_tnl_init_net(struct net *net) if (err < 0) goto err_assign; + ip6n->tnls[0] = ip6n->tnls_wc; + ip6n->tnls[1] = ip6n->tnls_r_l; + err = -ENOMEM; ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0", ip6_tnl_dev_setup); @@ -1441,6 +1461,9 @@ static void ip6_tnl_exit_net(struct net *net) struct ip6_tnl_net *ip6n; ip6n = net_generic(net, ip6_tnl_net_id); + rtnl_lock(); + ip6_tnl_destroy_tunnels(ip6n); + rtnl_unlock(); kfree(ip6n); } @@ -1483,20 +1506,6 @@ out: return err; } -static void __exit ip6_tnl_destroy_tunnels(void) -{ - int h; - struct ip6_tnl *t; - - for (h = 0; h < HASH_SIZE; h++) { - while ((t = tnls_r_l[h]) != NULL) - unregister_netdevice(t->dev); - } - - t = tnls_wc[0]; - unregister_netdevice(t->dev); -} - /** * ip6_tunnel_cleanup - free resources and unregister protocol **/ @@ -1509,10 +1518,6 @@ static void __exit ip6_tunnel_cleanup(void) if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6)) printk(KERN_INFO "ip6_tunnel close: can't deregister ip6ip6\n"); - rtnl_lock(); - ip6_tnl_destroy_tunnels(); - rtnl_unlock(); - unregister_pernet_gen_device(ip6_tnl_net_id, &ip6_tnl_net_ops); } -- cgit v1.2.3-59-g8ed1b From 2f7f54b725f1a93f0a4daace1a924bee382b33b6 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:23:44 -0700 Subject: [IP6TUNNEL]: Use proper net instead of init_net stubs. All the ip_route_output_key(), dev_get_by_...() and ipv6_chk_addr() calls are now stubbed with init_net. Fortunately, all the places already have where to get the proper net from. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'net') diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 7d2aa6e772ac..d9b272159097 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -543,7 +543,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, fl.fl4_dst = eiph->saddr; fl.fl4_tos = RT_TOS(eiph->tos); fl.proto = IPPROTO_IPIP; - if (ip_route_output_key(&init_net, &rt, &fl)) + if (ip_route_output_key(dev_net(skb->dev), &rt, &fl)) goto out; skb2->dev = rt->u.dst.dev; @@ -555,7 +555,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, fl.fl4_dst = eiph->daddr; fl.fl4_src = eiph->saddr; fl.fl4_tos = eiph->tos; - if (ip_route_output_key(&init_net, &rt, &fl) || + if (ip_route_output_key(dev_net(skb->dev), &rt, &fl) || rt->u.dst.dev->type != ARPHRD_TUNNEL) { ip_rt_put(rt); goto out; @@ -612,7 +612,8 @@ ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, skb_reset_network_header(skb2); /* Try to guess incoming interface */ - rt = rt6_lookup(&init_net, &ipv6_hdr(skb2)->saddr, NULL, 0, 0); + rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, + NULL, 0, 0); if (rt && rt->rt6i_dev) skb2->dev = rt->rt6i_dev; @@ -656,16 +657,17 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t) { struct ip6_tnl_parm *p = &t->parms; int ret = 0; + struct net *net = dev_net(t->dev); if (p->flags & IP6_TNL_F_CAP_RCV) { struct net_device *ldev = NULL; if (p->link) - ldev = dev_get_by_index(&init_net, p->link); + ldev = dev_get_by_index(net, p->link); if ((ipv6_addr_is_multicast(&p->laddr) || - likely(ipv6_chk_addr(&init_net, &p->laddr, ldev, 0))) && - likely(!ipv6_chk_addr(&init_net, &p->raddr, NULL, 0))) + likely(ipv6_chk_addr(net, &p->laddr, ldev, 0))) && + likely(!ipv6_chk_addr(net, &p->raddr, NULL, 0))) ret = 1; if (ldev) @@ -793,19 +795,20 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t) { struct ip6_tnl_parm *p = &t->parms; int ret = 0; + struct net *net = dev_net(t->dev); if (p->flags & IP6_TNL_F_CAP_XMIT) { struct net_device *ldev = NULL; if (p->link) - ldev = dev_get_by_index(&init_net, p->link); + ldev = dev_get_by_index(net, p->link); - if (unlikely(!ipv6_chk_addr(&init_net, &p->laddr, ldev, 0))) + if (unlikely(!ipv6_chk_addr(net, &p->laddr, ldev, 0))) printk(KERN_WARNING "%s xmit: Local address not yet configured!\n", p->name); else if (!ipv6_addr_is_multicast(&p->raddr) && - unlikely(ipv6_chk_addr(&init_net, &p->raddr, NULL, 0))) + unlikely(ipv6_chk_addr(net, &p->raddr, NULL, 0))) printk(KERN_WARNING "%s xmit: Routing loop! " "Remote address found on this node!\n", @@ -858,7 +861,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, if ((dst = ip6_tnl_dst_check(t)) != NULL) dst_hold(dst); else { - dst = ip6_route_output(&init_net, NULL, fl); + dst = ip6_route_output(dev_net(dev), NULL, fl); if (dst->error || xfrm_lookup(&dst, fl, NULL, 0) < 0) goto tx_err_link_failure; @@ -1123,7 +1126,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) int strict = (ipv6_addr_type(&p->raddr) & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL)); - struct rt6_info *rt = rt6_lookup(&init_net, &p->raddr, &p->laddr, + struct rt6_info *rt = rt6_lookup(dev_net(dev), + &p->raddr, &p->laddr, p->link, strict); if (rt == NULL) -- cgit v1.2.3-59-g8ed1b From 554eb27782d4bb79e0a286a08ecafb81f758058c Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 01:24:13 -0700 Subject: [IP6TUNNEL]: Allow to create IP6 tunnels in net namespaces. And no need in some IPPROTO_XXX enabling, since ipv6 code doesn't have any filtering. So, just set proper net and mark device with NETNS_LOCAL. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/ipv6/ip6_tunnel.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net') diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index d9b272159097..2bda3ba100b1 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -243,6 +243,8 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p) if (dev == NULL) goto failed; + dev_net_set(dev, net); + if (strchr(name, '%')) { if (dev_alloc_name(dev, name) < 0) goto failed_free; @@ -1341,6 +1343,7 @@ static void ip6_tnl_dev_setup(struct net_device *dev) dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr); dev->flags |= IFF_NOARP; dev->addr_len = sizeof(struct in6_addr); + dev->features |= NETIF_F_NETNS_LOCAL; } -- cgit v1.2.3-59-g8ed1b From 5d1e4468a7705db7c1415a65fd16f07113afc1b2 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 16 Apr 2008 01:58:04 -0700 Subject: [NETNS]: Make netns refconting debug like a socket one. Make release_net/hold_net noop for performance-hungry people. This is a debug staff and should be used in the debug mode only. Add check for net != NULL in hold/release calls. This will be required later on. [ Added minor simplifications suggested by Brian Haley. -DaveM ] Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/net_namespace.h | 40 ++++++++++++++++++++++++---------------- net/core/net_namespace.c | 4 ++++ 2 files changed, 28 insertions(+), 16 deletions(-) (limited to 'net') diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index f880b0f9f107..aa540e6be502 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -26,9 +26,11 @@ struct net { atomic_t count; /* To decided when the network * namespace should be freed. */ +#ifdef NETNS_REFCNT_DEBUG atomic_t use_count; /* To track references we * destroy on demand */ +#endif struct list_head list; /* list of network namespaces */ struct work_struct work; /* work struct for freeing */ @@ -117,17 +119,6 @@ static inline void put_net(struct net *net) __put_net(net); } -static inline struct net *hold_net(struct net *net) -{ - atomic_inc(&net->use_count); - return net; -} - -static inline void release_net(struct net *net) -{ - atomic_dec(&net->use_count); -} - static inline int net_eq(const struct net *net1, const struct net *net2) { @@ -143,27 +134,44 @@ static inline void put_net(struct net *net) { } +static inline struct net *maybe_get_net(struct net *net) +{ + return net; +} + +static inline +int net_eq(const struct net *net1, const struct net *net2) +{ + return 1; +} +#endif + + +#ifdef NETNS_REFCNT_DEBUG static inline struct net *hold_net(struct net *net) { + if (net) + atomic_inc(&net->use_count); return net; } static inline void release_net(struct net *net) { + if (net) + atomic_dec(&net->use_count); } - -static inline struct net *maybe_get_net(struct net *net) +#else +static inline struct net *hold_net(struct net *net) { return net; } -static inline -int net_eq(const struct net *net1, const struct net *net2) +static inline void release_net(struct net *net) { - return 1; } #endif + #define for_each_net(VAR) \ list_for_each_entry(VAR, &net_namespace_list, list) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 763674e1e593..72b4c184dd84 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -35,7 +35,9 @@ static __net_init int setup_net(struct net *net) struct net_generic *ng; atomic_set(&net->count, 1); +#ifdef NETNS_REFCNT_DEBUG atomic_set(&net->use_count, 0); +#endif error = -ENOMEM; ng = kzalloc(sizeof(struct net_generic) + @@ -86,11 +88,13 @@ static void net_free(struct net *net) if (!net) return; +#ifdef NETNS_REFCNT_DEBUG if (unlikely(atomic_read(&net->use_count) != 0)) { printk(KERN_EMERG "network namespace not free! Usage: %d\n", atomic_read(&net->use_count)); return; } +#endif kmem_cache_free(net_cachep, net); } -- cgit v1.2.3-59-g8ed1b From 65a18ec58e5e6186103f62f720acea94dfb26f4e Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 16 Apr 2008 01:59:46 -0700 Subject: [NETNS]: Add netns refcnt debug for kernel sockets. Protocol control sockets and netlink kernel sockets should not prevent the namespace stop request. They are initialized and disposed in a special way by sk_change_net/sk_release_kernel. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/sock.h | 2 +- net/core/sock.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/net/sock.h b/include/net/sock.h index 09255eae93e9..dc42b44c2aa1 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1314,7 +1314,7 @@ void sock_net_set(struct sock *sk, struct net *net) static inline void sk_change_net(struct sock *sk, struct net *net) { put_net(sock_net(sk)); - sock_net_set(sk, net); + sock_net_set(sk, hold_net(net)); } extern void sock_enable_timestamp(struct sock *sk); diff --git a/net/core/sock.c b/net/core/sock.c index c0ecbdcf75d8..54c836a2216b 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1001,6 +1001,7 @@ void sk_release_kernel(struct sock *sk) sock_hold(sk); sock_release(sk->sk_socket); + release_net(sock_net(sk)); sock_net_set(sk, get_net(&init_net)); sock_put(sk); } -- cgit v1.2.3-59-g8ed1b From cd5342d9055545624187a2d47e68bdabc1ca9963 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 16 Apr 2008 02:00:28 -0700 Subject: [NETNS]: Add netns refcnt debug for timewait buckets. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/inet_timewait_sock.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index a74137866fbc..ce16e9ac24c1 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -57,6 +57,7 @@ void inet_twsk_put(struct inet_timewait_sock *tw) printk(KERN_DEBUG "%s timewait_sock %p released\n", tw->tw_prot->name, tw); #endif + release_net(twsk_net(tw)); kmem_cache_free(tw->tw_prot->twsk_prot->twsk_slab, tw); module_put(owner); } @@ -124,7 +125,7 @@ struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, const int stat tw->tw_hash = sk->sk_hash; tw->tw_ipv6only = 0; tw->tw_prot = sk->sk_prot_creator; - twsk_net_set(tw, sock_net(sk)); + twsk_net_set(tw, hold_net(sock_net(sk))); atomic_set(&tw->tw_refcnt, 1); inet_twsk_dead_node_init(tw); __module_get(tw->tw_prot->owner); -- cgit v1.2.3-59-g8ed1b From 57d7a6009241fe04a699e5f65d55cf5cb7008fc7 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 16 Apr 2008 02:00:50 -0700 Subject: [NETNS]: Add netns refcnt debug into fib_info. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/fib_semantics.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index a13c84763d4c..3b83c34019fc 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -152,6 +152,7 @@ void free_fib_info(struct fib_info *fi) nh->nh_dev = NULL; } endfor_nexthops(fi); fib_info_cnt--; + release_net(fi->fib_net); kfree(fi); } @@ -730,7 +731,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) goto failure; fib_info_cnt++; - fi->fib_net = net; + fi->fib_net = hold_net(net); fi->fib_protocol = cfg->fc_protocol; fi->fib_flags = cfg->fc_flags; fi->fib_priority = cfg->fc_priority; -- cgit v1.2.3-59-g8ed1b From 8c5da49a63c7675a3e137eb384b982e562622342 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 16 Apr 2008 02:01:11 -0700 Subject: [NETNS]: Add netns refcnt debug for inet bind buckets. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv4/inet_hashtables.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 32ca2f8b581c..1612184ecc6f 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -35,7 +35,7 @@ struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep, struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, GFP_ATOMIC); if (tb != NULL) { - tb->ib_net = net; + tb->ib_net = hold_net(net); tb->port = snum; tb->fastreuse = 0; INIT_HLIST_HEAD(&tb->owners); @@ -51,6 +51,7 @@ void inet_bind_bucket_destroy(struct kmem_cache *cachep, struct inet_bind_bucket { if (hlist_empty(&tb->owners)) { __hlist_del(&tb->node); + release_net(tb->ib_net); kmem_cache_free(cachep, tb); } } -- cgit v1.2.3-59-g8ed1b From 48115becf6ad9c0e700ff7c1792b7f2a288ef8fb Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 16 Apr 2008 02:01:34 -0700 Subject: [NETNS]: Add netns refcnt debug for dst ops. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- net/ipv6/route.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6293cb91ed1d..210a079cfc6f 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2622,7 +2622,7 @@ static int ip6_route_net_init(struct net *net) GFP_KERNEL); if (!net->ipv6.ip6_dst_ops) goto out; - net->ipv6.ip6_dst_ops->dst_net = net; + net->ipv6.ip6_dst_ops->dst_net = hold_net(net); net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, sizeof(*net->ipv6.ip6_null_entry), @@ -2669,6 +2669,7 @@ out: return ret; out_ip6_dst_ops: + release_net(net->ipv6.ip6_dst_ops->dst_net); kfree(net->ipv6.ip6_dst_ops); goto out; } @@ -2684,6 +2685,7 @@ static void ip6_route_net_exit(struct net *net) kfree(net->ipv6.ip6_prohibit_entry); kfree(net->ipv6.ip6_blk_hole_entry); #endif + release_net(net->ipv6.ip6_dst_ops->dst_net); kfree(net->ipv6.ip6_dst_ops); } -- cgit v1.2.3-59-g8ed1b From 3661a910836a509be65afc3c1e512d900e1280f9 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 16 Apr 2008 02:01:56 -0700 Subject: [NETNS]: Add netns refcnt debug to fib rules. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/net/fib_rules.h | 1 + net/core/fib_rules.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 34349f9f4331..a5c6ccc5bb19 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -87,6 +87,7 @@ static inline void fib_rule_get(struct fib_rule *rule) static inline void fib_rule_put_rcu(struct rcu_head *head) { struct fib_rule *rule = container_of(head, struct fib_rule, rcu); + release_net(rule->fr_net); kfree(rule); } diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 540c07283e31..e3e9ab0f74e3 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -29,7 +29,7 @@ int fib_default_rule_add(struct fib_rules_ops *ops, r->pref = pref; r->table = table; r->flags = flags; - r->fr_net = ops->fro_net; + r->fr_net = hold_net(ops->fro_net); /* The lock is not required here, the list in unreacheable * at the moment this function is called */ @@ -243,7 +243,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) err = -ENOMEM; goto errout; } - rule->fr_net = net; + rule->fr_net = hold_net(net); if (tb[FRA_PRIORITY]) rule->pref = nla_get_u32(tb[FRA_PRIORITY]); @@ -344,6 +344,7 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) return 0; errout_free: + release_net(rule->fr_net); kfree(rule); errout: rules_ops_put(ops); -- cgit v1.2.3-59-g8ed1b From f3005d7f4abe03ad41af33b1548602cd086d86a2 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Wed, 16 Apr 2008 02:02:18 -0700 Subject: [NETNS]: Add netns refcnt debug for network devices. dev_set_net is called for - just allocated devices - devices moving from one namespace to another release_net has proper check inside to distinguish these cases. Signed-off-by: Denis V. Lunev Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 ++- net/core/dev.c | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8b17ed40dea2..7c1d4466583b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -758,7 +758,8 @@ static inline void dev_net_set(struct net_device *dev, struct net *net) { #ifdef CONFIG_NET_NS - dev->nd_net = net; + release_net(dev->nd_net); + dev->nd_net = hold_net(net); #endif } diff --git a/net/core/dev.c b/net/core/dev.c index 7aa01125287e..77530e9a34fc 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4042,6 +4042,8 @@ EXPORT_SYMBOL(alloc_netdev_mq); */ void free_netdev(struct net_device *dev) { + release_net(dev_net(dev)); + /* Compatibility with error handling in drivers */ if (dev->reg_state == NETREG_UNINITIALIZED) { kfree((char *)dev - dev->padded); -- cgit v1.2.3-59-g8ed1b From d0498d9ae1a5cebac363e38907266d5cd2eedf89 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Wed, 16 Apr 2008 02:17:42 -0700 Subject: [NET]: Do not allocate unneeded memory for dev->priv alignment. The alloc_netdev_mq() tries to produce 32-bytes alignment for both the net_device itself and its private data. The second alignment is achieved by adding the NETDEV_ALIGN_CONST to the whole size of the memory to be allocated. However, for those devices that do not need the private area, this addition just makes the net_device weight 1024 + 32 = 1068 bytes, i.e. consume twice as much memory. Since loopback device is such (sizeof_priv == 0 for it), and each net namespace creates one, this can save a noticeable amount of memory for kernel with net namespaces turned on. After this set the lo device is actually allocated from a size-1024 kmem cache on i386 box even with NETPOLL and WIRELESS_EXT turned on. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- net/core/dev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index 77530e9a34fc..c16a07fde388 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4000,7 +4000,8 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST + (sizeof(struct net_device_subqueue) * (queue_count - 1))) & ~NETDEV_ALIGN_CONST; - alloc_size += sizeof_priv + NETDEV_ALIGN_CONST; + if (sizeof_priv) + alloc_size += sizeof_priv + NETDEV_ALIGN_CONST; p = kzalloc(alloc_size, GFP_KERNEL); if (!p) { -- cgit v1.2.3-59-g8ed1b From 50c4afb99166dc0d2e8a0b063fe83befaa426a44 Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Tue, 15 Apr 2008 14:09:27 -0400 Subject: mlme.c: fixup some merge damage This one got renamed, complicating the merge a bit...this should restore it to its intended state. Signed-off-by: John W. Linville --- net/mac80211/mlme.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) (limited to 'net') diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index bdaab1391d4e..83e8b497e6db 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -350,14 +350,12 @@ static void ieee80211_sta_wmm_params(struct net_device *dev, } } - -static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata, - u8 erp_value) +static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata, + bool use_protection, + bool use_short_preamble) { struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; struct ieee80211_if_sta *ifsta = &sdata->u.sta; - bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; - bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0; DECLARE_MAC_BUF(mac); u32 changed = 0; @@ -388,6 +386,32 @@ static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata, return changed; } +static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata, + u8 erp_value) +{ + bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; + bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0; + + return ieee80211_handle_protect_preamb(sdata, + use_protection, use_short_preamble); +} + +static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta_bss *bss) +{ + u32 changed = 0; + + if (bss->has_erp_value) + changed |= ieee80211_handle_erp_ie(sdata, bss->erp_value); + else { + u16 capab = bss->capability; + changed |= ieee80211_handle_protect_preamb(sdata, false, + (capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0); + } + + return changed; +} + int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, struct ieee80211_ht_info *ht_info) { @@ -511,9 +535,7 @@ static void ieee80211_set_associated(struct net_device *dev, sdata->bss_conf.beacon_int = bss->beacon_int; sdata->bss_conf.timestamp = bss->timestamp; - if (bss->has_erp_value) - changed |= ieee80211_handle_erp_ie( - sdata, bss->erp_value); + changed |= ieee80211_handle_bss_capability(sdata, bss); ieee80211_rx_bss_put(dev, bss); } @@ -2777,6 +2799,11 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, if (elems.erp_info && elems.erp_info_len >= 1) changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]); + else { + u16 capab = le16_to_cpu(mgmt->u.beacon.capab_info); + changed |= ieee80211_handle_protect_preamb(sdata, false, + (capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0); + } if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { -- cgit v1.2.3-59-g8ed1b From 3a245766901a9dfdc3f53457a7954b369b50f281 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 Apr 2008 16:45:37 +0200 Subject: mac80211: fix key hwaccel race The previous key locking patch left a small race: it would be possible to add a key and take the interface down before the key todo is run so that hwaccel for that key is enabled on an interface that is down. Avoid this by running the todo list when an interface is brought up or down. This patch also fixes a small bug: before this change, a few functions used the key list without the lock that protects it. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/key.c | 84 +++++++++++++++++++++++++++++++++--------------------- net/mac80211/key.h | 11 ++++--- 2 files changed, 59 insertions(+), 36 deletions(-) (limited to 'net') diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 711e36e54ff8..acf8d0370a37 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -355,61 +355,74 @@ void ieee80211_key_link(struct ieee80211_key *key, add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); if (netif_running(sdata->dev)) - add_todo(key, KEY_FLAG_TODO_HWACCEL); + add_todo(key, KEY_FLAG_TODO_HWACCEL_ADD); } -void ieee80211_key_free(struct ieee80211_key *key) +static void __ieee80211_key_free(struct ieee80211_key *key) { - unsigned long flags; - - if (!key) - return; - /* * Replace key with nothingness if it was ever used. */ - if (key->sdata) { - spin_lock_irqsave(&key->sdata->local->sta_lock, flags); + if (key->sdata) __ieee80211_key_replace(key->sdata, key->sta, key, NULL); - spin_unlock_irqrestore(&key->sdata->local->sta_lock, flags); - } add_todo(key, KEY_FLAG_TODO_DELETE); } -void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) +void ieee80211_key_free(struct ieee80211_key *key) { - struct ieee80211_key *key; - - might_sleep(); + unsigned long flags; - if (WARN_ON(!netif_running(sdata->dev))) + if (!key) return; - ieee80211_key_lock(); + spin_lock_irqsave(&key->sdata->local->sta_lock, flags); + __ieee80211_key_free(key); + spin_unlock_irqrestore(&key->sdata->local->sta_lock, flags); +} + +/* + * To be safe against concurrent manipulations of the list (which shouldn't + * actually happen) we need to hold the spinlock. But under the spinlock we + * can't actually do much, so we defer processing to the todo list. Then run + * the todo list to be sure the operation and possibly previously pending + * operations are completed. + */ +static void ieee80211_todo_for_each_key(struct ieee80211_sub_if_data *sdata, + u32 todo_flags) +{ + struct ieee80211_key *key; + unsigned long flags; + might_sleep(); + + spin_lock_irqsave(&sdata->local->sta_lock, flags); list_for_each_entry(key, &sdata->key_list, list) - ieee80211_key_enable_hw_accel(key); + add_todo(key, todo_flags); + spin_unlock_irqrestore(&sdata->local->sta_lock, flags); - ieee80211_key_unlock(); + ieee80211_key_todo(); } -void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) +void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) { - struct ieee80211_key *key; + ASSERT_RTNL(); - might_sleep(); + if (WARN_ON(!netif_running(sdata->dev))) + return; - ieee80211_key_lock(); + ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_ADD); +} - list_for_each_entry(key, &sdata->key_list, list) - ieee80211_key_disable_hw_accel(key); +void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) +{ + ASSERT_RTNL(); - ieee80211_key_unlock(); + ieee80211_todo_for_each_key(sdata, KEY_FLAG_TODO_HWACCEL_REMOVE); } -static void __ieee80211_key_free(struct ieee80211_key *key) +static void __ieee80211_key_destroy(struct ieee80211_key *key) { if (!key) return; @@ -440,7 +453,8 @@ static void __ieee80211_key_todo(void) list_del_init(&key->todo); todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS | KEY_FLAG_TODO_DEFKEY | - KEY_FLAG_TODO_HWACCEL | + KEY_FLAG_TODO_HWACCEL_ADD | + KEY_FLAG_TODO_HWACCEL_REMOVE | KEY_FLAG_TODO_DELETE); key->flags &= ~todoflags; spin_unlock(&todo_lock); @@ -456,12 +470,16 @@ static void __ieee80211_key_todo(void) ieee80211_debugfs_key_add_default(key->sdata); work_done = true; } - if (todoflags & KEY_FLAG_TODO_HWACCEL) { + if (todoflags & KEY_FLAG_TODO_HWACCEL_ADD) { ieee80211_key_enable_hw_accel(key); work_done = true; } + if (todoflags & KEY_FLAG_TODO_HWACCEL_REMOVE) { + ieee80211_key_disable_hw_accel(key); + work_done = true; + } if (todoflags & KEY_FLAG_TODO_DELETE) { - __ieee80211_key_free(key); + __ieee80211_key_destroy(key); work_done = true; } @@ -482,14 +500,16 @@ void ieee80211_key_todo(void) void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) { struct ieee80211_key *key, *tmp; - LIST_HEAD(tmp_list); + unsigned long flags; ieee80211_key_lock(); ieee80211_debugfs_key_remove_default(sdata); + spin_lock_irqsave(&sdata->local->sta_lock, flags); list_for_each_entry_safe(key, tmp, &sdata->key_list, list) - ieee80211_key_free(key); + __ieee80211_key_free(key); + spin_unlock_irqrestore(&sdata->local->sta_lock, flags); __ieee80211_key_todo(); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 5d48518985b3..f52c3df1fe9a 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -54,16 +54,19 @@ struct sta_info; * @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an * RCU grace period, no longer be reachable other than from the * todo list. - * @KEY_FLAG_TODO_HWACCEL: Key needs to be added to hardware acceleration. + * @KEY_FLAG_TODO_HWACCEL_ADD: Key needs to be added to hardware acceleration. + * @KEY_FLAG_TODO_HWACCEL_REMOVE: Key needs to be removed from hardware + * acceleration. * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated. * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs. */ enum ieee80211_internal_key_flags { KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), KEY_FLAG_TODO_DELETE = BIT(1), - KEY_FLAG_TODO_HWACCEL = BIT(2), - KEY_FLAG_TODO_DEFKEY = BIT(3), - KEY_FLAG_TODO_ADD_DEBUGFS = BIT(4), + KEY_FLAG_TODO_HWACCEL_ADD = BIT(2), + KEY_FLAG_TODO_HWACCEL_REMOVE = BIT(3), + KEY_FLAG_TODO_DEFKEY = BIT(4), + KEY_FLAG_TODO_ADD_DEBUGFS = BIT(5), }; struct ieee80211_key { -- cgit v1.2.3-59-g8ed1b From 98dd6a575928ed9c42130d208e6bfb0f7a914d5a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 10 Apr 2008 15:36:09 +0200 Subject: mac80211: further RCU fixes There were a few more instances of sta_info_get calls not being protected by RCU, fix them. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 20 +++++++++++++++++--- net/mac80211/wext.c | 5 +++++ 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 8af576c1d2f1..0c1095aa94dd 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -718,12 +718,18 @@ static int ieee80211_del_station(struct wiphy *wiphy, struct net_device *dev, struct sta_info *sta; if (mac) { + rcu_read_lock(); + /* XXX: get sta belonging to dev */ sta = sta_info_get(local, mac); - if (!sta) + if (!sta) { + rcu_read_unlock(); return -ENOENT; + } sta_info_unlink(&sta); + rcu_read_unlock(); + sta_info_destroy(sta); } else sta_info_flush(local, sdata); @@ -740,17 +746,23 @@ static int ieee80211_change_station(struct wiphy *wiphy, struct sta_info *sta; struct ieee80211_sub_if_data *vlansdata; + rcu_read_lock(); + /* XXX: get sta belonging to dev */ sta = sta_info_get(local, mac); - if (!sta) + if (!sta) { + rcu_read_unlock(); return -ENOENT; + } if (params->vlan && params->vlan != sta->sdata->dev) { vlansdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); if (vlansdata->vif.type != IEEE80211_IF_TYPE_VLAN || - vlansdata->vif.type != IEEE80211_IF_TYPE_AP) + vlansdata->vif.type != IEEE80211_IF_TYPE_AP) { + rcu_read_unlock(); return -EINVAL; + } sta->sdata = IEEE80211_DEV_TO_SUB_IF(params->vlan); ieee80211_send_layer2_update(sta); @@ -758,6 +770,8 @@ static int ieee80211_change_station(struct wiphy *wiphy, sta_apply_parameters(local, sta, params); + rcu_read_unlock(); + return 0; } diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 69aed16faff3..5a452575719d 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -980,6 +980,8 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct sta_info *sta = NULL; + rcu_read_lock(); + if (sdata->vif.type == IEEE80211_IF_TYPE_STA || sdata->vif.type == IEEE80211_IF_TYPE_IBSS) sta = sta_info_get(local, sdata->u.sta.bssid); @@ -996,6 +998,9 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev wstats->qual.noise = sta->last_noise; wstats->qual.updated = local->wstats_flags; } + + rcu_read_unlock(); + return wstats; } -- cgit v1.2.3-59-g8ed1b From d18ef29f34eb33099d387a327abe139f3915a829 Mon Sep 17 00:00:00 2001 From: Reinette Chatre Date: Wed, 9 Apr 2008 16:56:15 -0700 Subject: mac80211: no BSS changes to driver from beacons processed during scanning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need to send BSS changes to driver from beacons processed during scanning. We are more interested in beacons from an AP with which we are associated - these will still be used to send updates to driver as the beacons are received without scanning. This change·removes the requirement that bss_info_changed needs to be atomic. The beacons received during scanning are processed from a tasklet, but if we do not call bss_info_changed for these beacons there is no need for it to be atomic. This function (bss_info_changed) is called either from workqueue or ioctl in all other instances. Signed-off-by: Reinette Chatre Acked-by: Tomas Winkler Acked-by: Johannes Berg Signed-off-by: John W. Linville --- include/net/mac80211.h | 3 +-- net/mac80211/mlme.c | 16 +++++++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'net') diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 079e7bd86c90..4a80d74975e8 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1020,8 +1020,7 @@ enum ieee80211_ampdu_mlme_action { * level driver (e.g. assoc/disassoc status, erp parameters). * This function should not be used if no BSS has been set, unless * for association indication. The @changed parameter indicates which - * of the bss parameters has changed when a call is made. This callback - * has to be atomic. + * of the bss parameters has changed when a call is made. * * @configure_filter: Configure the device's RX filter. * See the section "Frame filtering" for more information. diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 83e8b497e6db..e3f2cb086588 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2797,6 +2797,17 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); + if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { + ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, + elems.wmm_param_len); + } + + /* Do not send changes to driver if we are scanning. This removes + * requirement that driver's bss_info_changed function needs to be + * atomic. */ + if (local->sta_sw_scanning || local->sta_hw_scanning) + return; + if (elems.erp_info && elems.erp_info_len >= 1) changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]); else { @@ -2816,11 +2827,6 @@ static void ieee80211_rx_mgmt_beacon(struct net_device *dev, &bss_info); } - if (elems.wmm_param && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { - ieee80211_sta_wmm_params(dev, ifsta, elems.wmm_param, - elems.wmm_param_len); - } - ieee80211_bss_info_change_notify(sdata, changed); } -- cgit v1.2.3-59-g8ed1b From b16bd15c379410f2aa47837aa4a0de5712856ad5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 11 Apr 2008 21:40:35 +0200 Subject: mac80211: fix spinlock recursion When STAs are expired, we need to hold the sta_lock. Using the same lock for keys too would then mean we'd need another key free function, and that'll just lead to confusion, so just use a new spinlock for all key lists. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 10 ++++++++-- net/mac80211/key.c | 20 ++++++++++---------- net/mac80211/main.c | 2 ++ 3 files changed, 20 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c642538e8282..ce566f3e0169 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -600,8 +600,7 @@ struct ieee80211_local { /* * The lock only protects the list, hash, timer and counter * against manipulation, reads are done in RCU. Additionally, - * the lock protects each BSS's TIM bitmap, a few items in - * STA info structures and various key pointers. + * the lock protects each BSS's TIM bitmap. */ spinlock_t sta_lock; unsigned long num_sta; @@ -635,6 +634,13 @@ struct ieee80211_local { struct list_head interfaces; + /* + * Key lock, protects sdata's key_list and sta_info's + * key pointers (write access, they're RCU.) + */ + spinlock_t key_lock; + + bool sta_sw_scanning; bool sta_hw_scanning; int scan_channel_idx; diff --git a/net/mac80211/key.c b/net/mac80211/key.c index acf8d0370a37..b98711dcdc54 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -210,9 +210,9 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) { unsigned long flags; - spin_lock_irqsave(&sdata->local->sta_lock, flags); + spin_lock_irqsave(&sdata->local->key_lock, flags); __ieee80211_set_default_key(sdata, idx); - spin_unlock_irqrestore(&sdata->local->sta_lock, flags); + spin_unlock_irqrestore(&sdata->local->key_lock, flags); } @@ -339,7 +339,7 @@ void ieee80211_key_link(struct ieee80211_key *key, } } - spin_lock_irqsave(&sdata->local->sta_lock, flags); + spin_lock_irqsave(&sdata->local->key_lock, flags); if (sta) old_key = sta->key; @@ -348,7 +348,7 @@ void ieee80211_key_link(struct ieee80211_key *key, __ieee80211_key_replace(sdata, sta, old_key, key); - spin_unlock_irqrestore(&sdata->local->sta_lock, flags); + spin_unlock_irqrestore(&sdata->local->key_lock, flags); /* free old key later */ add_todo(old_key, KEY_FLAG_TODO_DELETE); @@ -377,9 +377,9 @@ void ieee80211_key_free(struct ieee80211_key *key) if (!key) return; - spin_lock_irqsave(&key->sdata->local->sta_lock, flags); + spin_lock_irqsave(&key->sdata->local->key_lock, flags); __ieee80211_key_free(key); - spin_unlock_irqrestore(&key->sdata->local->sta_lock, flags); + spin_unlock_irqrestore(&key->sdata->local->key_lock, flags); } /* @@ -397,10 +397,10 @@ static void ieee80211_todo_for_each_key(struct ieee80211_sub_if_data *sdata, might_sleep(); - spin_lock_irqsave(&sdata->local->sta_lock, flags); + spin_lock_irqsave(&sdata->local->key_lock, flags); list_for_each_entry(key, &sdata->key_list, list) add_todo(key, todo_flags); - spin_unlock_irqrestore(&sdata->local->sta_lock, flags); + spin_unlock_irqrestore(&sdata->local->key_lock, flags); ieee80211_key_todo(); } @@ -506,10 +506,10 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) ieee80211_debugfs_key_remove_default(sdata); - spin_lock_irqsave(&sdata->local->sta_lock, flags); + spin_lock_irqsave(&sdata->local->key_lock, flags); list_for_each_entry_safe(key, tmp, &sdata->key_list, list) __ieee80211_key_free(key); - spin_unlock_irqrestore(&sdata->local->sta_lock, flags); + spin_unlock_irqrestore(&sdata->local->key_lock, flags); __ieee80211_key_todo(); diff --git a/net/mac80211/main.c b/net/mac80211/main.c index bfcbcf5353ad..e9a978979d38 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1587,6 +1587,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, INIT_LIST_HEAD(&local->interfaces); + spin_lock_init(&local->key_lock); + INIT_DELAYED_WORK(&local->scan_work, ieee80211_sta_scan_work); sta_info_init(local); -- cgit v1.2.3-59-g8ed1b From 245cbe7a65f3e17999de276ea1c84538f3a7451e Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Sun, 13 Apr 2008 10:43:50 +0200 Subject: mac80211: fix key todo list order When we add multiple todo entries, we rely on them being executed mostly in the right order, especially when a key is being replaced. But when a default key is replaced, the todo list order will differ from the order when the key being replaced is not a default key, so problems will happen. Hence, just move each todo item to the end of the list when it is added so we can in the other code ensure that hw accel for a key will be disabled before it is enabled for the replacement. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/key.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/mac80211/key.c b/net/mac80211/key.c index b98711dcdc54..150d66dbda9d 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -74,9 +74,12 @@ static void add_todo(struct ieee80211_key *key, u32 flag) spin_lock(&todo_lock); key->flags |= flag; - /* only add if not already added */ - if (list_empty(&key->todo)) - list_add(&key->todo, &todo_list); + /* + * Remove again if already on the list so that we move it to the end. + */ + if (!list_empty(&key->todo)) + list_del(&key->todo); + list_add_tail(&key->todo, &todo_list); schedule_work(&todo_work); spin_unlock(&todo_lock); } -- cgit v1.2.3-59-g8ed1b From b454048cb933eb69dd9d46c16bf01e9df997fa3d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Mon, 14 Apr 2008 15:37:03 +0200 Subject: mac80211: allow WDS mode This allows creating interfaces in WDS mode or switching existing ones into WDS mode (both via cfg80211 and wext.) Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/cfg.c | 2 ++ net/mac80211/wext.c | 3 +++ 2 files changed, 5 insertions(+) (limited to 'net') diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 0c1095aa94dd..699d97b8de5e 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -33,6 +33,8 @@ nl80211_type_to_mac80211_type(enum nl80211_iftype type) case NL80211_IFTYPE_MESH_POINT: return IEEE80211_IF_TYPE_MESH_POINT; #endif + case NL80211_IFTYPE_WDS: + return IEEE80211_IF_TYPE_WDS; default: return IEEE80211_IF_TYPE_INVALID; } diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index 5a452575719d..76e1de1dc735 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -236,6 +236,9 @@ static int ieee80211_ioctl_siwmode(struct net_device *dev, case IW_MODE_ADHOC: type = IEEE80211_IF_TYPE_IBSS; break; + case IW_MODE_REPEAT: + type = IEEE80211_IF_TYPE_WDS; + break; case IW_MODE_MONITOR: type = IEEE80211_IF_TYPE_MNTR; break; -- cgit v1.2.3-59-g8ed1b From 30b89b0f5e1313c8a5a039abeaa89248b6338d81 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 16 Apr 2008 17:43:20 +0200 Subject: mac80211: rework scanning to account for probe response/beacon difference This patch reworks the scanning code (ieee80211_rx_bss_info) to take more parameters from beacons and keep a BSS info structure alive when only beacons for it are received. This fixes a problem with iwlwifi drivers (where we don't understand the root cause of the problem yet) and another driver for some broken hardware (which cannot send probe requests unless associated, so can't always actively scan.) Signed-off-by: Bill Moss [jmberg: reformatted comments, make probe_resp a bool] Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- net/mac80211/ieee80211_i.h | 2 +- net/mac80211/mlme.c | 85 +++++++++++++++++++++++++++------------------- 2 files changed, 52 insertions(+), 35 deletions(-) (limited to 'net') diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index ce566f3e0169..8e53ce7ed444 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -102,7 +102,7 @@ struct ieee80211_sta_bss { u64 timestamp; int beacon_int; - int probe_resp; + bool probe_resp; unsigned long last_update; /* during assocation, we save an ERP value from a probe response so diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index e3f2cb086588..6b75cb6c6300 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -2588,22 +2588,29 @@ static void ieee80211_rx_bss_info(struct net_device *dev, #endif } - bss->band = rx_status->band; - - if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && - bss->probe_resp && beacon) { - /* STA mode: - * Do not allow beacon to override data from Probe Response. */ - ieee80211_rx_bss_put(dev, bss); - return; - } - /* save the ERP value so that it is available at association time */ if (elems.erp_info && elems.erp_info_len >= 1) { bss->erp_value = elems.erp_info[0]; bss->has_erp_value = 1; } + if (elems.ht_cap_elem && + (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len || + memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) { + kfree(bss->ht_ie); + bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC); + if (bss->ht_ie) { + memcpy(bss->ht_ie, elems.ht_cap_elem - 2, + elems.ht_cap_elem_len + 2); + bss->ht_ie_len = elems.ht_cap_elem_len + 2; + } else + bss->ht_ie_len = 0; + } else if (!elems.ht_cap_elem && bss->ht_ie) { + kfree(bss->ht_ie); + bss->ht_ie = NULL; + bss->ht_ie_len = 0; + } + bss->beacon_int = le16_to_cpu(mgmt->u.beacon.beacon_int); bss->capability = le16_to_cpu(mgmt->u.beacon.capab_info); @@ -2625,6 +2632,26 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->supp_rates_len += clen; } + bss->band = rx_status->band; + + bss->timestamp = beacon_timestamp; + bss->last_update = jiffies; + bss->rssi = rx_status->ssi; + bss->signal = rx_status->signal; + bss->noise = rx_status->noise; + if (!beacon && !bss->probe_resp) + bss->probe_resp = true; + + /* + * In STA mode, the remaining parameters should not be overridden + * by beacons because they're not necessarily accurate there. + */ + if (sdata->vif.type != IEEE80211_IF_TYPE_IBSS && + bss->probe_resp && beacon) { + ieee80211_rx_bss_put(dev, bss); + return; + } + if (elems.wpa && (!bss->wpa_ie || bss->wpa_ie_len != elems.wpa_len || memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) { @@ -2657,6 +2684,20 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->rsn_ie_len = 0; } + /* + * Cf. + * http://www.wipo.int/pctdb/en/wo.jsp?wo=2007047181&IA=WO2007047181&DISPLAY=DESC + * + * quoting: + * + * In particular, "Wi-Fi CERTIFIED for WMM - Support for Multimedia + * Applications with Quality of Service in Wi-Fi Networks," Wi- Fi + * Alliance (September 1, 2004) is incorporated by reference herein. + * The inclusion of the WMM Parameters in probe responses and + * association responses is mandatory for WMM enabled networks. The + * inclusion of the WMM Parameters in beacons, however, is optional. + */ + if (elems.wmm_param && (!bss->wmm_ie || bss->wmm_ie_len != elems.wmm_param_len || memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) { @@ -2673,30 +2714,6 @@ static void ieee80211_rx_bss_info(struct net_device *dev, bss->wmm_ie = NULL; bss->wmm_ie_len = 0; } - if (elems.ht_cap_elem && - (!bss->ht_ie || bss->ht_ie_len != elems.ht_cap_elem_len || - memcmp(bss->ht_ie, elems.ht_cap_elem, elems.ht_cap_elem_len))) { - kfree(bss->ht_ie); - bss->ht_ie = kmalloc(elems.ht_cap_elem_len + 2, GFP_ATOMIC); - if (bss->ht_ie) { - memcpy(bss->ht_ie, elems.ht_cap_elem - 2, - elems.ht_cap_elem_len + 2); - bss->ht_ie_len = elems.ht_cap_elem_len + 2; - } else - bss->ht_ie_len = 0; - } else if (!elems.ht_cap_elem && bss->ht_ie) { - kfree(bss->ht_ie); - bss->ht_ie = NULL; - bss->ht_ie_len = 0; - } - - bss->timestamp = beacon_timestamp; - bss->last_update = jiffies; - bss->rssi = rx_status->ssi; - bss->signal = rx_status->signal; - bss->noise = rx_status->noise; - if (!beacon) - bss->probe_resp++; /* check if we need to merge IBSS */ if (sdata->vif.type == IEEE80211_IF_TYPE_IBSS && beacon && -- cgit v1.2.3-59-g8ed1b From 4784b7c348779e957c82ba638ba2ada5ad8502d8 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 16 Apr 2008 18:21:16 -0700 Subject: [TIPC]: Remove inlining of reference table locking routines This patch converts the TIPC reference table locking routines into non-inlined routines, since they are mainly called from non-performance critical areas of TIPC and the added code footprint incurred through inlining can no longer be justified. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/ref.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- net/tipc/ref.h | 89 +++----------------------------------------------------- 2 files changed, 91 insertions(+), 89 deletions(-) (limited to 'net') diff --git a/net/tipc/ref.c b/net/tipc/ref.c index c38744c96ed1..d0b240e86ccd 100644 --- a/net/tipc/ref.c +++ b/net/tipc/ref.c @@ -2,7 +2,7 @@ * net/tipc/ref.c: TIPC object registry code * * Copyright (c) 1991-2006, Ericsson AB - * Copyright (c) 2004-2005, Wind River Systems + * Copyright (c) 2004-2007, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,6 +46,37 @@ #include "node.h" #include "bcast.h" +/** + * struct reference - TIPC object reference entry + * @object: pointer to object associated with reference entry + * @lock: spinlock controlling access to object + * @data: reference value associated with object (or link to next unused entry) + */ + +struct reference { + void *object; + spinlock_t lock; + union { + u32 next_plus_upper; + u32 reference; + } data; +}; + +/** + * struct tipc_ref_table - table of TIPC object reference entries + * @entries: pointer to array of reference entries + * @index_mask: bitmask for array index portion of reference values + * @first_free: array index of first unused object reference entry + * @last_free: array index of last unused object reference entry + */ + +struct ref_table { + struct reference *entries; + u32 index_mask; + u32 first_free; + u32 last_free; +}; + /* * Object reference table consists of 2**N entries. * @@ -61,7 +92,7 @@ * because entry 0's reference field has the form XXXX|1--1. */ -struct ref_table tipc_ref_table = { NULL }; +static struct ref_table tipc_ref_table = { NULL }; static DEFINE_RWLOCK(ref_table_lock); @@ -198,8 +229,8 @@ void tipc_ref_discard(u32 ref) tipc_ref_table.first_free = index; else /* next_plus_upper is always XXXX|0--0 for last free entry */ - tipc_ref_table.entries[tipc_ref_table.last_free].data.next_plus_upper - |= index; + tipc_ref_table.entries[tipc_ref_table.last_free]. + data.next_plus_upper |= index; tipc_ref_table.last_free = index; /* increment upper bits of entry to invalidate subsequent references */ @@ -208,3 +239,55 @@ exit: write_unlock_bh(&ref_table_lock); } +/** + * tipc_ref_lock - lock referenced object and return pointer to it + */ + +void *tipc_ref_lock(u32 ref) +{ + if (likely(tipc_ref_table.entries)) { + struct reference *r; + + r = &tipc_ref_table.entries[ref & tipc_ref_table.index_mask]; + spin_lock_bh(&r->lock); + if (likely(r->data.reference == ref)) + return r->object; + spin_unlock_bh(&r->lock); + } + return NULL; +} + +/** + * tipc_ref_unlock - unlock referenced object + */ + +void tipc_ref_unlock(u32 ref) +{ + if (likely(tipc_ref_table.entries)) { + struct reference *r; + + r = &tipc_ref_table.entries[ref & tipc_ref_table.index_mask]; + if (likely(r->data.reference == ref)) + spin_unlock_bh(&r->lock); + else + err("tipc_ref_unlock() invoked using " + "obsolete reference\n"); + } +} + +/** + * tipc_ref_deref - return pointer referenced object (without locking it) + */ + +void *tipc_ref_deref(u32 ref) +{ + if (likely(tipc_ref_table.entries)) { + struct reference *r; + + r = &tipc_ref_table.entries[ref & tipc_ref_table.index_mask]; + if (likely(r->data.reference == ref)) + return r->object; + } + return NULL; +} + diff --git a/net/tipc/ref.h b/net/tipc/ref.h index 38f3a7f4a78d..7e3798ea93b9 100644 --- a/net/tipc/ref.h +++ b/net/tipc/ref.h @@ -2,7 +2,7 @@ * net/tipc/ref.h: Include file for TIPC object registry code * * Copyright (c) 1991-2006, Ericsson AB - * Copyright (c) 2005, Wind River Systems + * Copyright (c) 2005-2006, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,95 +37,14 @@ #ifndef _TIPC_REF_H #define _TIPC_REF_H -/** - * struct reference - TIPC object reference entry - * @object: pointer to object associated with reference entry - * @lock: spinlock controlling access to object - * @data: reference value associated with object (or link to next unused entry) - */ - -struct reference { - void *object; - spinlock_t lock; - union { - u32 next_plus_upper; - u32 reference; - } data; -}; - -/** - * struct tipc_ref_table - table of TIPC object reference entries - * @entries: pointer to array of reference entries - * @index_mask: bitmask for array index portion of reference values - * @first_free: array index of first unused object reference entry - * @last_free: array index of last unused object reference entry - */ - -struct ref_table { - struct reference *entries; - u32 index_mask; - u32 first_free; - u32 last_free; -}; - -extern struct ref_table tipc_ref_table; - int tipc_ref_table_init(u32 requested_size, u32 start); void tipc_ref_table_stop(void); u32 tipc_ref_acquire(void *object, spinlock_t **lock); void tipc_ref_discard(u32 ref); - -/** - * tipc_ref_lock - lock referenced object and return pointer to it - */ - -static inline void *tipc_ref_lock(u32 ref) -{ - if (likely(tipc_ref_table.entries)) { - struct reference *r = - &tipc_ref_table.entries[ref & tipc_ref_table.index_mask]; - - spin_lock_bh(&r->lock); - if (likely(r->data.reference == ref)) - return r->object; - spin_unlock_bh(&r->lock); - } - return NULL; -} - -/** - * tipc_ref_unlock - unlock referenced object - */ - -static inline void tipc_ref_unlock(u32 ref) -{ - if (likely(tipc_ref_table.entries)) { - struct reference *r = - &tipc_ref_table.entries[ref & tipc_ref_table.index_mask]; - - if (likely(r->data.reference == ref)) - spin_unlock_bh(&r->lock); - else - err("tipc_ref_unlock() invoked using obsolete reference\n"); - } -} - -/** - * tipc_ref_deref - return pointer referenced object (without locking it) - */ - -static inline void *tipc_ref_deref(u32 ref) -{ - if (likely(tipc_ref_table.entries)) { - struct reference *r = - &tipc_ref_table.entries[ref & tipc_ref_table.index_mask]; - - if (likely(r->data.reference == ref)) - return r->object; - } - return NULL; -} +void *tipc_ref_lock(u32 ref); +void tipc_ref_unlock(u32 ref); +void *tipc_ref_deref(u32 ref); #endif -- cgit v1.2.3-59-g8ed1b From 0089509826b4997c37f08dfbdfb96ee952096cc9 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 16 Apr 2008 18:21:47 -0700 Subject: [TIPC]: Optimized initialization of TIPC reference table This patch modifies TIPC's reference table code to delay initializing table entries until they are actually needed by applications. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/ref.c | 123 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 76 insertions(+), 47 deletions(-) (limited to 'net') diff --git a/net/tipc/ref.c b/net/tipc/ref.c index d0b240e86ccd..1853cca66c68 100644 --- a/net/tipc/ref.c +++ b/net/tipc/ref.c @@ -50,7 +50,7 @@ * struct reference - TIPC object reference entry * @object: pointer to object associated with reference entry * @lock: spinlock controlling access to object - * @data: reference value associated with object (or link to next unused entry) + * @data: reference value for object (combines instance & array index info) */ struct reference { @@ -65,31 +65,40 @@ struct reference { /** * struct tipc_ref_table - table of TIPC object reference entries * @entries: pointer to array of reference entries - * @index_mask: bitmask for array index portion of reference values + * @capacity: array index of first unusable entry + * @init_point: array index of first uninitialized entry * @first_free: array index of first unused object reference entry * @last_free: array index of last unused object reference entry + * @index_mask: bitmask for array index portion of reference values + * @start_mask: initial value for instance value portion of reference values */ struct ref_table { struct reference *entries; - u32 index_mask; + u32 capacity; + u32 init_point; u32 first_free; u32 last_free; + u32 index_mask; + u32 start_mask; }; /* * Object reference table consists of 2**N entries. * - * A used entry has object ptr != 0, reference == XXXX|own index - * (XXXX changes each time entry is acquired) - * A free entry has object ptr == 0, reference == YYYY|next free index - * (YYYY is one more than last used XXXX) + * State Object ptr Reference + * ----- ---------- --------- + * In use non-NULL XXXX|own index + * (XXXX changes each time entry is acquired) + * Free NULL YYYY|next free index + * (YYYY is one more than last used XXXX) + * Uninitialized NULL 0 * - * Free list is initially chained from entry (2**N)-1 to entry 1. - * Entry 0 is not used to allow index 0 to indicate the end of the free list. + * Entry 0 is not used; this allows index 0 to denote the end of the free list. * - * Note: Any accidental reference of the form XXXX|0--0 won't match entry 0 - * because entry 0's reference field has the form XXXX|1--1. + * Note that a reference value of 0 does not necessarily indicate that an + * entry is uninitialized, since the last entry in the free list could also + * have a reference value of 0 (although this is unlikely). */ static struct ref_table tipc_ref_table = { NULL }; @@ -103,29 +112,29 @@ static DEFINE_RWLOCK(ref_table_lock); int tipc_ref_table_init(u32 requested_size, u32 start) { struct reference *table; - u32 sz = 1 << 4; - u32 index_mask; - int i; + u32 actual_size; - while (sz < requested_size) { - sz <<= 1; - } - table = vmalloc(sz * sizeof(*table)); + /* account for unused entry, then round up size to a power of 2 */ + + requested_size++; + for (actual_size = 16; actual_size < requested_size; actual_size <<= 1) + /* do nothing */ ; + + /* allocate table & mark all entries as uninitialized */ + + table = __vmalloc(actual_size * sizeof(struct reference), + GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL); if (table == NULL) return -ENOMEM; - write_lock_bh(&ref_table_lock); - index_mask = sz - 1; - for (i = sz - 1; i >= 0; i--) { - table[i].object = NULL; - spin_lock_init(&table[i].lock); - table[i].data.next_plus_upper = (start & ~index_mask) + i - 1; - } tipc_ref_table.entries = table; - tipc_ref_table.index_mask = index_mask; - tipc_ref_table.first_free = sz - 1; - tipc_ref_table.last_free = 1; - write_unlock_bh(&ref_table_lock); + tipc_ref_table.capacity = requested_size; + tipc_ref_table.init_point = 1; + tipc_ref_table.first_free = 0; + tipc_ref_table.last_free = 0; + tipc_ref_table.index_mask = actual_size - 1; + tipc_ref_table.start_mask = start & ~tipc_ref_table.index_mask; + return TIPC_OK; } @@ -156,7 +165,7 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock) u32 index; u32 index_mask; u32 next_plus_upper; - u32 reference = 0; + u32 reference; if (!object) { err("Attempt to acquire reference to non-existent object\n"); @@ -167,6 +176,8 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock) return 0; } + /* take a free entry, if available; otherwise initialize a new entry */ + write_lock_bh(&ref_table_lock); if (tipc_ref_table.first_free) { index = tipc_ref_table.first_free; @@ -179,11 +190,23 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock) reference = (next_plus_upper & ~index_mask) + index; entry->data.reference = reference; entry->object = object; - if (lock != NULL) - *lock = &entry->lock; spin_unlock_bh(&entry->lock); + *lock = &entry->lock; + } + else if (tipc_ref_table.init_point < tipc_ref_table.capacity) { + index = tipc_ref_table.init_point++; + entry = &(tipc_ref_table.entries[index]); + spin_lock_init(&entry->lock); + reference = tipc_ref_table.start_mask + index; + entry->data.reference = reference; + entry->object = object; + *lock = &entry->lock; + } + else { + reference = 0; } write_unlock_bh(&ref_table_lock); + return reference; } @@ -200,20 +223,17 @@ void tipc_ref_discard(u32 ref) u32 index; u32 index_mask; - if (!ref) { - err("Attempt to discard reference 0\n"); - return; - } if (!tipc_ref_table.entries) { err("Reference table not found during discard attempt\n"); return; } - write_lock_bh(&ref_table_lock); index_mask = tipc_ref_table.index_mask; index = ref & index_mask; entry = &(tipc_ref_table.entries[index]); + write_lock_bh(&ref_table_lock); + if (!entry->object) { err("Attempt to discard reference to non-existent object\n"); goto exit; @@ -223,18 +243,23 @@ void tipc_ref_discard(u32 ref) goto exit; } - /* mark entry as unused */ + /* + * mark entry as unused; increment upper bits of entry's data field + * to invalidate any subsequent references + */ + entry->object = NULL; + entry->data.next_plus_upper = (ref & ~index_mask) + (index_mask + 1); + + /* append entry to free entry list */ + if (tipc_ref_table.first_free == 0) tipc_ref_table.first_free = index; else - /* next_plus_upper is always XXXX|0--0 for last free entry */ tipc_ref_table.entries[tipc_ref_table.last_free]. data.next_plus_upper |= index; tipc_ref_table.last_free = index; - /* increment upper bits of entry to invalidate subsequent references */ - entry->data.next_plus_upper = (ref & ~index_mask) + (index_mask + 1); exit: write_unlock_bh(&ref_table_lock); } @@ -249,10 +274,13 @@ void *tipc_ref_lock(u32 ref) struct reference *r; r = &tipc_ref_table.entries[ref & tipc_ref_table.index_mask]; - spin_lock_bh(&r->lock); - if (likely(r->data.reference == ref)) - return r->object; - spin_unlock_bh(&r->lock); + + if (likely(r->data.reference != 0)) { + spin_lock_bh(&r->lock); + if (likely((r->data.reference == ref) && (r->object))) + return r->object; + spin_unlock_bh(&r->lock); + } } return NULL; } @@ -267,11 +295,12 @@ void tipc_ref_unlock(u32 ref) struct reference *r; r = &tipc_ref_table.entries[ref & tipc_ref_table.index_mask]; - if (likely(r->data.reference == ref)) + + if (likely((r->data.reference == ref) && (r->object))) spin_unlock_bh(&r->lock); else err("tipc_ref_unlock() invoked using " - "obsolete reference\n"); + "invalid reference\n"); } } -- cgit v1.2.3-59-g8ed1b From bcff122d478b774f4fd5262f35eedebe2f2fb274 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Wed, 16 Apr 2008 18:22:20 -0700 Subject: [TIPC]: Cleanup of TIPC reference table code This patch is a largely cosmetic cleanup of the TIPC reference table code. - The object reference field in each table entry is now single 32-bit integer instead of a union of two 32-bit integers. - Variable naming has been made more consistent. - Error message output has been made more consistent. - Useless #includes have been eliminated. Signed-off-by: Allan Stephens Signed-off-by: David S. Miller --- net/tipc/ref.c | 81 ++++++++++++++++++++++++---------------------------------- 1 file changed, 34 insertions(+), 47 deletions(-) (limited to 'net') diff --git a/net/tipc/ref.c b/net/tipc/ref.c index 1853cca66c68..89cbab24d08f 100644 --- a/net/tipc/ref.c +++ b/net/tipc/ref.c @@ -36,30 +36,18 @@ #include "core.h" #include "ref.h" -#include "port.h" -#include "subscr.h" -#include "name_distr.h" -#include "name_table.h" -#include "config.h" -#include "discover.h" -#include "bearer.h" -#include "node.h" -#include "bcast.h" /** * struct reference - TIPC object reference entry * @object: pointer to object associated with reference entry * @lock: spinlock controlling access to object - * @data: reference value for object (combines instance & array index info) + * @ref: reference value for object (combines instance & array index info) */ struct reference { void *object; spinlock_t lock; - union { - u32 next_plus_upper; - u32 reference; - } data; + u32 ref; }; /** @@ -165,7 +153,7 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock) u32 index; u32 index_mask; u32 next_plus_upper; - u32 reference; + u32 ref; if (!object) { err("Attempt to acquire reference to non-existent object\n"); @@ -185,10 +173,10 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock) index_mask = tipc_ref_table.index_mask; /* take lock in case a previous user of entry still holds it */ spin_lock_bh(&entry->lock); - next_plus_upper = entry->data.next_plus_upper; + next_plus_upper = entry->ref; tipc_ref_table.first_free = next_plus_upper & index_mask; - reference = (next_plus_upper & ~index_mask) + index; - entry->data.reference = reference; + ref = (next_plus_upper & ~index_mask) + index; + entry->ref = ref; entry->object = object; spin_unlock_bh(&entry->lock); *lock = &entry->lock; @@ -197,17 +185,17 @@ u32 tipc_ref_acquire(void *object, spinlock_t **lock) index = tipc_ref_table.init_point++; entry = &(tipc_ref_table.entries[index]); spin_lock_init(&entry->lock); - reference = tipc_ref_table.start_mask + index; - entry->data.reference = reference; + ref = tipc_ref_table.start_mask + index; + entry->ref = ref; entry->object = object; *lock = &entry->lock; } else { - reference = 0; + ref = 0; } write_unlock_bh(&ref_table_lock); - return reference; + return ref; } /** @@ -238,26 +226,25 @@ void tipc_ref_discard(u32 ref) err("Attempt to discard reference to non-existent object\n"); goto exit; } - if (entry->data.reference != ref) { + if (entry->ref != ref) { err("Attempt to discard non-existent reference\n"); goto exit; } /* - * mark entry as unused; increment upper bits of entry's data field + * mark entry as unused; increment instance part of entry's reference * to invalidate any subsequent references */ entry->object = NULL; - entry->data.next_plus_upper = (ref & ~index_mask) + (index_mask + 1); + entry->ref = (ref & ~index_mask) + (index_mask + 1); /* append entry to free entry list */ if (tipc_ref_table.first_free == 0) tipc_ref_table.first_free = index; else - tipc_ref_table.entries[tipc_ref_table.last_free]. - data.next_plus_upper |= index; + tipc_ref_table.entries[tipc_ref_table.last_free].ref |= index; tipc_ref_table.last_free = index; exit: @@ -271,15 +258,15 @@ exit: void *tipc_ref_lock(u32 ref) { if (likely(tipc_ref_table.entries)) { - struct reference *r; - - r = &tipc_ref_table.entries[ref & tipc_ref_table.index_mask]; - - if (likely(r->data.reference != 0)) { - spin_lock_bh(&r->lock); - if (likely((r->data.reference == ref) && (r->object))) - return r->object; - spin_unlock_bh(&r->lock); + struct reference *entry; + + entry = &tipc_ref_table.entries[ref & + tipc_ref_table.index_mask]; + if (likely(entry->ref != 0)) { + spin_lock_bh(&entry->lock); + if (likely((entry->ref == ref) && (entry->object))) + return entry->object; + spin_unlock_bh(&entry->lock); } } return NULL; @@ -292,15 +279,14 @@ void *tipc_ref_lock(u32 ref) void tipc_ref_unlock(u32 ref) { if (likely(tipc_ref_table.entries)) { - struct reference *r; - - r = &tipc_ref_table.entries[ref & tipc_ref_table.index_mask]; + struct reference *entry; - if (likely((r->data.reference == ref) && (r->object))) - spin_unlock_bh(&r->lock); + entry = &tipc_ref_table.entries[ref & + tipc_ref_table.index_mask]; + if (likely((entry->ref == ref) && (entry->object))) + spin_unlock_bh(&entry->lock); else - err("tipc_ref_unlock() invoked using " - "invalid reference\n"); + err("Attempt to unlock non-existent reference\n"); } } @@ -311,11 +297,12 @@ void tipc_ref_unlock(u32 ref) void *tipc_ref_deref(u32 ref) { if (likely(tipc_ref_table.entries)) { - struct reference *r; + struct reference *entry; - r = &tipc_ref_table.entries[ref & tipc_ref_table.index_mask]; - if (likely(r->data.reference == ref)) - return r->object; + entry = &tipc_ref_table.entries[ref & + tipc_ref_table.index_mask]; + if (likely(entry->ref == ref)) + return entry->object; } return NULL; } -- cgit v1.2.3-59-g8ed1b From 8b73a07c8ffaa70683022566080f4df3328ea18d Mon Sep 17 00:00:00 2001 From: Gui Jianfeng Date: Thu, 17 Apr 2008 14:22:18 -0700 Subject: SCTP: Initialize partial_bytes_acked to 0, when all of the data is acked. According to RFC4960 7.2.2, When all of the data transmitted by the sender has been acknowledged by the recerver, partial_bytes_acked is initialized to 0. This patch conforms to rfc requirement. Without this fix, cwnd might be error incremented. Signed-off-by: Gui Jianfeng Acked-by: Vlad Yasevich Signed-off-by: David S. Miller --- net/sctp/outqueue.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net') diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index a7ba9e146dff..59edfd25a19c 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -1532,6 +1532,8 @@ static void sctp_check_transmitted(struct sctp_outq *q, bytes_acked); transport->flight_size -= bytes_acked; + if (transport->flight_size == 0) + transport->partial_bytes_acked = 0; q->outstanding_bytes -= bytes_acked; } else { /* RFC 2960 6.1, sctpimpguide-06 2.15.2 -- cgit v1.2.3-59-g8ed1b From e56d8b8a2ee5fb7f63ceba58e1c0fb3c844888a4 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 17 Apr 2008 23:17:34 -0700 Subject: [INET]: Drop the inet_inherit_port() call. As I can see from the code, two places (tcp_v6_syn_recv_sock and dccp_v6_request_recv_sock) that call this one already run with BHs disabled, so it's safe to call __inet_inherit_port there. Besides (in case I missed smth with code review) the calltrace tcp_v6_syn_recv_sock `- tcp_v4_syn_recv_sock `- __inet_inherit_port and the similar for DCCP are valid, but assumes BHs to be disabled. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/net/inet_hashtables.h | 7 ------- net/dccp/ipv6.c | 2 +- net/ipv6/tcp_ipv6.c | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) (limited to 'net') diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 5525227c5e92..5ec91d88b517 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -235,13 +235,6 @@ static inline void __inet_inherit_port(struct sock *sk, struct sock *child) spin_unlock(&head->lock); } -static inline void inet_inherit_port(struct sock *sk, struct sock *child) -{ - local_bh_disable(); - __inet_inherit_port(sk, child); - local_bh_enable(); -} - extern void inet_put_port(struct sock *sk); extern void inet_listen_wlock(struct inet_hashinfo *hashinfo); diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index f8371c7e5e80..9b1129bb7ece 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -625,7 +625,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, newinet->daddr = newinet->saddr = newinet->rcv_saddr = LOOPBACK4_IPV6; __inet6_hash(newsk); - inet_inherit_port(sk, newsk); + __inet_inherit_port(sk, newsk); return newsk; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 231c4dddfb8c..715965f0fac0 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1534,7 +1534,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, #endif __inet6_hash(newsk); - inet_inherit_port(sk, newsk); + __inet_inherit_port(sk, newsk); return newsk; -- cgit v1.2.3-59-g8ed1b From 53083773dcbd3c80477e2ace143e361e1e806745 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Thu, 17 Apr 2008 23:18:15 -0700 Subject: [INET]: Uninline the __inet_inherit_port call. This deblats ~200 bytes when ipv6 and dccp are 'y'. Besides, this will ease compilation issues for patches I'm working on to make inet hash tables more scalable wrt net namespaces. Signed-off-by: Pavel Emelyanov Signed-off-by: David S. Miller --- include/net/inet_hashtables.h | 14 +------------- net/ipv4/inet_hashtables.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 5ec91d88b517..735b926a3497 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -221,19 +221,7 @@ static inline int inet_sk_listen_hashfn(const struct sock *sk) } /* Caller must disable local BH processing. */ -static inline void __inet_inherit_port(struct sock *sk, struct sock *child) -{ - struct inet_hashinfo *table = sk->sk_prot->h.hashinfo; - const int bhash = inet_bhashfn(inet_sk(child)->num, table->bhash_size); - struct inet_bind_hashbucket *head = &table->bhash[bhash]; - struct inet_bind_bucket *tb; - - spin_lock(&head->lock); - tb = inet_csk(sk)->icsk_bind_hash; - sk_add_bind_node(child, &tb->owners); - inet_csk(child)->icsk_bind_hash = tb; - spin_unlock(&head->lock); -} +extern void __inet_inherit_port(struct sock *sk, struct sock *child); extern void inet_put_port(struct sock *sk); diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 1612184ecc6f..2023d37b2708 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -92,6 +92,22 @@ void inet_put_port(struct sock *sk) EXPORT_SYMBOL(inet_put_port); +void __inet_inherit_port(struct sock *sk, struct sock *child) +{ + struct inet_hashinfo *table = sk->sk_prot->h.hashinfo; + const int bhash = inet_bhashfn(inet_sk(child)->num, table->bhash_size); + struct inet_bind_hashbucket *head = &table->bhash[bhash]; + struct inet_bind_bucket *tb; + + spin_lock(&head->lock); + tb = inet_csk(sk)->icsk_bind_hash; + sk_add_bind_node(child, &tb->owners); + inet_csk(child)->icsk_bind_hash = tb; + spin_unlock(&head->lock); +} + +EXPORT_SYMBOL_GPL(__inet_inherit_port); + /* * This lock without WQ_FLAG_EXCLUSIVE is good on UP and it can be very bad on SMP. * Look, when several writers sleep and reader wakes them up, all but one -- cgit v1.2.3-59-g8ed1b From f5ba2d32170679eb9b7c251ac3d9687916a41c18 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 17 Apr 2008 23:19:55 -0700 Subject: [PKT_SCHED]: Fix datalen check in tcf_simp_init(). datalen is unsigned so it can never be less than zero, but that's ok because the attribute passed to nla_len() has been validated and therefore a negative return value is impossible. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/act_simple.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index fbde461b716c..64b2d136c78e 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -115,7 +115,7 @@ static int tcf_simp_init(struct nlattr *nla, struct nlattr *est, return -EINVAL; datalen = nla_len(tb[TCA_DEF_DATA]); - if (datalen <= 0) + if (datalen == 0) return -EINVAL; pc = tcf_hash_check(parm->index, a, bind, &simp_hash_info); -- cgit v1.2.3-59-g8ed1b From 794eb6bf20ebf992c040ea831cd3a9c64b0c1f7a Mon Sep 17 00:00:00 2001 From: Jesper Juhl Date: Thu, 17 Apr 2008 23:22:54 -0700 Subject: [NETLABEL]: Fix NULL deref in netlbl_unlabel_staticlist_gen() if ifindex not found dev_get_by_index() may return NULL if nothing is found. In net/netlabel/netlabel_unlabeled.c::netlbl_unlabel_staticlist_gen() the function is called, but the return value is never checked. If it returns NULL then we'll deref a NULL pointer on the very next line. I checked the callers, and I don't think this can actually happen today, but code changes over time and in the future it might happen and it does no harm to be defensive and check for the failure, so that if/when it happens we'll fail gracefully instead of crashing. Signed-off-by: Jesper Juhl Acked-by: Paul Moore Signed-off-by: David S. Miller --- net/netlabel/netlabel_unlabeled.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index a547c6320eb3..d282ad1570a7 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -1339,6 +1339,10 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd, if (iface->ifindex > 0) { dev = dev_get_by_index(&init_net, iface->ifindex); + if (!dev) { + ret_val = -ENODEV; + goto list_cb_failure; + } ret_val = nla_put_string(cb_arg->skb, NLBL_UNLABEL_A_IFACE, dev->name); dev_put(dev); -- cgit v1.2.3-59-g8ed1b From 3c051235a7f115c34e675c9cf55820bd3435f860 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 18 Apr 2008 01:46:19 -0700 Subject: [IPV6]: Fix dangling references on error in fib6_add(). Fixes bugzilla #8895 If a super-tree leaf has 'rt' assigned to it and we get an error from fib6_add_rt2node(), we'll leave a reference to 'rt' in pn->leaf and then do an unconditional dst_free(). We should prune such references. Based upon a report by Vincent Perrier. Signed-off-by: David S. Miller --- net/ipv6/ip6_fib.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index b3f6e03c454c..50f3f8f8a59b 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -772,6 +772,10 @@ out: * If fib6_add_1 has cleared the old leaf pointer in the * super-tree leaf node we have to find a new one for it. */ + if (pn != fn && pn->leaf == rt) { + pn->leaf = NULL; + atomic_dec(&rt->rt6i_ref); + } if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) { pn->leaf = fib6_find_prefix(info->nl_net, pn); #if RT6_DEBUG >= 2 -- cgit v1.2.3-59-g8ed1b From d1643d24c61b725bef399cc1cf2944b4c9c23177 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 18 Apr 2008 15:43:32 -0700 Subject: [NET]: Fix and allocate less memory for ->priv'less netdevices This patch effectively reverts commit d0498d9ae1a5cebac363e38907266d5cd2eedf89 aka "[NET]: Do not allocate unneeded memory for dev->priv alignment." It was found to be buggy because of final unconditional += NETDEV_ALIGN_CONST removal. For example, for sizeof(struct net_device) being 2048 bytes, "alloc_size" was also 2048 bytes, but allocator with debugging options turned on started giving out !32-byte aligned memory resulting in redzones overwrites. Patch does small optimization in ->priv'less case: bumping size to next 32-byte boundary was always done to ensure ->priv will also be aligned. But, no ->priv, no need to do that. Signed-off-by: Alexey Dobriyan Signed-off-by: David S. Miller --- net/core/dev.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'net') diff --git a/net/core/dev.c b/net/core/dev.c index c16a07fde388..e1df1ab3e04a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3996,12 +3996,15 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, BUG_ON(strlen(name) >= sizeof(dev->name)); - /* ensure 32-byte alignment of both the device and private area */ - alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST + - (sizeof(struct net_device_subqueue) * (queue_count - 1))) & - ~NETDEV_ALIGN_CONST; - if (sizeof_priv) - alloc_size += sizeof_priv + NETDEV_ALIGN_CONST; + alloc_size = sizeof(struct net_device) + + sizeof(struct net_device_subqueue) * (queue_count - 1); + if (sizeof_priv) { + /* ensure 32-byte alignment of private area */ + alloc_size = (alloc_size + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST; + alloc_size += sizeof_priv; + } + /* ensure 32-byte alignment of whole construct */ + alloc_size += NETDEV_ALIGN_CONST; p = kzalloc(alloc_size, GFP_KERNEL); if (!p) { -- cgit v1.2.3-59-g8ed1b