diff options
Diffstat (limited to 'net')
295 files changed, 16223 insertions, 10870 deletions
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index b33410abfd6b..5975ec3be7f3 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; @@ -394,7 +404,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 (is_vlan_dev(dev)) { diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 480ea90e7dcd..0e3b2d3e2339 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); @@ -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__, ntohs(veth->h_vlan_proto)); + __func__, ntohs(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 9671aa51af2c..24cd96ee8109 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/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!). diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 18058bbc7962..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. */ @@ -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/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 2ab1e36098fd..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) { @@ -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. diff --git a/net/atm/lec.c b/net/atm/lec.c index a2efa7ff41f1..aa3785ebf6d1 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/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/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, 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 48bfcc741f25..2712544cf0ca 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 */ @@ -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/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/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 2957df4b6c0b..a4849f2c1d81 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 af4e3934ee84..5083adcbfae5 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 cd887cdca426..b0d487e2db20 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_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/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/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/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/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 460e7f99ce3e..7aa01125287e 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 { + 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 @@ -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, }; @@ -3688,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); @@ -4010,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 + @@ -4021,6 +4022,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); @@ -4134,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 (net_eq(dev_net(dev), net)) goto out; /* Pick the destination device name, and ensure @@ -4185,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/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, }; diff --git a/net/core/dst.c b/net/core/dst.c index 7deef483c79f..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 @@ -279,7 +289,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) { @@ -295,9 +305,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: diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 42ccaf5b8509..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; @@ -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 19b8e003f150..75075c303c44 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) @@ -388,7 +392,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)) { + net_eq(dev_net(n->dev), net)) { neigh_hold(n); NEIGH_CACHE_STAT_INC(tbl, hits); break; @@ -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,28 +470,44 @@ 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) +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) && - (n->net == 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); struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, struct net *net, const void *pkey, @@ -494,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) && - (n->net == 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(); @@ -522,7 +531,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) @@ -544,6 +555,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, @@ -551,25 +563,20 @@ 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; np = &n->next) { if (!memcmp(n->key, pkey, key_len) && n->dev == dev && - (n->net == net)) { + net_eq(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; } @@ -592,7 +599,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; } @@ -651,6 +658,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. @@ -931,6 +939,7 @@ out_unlock_bh: write_unlock_bh(&neigh->lock); return rc; } +EXPORT_SYMBOL(__neigh_event_send); static void neigh_update_hhs(struct neighbour *neigh) { @@ -1103,6 +1112,7 @@ out: return err; } +EXPORT_SYMBOL(neigh_update); struct neighbour *neigh_event_ns(struct neigh_table *tbl, u8 *lladdr, void *saddr, @@ -1115,6 +1125,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) @@ -1169,6 +1180,7 @@ int neigh_compat_output(struct sk_buff *skb) return dev_queue_xmit(skb); } +EXPORT_SYMBOL(neigh_compat_output); /* Slow and careful. */ @@ -1214,6 +1226,7 @@ out_kfree_skb: kfree_skb(skb); goto out; } +EXPORT_SYMBOL(neigh_resolve_output); /* As fast as possible without hh cache */ @@ -1238,6 +1251,7 @@ int neigh_connected_output(struct sk_buff *skb) } return err; } +EXPORT_SYMBOL(neigh_connected_output); static void neigh_proxy_process(unsigned long arg) { @@ -1299,6 +1313,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) @@ -1306,9 +1321,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 && net_eq(neigh_parms_net(p), net)) || (!p->dev && !ifindex)) return p; } @@ -1322,7 +1335,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; @@ -1342,7 +1355,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; @@ -1351,6 +1366,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) { @@ -1381,10 +1397,11 @@ 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) { - release_net(parms->net); + release_net(neigh_parms_net(parms)); kfree(parms); } @@ -1395,7 +1412,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 = @@ -1441,6 +1460,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) { @@ -1462,6 +1482,7 @@ void neigh_table_init(struct neigh_table *tbl) dump_stack(); } } +EXPORT_SYMBOL(neigh_table_init); int neigh_table_clear(struct neigh_table *tbl) { @@ -1499,10 +1520,11 @@ 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) { - 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; @@ -1568,7 +1590,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; @@ -1836,7 +1858,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]; @@ -1961,7 +1983,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]; @@ -1982,7 +2004,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_eq(neigh_parms_net(p), net)) continue; if (nidx++ < neigh_skip) @@ -2061,7 +2083,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]; @@ -2074,7 +2096,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) @@ -2169,7 +2191,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; @@ -2179,7 +2201,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 (!net_eq(dev_net(n->dev), net)) goto next; if (state->neigh_sub_iter) { loff_t fakep = 0; @@ -2210,7 +2232,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) { @@ -2222,7 +2244,7 @@ static struct neighbour *neigh_get_next(struct seq_file *seq, while (1) { while (n) { - if (n->dev->nd_net != 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); @@ -2270,7 +2292,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; @@ -2278,7 +2300,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 && !net_eq(pneigh_net(pn), net)) pn = pn->next; if (pn) break; @@ -2293,7 +2315,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; @@ -2301,7 +2323,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 && !net_eq(pneigh_net(pn), net)) pn = pn->next; if (pn) break; @@ -2506,7 +2528,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; @@ -2532,6 +2554,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 @@ -2763,7 +2786,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(neigh_parms_net(p), neigh_path, t->neigh_vars); if (!t->sysctl_header) goto free_procname; @@ -2777,6 +2801,7 @@ free: err: return -ENOBUFS; } +EXPORT_SYMBOL(neigh_sysctl_register); void neigh_sysctl_unregister(struct neigh_parms *p) { @@ -2788,6 +2813,7 @@ void neigh_sysctl_unregister(struct neigh_parms *p) kfree(t); } } +EXPORT_SYMBOL(neigh_sysctl_unregister); #endif /* CONFIG_SYSCTL */ @@ -2805,32 +2831,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 diff --git a/net/core/netpoll.c b/net/core/netpoll.c index c635de52526c..b04d643fc3c7 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -390,9 +390,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); @@ -420,7 +418,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/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..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; @@ -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]) @@ -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; @@ -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; @@ -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/skbuff.c b/net/core/skbuff.c index 0d0fd28a9041..e4259215607f 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -263,6 +263,28 @@ 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) +{ + /* + * There is more code here than it seems: + * __dev_alloc_skb is an inline + */ + 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; @@ -857,6 +879,78 @@ 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); + +/** + * 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->data<skb->head)) + 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 + * @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); + +/** + * 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. */ diff --git a/net/core/sock.c b/net/core/sock.c index 09cb3a74de7f..83e11f7260ff 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; @@ -981,12 +981,31 @@ 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); + put_net(sock_net(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); + sock_net_set(sk, get_net(&init_net)); + sock_put(sk); +} +EXPORT_SYMBOL(sk_release_kernel); + struct sock *sk_clone(const struct sock *sk, const gfp_t priority) { struct sock *newsk; @@ -998,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); @@ -1076,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); @@ -1919,16 +1940,113 @@ 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 */ +struct prot_inuse { + int val[PROTO_INUSE_NR]; +}; + +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) +{ + __get_cpu_var(prot_inuse).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(prot_inuse, cpu).val[idx]; + + return res >= 0 ? res : 0; +} +EXPORT_SYMBOL_GPL(sock_prot_inuse_get); +#endif + +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; 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); @@ -1936,7 +2054,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) { @@ -1979,6 +2097,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; @@ -1994,8 +2113,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; } @@ -2005,11 +2122,10 @@ 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); - sock_prot_inuse_free(prot); - if (prot->slab != NULL) { kmem_cache_destroy(prot->slab); prot->slab = NULL; 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/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/dccp/ipv4.c b/net/dccp/ipv4.c index 474075adbde4..7d62f7eb6134 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, @@ -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); @@ -512,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); @@ -564,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)) { @@ -620,7 +618,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); @@ -917,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, @@ -943,12 +939,11 @@ 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, #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 490333d47c7b..ea3f32648618 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); @@ -1102,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, @@ -1128,12 +1124,11 @@ 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, #endif - REF_PROTO_INUSE(dccp_v6) }; static struct inet6_protocol dccp_v6_protocol = { 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/decnet/af_decnet.c b/net/decnet/af_decnet.c index acd48ee522d6..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); @@ -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) { @@ -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 = { 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 9dc0abb50eaf..2f665a516476 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) @@ -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/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/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 <johannes@sipsolutions.net> - * Joseph Jezak <josejx@gentoo.org> - * Larry Finger <Larry.Finger@lwfinger.net> - * Danny van Dyk <kugelfang@gentoo.org> - * Michael Buesch <mbuesch@freenet.de> - * - * 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 <johannes@sipsolutions.net> - * Joseph Jezak <josejx@gentoo.org> - * Larry Finger <Larry.Finger@lwfinger.net> - * Danny van Dyk <kugelfang@gentoo.org> - * Michael Buesch <mbuesch@freenet.de> - * - * 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 <johannes@sipsolutions.net> - * Joseph Jezak <josejx@gentoo.org> - * Larry Finger <Larry.Finger@lwfinger.net> - * Danny van Dyk <kugelfang@gentoo.org> - * Michael Buesch <mbuesch@freenet.de> - * - * 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 <johannes@sipsolutions.net> - * Joseph Jezak <josejx@gentoo.org> - * Larry Finger <Larry.Finger@lwfinger.net> - * Danny van Dyk <kugelfang@gentoo.org> - * Michael Buesch <mbuesch@freenet.de> - * - * 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 <linux/sort.h> -#include <linux/etherdevice.h> - -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; i<ri->count-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; i<ri->count; 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 c43b189634df..000000000000 --- a/net/ieee80211/softmac/ieee80211softmac_priv.h +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Internal softmac API definitions. - * - * Copyright (c) 2005, 2006 Johannes Berg <johannes@sipsolutions.net> - * Joseph Jezak <josejx@gentoo.org> - * Larry Finger <Larry.Finger@lwfinger.net> - * Danny van Dyk <kugelfang@gentoo.org> - * Michael Buesch <mbuesch@freenet.de> - * - * 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 <net/ieee80211softmac.h> -#include <net/ieee80211softmac_wx.h> -#include <linux/kernel.h> -#include <linux/stringify.h> - - -#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__, __FUNCTION__); \ - } \ - } 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 <johannes@sipsolutions.net> - * Joseph Jezak <josejx@gentoo.org> - * Larry Finger <Larry.Finger@lwfinger.net> - * Danny van Dyk <kugelfang@gentoo.org> - * Michael Buesch <mbuesch@freenet.de> - * - * 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 <linux/completion.h> -#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 <johannes@sipsolutions.net> - * Joseph Jezak <josejx@gentoo.org> - * Larry Finger <Larry.Finger@lwfinger.net> - * Danny van Dyk <kugelfang@gentoo.org> - * Michael Buesch <mbuesch@freenet.de> - * - * 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 <net/iw_handler.h> -/* for is_broadcast_ether_addr and is_zero_ether_addr */ -#include <linux/etherdevice.h> - -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;i<wrqu->data.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); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 0d109504ed86..5882a1316441 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; @@ -446,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(&init_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 @@ -784,6 +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 = sock_net(sk); switch (cmd) { case SIOCGSTAMP: @@ -795,12 +814,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 +832,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) @@ -1059,7 +1078,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)); } @@ -1113,7 +1132,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(sock_net(sk), &rt, &fl, sk, 0); } if (!err) sk_setup_caps(sk, &rt->u.dst); @@ -1283,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) @@ -1414,7 +1436,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(); @@ -1429,7 +1451,8 @@ static int __init inet_init(void) * Set the ICMP layer up */ - icmp_init(&inet_family_ops); + if (icmp_init() < 0) + panic("Failed to create the ICMP control socket.\n"); /* * Initialise the multicast router diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 8e17f65f4002..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(&init_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(&init_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(&init_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(&init_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); @@ -475,9 +475,9 @@ 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)) + if (arp_set_predefined(inet_addr_type(dev_net(dev), paddr), haddr, paddr, dev)) return 0; n = __neigh_lookup(&arp_tbl, &paddr, dev, 1); @@ -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) @@ -710,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_net(dev); /* arp_rcv below verifies the ARP header and verifies the device * is ARP'able. @@ -805,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); @@ -815,7 +815,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) { @@ -835,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); @@ -858,14 +858,14 @@ 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) */ 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); } @@ -912,13 +912,8 @@ 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, (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); @@ -1201,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); @@ -1385,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) 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/devinet.c b/net/ipv4/devinet.c index 87490f7bb0f7..6848e4760f34 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; @@ -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; @@ -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; @@ -555,14 +552,11 @@ 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(); - if (net != &init_net) - return -EINVAL; - ifa = rtm_to_ifaddr(net, nlh); if (IS_ERR(ifa)) return PTR_ERR(ifa); @@ -595,7 +589,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 +618,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 +659,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) @@ -878,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_net(dev); rcu_read_lock(); in_dev = __in_dev_get_rcu(dev); @@ -906,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; @@ -979,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) { @@ -1045,9 +1040,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) { @@ -1166,16 +1158,13 @@ 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; 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) { @@ -1214,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; @@ -1528,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..0f1557a4ac7a 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) @@ -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; @@ -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 @@ -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))) @@ -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/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_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/fib_trie.c b/net/ipv4/fib_trie.c index f6cdc012eec5..9e491e70e855 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2029,9 +2029,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; }; @@ -2084,31 +2083,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) @@ -2119,8 +2113,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; @@ -2209,36 +2202,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; + + fib_table_print(seq, tb); - tb = fib_get_table(net, RT_TABLE_MAIN); - if (tb) - fib_trie_show(seq, "Main", (struct trie *) tb->tb_data); + 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; } @@ -2274,67 +2279,79 @@ 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 fib_trie_iter *iter = seq->private; + struct net *net = seq_file_net(seq); 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; } 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(seq, *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 = seq_file_net(seq); + 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) @@ -2391,15 +2408,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, "<local>:\n"); - else - seq_puts(seq, "<main>:\n"); - } + if (!node_parent_rcu(n)) + fib_table_print(seq, iter->tb); if (IS_TNODE(n)) { struct tnode *tn = (struct tnode *) n; @@ -2502,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/icmp.c b/net/ipv4/icmp.c index a944e8053e28..803bc9f173a7 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. */ @@ -229,14 +206,16 @@ 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 struct sock *icmp_sk(struct net *net) +{ + return net->ipv4.icmp_sk[smp_processor_id()]; +} -static inline int icmp_xmit_lock(void) +static inline int icmp_xmit_lock(struct sock *sk) { local_bh_disable(); - if (unlikely(!spin_trylock(&icmp_socket->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 +225,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_socket->sk->sk_lock.slock); + spin_unlock_bh(&sk->sk_lock.slock); } /* @@ -291,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; @@ -308,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) & sysctl_icmp_ratemask) - rc = xrlim_allow(dst, sysctl_icmp_ratelimit); + if ((1 << type) & net->ipv4.sysctl_icmp_ratemask) + rc = xrlim_allow(dst, net->ipv4.sysctl_icmp_ratelimit); out: return rc; } @@ -346,19 +326,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_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, 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 +348,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); } } @@ -376,16 +358,17 @@ 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 inet_sock *inet = inet_sk(sk); struct ipcm_cookie ipc; - struct rtable *rt = (struct rtable *)skb->dst; + struct rtable *rt = skb->rtable; + struct net *net = dev_net(rt->u.dst.dev); + struct sock *sk = icmp_sk(net); + struct inet_sock *inet = inet_sk(sk); __be32 daddr; 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; @@ -405,15 +388,15 @@ 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, + 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); out_unlock: - icmp_xmit_unlock(); + icmp_xmit_unlock(sk); } @@ -433,15 +416,17 @@ 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; struct net *net; + struct sock *sk; if (!rt) goto out; - net = rt->u.dst.dev->nd_net; + net = dev_net(rt->u.dst.dev); + sk = icmp_sk(net); /* * Find the original header. It is expected to be valid, of course. @@ -505,7 +490,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; /* @@ -516,7 +501,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 && + net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr) dev = dev_get_by_index(net, rt->fl.iif); if (dev) { @@ -544,7 +530,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(sk)->tos = tos; ipc.addr = iph->saddr; ipc.opt = &icmp_param.replyopts; @@ -609,7 +595,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; } @@ -632,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. */ @@ -652,7 +638,7 @@ route_done: ende: ip_rt_put(rt); out_unlock: - icmp_xmit_unlock(); + icmp_xmit_unlock(sk); out:; } @@ -670,7 +656,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 ? @@ -738,7 +724,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 (!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 " @@ -833,7 +819,10 @@ out_err: static void icmp_echo(struct sk_buff *skb) { - if (!sysctl_icmp_echo_ignore_all) { + struct net *net; + + net = dev_net(skb->dst->dev); + if (!net->ipv4.sysctl_icmp_echo_ignore_all) { struct icmp_bxm icmp_param; icmp_param.data.icmph = *icmp_hdr(skb); @@ -936,7 +925,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; @@ -981,7 +970,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; @@ -1036,6 +1025,9 @@ int icmp_rcv(struct sk_buff *skb) */ if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) { + struct net *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). @@ -1044,7 +1036,7 @@ int icmp_rcv(struct sk_buff *skb) */ if ((icmph->type == ICMP_ECHO || icmph->type == ICMP_TIMESTAMP) && - sysctl_icmp_echo_ignore_broadcasts) { + net->ipv4.sysctl_icmp_echo_ignore_broadcasts) { goto error; } if (icmph->type != ICMP_ECHO && @@ -1139,29 +1131,46 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { }, }; -void __init icmp_init(struct net_proto_family *ops) +static void __net_exit icmp_sk_exit(struct net *net) { - struct inet_sock *inet; int i; - for_each_possible_cpu(i) { - int err; + for_each_possible_cpu(i) + sk_release_kernel(net->ipv4.icmp_sk[i]); + kfree(net->ipv4.icmp_sk); + net->ipv4.icmp_sk = NULL; +} + +int __net_init icmp_sk_init(struct net *net) +{ + int i, err; - err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP, - &per_cpu(__icmp_socket, i)); + 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) { + struct sock *sk; + struct socket *sock; + struct inet_sock *inet; + + err = sock_create_kern(PF_INET, SOCK_RAW, IPPROTO_ICMP, &sock); if (err < 0) - panic("Failed to create the ICMP control socket.\n"); + goto fail; + + net->ipv4.icmp_sk[i] = sk = sock->sk; + sk_change_net(sk, net); - per_cpu(__icmp_socket, i)->sk->sk_allocation = GFP_ATOMIC; + 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; @@ -1169,8 +1178,49 @@ void __init icmp_init(struct net_proto_family *ops) * 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); } + + /* 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: + for_each_possible_cpu(i) + sk_release_kernel(net->ipv4.icmp_sk[i]); + kfree(net->ipv4.icmp_sk); + 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); diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 732cd07e6071..6250f4239b61 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))) @@ -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 || @@ -1198,6 +1198,9 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) ASSERT_RTNL(); + if (dev_net(in_dev->dev) != &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 (dev_net(in_dev->dev) != &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 (dev_net(in_dev->dev) != &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 (dev_net(in_dev->dev) != &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 (dev_net(in_dev->dev) != &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 (dev_net(in_dev->dev) != &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 (sock_net(sk) != &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 (sock_net(sk) != &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 (sock_net(sk) != &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 (sock_net(sk) != &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 (sock_net(sk) != &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 (sock_net(sk) != &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 (sock_net(sk) != &init_net) + return; + rtnl_lock(); while ((iml = inet->mc_list) != NULL) { struct in_device *in_dev; diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index b189278c7bc1..a7fcaf205644 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -80,12 +80,12 @@ 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; 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(&init_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; } @@ -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 < thresh || - (inet_rsk(req)->acked && req->retrans < max_retries)) - && !req->rsk_ops->rtx_syn_ack(parent, req, NULL)) { + if (req->retrans < thresh && + !req->rsk_ops->rtx_syn_ack(parent, req)) { unsigned long timeo; if (req->retrans++ == 0) diff --git a/net/ipv4/inet_fragment.c b/net/ipv4/inet_fragment.c index a0a3c78cb5e0..4ed429bd5951 100644 --- a/net/ipv4/inet_fragment.c +++ b/net/ipv4/inet_fragment.c @@ -107,10 +107,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; } } @@ -134,7 +134,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. */ @@ -177,7 +177,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); @@ -209,7 +209,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/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 1aba606f6bbb..32ca2f8b581c 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; @@ -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 (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 && sk->sk_net == 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); } @@ -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); @@ -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) { @@ -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; @@ -332,14 +332,14 @@ 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); 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; @@ -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); } @@ -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; @@ -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) @@ -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 876169f3a528..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); @@ -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; + 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_forward.c b/net/ipv4/ip_forward.c index a4506c8cfef0..4813c39b438b 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_fragment.c b/net/ipv4/ip_fragment.c index 3b2e5adca838..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,10 +202,13 @@ 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; + + 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); } @@ -298,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) && @@ -324,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) { @@ -336,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; } @@ -435,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); @@ -568,7 +572,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 e7821ba7a9a0..50972b397a9a 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; } @@ -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 65631391d479..4be00959b748 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) && + 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); @@ -197,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 = dev_net(skb->dev); + __skb_pull(skb, ip_hdrlen(skb)); /* Point into the IP datagram, just past the header. */ @@ -212,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) { @@ -283,13 +288,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(dev_net(dev), 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) { @@ -351,7 +357,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) @@ -372,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. */ diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 4d315158fd3c..d107543d3f81 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) { @@ -107,10 +104,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 = skb->rtable->rt_spec_dst; if (sopt->rr) { optlen = sptr[sopt->rr+1]; @@ -151,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(dev_net(skb->dst->dev), addr) != RTN_LOCAL) { dopt->ts_needtime = 1; soffset += 8; } @@ -254,26 +248,22 @@ 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; unsigned char * optptr; int optlen; unsigned char * pp_ptr = NULL; - struct rtable *rt = skb ? (struct rtable*)skb->dst : 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); - opt->is_data = 0; - } else { - optptr = opt->is_data ? opt->__data : - (unsigned char *)&(ip_hdr(skb)[1]); - iph = optptr - sizeof(struct iphdr); - } + 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); for (l = opt->optlen; l > 0; ) { switch (*optptr) { @@ -400,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]; @@ -517,14 +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; - opt->is_data = 1; - if (optlen && ip_options_compile(opt, NULL)) { + if (optlen && ip_options_compile(net, opt, NULL)) { kfree(opt); return -EINVAL; } @@ -533,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); @@ -543,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); @@ -554,14 +545,14 @@ 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) { 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) { @@ -609,7 +600,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; @@ -634,13 +625,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..08349267ceb4 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; @@ -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(sock_net(sk), &rt, &fl, sk, 0)) goto no_route; } sk_setup_caps(sk, &rt->u.dst); @@ -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; @@ -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; @@ -1357,7 +1355,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; @@ -1384,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 f72457b4b0a7..d6e76f5229cc 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) { @@ -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(&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; @@ -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(&opt, optval, optlen); + err = ip_options_get_from_user(sock_net(sk), &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(sock_net(sk), 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(sock_net(sk), mreq.imr_ifindex); err = -EADDRNOTAVAIL; diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 7c992fbbc2c3..08e8fb60d315 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -292,7 +292,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; } @@ -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) @@ -460,10 +460,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... */ @@ -857,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/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..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; @@ -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) @@ -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/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 a7591ce344d2..1563f29b5117 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) @@ -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; @@ -1499,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: @@ -1647,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); @@ -1668,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: @@ -1692,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_queue.c b/net/ipv4/netfilter/ip_queue.c index 4dc162894cb2..719be29f7506 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/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 600737f122d2..a819d191e1aa 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) @@ -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/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 52926c8e3cc1..965b08a7d738 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 - 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)) { diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index d80fee8327e4..84c26dd27d81 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); @@ -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) { @@ -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 = { diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c index f500b0fdaef4..e60b885d2dcd 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/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/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index b4c8d4968bb2..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 <chentschel@arnet.com.ar> * based on RR's ip_nat_ftp.c and other modules. + * (C) 2007 United Security Providers + * (C) 2007, 2008 Patrick McHardy <kaber@trash.net> * * 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 @@ -26,275 +28,461 @@ MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>"); 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) +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) { - 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; - } + 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, - 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, + union nf_inet_addr *addr, __be16 port) { + 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; - - if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) + 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 ((matchlen == map->addr[dir].srciplen || - matchlen == map->addr[dir].srclen) && - memcmp(*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) { - addr = map->addr[!dir].src; - addrlen = map->addr[!dir].srclen; - } else + if (newaddr == addr->ip && newport == port) 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; + buflen = sprintf(buffer, "%u.%u.%u.%u:%u", + NIPQUAD(newaddr), ntohs(newport)); + return mangle_packet(skb, dptr, datalen, matchoff, matchlen, + buffer, buflen); } -static unsigned int ip_nat_sip(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, - const char **dptr) +static int map_sip_addr(struct sk_buff *skb, + const char **dptr, unsigned int *datalen, + enum sip_header_types type) { - enum sip_header_pos pos; - struct addr_map map; - int dataoff, datalen; + 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; - dataoff = ip_hdrlen(skb) + sizeof(struct udphdr); - datalen = skb->len - dataoff; - if (datalen < sizeof("SIP/2.0") - 1) - return NF_ACCEPT; + 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, &addr, port); +} - addr_map_init(ct, &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 ip_conntrack_dir dir = CTINFO2DIR(ctinfo); + unsigned int dataoff, matchoff, matchlen; + union nf_inet_addr addr; + __be16 port; + int request, in_header; /* Basic rules: requests and responses. */ - if (strncmp(*dptr, "SIP/2.0", sizeof("SIP/2.0") - 1) != 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) - pos = POS_REG_REQ_URI; - else - pos = POS_REQ_URI; - - if (!map_sip_addr(skb, ctinfo, ct, dptr, datalen, pos, &map)) + if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { + if (ct_sip_parse_request(ct, *dptr, *datalen, + &matchoff, &matchlen, + &addr, &port) > 0 && + !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; + } } - 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)) +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)) 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, size_t dlen, - char *buffer, int bufflen, - enum sip_header_pos pos) +/* Handles expected signalling connections and media streams */ +static void ip_nat_sip_expected(struct nf_conn *ct, + struct nf_conntrack_expect *exp) { - unsigned int matchlen, matchoff; + struct nf_nat_range range; - if (ct_sip_get_info(ct, *dptr, dlen, &matchoff, &matchlen, pos) <= 0) - return 0; + /* This must be a fresh one. */ + BUG_ON(ct->status & IPS_NAT_DONE_MASK); - if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, - matchoff, matchlen, buffer, bufflen)) - return 0; + /* 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); - /* We need to reload this. Thanks Patrick. */ - *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr); - return 1; + /* 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 int mangle_content_len(struct sk_buff *skb, - enum ip_conntrack_info ctinfo, - struct nf_conn *ct, - const char *dptr) +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) { - unsigned int dataoff, matchoff, matchlen; - char buffer[sizeof("65536")]; - int bufflen; + 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; - dataoff = ip_hdrlen(skb) + sizeof(struct udphdr); + /* 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; - /* Get actual SDP length */ - if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff, - &matchlen, POS_SDP_HEADER) > 0) { + /* 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; - /* 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; + for (; port != 0; port++) { + exp->tuple.dst.u.udp.port = htons(port); + if (nf_ct_expect_related(exp) == 0) + break; + } - /* Now, update SDP length */ - if (ct_sip_get_info(ct, dptr, skb->len - dataoff, &matchoff, - &matchlen, POS_CONTENT) > 0) { + if (port == 0) + return NF_DROP; - bufflen = sprintf(buffer, "%u", c_len); - return nf_nat_mangle_udp_packet(skb, ct, ctinfo, - matchoff, matchlen, - buffer, bufflen); - } + 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 0; + return NF_ACCEPT; + +err: + nf_ct_unexpect_related(exp); + return NF_DROP; } -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) +static int mangle_content_len(struct sk_buff *skb, + const char **dptr, unsigned int *datalen) { - char buffer[sizeof("nnn.nnn.nnn.nnn")]; - unsigned int dataoff, bufflen; + enum ip_conntrack_info ctinfo; + struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + unsigned int matchoff, matchlen; + char buffer[sizeof("65536")]; + int buflen, c_len; - dataoff = ip_hdrlen(skb) + sizeof(struct udphdr); + /* 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="); - /* 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, - buffer, bufflen, POS_OWNER_IP4)) + /* Now, update SDP length */ + if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH, + &matchoff, &matchlen) <= 0) return 0; - if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff, - buffer, bufflen, POS_CONNECTION_IP4)) + buflen = sprintf(buffer, "%u", c_len); + return mangle_packet(skb, dptr, datalen, matchoff, matchlen, + buffer, buflen); +} + +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, dataoff, *datalen, type, term, + &matchoff, &matchlen) <= 0) return 0; + return mangle_packet(skb, dptr, datalen, matchoff, matchlen, + buffer, buflen); +} - /* Mangle media port. */ - bufflen = sprintf(buffer, "%u", port); - if (!mangle_sip_packet(skb, ctinfo, ct, &dptr, skb->len - dataoff, - buffer, bufflen, POS_MEDIA)) +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 buflen; + + buflen = sprintf(buffer, NIPQUAD_FMT, NIPQUAD(addr->ip)); + if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, type, term, + buffer, buflen)) return 0; - return mangle_content_len(skb, ctinfo, ct, dptr); + return mangle_content_len(skb, dptr, datalen); } -static void ip_nat_sdp_expect(struct nf_conn *ct, - struct nf_conntrack_expect *exp) +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) { - struct nf_nat_range range; + char buffer[sizeof("nnnnn")]; + unsigned int buflen; - /* This must be a fresh one. */ - BUG_ON(ct->status & IPS_NAT_DONE_MASK); + buflen = sprintf(buffer, "%u", port); + if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen, + buffer, buflen)) + return 0; - /* 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); + return mangle_content_len(skb, dptr, datalen); +} - /* 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); +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); } /* 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) +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) { - 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; /* 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; + rtp_addr->ip = 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_sdp_expect; - - /* 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_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 = 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 = 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; + + /* 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; + 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)) { - nf_ct_unexpect_related(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_sdp_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(); } static int __init nf_nat_sip_init(void) { BUG_ON(nf_nat_sip_hook != NULL); - BUG_ON(nf_nat_sdp_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_sdp_hook, ip_nat_sdp); + 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/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 <net/udp.h> #include <net/netfilter/nf_nat.h> +#include <net/netfilter/nf_conntrack_expect.h> #include <net/netfilter/nf_conntrack_helper.h> #include <net/netfilter/nf_nat_helper.h> @@ -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/ipv4/proc.c b/net/ipv4/proc.c index d63474c6b400..552169b41b16 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -51,24 +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(&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(&udp_prot), + seq_printf(seq, "UDP: inuse %d mem %d\n", + sock_prot_inuse_get(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(net, &udplite_prot)); + seq_printf(seq, "RAW: inuse %d\n", + 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 = { @@ -76,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 */ @@ -423,25 +453,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/ipv4/raw.c b/net/ipv4/raw.c index a3002fe65b7f..11d7f753a820 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -81,41 +81,34 @@ #include <linux/netfilter_ipv4.h> 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) +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)]; 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); -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); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); write_unlock_bh(&h->lock); } 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) { @@ -124,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 (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)) @@ -175,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); @@ -283,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, @@ -506,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(sock_net(sk), msg, &ipc); if (err) goto out; if (ipc.opt) @@ -560,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(sock_net(sk), &rt, &fl, sk, 1); } if (err) goto done; @@ -627,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) @@ -825,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, @@ -841,14 +832,14 @@ 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, #endif - REF_PROTO_INUSE(raw) }; #ifdef CONFIG_PROC_FS @@ -862,7 +853,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) == seq_file_net(seq)) goto found; } sk = NULL; @@ -878,7 +869,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) != 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 7b5e8e1d94be..230716c2dfe0 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) \ @@ -273,19 +271,22 @@ 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; }; -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 (r->rt_genid == st->genid) + 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,8 +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, struct rtable *r) +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(); @@ -307,25 +310,34 @@ 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_idx(struct rt_cache_iter_state *st, loff_t pos) +static struct rtable *rt_cache_get_next(struct seq_file *seq, + struct rtable *r) { - struct rtable *r = rt_cache_get_first(st); + 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; + } + return r; +} + +static struct rtable *rt_cache_get_idx(struct seq_file *seq, loff_t pos) +{ + struct rtable *r = rt_cache_get_first(seq); 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(seq, r))) --pos; - } return pos ? NULL : r; } 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; } @@ -333,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; } @@ -390,7 +401,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)); } @@ -399,7 +410,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, }; @@ -533,7 +544,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; @@ -564,8 +575,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; } @@ -652,7 +681,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); } /* @@ -1131,10 +1160,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_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)) @@ -1146,7 +1177,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 +1195,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) || + !net_eq(dev_net(rth->u.dst.dev), net)) { rthp = &rth->u.dst.rt_next; continue; } @@ -1256,7 +1288,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) { @@ -1297,7 +1329,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) @@ -1346,7 +1378,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; @@ -1423,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)) && - rth->u.dst.dev->nd_net == net && + net_eq(dev_net(rth->u.dst.dev), net) && rth->rt_genid == atomic_read(&rt_genid)) { unsigned short mtu = new_mtu; @@ -1499,9 +1531,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); @@ -1515,7 +1547,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); } @@ -1545,7 +1577,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 @@ -1675,7 +1707,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); @@ -1836,7 +1868,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); } /* @@ -1869,7 +1901,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. */ @@ -1992,7 +2024,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: @@ -2040,7 +2072,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); @@ -2053,12 +2085,12 @@ 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 && + 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); rcu_read_unlock(); - skb->dst = (struct dst_entry*)rth; + skb->rtable = rth; return 0; } RT_CACHE_STAT_INC(in_hlist_search); @@ -2455,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)) && - rth->u.dst.dev->nd_net == 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); @@ -2487,7 +2519,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 *) @@ -2547,7 +2579,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; } @@ -2565,7 +2597,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; @@ -2658,7 +2690,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; @@ -2668,9 +2700,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; @@ -2700,7 +2729,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; @@ -2712,7 +2741,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 { @@ -2726,22 +2755,22 @@ 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) goto errout_free; - skb->dst = &rt->u.dst; + skb->rtable = rt; if (rtm->rtm_flags & RTM_F_NOTIFY) 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; @@ -2755,6 +2784,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 = sock_net(skb->sk); s_h = cb->args[0]; if (s_h < 0) @@ -2764,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 (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; @@ -3040,7 +3072,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(); diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c index f470fe4511db..abc752d45cf7 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 <linux/tcp.h> @@ -23,24 +21,27 @@ extern int sysctl_tcp_syncookies; -static __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) { 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) +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])); + 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/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 88286f35d1e2..c437f804ee38 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -404,38 +404,6 @@ static struct ctl_table ipv4_table[] = { .strategy = &ipv4_sysctl_local_port_range, }, { - .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_ALL, - .procname = "icmp_echo_ignore_all", - .data = &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 = &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 = &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 = &sysctl_icmp_errors_use_inbound_ifaddr, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { .ctl_name = NET_IPV4_ROUTE, .procname = "route", .maxlen = 0, @@ -586,22 +554,6 @@ static struct ctl_table ipv4_table[] = { .proc_handler = &proc_dointvec }, { - .ctl_name = NET_IPV4_ICMP_RATELIMIT, - .procname = "icmp_ratelimit", - .data = &sysctl_icmp_ratelimit, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .ctl_name = NET_IPV4_ICMP_RATEMASK, - .procname = "icmp_ratemask", - .data = &sysctl_icmp_ratemask, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { .ctl_name = NET_TCP_TW_REUSE, .procname = "tcp_tw_reuse", .data = &sysctl_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, }, @@ -811,12 +815,72 @@ 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) +{ + 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 = { + .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); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 39b629ac2404..58ac838bf460 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_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"); diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 7facdb0f6960..6e46b4c0f28c 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; } @@ -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: @@ -5330,6 +5376,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_ipv4.c b/net/ipv4/tcp_ipv4.c index 00156bf421ca..ef141b841d2f 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); @@ -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. */ @@ -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. */ @@ -1258,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 @@ -1351,8 +1354,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. */ @@ -1372,24 +1374,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: @@ -1487,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) { @@ -1645,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; @@ -1719,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)); @@ -1921,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; @@ -1949,6 +1956,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; @@ -1965,7 +1973,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 && + net_eq(sock_net(req->sk), net)) { cur = req; goto out; } @@ -1989,7 +1998,7 @@ get_req: } get_sk: sk_for_each_from(sk, node) { - if (sk->sk_family == st->family) { + if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) { cur = sk; goto out; } @@ -2028,6 +2037,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) { @@ -2038,7 +2048,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 || + !net_eq(sock_net(sk), net)) { continue; } rc = sk; @@ -2047,7 +2058,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 || + !net_eq(twsk_net(tw), net)) { continue; } rc = tw; @@ -2066,6 +2078,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; @@ -2073,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) { + while (tw && (tw->tw_family != st->family || !net_eq(twsk_net(tw), net))) { tw = tw_next(tw); } if (tw) { @@ -2094,7 +2107,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 && net_eq(sock_net(sk), net)) goto found; } @@ -2202,6 +2215,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)) @@ -2210,25 +2224,44 @@ 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; } -int tcp_proc_register(struct tcp_seq_afinfo *afinfo) +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 net *net, struct tcp_seq_afinfo *afinfo) { int rc = 0; struct proc_dir_entry *p; @@ -2239,9 +2272,9 @@ 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); + p = proc_net_fops_create(net, afinfo->name, S_IRUGO, afinfo->seq_fops); if (p) p->data = afinfo; else @@ -2249,11 +2282,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)); } @@ -2392,19 +2425,32 @@ 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(&tcp4_seq_afinfo); + return register_pernet_subsys(&tcp4_net_ops); } void tcp4_proc_exit(void) { - tcp_proc_unregister(&tcp4_seq_afinfo); + unregister_pernet_subsys(&tcp4_net_ops); } #endif /* CONFIG_PROC_FS */ -DEFINE_PROTO_INUSE(tcp) - struct proto tcp_prot = { .name = "TCP", .owner = THIS_MODULE, @@ -2435,15 +2481,14 @@ 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, #endif - 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/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index b61b76847ad9..019c8c16e5cc 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 = { @@ -536,7 +538,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; } @@ -569,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. @@ -640,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 @@ -685,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_output.c b/net/ipv4/tcp_output.c index 72b9350006fe..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) { @@ -2568,6 +2568,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/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; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 1704c1474ea1..7b7fcacec4a0 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -137,29 +137,28 @@ 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 (net_eq(sock_net(sk), net) && sk->sk_hash == num) return 1; return 0; } /** - * __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; int error = 1; - struct net *net = sk->sk_net; + struct net *net = sock_net(sk); write_lock_bh(&udp_hash_lock); @@ -219,7 +218,7 @@ gotit: sk_for_each(sk2, node, head) if (sk2->sk_hash == snum && sk2 != sk && - sk2->sk_net == 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) && @@ -232,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: @@ -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 @@ -276,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 (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) { @@ -364,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); @@ -614,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(sock_net(sk), msg, &ipc); if (err) return err; if (ipc.opt) @@ -663,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(sock_net(sk), &rt, &fl, sk, 1); if (err) { if (err == -ENETUNREACH) IP_INC_STATS_BH(IPSTATS_MIB_OUTNOROUTES); @@ -1188,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) { @@ -1474,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, @@ -1498,11 +1489,11 @@ 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, #endif - REF_PROTO_INUSE(udp) }; /* ------------------------------------------------------------------------ */ @@ -1512,10 +1503,13 @@ static struct sock *udp_get_first(struct seq_file *seq) { struct sock *sk; struct udp_iter_state *state = seq->private; + struct net *net = seq_file_net(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 (!net_eq(sock_net(sk), net)) + continue; if (sk->sk_family == state->family) goto found; } @@ -1528,12 +1522,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 = seq_file_net(seq); do { sk = sk_next(sk); try_again: ; - } while (sk && 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); @@ -1581,47 +1576,36 @@ 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; - int rc = -ENOMEM; - struct udp_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL); + struct udp_iter_state *s; + int err; - if (!s) - goto out; + 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->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; - - rc = seq_open(file, &s->seq_ops); - if (rc) - goto out_kfree; - - seq = file->private_data; - seq->private = s; -out: - return rc; -out_kfree: - kfree(s); - goto out; + return err; } /* ------------------------------------------------------------------------ */ -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; - if (!afinfo) - return -EINVAL; - 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_private; + 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(&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 @@ -1629,12 +1613,9 @@ 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); - memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops)); + proc_net_remove(net, afinfo->name); } /* ------------------------------------------------------------------------ */ @@ -1673,24 +1654,41 @@ 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_show = udp4_seq_show, - .seq_fops = &udp4_seq_fops, + .seq_fops = { + .owner = THIS_MODULE, + }, + .seq_ops = { + .show = udp4_seq_show, + }, +}; + +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(&udp4_seq_afinfo); + return register_pernet_subsys(&udp4_net_ops); } void udp4_proc_exit(void) { - udp_proc_unregister(&udp4_seq_afinfo); + unregister_pernet_subsys(&udp4_net_ops); } #endif /* CONFIG_PROC_FS */ @@ -1717,12 +1715,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 001b881ca36f..72ce26b6c4d3 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); @@ -42,10 +31,9 @@ static struct net_protocol udplite_protocol = { .handler = udplite_rcv, .err_handler = udplite_err, .no_policy = 1, + .netns_ok = 1, }; -DEFINE_PROTO_INUSE(udplite) - struct proto udplite_prot = { .name = "UDP-Lite", .owner = THIS_MODULE, @@ -63,13 +51,13 @@ 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, #endif - REF_PROTO_INUSE(udplite) }; static struct inet_protosw udplite4_protosw = { @@ -83,15 +71,42 @@ 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_show = udp4_seq_show, - .seq_fops = &udplite4_seq_fops, + .seq_fops = { + .owner = THIS_MODULE, + }, + .seq_ops = { + .show = udp4_seq_show, + }, +}; + +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 register_pernet_subsys(&udplite4_net_ops); +} +#else +static inline int udplite4_proc_init(void) +{ + return 0; +} #endif void __init udplite4_register(void) @@ -104,18 +119,15 @@ void __init udplite4_register(void) 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 + if (udplite4_proc_init()) + printk(KERN_ERR "%s: Cannot register /proc!\n", __func__); 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); EXPORT_SYMBOL(udplite_prot); -EXPORT_SYMBOL(udplite_get_port); 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/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/addrconf.c b/net/ipv6/addrconf.c index e7a1882db048..87f688857ade 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); @@ -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); @@ -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 @@ -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(dev_net(idev->dev), 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 = dev_net(ifp->idev->dev); ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); - rt = rt6_lookup(&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) { @@ -893,20 +893,40 @@ 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; + unsigned int prefs; +}; static inline int ipv6_saddr_preferred(int type) { @@ -916,27 +936,152 @@ static inline int ipv6_saddr_preferred(int type) return 0; } -int ipv6_dev_get_saddr(struct net_device *daddr_dev, - struct in6_addr *daddr, struct in6_addr *saddr) +static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score, + struct ipv6_saddr_dst *dst, + int i) { - struct ipv6_saddr_score hiscore; - struct inet6_ifaddr *ifa_result = NULL; - 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); + 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 */ + 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 */ + 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 + */ + 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 + * 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, unsigned int prefs, + struct in6_addr *saddr) +{ + struct ipv6_saddr_score scores[2], + *score = &scores[0], *hiscore = &scores[1]; + struct net *net = dev_net(dst_dev); + 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); + dst.prefs = prefs; - memset(&hiscore, 0, sizeof(hiscore)); + hiscore->rule = -1; + hiscore->ifa = NULL; 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; - /* 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 @@ -948,9 +1093,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); @@ -958,12 +1103,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; - - score.addr_type = __ipv6_addr_type(&ifa->addr); + for (score->ifa = idev->addr_list; score->ifa; score->ifa = score->ifa->if_next) { + int i; - /* Rule 0: + /* * - Tentative Address (RFC2462 section 5.4) * - A tentative address is not considered * "assigned to an interface" in the traditional @@ -973,11 +1116,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", @@ -985,207 +1131,63 @@ 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; - } - - /* 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; - } - } + 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 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; - } + if (hiscore->ifa) + in6_ifa_put(hiscore->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 + in6_ifa_hold(score->ifa); - /* 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; - } + tmp = hiscore; + hiscore = score; + score = tmp; - /* 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 - /* 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; } - -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) @@ -1231,7 +1233,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 (!net_eq(dev_net(ifp->idev->dev), net)) continue; if (ipv6_addr_equal(&ifp->addr, addr) && !(ifp->flags&IFA_F_TENTATIVE)) { @@ -1253,7 +1255,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 (!net_eq(dev_net(ifp->idev->dev), net)) continue; if (ipv6_addr_equal(&ifp->addr, addr)) { if (dev == NULL || ifp->idev->dev == dev) @@ -1271,7 +1273,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 (!net_eq(dev_net(ifp->idev->dev), net)) continue; if (ipv6_addr_equal(&ifp->addr, addr)) { if (dev == NULL || ifp->idev->dev == dev || @@ -1573,7 +1575,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_net(dev), }; ipv6_addr_copy(&cfg.fc_dst, pfx); @@ -1600,7 +1602,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_net(dev), }; ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0); @@ -1617,7 +1619,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_net(dev), }; /* prefix length - 96 bits "::d.d.d.d" */ @@ -1718,7 +1720,8 @@ 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(dev_net(dev), &pinfo->prefix, NULL, + dev->ifindex, 1); if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { if (rt->rt6i_flags&RTF_EXPIRES) { @@ -1761,7 +1764,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_net(dev), &addr, dev, 1); if (ifp == NULL && valid_lft) { int max_addresses = in6_dev->cnf.max_addresses; @@ -1887,7 +1890,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; @@ -1899,7 +1902,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) @@ -1930,7 +1933,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); } @@ -1945,8 +1949,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; @@ -1960,7 +1965,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) @@ -2005,13 +2011,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) @@ -2039,7 +2047,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; @@ -2051,13 +2059,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; @@ -2069,7 +2078,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; } @@ -2080,6 +2090,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 = dev_net(idev->dev); int scope; ASSERT_RTNL(); @@ -2106,7 +2117,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; @@ -2269,15 +2280,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 = dev_net(idev->dev); /* 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; } @@ -2310,9 +2322,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) { @@ -2452,6 +2461,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) { struct inet6_dev *idev; struct inet6_ifaddr *ifa, **bifa; + struct net *net = dev_net(dev); int i; ASSERT_RTNL(); @@ -2459,7 +2469,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); @@ -2775,12 +2785,12 @@ 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]; - while (ifa && ifa->idev->dev->nd_net != net) + while (ifa && !net_eq(dev_net(ifa->idev->dev), net)) ifa = ifa->lst_next; if (ifa) break; @@ -2791,12 +2801,12 @@ 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: if (ifa) { - if (ifa->idev->dev->nd_net != net) { + if (!net_eq(dev_net(ifa->idev->dev), net)) { ifa = ifa->lst_next; goto try_again; } @@ -2914,7 +2924,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 (!net_eq(dev_net(ifp->idev->dev), net)) continue; if (ipv6_addr_cmp(&ifp->addr, addr) == 0 && (ifp->flags & IFA_F_HOMEADDRESS)) { @@ -3063,15 +3073,12 @@ 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; 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; @@ -3081,7 +3088,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, @@ -3124,7 +3131,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; @@ -3134,9 +3141,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; @@ -3157,7 +3161,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; @@ -3170,8 +3174,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 || @@ -3336,12 +3341,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 = sock_net(skb->sk); 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) @@ -3408,42 +3414,30 @@ 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); } 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; @@ -3452,9 +3446,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; @@ -3467,7 +3458,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; @@ -3487,7 +3478,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: @@ -3497,6 +3488,7 @@ errout: static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) { struct sk_buff *skb; + struct net *net = dev_net(ifa->idev->dev); int err = -ENOBUFS; skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC); @@ -3510,10 +3502,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, @@ -3672,18 +3664,15 @@ 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; 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) @@ -3705,6 +3694,7 @@ cont: void inet6_ifinfo_notify(int event, struct inet6_dev *idev) { struct sk_buff *skb; + struct net *net = dev_net(idev->dev); int err = -ENOBUFS; skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC); @@ -3718,10 +3708,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) @@ -3774,6 +3764,7 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev, struct prefix_info *pinfo) { struct sk_buff *skb; + struct net *net = dev_net(idev->dev); int err = -ENOBUFS; skb = nlmsg_new(inet6_prefix_nlmsg_size(), GFP_ATOMIC); @@ -3787,10 +3778,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) @@ -4185,7 +4176,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); } @@ -4280,6 +4271,32 @@ 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) +{ + struct net_device *dev; + + 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 = { + .init = addrconf_net_init, + .exit = addrconf_net_exit, +}; + /* * Init / cleanup code */ @@ -4321,14 +4338,9 @@ 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 + err = register_pernet_device(&addrconf_net_ops); + if (err) + return err; register_netdevice_notifier(&ipv6_dev_notf); @@ -4358,31 +4370,19 @@ errlo: void addrconf_cleanup(void) { - struct net_device *dev; struct inet6_ifaddr *ifa; int i; unregister_netdevice_notifier(&ipv6_dev_notf); + unregister_pernet_device(&addrconf_net_ops); unregister_pernet_subsys(&addrconf_ops); 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; ) { @@ -4399,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/addrlabel.c b/net/ipv6/addrlabel.c index a3c5a72218fd..9bfa8846f262 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, @@ -161,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); @@ -177,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); @@ -221,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)) { @@ -263,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, @@ -289,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); @@ -313,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); @@ -330,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, @@ -359,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; @@ -447,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]; @@ -485,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 f0aa97738746..1731b0abf7f5 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 = sock_net(sk); __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); @@ -440,6 +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 = sock_net(sk); switch(cmd) { @@ -452,14 +451,14 @@ 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); + 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; @@ -678,6 +677,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, @@ -720,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; @@ -731,12 +855,36 @@ 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; + 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; +#endif } static void inet6_net_exit(struct net *net) { - return; +#ifdef CONFIG_PROC_FS + udp6_proc_exit(net); + tcp6_proc_exit(net); + ac6_proc_exit(net); +#endif } static struct pernet_operations inet6_net_ops = { @@ -802,19 +950,13 @@ 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(&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(); @@ -825,17 +967,10 @@ 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 (udp6_proc_init()) - goto proc_udp6_fail; if (udplite6_proc_init()) 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 @@ -874,9 +1009,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: @@ -897,16 +1042,10 @@ 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(); proc_udplite6_fail: - udp6_proc_exit(); -proc_udp6_fail: - tcp6_proc_exit(); -proc_tcp6_fail: raw6_proc_exit(); proc_raw6_fail: #endif @@ -918,10 +1057,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(); @@ -949,6 +1084,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(); udplitev6_exit(); tcpv6_exit(); @@ -964,11 +1102,8 @@ static void __exit inet6_exit(void) /* Cleanup code parts. */ if6_proc_exit(); - ac6_proc_exit(); ipv6_misc_proc_exit(); udplite6_proc_exit(); - udp6_proc_exit(); - tcp6_proc_exit(); raw6_proc_exit(); #endif ipv6_netfilter_fini(); @@ -976,9 +1111,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); diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 9c7f83fbc3a1..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(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/fib6_rules.c b/net/ipv6/fib6_rules.c index 695c0ca8a417..cac580749ebe 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -29,24 +29,22 @@ struct fib6_rule u8 tclass; }; -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, }; - 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); 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, @@ -54,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->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; /* @@ -85,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; - if (ipv6_get_saddr(&rt->u.dst, &flp->fl6_dst, - &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, srcprefs, + &saddr)) goto again; if (!ipv6_prefix_equal(&saddr, &r->src.addr, r->src.plen)) @@ -145,13 +154,14 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, struct nlattr **tb) { int err = -EINVAL; + struct net *net = sock_net(skb->sk); 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(rule->table) == NULL) { + if (fib6_new_table(net, rule->table) == NULL) { err = -ENOBUFS; goto errout; } @@ -234,7 +244,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,45 +257,64 @@ 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, }; -static int __init fib6_default_rules_init(void) +static int fib6_rules_net_init(struct net *net) { - int err; + int err = -ENOMEM; - 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); - if (err < 0) - return err; - return 0; -} + 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; -int __init fib6_rules_init(void) -{ - int ret; + net->ipv6.fib6_rules_ops->fro_net = net; + INIT_LIST_HEAD(&net->ipv6.fib6_rules_ops->rules_list); - ret = fib6_default_rules_init(); - if (ret) - goto out; + err = fib_default_rule_add(net->ipv6.fib6_rules_ops, 0, + RT6_TABLE_LOCAL, FIB_RULE_PERMANENT); + if (err) + goto out_fib6_rules_ops; - ret = fib_rules_register(&fib6_rules_ops); - if (ret) - goto out_default_rules_init; + err = fib_default_rule_add(net->ipv6.fib6_rules_ops, + 0x7FFE, RT6_TABLE_MAIN, 0); + if (err) + goto out_fib6_default_rule_add; + + 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); +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); + return unregister_pernet_subsys(&fib6_rules_net_ops); } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index f204a7275a0d..227ce3d2339d 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 DEFINE_PER_CPU(struct socket *, __icmpv6_socket) = NULL; -#define icmpv6_socket __get_cpu_var(__icmpv6_socket) +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); @@ -90,11 +92,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_socket->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 +107,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_socket->sk->sk_lock.slock); + spin_unlock_bh(&sk->sk_lock.slock); } /* @@ -161,6 +163,7 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type, struct flowi *fl) { struct dst_entry *dst; + struct net *net = sock_net(sk); int res = 0; /* Informational messages are not limited. */ @@ -176,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(sk, fl); + dst = ip6_route_output(net, sk, fl); if (dst->error) { IP6_INC_STATS(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); @@ -184,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) @@ -303,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 = dev_net(skb->dev); struct inet6_dev *idev = NULL; struct ipv6hdr *hdr = ipv6_hdr(skb); struct sock *sk; @@ -332,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; /* @@ -389,12 +393,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_socket->sk; + sk = icmpv6_sk(net); np = inet6_sk(sk); + if (icmpv6_xmit_lock(sk)) + return; + if (!icmpv6_xrlim_allow(sk, type, &fl)) goto out; @@ -460,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) @@ -498,13 +500,14 @@ out_put: out_dst_release: dst_release(dst); out: - icmpv6_xmit_unlock(); + icmpv6_xmit_unlock(sk); } EXPORT_SYMBOL(icmpv6_send); static void icmpv6_echo_reply(struct sk_buff *skb) { + struct net *net = dev_net(skb->dev); struct sock *sk; struct inet6_dev *idev; struct ipv6_pinfo *np; @@ -535,12 +538,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_socket->sk; + sk = icmpv6_sk(net); 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; @@ -555,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) @@ -584,7 +585,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) @@ -775,19 +776,41 @@ 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_socket: + * Special lock-class for __icmpv6_sk: */ static struct lock_class_key icmpv6_socket_sk_dst_lock_key; -int __init icmpv6_init(struct net_proto_family *ops) +static int __net_init icmpv6_sk_init(struct net *net) { struct sock *sk; int err, i, j; + 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) { + 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 +819,14 @@ int __init icmpv6_init(struct net_proto_family *ops) goto fail; } - sk = per_cpu(__icmpv6_socket, i)->sk; + net->ipv6.icmp_sk[i] = sk = sock->sk; + sk_change_net(sk, net); + 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, @@ -815,36 +840,56 @@ int __init icmpv6_init(struct net_proto_family *ops) 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++) { - if (!cpu_possible(j)) - continue; - sock_release(per_cpu(__icmpv6_socket, j)); - } - + for (j = 0; j < i; 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) { - sock_release(per_cpu(__icmpv6_socket, i)); + sk_release_kernel(net->ipv6.icmp_sk[i]); } + kfree(net->ipv6.icmp_sk); +} + +static struct pernet_operations 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 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; @@ -925,6 +970,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/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 99fd25f7f005..580014aea4d6 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; @@ -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); @@ -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 (net_eq(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); @@ -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/ip6_fib.c b/net/ipv6/ip6_fib.c index bab72b6f1444..b3f6e03c454c 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 @@ -66,6 +64,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,9 +77,10 @@ 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 struct rt6_info * fib6_find_prefix(struct fib6_node *fn); -static struct fib6_node * fib6_repair_tree(struct fib6_node *fn); +static void fib6_prune_clones(struct net *net, struct fib6_node *fn, + struct rt6_info *rt); +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); @@ -93,7 +93,7 @@ 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 struct fib6_walker_t fib6_walker_list = { .prev = &fib6_walker_list, @@ -166,22 +166,13 @@ 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, - }, -}; - #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 void fib6_link_table(struct fib6_table *tb) +static void fib6_link_table(struct net *net, struct fib6_table *tb) { unsigned int h; @@ -197,52 +188,46 @@ 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 = { - .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_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; } 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); + tb = fib6_alloc_table(net, 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; @@ -250,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; @@ -261,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, 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 @@ -361,18 +346,16 @@ 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; 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]; @@ -401,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); @@ -667,29 +651,29 @@ 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; } 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); } /* @@ -733,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(); @@ -776,9 +760,9 @@ 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); + fib6_prune_clones(info->nl_net, pn, rt); } out: @@ -789,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); @@ -809,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 @@ -975,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) @@ -997,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; @@ -1024,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); @@ -1101,14 +1086,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) @@ -1131,8 +1117,8 @@ 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--; - fn = fib6_repair_tree(fn); + net->ipv6.rt6_stats->fib_route_nodes--; + fn = fib6_repair_tree(net, fn); } if (atomic_read(&rt->rt6i_ref) != 1) { @@ -1144,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); } @@ -1160,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; @@ -1169,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); @@ -1184,7 +1171,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); } /* @@ -1314,12 +1301,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); @@ -1351,7 +1338,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) { @@ -1362,23 +1349,26 @@ 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); } -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; 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 = &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); } } @@ -1395,9 +1385,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); } /* @@ -1447,54 +1438,145 @@ 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)) { - mod_timer(&ip6_fib_timer, jiffies + HZ); + mod_timer(net->ipv6.ip6_fib_timer, jiffies + HZ); 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; - ndisc_dst_gc(&gc_args.more); - fib6_clean_all(fib6_age, 0, NULL); + icmp6_dst_gc(&gc_args.more); + + 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); + 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); } -int __init fib6_init(void) +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; + 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.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_rt6_stats; + + 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; + + net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN; + 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; + +#ifdef CONFIG_IPV6_MULTIPLE_TABLES + 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; + net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL; + 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 + fib6_tables_init(net); + + ret = 0; +out: + return ret; + +#ifdef CONFIG_IPV6_MULTIPLE_TABLES +out_fib6_main_tbl: + kfree(net->ipv6.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; + } + +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 + kfree(net->ipv6.fib6_local_tbl); +#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 = { + .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) - return -ENOMEM; + goto out; - fib6_tables_init(); + 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_kmem_cache_create; + 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; @@ -1502,6 +1584,6 @@ out_kmem_cache_create: void fib6_gc_cleanup(void) { - del_timer(&ip6_fib_timer); + unregister_pernet_subsys(&fib6_net_ops); kmem_cache_destroy(fib6_node_kmem); } diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index 2b7d9ee98832..eb7a940310f4 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 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 ip6_flowlabel *fl, __be32 label) +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; @@ -586,6 +611,7 @@ done: #ifdef CONFIG_PROC_FS struct ip6fl_iter_state { + struct seq_net_private p; int bucket; }; @@ -595,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; } @@ -608,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; @@ -683,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 = { @@ -692,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; } @@ -717,13 +753,24 @@ 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); + 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) { - 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); - ip6_flowlabel_proc_fini(&init_net); + unregister_pernet_subsys(&ip6_flowlabel_net_ops); } diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 98ab4f459905..43a617e2268b 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; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 8b67ca07467d..a8b4da25b0a7 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) @@ -404,6 +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 = dev_net(dst->dev); if (ipv6_devconf.forwarding == 0) goto error; @@ -450,7 +449,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); @@ -596,7 +595,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 *)) { @@ -912,15 +910,19 @@ static int ip6_dst_lookup_tail(struct sock *sk, struct dst_entry **dst, struct flowi *fl) { int err; + struct net *net = sock_net(sk); if (*dst == NULL) - *dst = ip6_route_output(sk, fl); + *dst = ip6_route_output(net, sk, fl); if ((err = (*dst)->error)) 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, + sk ? inet6_sk(sk)->srcprefs : 0, + &fl->fl6_src); if (err) 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, &fl_gw); + *dst = ip6_route_output(net, sk, &fl_gw); if ((err = (*dst)->error)) goto out_err_release; } @@ -1113,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; @@ -1134,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; @@ -1379,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)); @@ -1396,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; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 78f438880923..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 @@ -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; @@ -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; @@ -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/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index bf2a686aa13d..4195ac92345e 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); @@ -219,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 = sock_net(sk); int val, valbool; int retv = -ENOPROTOOPT; @@ -266,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; @@ -278,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; @@ -544,7 +435,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; } @@ -728,7 +619,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; @@ -1015,9 +966,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) @@ -1045,6 +994,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; } @@ -1128,13 +1095,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); -} diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index ab228d1ea114..d810cff818cf 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 = sock_net(sk); 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(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 = sock_net(sk); 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(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 = sock_net(sk); 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 = sock_net(sk); 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 = sock_net(sk); 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 = sock_net(sk); 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_net(dev); + struct sock *sk = net->ipv6.igmp_sk; struct sk_buff *skb; struct mld2_report *pmr; struct in6_addr addr_buf; @@ -1433,25 +1441,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); @@ -1459,7 +1448,9 @@ 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 = dev_net(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 +1460,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(net->ipv6.igmp_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 +1488,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) @@ -1749,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_net(dev); + struct sock *sk = net->ipv6.igmp_sk; struct inet6_dev *idev; struct sk_buff *skb; struct icmp6hdr *hdr; @@ -1761,6 +1775,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 +1828,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(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 +1855,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, @@ -2310,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; }; @@ -2320,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 = 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) @@ -2424,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 = { @@ -2433,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; @@ -2449,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 = seq_file_net(seq); 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)) @@ -2584,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 = { @@ -2593,47 +2631,96 @@ 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, }; + +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 -int __init igmp6_init(struct net_proto_family *ops) +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); np = inet6_sk(sk); 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); -#endif + err = igmp6_proc_init(net); + if (err) + goto out_sock_create; +out: + return err; - return 0; +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); + igmp6_proc_exit(net); +} -#ifdef CONFIG_PROC_FS - proc_net_remove(&init_net, "mcfilter6"); - proc_net_remove(&init_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/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 452a2ac4eec8..510aa747a404 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -89,8 +89,6 @@ #include <linux/netfilter.h> #include <linux/netfilter_ipv6.h> -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); @@ -270,7 +268,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 +299,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); } } @@ -441,21 +439,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, @@ -464,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_net(dev); + struct sock *sk = net->ipv6.ndisc_sk; struct sk_buff *skb; struct icmp6hdr *hdr; struct inet6_dev *idev; @@ -474,10 +458,9 @@ static void __ndisc_send(struct net_device *dev, type = icmp6h->icmp6_type; - ndisc_flow_init(&fl, type, saddr, daddr, - dev->ifindex); + icmpv6_flow_init(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; @@ -499,7 +482,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; } @@ -556,14 +539,16 @@ 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_net(dev), solicited_addr, dev, 1); if (ifp) { src_addr = solicited_addr; if (ifp->flags & IFA_F_OPTIMISTIC) 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_net(dev)->ipv6.ndisc_sk)->srcprefs, + &tmpaddr)) return; src_addr = &tmpaddr; } @@ -616,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_net(dev), saddr, dev, 1); if (ifp) { if (ifp->flags & IFA_F_OPTIMISTIC) { @@ -654,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_net(dev), &ipv6_hdr(skb)->saddr, dev, 1)) saddr = &ipv6_hdr(skb)->saddr; if ((probes -= neigh->parms->ucast_probes) < 0) { @@ -662,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); @@ -676,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, &init_net, 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) @@ -703,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 @@ -756,7 +741,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_net(dev), &msg->target, dev, 1); + if (ifp) { if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { if (dad) { @@ -801,11 +787,10 @@ 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 = 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 && @@ -826,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; @@ -914,7 +900,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_net(dev), &msg->target, dev, 1); + if (ifp) { if (ifp->flags & IFA_F_TENTATIVE) { addrconf_dad_failure(ifp); return; @@ -945,7 +932,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_net(dev), &msg->target, dev, 0)) { /* XXX: idev->cnf.prixy_ndp */ goto out; } @@ -1035,6 +1022,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 = dev_net(ra->dev); int err; int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg) + (opt->nd_opt_len << 3)); @@ -1064,7 +1052,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; @@ -1075,7 +1063,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) @@ -1178,7 +1166,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; } @@ -1187,7 +1175,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; @@ -1420,13 +1408,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_net(dev); + 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; @@ -1436,8 +1425,6 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, int err; 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", @@ -1452,10 +1439,10 @@ 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(sk, &fl, NDISC_REDIRECT, + &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); - dst = ip6_route_output(NULL, &fl); + dst = ip6_route_output(net, NULL, &fl); if (dst == NULL) return; @@ -1499,12 +1486,11 @@ 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; } - skb_reserve(buff, LL_RESERVED_SPACE(dev)); ip6_nd_hdr(sk, buff, dev, &saddr_buf, &ipv6_hdr(skb)->saddr, IPPROTO_ICMPV6, len); @@ -1625,18 +1611,16 @@ 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; - - if (dev->nd_net != &init_net) - return NOTIFY_DONE; + struct net *net = dev_net(dev); 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; @@ -1745,22 +1729,24 @@ static int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name, #endif -int __init ndisc_init(struct net_proto_family *ops) +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; @@ -1768,21 +1754,52 @@ int __init ndisc_init(struct net_proto_family *ops) 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) @@ -1792,6 +1809,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); } 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/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 8d366f7f2a9a..92a36c9e5402 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/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index bf9bb6e55bb5..70ef0d276cc0 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) @@ -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/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index b23baa635fe0..baf829075f6f 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)) @@ -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/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 24c0d03095bf..9e5f305b2022 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -185,7 +185,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); @@ -227,7 +227,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; } @@ -254,11 +254,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. @@ -273,7 +273,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; } @@ -385,7 +385,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); @@ -647,7 +647,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/proc.c b/net/ipv6/proc.c index 199ef379e501..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(&tcpv6_prot)); + sock_prot_inuse_get(net, &tcpv6_prot)); seq_printf(seq, "UDP6: inuse %d\n", - sock_prot_inuse_get(&udpv6_prot)); + sock_prot_inuse_get(net, &udpv6_prot)); seq_printf(seq, "UDPLITE6: inuse %d\n", - sock_prot_inuse_get(&udplitev6_prot)); + sock_prot_inuse_get(net, &udplitev6_prot)); seq_printf(seq, "RAW6: inuse %d\n", - sock_prot_inuse_get(&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) @@ -214,6 +241,9 @@ int snmp6_register_dev(struct inet6_dev *idev) if (!idev || !idev->dev) return -EINVAL; + if (dev_net(idev->dev) != &init_net) + return 0; + if (!proc_net_devsnmp6) return -ENOENT; @@ -240,27 +270,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; } @@ -270,5 +318,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); } diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 8897ccf8086a..aae6cedf1709 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -62,20 +62,9 @@ #include <linux/seq_file.h> 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) -{ - 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) @@ -87,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 (!net_eq(sock_net(sk), net)) continue; if (!ipv6_addr_any(&np->daddr) && @@ -179,15 +168,10 @@ 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; - net = skb->dev->nd_net; + net = dev_net(skb->dev); sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, IP6CB(skb)->iif); while (sk) { @@ -291,7 +275,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; @@ -304,7 +288,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); @@ -374,7 +358,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))) { @@ -896,9 +880,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) { @@ -1184,8 +1166,6 @@ static int rawv6_init_sk(struct sock *sk) return(0); } -DEFINE_PROTO_INUSE(rawv6) - struct proto rawv6_prot = { .name = "RAWv6", .owner = THIS_MODULE, @@ -1201,14 +1181,14 @@ 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, #endif - REF_PROTO_INUSE(rawv6) }; #ifdef CONFIG_PROC_FS diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index f936d045a39d..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); @@ -600,7 +601,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 e8b241cb60bc..cd82b6db35ff 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -40,6 +40,7 @@ #include <linux/if_arp.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> +#include <linux/nsproxy.h> #include <net/net_namespace.h> #include <net/snmp.h> #include <net/ipv6.h> @@ -87,14 +88,16 @@ 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 -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, @@ -124,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), @@ -134,8 +137,6 @@ struct rt6_info ip6_null_entry = { .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, .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), @@ -148,7 +149,7 @@ struct rt6_info ip6_null_entry = { 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), @@ -158,8 +159,6 @@ struct rt6_info ip6_prohibit_entry = { .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, .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), @@ -167,7 +166,7 @@ struct rt6_info ip6_prohibit_entry = { .rt6i_ref = ATOMIC_INIT(1), }; -struct rt6_info ip6_blk_hole_entry = { +static struct rt6_info ip6_blk_hole_entry_template = { .u = { .dst = { .__refcnt = ATOMIC_INIT(1), @@ -177,8 +176,6 @@ struct rt6_info ip6_blk_hole_entry = { .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, .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,9 +186,9 @@ struct rt6_info ip6_blk_hole_entry = { #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) @@ -211,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 = @@ -239,7 +236,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) { @@ -268,7 +266,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; } @@ -409,9 +407,10 @@ 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); + __func__, fn->leaf, oif); rt0 = fn->rr_ptr; if (!rt0) @@ -432,15 +431,17 @@ static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) } RT6_TRACE("%s() => %p\n", - __FUNCTION__, match); + __func__, match); - return (match ? match : &ip6_null_entry); + net = dev_net(rt0->rt6i_dev); + return (match ? match : net->ipv6.ip6_null_entry); } #ifdef CONFIG_IPV6_ROUTE_INFO int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, struct in6_addr *gwaddr) { + struct net *net = dev_net(dev); struct route_info *rinfo = (struct route_info *) opt; struct in6_addr prefix_buf, *prefix; unsigned int pref; @@ -488,7 +489,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); @@ -496,7 +498,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 | @@ -515,9 +517,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) \ @@ -533,7 +535,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; @@ -543,8 +546,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); @@ -552,8 +555,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, @@ -571,7 +574,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(net, &fl, flags, ip6_pol_route_lookup); if (dst->error == 0) return (struct rt6_info *) dst; @@ -604,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 = &init_net, + .nl_net = dev_net(rt->rt6i_dev), }; return __ip6_ins_rt(rt, &info); } @@ -660,8 +663,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; @@ -680,8 +683,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; @@ -699,7 +703,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) { @@ -732,15 +736,16 @@ 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) { struct ipv6hdr *iph = ipv6_hdr(skb); + struct net *net = dev_net(skb->dev); int flags = RT6_LOOKUP_F_HAS_SADDR; struct flowi fl = { .iif = skb->dev->ifindex, @@ -758,16 +763,17 @@ 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(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) +struct dst_entry * ip6_route_output(struct net *net, struct sock *sk, + struct flowi *fl) { int flags = 0; @@ -776,8 +782,17 @@ 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; + 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(fl, flags, ip6_pol_route_output); + return fib6_rule_lookup(net, fl, flags, ip6_pol_route_output); } EXPORT_SYMBOL(ip6_route_output); @@ -886,12 +901,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 @@ -904,21 +919,21 @@ 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); + struct net *net = dev_net(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; @@ -936,8 +951,8 @@ struct dst_entry *ndisc_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.output = output; + 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 */ rt->u.dst.flags = ipv6_addr_type(addr) & IPV6_ADDR_UNICAST @@ -947,18 +962,18 @@ 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(); + fib6_force_start_gc(net); 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 +981,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,30 +995,33 @@ int ndisc_dst_gc(int *more) } } - spin_unlock_bh(&ndisc_lock); + spin_unlock_bh(&icmp6_dst_lock); return freed; } static int ip6_dst_gc(struct dst_ops *ops) { - static unsigned expire = 30*HZ; - static unsigned long last_gc; 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) + 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; - expire++; - fib6_run_gc(expire); - 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; - + 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(&ops->entries) < ops->gc_thresh) + net->ipv6.ip6_rt_gc_expire = 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); + 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, @@ -1025,15 +1043,17 @@ static int ipv6_get_mtu(struct net_device *dev) return mtu; } -int ipv6_get_hoplimit(struct net_device *dev) +int ip6_dst_hoplimit(struct dst_entry *dst) { - 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 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; } @@ -1045,6 +1065,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; @@ -1059,7 +1080,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); @@ -1070,13 +1091,13 @@ 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(net, cfg->fc_table); if (table == NULL) { err = -ENOBUFS; goto out; } - rt = ip6_dst_alloc(); + rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); if (rt == NULL) { err = -ENOMEM; @@ -1117,12 +1138,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) { @@ -1159,7 +1180,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(net, gw_addr, NULL, cfg->fc_ifindex, 1); err = -EHOSTUNREACH; if (grt == NULL) @@ -1226,10 +1247,13 @@ 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; + + cfg->fc_nlinfo.nl_net = dev_net(dev); + return __ip6_ins_rt(rt, &cfg->fc_nlinfo); out: @@ -1246,8 +1270,9 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) { int err; struct fib6_table *table; + struct net *net = dev_net(rt->rt6i_dev); - if (rt == &ip6_null_entry) + if (rt == net->ipv6.ip6_null_entry) return -ENOENT; table = rt->rt6i_table; @@ -1264,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 = &init_net, + .nl_net = dev_net(rt->rt6i_dev), }; return __ip6_del_rt(rt, &info); } @@ -1276,7 +1301,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(cfg->fc_nlinfo.nl_net, cfg->fc_table); if (table == NULL) return err; @@ -1316,7 +1341,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) { @@ -1359,8 +1385,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); @@ -1375,6 +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_net(dev); struct ip6rd_flowi rdfl = { .fl = { .oif = dev->ifindex, @@ -1391,7 +1418,8 @@ 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(net, (struct flowi *)&rdfl, + flags, __ip6_route_redirect); } void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, @@ -1400,10 +1428,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 = dev_net(neigh->dev); 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"); @@ -1448,7 +1477,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(dev_net(neigh->dev), + dst_mtu(&nrt->u.dst)); if (ip6_ins_rt(nrt)) goto out; @@ -1476,9 +1506,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_net(dev); int allfrag = 0; - rt = rt6_lookup(daddr, saddr, dev->ifindex, 0); + rt = rt6_lookup(net, daddr, saddr, dev->ifindex, 0); if (rt == NULL) return; @@ -1511,7 +1542,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; } @@ -1537,7 +1568,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); @@ -1552,7 +1583,8 @@ out: static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) { - struct rt6_info *rt = ip6_dst_alloc(); + struct net *net = dev_net(ort->rt6i_dev); + struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); if (rt) { rt->u.dst.input = ort->u.dst.input; @@ -1583,14 +1615,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(RT6_TABLE_INFO); + table = fib6_get_table(net, RT6_TABLE_INFO); if (table == NULL) return NULL; @@ -1614,7 +1647,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) { @@ -1625,6 +1659,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); @@ -1636,7 +1673,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 @@ -1645,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(RT6_TABLE_DFLT); + table = fib6_get_table(dev_net(dev), RT6_TABLE_DFLT); if (table == NULL) return NULL; @@ -1674,6 +1711,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_net(dev), }; ipv6_addr_copy(&cfg.fc_gateway, gwaddr); @@ -1683,13 +1723,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(RT6_TABLE_DFLT); + table = fib6_get_table(net, RT6_TABLE_DFLT); if (table == NULL) return; @@ -1706,7 +1746,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)); @@ -1719,14 +1760,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; @@ -1742,7 +1783,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) { @@ -1821,21 +1862,22 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, const struct in6_addr *addr, int anycast) { - struct rt6_info *rt = ip6_dst_alloc(); + struct net *net = dev_net(idev->dev); + struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops); 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; @@ -1852,26 +1894,39 @@ 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(net, RT6_TABLE_LOCAL); atomic_set(&rt->u.dst.__refcnt, 1); 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; } 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); + struct arg_dev_net adn = { + .dev = dev, + .net = net, + }; + + fib6_clean_all(net, fib6_ifdown, 0, &adn); } struct rt6_mtu_change_arg @@ -1884,6 +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 = dev_net(arg->dev); /* In IPv6 pmtu discovery is not optional, so that RTAX_MTU lock cannot disable it. @@ -1915,7 +1971,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; } @@ -1927,7 +1983,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_net(dev), rt6_mtu_change_route, 0, &arg); } static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { @@ -1964,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); @@ -2010,13 +2066,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; @@ -2026,13 +2078,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; @@ -2122,7 +2170,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, 0, &saddr_buf) == 0) NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } @@ -2167,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; @@ -2175,9 +2224,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; @@ -2207,7 +2253,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; @@ -2226,7 +2272,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(net, NULL, &fl); skb->dst = &rt->u.dst; err = rt6_fill_node(skb, rt, &fl.fl6_dst, &fl.fl6_src, iif, @@ -2237,7 +2283,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; } @@ -2245,6 +2291,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; @@ -2263,11 +2310,31 @@ 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); +} + +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_net(dev); + + 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; } /* @@ -2316,13 +2383,33 @@ 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); + int err; + struct net *net = get_proc_net(inode); + if (!net) + return -ENXIO; + + 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) +{ + 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 = { @@ -2330,24 +2417,46 @@ 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) { + struct net *net = (struct net *)seq->private; 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); + 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(&net->ipv6.ip6_dst_ops->entries), + 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); + int err; + struct net *net = get_proc_net(inode); + 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) +{ + 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 = { @@ -2355,42 +2464,8 @@ 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, }; - -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 @@ -2399,10 +2474,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; @@ -2419,7 +2495,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, @@ -2505,33 +2581,141 @@ 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 = &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; + 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 +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_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 = net->ipv6.ip6_dst_ops; + +#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_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), + 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; + net->ipv6.ip6_blk_hole_entry->u.dst.ops = net->ipv6.ip6_dst_ops; +#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 + net->ipv6.ip6_rt_gc_expire = 30*HZ; + + 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) +{ +#ifdef CONFIG_PROC_FS + proc_net_remove(net, "ipv6_route"); + proc_net_remove(net, "rt6_stats"); +#endif + 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 + kfree(net->ipv6.ip6_dst_ops); +} + +static struct pernet_operations ip6_route_net_ops = { + .init = ip6_route_net_init, + .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; - ip6_dst_ops.kmem_cachep = + 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_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep; - - ret = fib6_init(); + ret = register_pernet_subsys(&ip6_route_net_ops); if (ret) goto out_kmem_cache; - ret = ipv6_route_proc_init(&init_net); + /* 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_fib6_init; + goto out_register_subsys; ret = xfrm6_init(); if (ret) - goto out_proc_init; + goto out_fib6_init; ret = fib6_rules_init(); if (ret) @@ -2543,7 +2727,10 @@ int __init ip6_route_init(void) __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL)) goto fib6_rules_init; - ret = 0; + ret = register_netdevice_notifier(&ip6_route_dev_notifier); + if (ret) + goto fib6_rules_init; + out: return ret; @@ -2551,22 +2738,21 @@ fib6_rules_init: fib6_rules_cleanup(); xfrm6_init: xfrm6_fini(); -out_proc_init: - ipv6_route_proc_fini(&init_net); out_fib6_init: - rt6_ifdown(NULL); fib6_gc_cleanup(); +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_template.kmem_cachep); goto out; } void ip6_route_cleanup(void) { + unregister_netdevice_notifier(&ip6_route_dev_notifier); fib6_rules_cleanup(); - ipv6_route_proc_fini(&init_net); xfrm6_fini(); - rt6_ifdown(NULL); fib6_gc_cleanup(); - kmem_cache_destroy(ip6_dst_ops.kmem_cachep); + unregister_pernet_subsys(&ip6_route_net_ops); + kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); } diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 1656c003b989..1b8196c8d145 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); @@ -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/syncookies.c b/net/ipv6/syncookies.c new file mode 100644 index 000000000000..3a622e7abc02 --- /dev/null +++ b/net/ipv6/syncookies.c @@ -0,0 +1,267 @@ +/* + * IPv6 Syncookies implementation for the Linux kernel + * + * Authors: + * Glenn Griffin <ggriffin.kernel@gmail.com> + * + * 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 <linux/tcp.h> +#include <linux/random.h> +#include <linux/cryptohash.h> +#include <linux/kernel.h> +#include <net/ipv6.h> +#include <net/tcp.h> + +extern int sysctl_tcp_syncookies; +extern __u32 syncookie_secret[2][16-4+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/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; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 12750f2b05ab..6d851c3c3db9 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -69,9 +69,6 @@ #include <linux/crypto.h> #include <linux/scatterlist.h> -/* 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, @@ -324,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) { @@ -455,8 +452,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 +460,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 +473,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); @@ -514,6 +509,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) @@ -741,7 +750,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; @@ -781,17 +790,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; } @@ -917,7 +926,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, @@ -979,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 = dev_net(skb->dst->dev); + struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(*th); #ifdef CONFIG_TCP_MD5SIG struct tcp_md5sig_key *key; @@ -1059,11 +1070,14 @@ 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(ctl_sk, &buff->dst, &fl)) { if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { - ip6_xmit(tcp6_socket->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; @@ -1079,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 = dev_net(skb->dev); + struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(struct tcphdr); __be32 *topt; #ifdef CONFIG_TCP_MD5SIG @@ -1160,9 +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(NULL, &buff->dst, &fl)) { + if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) { if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { - ip6_xmit(tcp6_socket->sk, buff, &fl, NULL, 0); + ip6_xmit(ctl_sk, buff, &fl, NULL, 0); TCP_INC_STATS_BH(TCP_MIB_OUTSEGS); return; } @@ -1202,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)); @@ -1215,9 +1231,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; } @@ -1233,6 +1249,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); @@ -1240,12 +1261,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; } @@ -1266,39 +1289,51 @@ 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; 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); - return 0; + if (!want_cookie) { + inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); + return 0; + } drop: if (req) @@ -1704,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)); @@ -1787,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) { @@ -2094,19 +2129,17 @@ 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 -DEFINE_PROTO_INUSE(tcpv6) - struct proto tcpv6_prot = { .name = "TCPv6", .owner = THIS_MODULE, @@ -2137,12 +2170,11 @@ 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, #endif - REF_PROTO_INUSE(tcpv6) }; static struct inet6_protocol tcpv6_protocol = { @@ -2164,6 +2196,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; @@ -2177,8 +2234,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: @@ -2193,7 +2249,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); } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 53739de829db..30ef7dc5d403 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -51,9 +51,9 @@ #include <linux/seq_file.h> #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, @@ -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 (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; @@ -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; @@ -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 (sock_net(s) != sock_net(sk)) + continue; + if (s->sk_hash == num && s->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(s); if (inet->dport) { @@ -480,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) { @@ -789,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) { @@ -976,30 +977,30 @@ 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_show = udp6_seq_show, - .seq_fops = &udp6_seq_fops, + .seq_fops = { + .owner = THIS_MODULE, + }, + .seq_ops = { + .show = udp6_seq_show, + }, }; -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 */ /* ------------------------------------------------------------------------ */ -DEFINE_PROTO_INUSE(udpv6) - struct proto udpv6_prot = { .name = "UDPv6", .owner = THIS_MODULE, @@ -1021,11 +1022,11 @@ 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, #endif - REF_PROTO_INUSE(udpv6) }; static struct inet_protosw udpv6_protosw = { 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 87d4202522ee..491efd00a866 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -35,13 +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 = { .name = "UDPLITEv6", .owner = THIS_MODULE, @@ -58,13 +51,13 @@ 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, #endif - REF_PROTO_INUSE(udplitev6) }; static struct inet_protosw udplite6_protosw = { @@ -103,23 +96,40 @@ 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_show = udp6_seq_show, - .seq_fops = &udplite6_seq_fops, + .seq_fops = { + .owner = THIS_MODULE, + }, + .seq_ops = { + .show = udp6_seq_show, + }, +}; + +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(&udplite6_seq_afinfo); + return register_pernet_subsys(&udplite6_net_ops); } void udplite6_proc_exit(void) { - udp_proc_unregister(&udplite6_seq_afinfo); + unregister_pernet_subsys(&udplite6_net_ops); } #endif 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) { diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 7d20199ee1f3..8f1e0543b3c4 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) { @@ -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, 0, + (struct in6_addr *)&saddr->a6); dst_release(dst); return 0; } @@ -246,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/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index ff1e1db8e236..89884a4f23aa 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) 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; 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/af_irda.c b/net/irda/af_irda.c index 240b0cbfb532..ae54b20d0470 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,9 +835,9 @@ 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); + err = irda_create(sock_net(sk), newsock, sk->sk_protocol); if (err) return 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 <val> 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; i<count;i++) { ret = irlan_extract_param(ptr, name, value, &val_len); if (ret < 0) { - IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __func__ ); break; } ptr += ret; @@ -438,7 +438,7 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param, int i; DECLARE_MAC_BUF(mac); - IRDA_DEBUG(4, "%s(), parm=%s\n", __FUNCTION__ , param); + IRDA_DEBUG(4, "%s(), parm=%s\n", __func__ , param); IRDA_ASSERT(self != NULL, return;); IRDA_ASSERT(self->magic == 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; i<count;i++) { ret = irlan_extract_param(ptr, name, value, &val_len); if (ret < 0) { - IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __FUNCTION__ ); + IRDA_DEBUG(2, "%s(), IrLAN, Error!\n", __func__ ); break; } ptr+=ret; @@ -291,7 +291,7 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command, { 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 == 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..90894534f3cc 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; } @@ -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? */ @@ -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 7873c392ab4c..b001c361ad30 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/key/af_key.c b/net/key/af_key.c index e9ef9af4a53b..6db58924368a 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,45 +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 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; - return xfrm_state_walk(proto, dump_sa, &data); + 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 pfkey_do_dump(pfk); } static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) @@ -1780,7 +1827,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 +1837,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; @@ -2638,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); @@ -2652,21 +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 pfkey_sock *pfk = pfkey_sk(sk); + + if (pfk->dump.dump != NULL) + return -EBUSY; + + 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 xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data); + return pfkey_do_dump(pfk); } static int key_notify_policy_flush(struct km_event *c) @@ -3671,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; @@ -3698,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: diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 8c50eb430c19..97101dcde4c0 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -188,7 +188,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); @@ -298,7 +298,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; @@ -435,7 +435,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; @@ -607,7 +607,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)) @@ -622,7 +622,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; @@ -643,7 +643,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); @@ -836,7 +836,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) { @@ -894,7 +894,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 71a00225bdb3..019c780512e8 100644 --- a/net/llc/llc_c_ac.c +++ b/net/llc/llc_c_ac.c @@ -1430,7 +1430,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..5c6d89c6d51d 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 */ @@ -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); @@ -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 bfd2567dd365..1c45f172991e 100644 --- a/net/llc/llc_input.c +++ b/net/llc/llc_input.c @@ -150,7 +150,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; /* @@ -158,7 +158,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); @@ -171,7 +171,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/Kconfig b/net/mac80211/Kconfig index 45c7c0c3875e..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,16 +60,16 @@ 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)" +endmenu + +config MAC80211_MESH + bool "Enable mac80211 mesh networking (pre-802.11s) support" + depends on MAC80211 && EXPERIMENTAL ---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. + 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/. - Say N unless you know what you are doing. -endmenu config MAC80211_LEDS bool "Enable LED triggers" @@ -166,3 +156,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 54f46bc80cfe..70f4b26c2d87 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 \ @@ -37,11 +36,15 @@ 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 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/cfg.c b/net/mac80211/cfg.c index 22c9619ba776..5f8db5cab65d 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -15,6 +15,7 @@ #include "ieee80211_i.h" #include "cfg.h" #include "ieee80211_rate.h" +#include "mesh.h" static enum ieee80211_if_types nl80211_type_to_mac80211_type(enum nl80211_iftype type) @@ -28,16 +29,24 @@ 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; } } static int ieee80211_add_iface(struct wiphy *wiphy, char *name, - enum nl80211_iftype type) + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) { 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 +55,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, params); + 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) @@ -69,7 +84,8 @@ static int ieee80211_del_iface(struct wiphy *wiphy, int ifindex) } static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, - enum nl80211_iftype type) + enum nl80211_iftype type, u32 *flags, + struct vif_params *params) { struct ieee80211_local *local = wiphy_priv(wiphy); struct net_device *dev; @@ -99,6 +115,15 @@ static int ieee80211_change_iface(struct wiphy *wiphy, int ifindex, ieee80211_if_reinit(dev); ieee80211_if_set_type(dev, itype); + 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; + + sdata->u.mntr_flags = *flags; return 0; } @@ -109,7 +134,7 @@ 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); @@ -128,21 +153,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; + } } - ret = 0; - if (!ieee80211_key_alloc(sdata, sta, alg, key_idx, - params->key_len, params->key)) - ret = -ENOMEM; - - if (sta) - sta_info_put(sta); + ieee80211_key_link(key, sdata, sta); - return ret; + return 0; } static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, @@ -160,12 +185,12 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, return -ENOENT; ret = 0; - if (sta->key) + if (sta->key) { ieee80211_key_free(sta->key); - else + WARN_ON(sta->key); + } else ret = -ENOENT; - sta_info_put(sta); return ret; } @@ -173,6 +198,7 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, return -ENOENT; ieee80211_key_free(sdata->keys[key_idx]); + WARN_ON(sdata->keys[key_idx]); return 0; } @@ -254,8 +280,6 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, err = 0; out: - if (sta) - sta_info_put(sta); return err; } @@ -271,29 +295,73 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, return 0; } +static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + + 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; + + if (ieee80211_vif_is_mesh(&sdata->vif)) { +#ifdef CONFIG_MAC80211_MESH + 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; + int ret = -ENOENT; + + rcu_read_lock(); + + sta = sta_info_get_by_idx(local, idx, dev); + if (sta) { + ret = 0; + memcpy(mac, sta->addr, ETH_ALEN); + sta_set_sinfo(sta, sinfo); + } + + rcu_read_unlock(); + + return ret; +} + static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, - u8 *mac, struct station_stats *stats) + u8 *mac, struct station_info *sinfo) { 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 */ - stats->filled = STATION_STAT_INACTIVE_TIME | - STATION_STAT_RX_BYTES | - STATION_STAT_TX_BYTES; - - stats->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); - stats->rx_bytes = sta->rx_bytes; - stats->tx_bytes = sta->tx_bytes; + sta = sta_info_get(local, mac); + if (sta) { + ret = 0; + sta_set_sinfo(sta, sinfo); + } - sta_info_put(sta); + rcu_read_unlock(); - return 0; + return ret; } /* @@ -486,8 +554,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); } @@ -498,7 +566,14 @@ static void sta_apply_parameters(struct ieee80211_local *local, { u32 rates; int i, j; - struct ieee80211_hw_mode *mode; + 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; @@ -514,6 +589,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) @@ -525,15 +607,27 @@ 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; + } + + if (ieee80211_vif_is_mesh(&sdata->vif) && 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; + } } } @@ -543,18 +637,12 @@ 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)) 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); @@ -564,22 +652,36 @@ 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); + 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; - sta->dev = sdata->dev; - if (sdata->vif.type == IEEE80211_IF_TYPE_VLAN || - sdata->vif.type == IEEE80211_IF_TYPE_AP) - ieee80211_send_layer2_update(sta); - sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; sta_apply_parameters(local, sta, params); rate_control_rate_init(sta, local); - sta_info_put(sta); + rcu_read_lock(); + + err = sta_info_insert(sta); + if (err) { + /* STA has been freed */ + 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; } @@ -587,7 +689,8 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, 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) { @@ -596,10 +699,10 @@ 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); + sta_info_destroy(sta); } else - sta_info_flush(local, dev); + sta_info_flush(local, sdata); return 0; } @@ -618,23 +721,190 @@ 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; +} + +#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; + + rcu_read_lock(); + sta = sta_info_get(local, next_hop); + if (!sta) { + rcu_read_unlock(); + return -ENOENT; + } + + err = mesh_path_add(dst, dev); + if (err) { + rcu_read_unlock(); + return err; + } + + mpath = mesh_path_lookup(dst, dev); + if (!mpath) { + rcu_read_unlock(); + return -ENXIO; + } + mesh_path_fix_nexthop(mpath, 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; + + rcu_read_lock(); + + sta = sta_info_get(local, next_hop); + if (!sta) { + rcu_read_unlock(); + return -ENOENT; + } + mpath = mesh_path_lookup(dst, dev); + if (!mpath) { + rcu_read_unlock(); + return -ENOENT; + } + + mesh_path_fix_nexthop(mpath, 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, @@ -651,4 +921,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 }; 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_netdev.c b/net/mac80211/debugfs_netdev.c index 829872a3ae81..3e19d42e61cb 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -31,14 +31,39 @@ 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; } +#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)); + if (copy_from_user(buf, userbuf, buf_size)) + return count; + read_lock(&dev_base_lock); + if (sdata->dev->reg_state == NETREG_REGISTERED) + (*format)(sdata, buf); + 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 +71,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,10 +126,37 @@ 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); -IEEE80211_IF_FILE(ieee802_1x_pac, ieee802_1x_pac, DEC); /* STA/IBSS attributes */ IEEE80211_IF_FILE(state, u.sta.state, DEC); @@ -107,6 +172,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) @@ -140,6 +206,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, u8); +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); @@ -148,7 +250,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); @@ -163,13 +264,13 @@ 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) { 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 +283,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,19 +290,63 @@ 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) { } +#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); @@ -234,7 +378,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); @@ -249,13 +392,13 @@ 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) { 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 +411,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,19 +418,67 @@ 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) { } +#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); diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 8f5944c53d4e..256ea880d28b 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -33,25 +33,16 @@ 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, \ + .open = mac80211_open_file_generic, \ } -#define STA_OPS(name) \ +#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, \ } @@ -60,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); @@ -70,27 +61,23 @@ 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); 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) { 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", 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" : "", @@ -111,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) { @@ -191,6 +153,118 @@ 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_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_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_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_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_state_tx[i]? + sta->ampdu_mlme.tid_tx[i]->ssn : 0); + + 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->sdata->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_state_rx[tid_num] |= + HT_AGG_STATE_DEBUGFS_CTL; + tid_static_rx[tid_num] = 0; + } else { + strcpy(state, "on "); + sta->ampdu_mlme.tid_state_rx[tid_num] &= + ~HT_AGG_STATE_DEBUGFS_CTL; + 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); @@ -203,12 +277,13 @@ STA_OPS(wme_tx_queue); 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) @@ -216,28 +291,26 @@ 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 DEBUGFS_ADD(wme_rx_queue); DEBUGFS_ADD(wme_tx_queue); #endif + DEBUGFS_ADD(agg_status); } 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 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/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 8e586390a2ef..aaa5480e204a 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -26,6 +26,7 @@ #include "ieee80211_i.h" #include "ieee80211_rate.h" +#include "mesh.h" #include "wep.h" #include "wme.h" #include "aes_ccm.h" @@ -67,9 +68,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; @@ -128,9 +139,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; @@ -166,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); @@ -173,8 +191,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 */ @@ -186,8 +248,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; } } @@ -196,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 has been freed */ + return res; + } break; case IEEE80211_IF_TYPE_VLAN: if (!sdata->u.vlan.ap) @@ -205,6 +280,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: @@ -229,15 +305,28 @@ 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) { - 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: @@ -305,24 +394,46 @@ 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); - list_for_each_entry(sta, &local->sta_list, list) { - if (sta->dev == dev) - for (i = 0; i < STA_TID_NUM; i++) - ieee80211_sta_stop_rx_ba_session(sta->dev, - sta->addr, i, - WLAN_BACK_RECIPIENT, - WLAN_REASON_QSTA_LEAVE_QBSS); + /* + * 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); } - netif_stop_queue(dev); + 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 @@ -364,15 +475,29 @@ static int ieee80211_stop(struct net_device *dev) /* no need to tell driver */ 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 (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; @@ -426,6 +551,359 @@ 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 */ + + 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; + +#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) { + 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) { +#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); + 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; + } + + 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_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); @@ -477,41 +955,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; - DECLARE_MAC_BUF(mac); - - if (compare_ether_addr(remote_addr, sdata->u.wds.remote_addr) == 0) - return 0; - - /* Create STA entry for the new peer */ - sta = sta_info_add(local, dev, remote_addr, GFP_KERNEL); - if (!sta) - return -ENOMEM; - 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 { - 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); - - return 0; -} - /* everything else */ static int __ieee80211_if_config(struct net_device *dev, @@ -532,6 +975,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; + } 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; @@ -544,6 +990,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); } @@ -565,37 +1016,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); @@ -613,11 +1055,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; } @@ -627,17 +1071,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 @@ -725,6 +1169,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))) { @@ -745,6 +1190,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); @@ -822,6 +1279,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) { @@ -831,7 +1359,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 @@ -841,18 +1369,24 @@ 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); 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); + rcu_read_unlock(); + return; } - sta_info_put(sta); } } @@ -860,53 +1394,16 @@ 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); - } - sta_info_put(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 @@ -944,7 +1441,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; } @@ -978,51 +1479,44 @@ 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); 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; @@ -1068,25 +1562,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->rx_pre_handlers = ieee80211_rx_pre_handlers; - local->rx_handlers = ieee80211_rx_handlers; - local->tx_handlers = ieee80211_tx_handlers; - local->bridge_packets = 1; local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; @@ -1095,33 +1572,12 @@ 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); - 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); @@ -1143,11 +1599,63 @@ 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) { @@ -1215,7 +1723,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)); @@ -1239,49 +1747,18 @@ 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); -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); @@ -1322,11 +1799,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", @@ -1338,6 +1810,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); @@ -1345,7 +1819,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); @@ -1357,13 +1830,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) { @@ -1373,23 +1842,22 @@ static int __init ieee80211_init(void) } ieee80211_debugfs_netdev_init(); - ieee80211_regdomain_init(); return 0; 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) + ieee80211s_stop(); + ieee80211_wme_unregister(); ieee80211_debugfs_netdev_exit(); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 72ecbf7bf962..6c62dd42f915 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -69,18 +69,26 @@ 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; 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 */ - int hw_mode; - int channel; + enum ieee80211_band band; int freq; int rssi, signal, noise; u8 *wpa_ie; @@ -91,11 +99,16 @@ 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; + struct bss_mesh_config *mesh_cfg; +#endif #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; @@ -108,56 +121,99 @@ struct ieee80211_sta_bss { u8 erp_value; }; +static inline +struct bss_mesh_config *bss_mesh_cfg(struct ieee80211_sta_bss *bss) +{ +#ifdef CONFIG_MAC80211_MESH + return bss->mesh_cfg; +#endif + return NULL; +} -typedef enum { - TXRX_CONTINUE, TXRX_DROP, TXRX_QUEUED -} ieee80211_txrx_result; +static inline u8 *bss_mesh_id(struct ieee80211_sta_bss *bss) +{ +#ifdef CONFIG_MAC80211_MESH + return bss->mesh_id; +#endif + return NULL; +} -/* 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) -/* 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) -struct ieee80211_txrx_data { +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) +#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; + struct ieee80211_key *key; + + 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) */ + struct sk_buff **extra_frag; + int num_extra_frag; + u16 fc, ethertype; + unsigned int flags; +}; + + +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) + +#define IEEE80211_RX_IN_SCAN BIT(0) +/* frame is destined to interface currently processed (incl. multicast frames) */ +#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; + struct ieee80211_sub_if_data *sdata; + struct sta_info *sta; struct ieee80211_key *key; + struct ieee80211_rx_status *status; + struct ieee80211_rate *rate; + + u16 fc, ethertype; unsigned int flags; - union { - struct { - struct ieee80211_tx_control *control; - struct ieee80211_hw_mode *mode; - 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) */ - int num_extra_frag; - struct sk_buff **extra_frag; - } tx; - struct { - struct ieee80211_rx_status *status; - int sent_ps_buffered; - int queue; - int load; - u32 tkip_iv32; - u16 tkip_iv16; - } rx; - } u; + int sent_ps_buffered; + int queue; + int load; + u32 tkip_iv32; + u16 tkip_iv16; }; /* flags used in struct ieee80211_tx_packet_data.flags */ @@ -165,6 +221,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; @@ -176,20 +233,12 @@ 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; - int last_frag_rateidx; - int last_frag_hwrate; struct ieee80211_rate *last_frag_rate; + int num_extra_frag; unsigned int last_frag_rate_ctrl_probe; }; -typedef ieee80211_txrx_result (*ieee80211_tx_handler) -(struct ieee80211_txrx_data *tx); - -typedef ieee80211_txrx_result (*ieee80211_rx_handler) -(struct ieee80211_txrx_data *rx); - struct beacon_data { u8 *head, *tail; int head_len, tail_len; @@ -206,10 +255,10 @@ 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; + 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 */ @@ -217,8 +266,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 { @@ -226,6 +275,41 @@ struct ieee80211_if_vlan { struct list_head list; }; +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 */ + u8 dot11MeshHWMPmaxPREQretries; + u32 path_refresh_time; + u16 min_discovery_timeout; + u32 dot11MeshHWMPactivePathTimeout; + u16 dot11MeshHWMPpreqMinInterval; + u16 dot11MeshHWMPnetDiameterTraversalTime; +}; + + /* flags used in struct ieee80211_if_sta.flags */ #define IEEE80211_STA_SSID_SET BIT(0) #define IEEE80211_STA_BSSID_SET BIT(1) @@ -241,18 +325,47 @@ struct ieee80211_if_vlan { #define IEEE80211_STA_AUTO_CHANNEL_SEL BIT(12) #define IEEE80211_STA_PRIVACY_INVOKED BIT(13) struct ieee80211_if_sta { - enum { - IEEE80211_DISABLED, IEEE80211_AUTHENTICATE, - IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED, - IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED - } state; 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; 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]; + 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]; + bool accepting_plinks; +#endif u16 aid; u16 ap_capab, capab; u8 *extra_ie; /* to be added to the end of AssocReq */ @@ -262,16 +375,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) @@ -282,16 +397,34 @@ 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; + 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) #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; @@ -306,11 +439,11 @@ 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 + * basic rates of this AP or the AP we're associated to */ - int ieee802_1x_pac; + u64 basic_rates; u16 sequence; @@ -338,6 +471,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; @@ -348,7 +482,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; @@ -363,11 +496,11 @@ 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; struct dentry *drop_unencrypted; - struct dentry *ieee802_1x_pac; struct dentry *num_sta_ps; struct dentry *dtim_count; struct dentry *num_beacons; @@ -378,19 +511,46 @@ 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; } 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; @@ -407,6 +567,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 { @@ -417,15 +579,15 @@ 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; + 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_* */ 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 { @@ -443,15 +605,23 @@ 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 list_head sta_flush_list; + struct work_struct sta_flush_work; 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 */ @@ -459,11 +629,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 */ @@ -477,21 +642,18 @@ 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; - struct list_head interfaces; 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; @@ -560,14 +722,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; @@ -577,9 +733,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; @@ -627,6 +781,63 @@ struct ieee80211_local { #endif }; +/* this struct represents 802.11n's RA/TID combination */ +struct ieee80211_ra_tid { + u8 ra[ETH_ALEN]; + 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) { @@ -650,57 +861,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); -} - -/** - * 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 || @@ -712,13 +872,8 @@ 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_tx_set_protected(struct ieee80211_tx_data *tx); 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); @@ -749,8 +904,9 @@ 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 */ +#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); @@ -763,9 +919,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); @@ -782,12 +938,36 @@ 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); +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); +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, - 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, @@ -796,16 +976,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); -/* 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_pre_handlers[]; -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/ieee80211_iface.c b/net/mac80211/ieee80211_iface.c index 92f1eb2da311..80954a512185 100644 --- a/net/mac80211/ieee80211_iface.c +++ b/net/mac80211/ieee80211_iface.c @@ -15,6 +15,7 @@ #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) { @@ -39,7 +40,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 +80,12 @@ int ieee80211_if_add(struct net_device *dev, const char *name, 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); @@ -118,6 +126,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 */ @@ -132,6 +142,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; @@ -153,15 +164,20 @@ 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; + + 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, __FUNCTION__, type); + dev->name, __func__, type); } ieee80211_debugfs_change_if_type(sdata, oldtype); } @@ -171,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(); @@ -180,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 */ @@ -189,6 +209,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) { @@ -206,7 +227,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--; @@ -216,17 +240,9 @@ void ieee80211_if_reinit(struct net_device *dev) break; } case IEEE80211_IF_TYPE_WDS: - sta = sta_info_get(local, sdata->u.wds.remote_addr); - if (sta) { - sta_info_free(sta); - sta_info_put(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 */ - } + /* 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); @@ -249,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, dev); + 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 5024d3733834..b047eebb6330 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c @@ -33,7 +33,6 @@ 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; struct ieee80211_key *key; struct ieee80211_sub_if_data *sdata; @@ -46,59 +45,52 @@ 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) + return -ENOENT; + 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 */ + ieee80211_key_free(key); + return 0; + } else { + key = ieee80211_key_alloc(alg, idx, key_len, _key); + if (!key) + return -ENOMEM; - return -ENOENT; - } + sta = NULL; - key = sta->key; - } + 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); + return -EINVAL; + } - if (remove) { - ieee80211_key_free(key); - 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; + sta = sta_info_get(local, sta_addr); + if (!sta) { + ieee80211_key_free(key); + return -ENOENT; + } } - } - if (set_tx_key || (!sta && !sdata->default_key && key)) - ieee80211_set_default_key(sdata, idx); + ieee80211_key_link(key, sdata, sta); - ret = 0; - err_out: - if (sta) - sta_info_put(sta); - return ret; + if (set_tx_key || (!sta && !sdata->default_key && key)) + ieee80211_set_default_key(sdata, idx); + } + + return 0; } static int ieee80211_ioctl_siwgenie(struct net_device *dev, @@ -129,22 +121,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 +133,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 +168,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,31 +274,17 @@ 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 ret = -EINVAL; + struct ieee80211_channel *chan; - list_for_each_entry(mode, &local->modes_list, list) { - if (!(local->enabled_modes & (1 << mode->mode))) - 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; - set = 1; - break; - } - } - if (set) - break; - } + chan = ieee80211_get_channel(local->hw.wiphy, freqMHz); + + if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { + local->oper_channel = chan; - if (set) { - if (local->sta_sw_scanning) + if (local->sta_sw_scanning || local->sta_hw_scanning) ret = 0; else ret = ieee80211_hw_config(local); @@ -347,13 +313,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 +333,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; @@ -480,10 +444,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; @@ -526,6 +500,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; @@ -566,15 +541,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 +559,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,19 +582,25 @@ 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; - sta_info_put(sta); + rate->value *= 100000; + return 0; } @@ -625,7 +610,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 +620,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) { @@ -988,7 +975,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_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 <linux/types.h> #include <linux/list.h> #include <linux/crypto.h> +#include <linux/rcupdate.h> #include <net/mac80211.h> /* 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/ieee80211_rate.c b/net/mac80211/ieee80211_rate.c index b957e67c5fba..4de06f128d90 100644 --- a/net/mac80211/ieee80211_rate.c +++ b/net/mac80211/ieee80211_rate.c @@ -163,34 +163,37 @@ 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); 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, 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; } } - 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 73f19e8aa51c..5b45f33cb766 100644 --- a/net/mac80211/ieee80211_rate.h +++ b/net/mac80211/ieee80211_rate.h @@ -14,10 +14,12 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <linux/types.h> +#include <linux/kref.h> #include <net/mac80211.h> #include "ieee80211_i.h" #include "sta_info.h" +/* TODO: kdoc */ struct rate_selection { /* Selected transmission rate */ struct ieee80211_rate *rate; @@ -34,7 +36,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 +69,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 +131,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 +156,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)]; } @@ -166,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/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index e0c72d04584b..c20ef89acad6 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c @@ -24,19 +24,23 @@ #include <linux/wireless.h> #include <linux/random.h> #include <linux/etherdevice.h> +#include <linux/rtnetlink.h> #include <net/iw_handler.h> #include <asm/types.h> +#include <asm/unaligned.h> #include <net/mac80211.h> #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) @@ -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 @@ -74,7 +79,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); @@ -87,46 +92,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 +182,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; } @@ -227,12 +218,61 @@ 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 (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); + } } - return cw - 1; } static void ieee80211_sta_wmm_params(struct net_device *dev, @@ -297,12 +337,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)) { @@ -465,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, + local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (bss) { if (bss->has_erp_value) @@ -480,8 +521,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); @@ -491,6 +532,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); } @@ -503,8 +545,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; @@ -591,7 +633,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; @@ -599,6 +640,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 + @@ -610,13 +652,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) @@ -655,23 +703,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); } } @@ -694,17 +742,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); @@ -787,7 +836,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; @@ -850,6 +900,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", @@ -865,7 +917,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, @@ -881,8 +933,16 @@ static void ieee80211_associated(struct net_device *dev, ifsta->ssid_len); } } - sta_info_put(sta); } + + rcu_read_unlock(); + + if (disassoc && sta) { + rtnl_lock(); + sta_info_destroy(sta); + rtnl_unlock(); + } + if (disassoc) { ifsta->state = IEEE80211_DISABLED; ieee80211_set_associated(dev, ifsta, 0); @@ -897,7 +957,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; @@ -931,11 +991,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]++; @@ -948,7 +1007,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); @@ -1043,6 +1102,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) @@ -1057,9 +1168,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; @@ -1083,7 +1198,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); @@ -1092,26 +1207,45 @@ 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]; /* 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 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 */ 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); @@ -1119,6 +1253,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, @@ -1126,18 +1261,20 @@ 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 */ 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; @@ -1149,13 +1286,89 @@ 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_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; + + 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); @@ -1206,19 +1419,23 @@ 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 + if (sta->ampdu_mlme.tid_state_rx[tid] != 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 = + 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); @@ -1228,35 +1445,38 @@ 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); /* 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; - sta_info_put(sta); + rcu_read_unlock(); } + static void ieee80211_sta_process_delba(struct net_device *dev, struct ieee80211_mgmt *mgmt, size_t len) { @@ -1266,9 +1486,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; @@ -1276,27 +1500,87 @@ 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 ? "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); - sta_info_put(sta); + 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 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) { /* 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; @@ -1304,11 +1588,24 @@ 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); } +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, @@ -1535,15 +1832,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. */ @@ -1613,22 +1911,23 @@ 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); + 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); + int err; + + sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC); if (!sta) { - printk(KERN_DEBUG "%s: failed to add STA entry for the" - " AP\n", dev->name); + 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, + local->hw.conf.channel->center_freq, ifsta->ssid, ifsta->ssid_len); if (bss) { sta->last_rssi = bss->rssi; @@ -1636,26 +1935,70 @@ 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); + rcu_read_unlock(); + return; + } } - sta->dev = dev; - sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_AP; + /* + * 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; - 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) { @@ -1674,12 +2017,15 @@ 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(); - sta_info_put(sta); + /* set AID, ieee80211_set_associated() will tell the driver */ + bss_conf->aid = aid; + ieee80211_set_associated(dev, ifsta, 1); ieee80211_associated(dev, ifsta); } @@ -1690,8 +2036,16 @@ 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; + + 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; } @@ -1718,7 +2072,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); @@ -1730,7 +2084,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; @@ -1744,9 +2098,8 @@ ieee80211_rx_bss_add(struct net_device *dev, u8 *bssid, int channel, return bss; } - 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); @@ -1755,8 +2108,9 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel, spin_lock_bh(&local->sta_bss_lock); bss = local->sta_bss_hash[STA_HASH(bssid)]; while (bss) { - if (!memcmp(bss->bssid, bssid, ETH_ALEN) && - bss->channel == channel && + 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); @@ -1768,6 +2122,85 @@ ieee80211_rx_bss_get(struct net_device *dev, u8 *bssid, int channel, return bss; } +#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) +{ + 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(sizeof(struct bss_mesh_config), 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); + 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); + /* 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) { @@ -1775,6 +2208,8 @@ static void ieee80211_rx_bss_free(struct ieee80211_sta_bss *bss) kfree(bss->rsn_ie); kfree(bss->wmm_ie); kfree(bss->ht_ie); + kfree(bss_mesh_id(bss)); + kfree(bss_mesh_cfg(bss)); kfree(bss); } @@ -1812,6 +2247,204 @@ 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]; + + 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, @@ -1821,11 +2454,12 @@ 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); - u64 timestamp; + u64 beacon_timestamp, rx_timestamp; + struct ieee80211_channel *channel; DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac2); @@ -1842,104 +2476,77 @@ static void ieee80211_rx_bss_info(struct net_device *dev, if (baselen > len) return; - timestamp = le64_to_cpu(mgmt->u.beacon.timestamp); + 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 && 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 */ + 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)); } - ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems); + 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))) { - struct ieee80211_hw_mode *mode; - struct ieee80211_rate *rates; - size_t num_rates; - u32 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; - - if (mode == NULL) - mode = local->oper_hw_mode; - } - rates = mode->rates; - num_rates = mode->num_rates; - - 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 (rates[j].rate == 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; - 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); } - if (!elems.ssid) - return; + rcu_read_unlock(); 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, - elems.ssid, elems.ssid_len); - if (!bss) { - bss = ieee80211_rx_bss_add(dev, mgmt->bssid, channel, + 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 { @@ -1951,8 +2558,12 @@ static void ieee80211_rx_bss_info(struct net_device *dev, #endif } - if (bss->probe_resp && beacon) { - /* Do not allow beacon to override data from Probe Response. */ + 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; } @@ -2049,27 +2660,69 @@ 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->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); } @@ -2220,8 +2873,11 @@ 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) { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + if (len < IEEE80211_MIN_ACTION_SIZE) return; @@ -2234,6 +2890,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))) @@ -2247,7 +2909,18 @@ static void ieee80211_rx_mgmt_action(struct net_device *dev, 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; } } @@ -2274,13 +2947,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; @@ -2339,7 +3012,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; } @@ -2347,7 +3020,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) { @@ -2355,31 +3028,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_UNUSABLE; 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_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 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; } @@ -2388,45 +3061,50 @@ 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(); - read_lock_bh(&local->sta_lock); - list_for_each_entry(sta, &local->sta_list, list) { - if (sta->dev == dev && + 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; } -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; 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 + - 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); - 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(); } @@ -2435,7 +3113,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; @@ -2445,6 +3123,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 = @@ -2456,7 +3164,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 = @@ -2473,7 +3180,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; @@ -2483,6 +3191,13 @@ 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)) { @@ -2518,6 +3233,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); @@ -2628,7 +3348,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; @@ -2659,11 +3379,12 @@ 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); 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); @@ -2683,162 +3404,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 ieee80211_hw_mode *mode; - struct rate_selection ratesel; - u8 *pos; - struct ieee80211_sub_if_data *sdata; - - /* 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_channel(local, -1, 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); - 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); - - pos = skb_put(skb, 2 + 1); - *pos++ = WLAN_EID_DS_PARAMS; - *pos++ = 1; - *pos++ = bss->channel; - - 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, local->oper_hw_mode, 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.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; - - 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; - mode = local->oper_hw_mode; - 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) - rates |= BIT(j); - } - ifsta->supp_rates_bits = 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) @@ -2846,7 +3411,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); @@ -2868,28 +3433,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; + local->hw.conf.beacon_int = 10000; 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); } @@ -2938,7 +3503,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", @@ -2966,13 +3532,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 @@ -2991,41 +3557,12 @@ 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); 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)); - /* TODO: are these ok defaults for all hw_modes? */ - qparam.aifs = 2; - qparam.cw_min = - local->hw.conf.phymode == MODE_IEEE80211B ? 31 : 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; - qparam.cw_min--; - local->ops->conf_tx(local_to_hw(local), - 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) @@ -3117,6 +3654,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); @@ -3130,6 +3674,15 @@ 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) + ieee80211_restart_sta_timer(sdata); + rcu_read_unlock(); + goto done; } @@ -3156,11 +3709,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); + + ieee80211_restart_sta_timer(sdata); netif_wake_queue(sdata->dev); } @@ -3184,7 +3738,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; @@ -3194,44 +3748,59 @@ 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. 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 = !(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; } } + /* advance state machine to next channel/band */ 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) { + /* + * 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) @@ -3242,13 +3811,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; } @@ -3323,10 +3893,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); @@ -3381,9 +3949,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; @@ -3393,15 +3958,25 @@ 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(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)) { + if (bss->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS) + || bss_mesh_cfg(bss)) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWMODE; - if (bss->capability & WLAN_CAPABILITY_ESS) + 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; @@ -3411,12 +3986,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); @@ -3487,6 +4065,42 @@ ieee80211_sta_scan_result(struct net_device *dev, } } + if (bss_mesh_cfg(bss)) { + char *buf; + 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->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%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%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%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%08X", cfg->channel_precedence); + iwe.u.data.length = strlen(buf); + current_ev = iwe_stream_add_point(current_ev, end_buf, + &iwe, buf); + kfree(buf); + } + } + return current_ev; } @@ -3555,15 +4169,21 @@ 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_alloc(sdata, addr, GFP_ATOMIC); if (!sta) return NULL; - sta->supp_rates = sdata->u.sta.supp_rates_bits; + 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); - return sta; /* caller will call sta_info_put() */ + if (sta_info_insert(sta)) + return NULL; + + return sta; } diff --git a/net/mac80211/key.c b/net/mac80211/key.c index ed57fb8e82fc..5df9e0cc009f 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -13,14 +13,15 @@ #include <linux/etherdevice.h> #include <linux/list.h> #include <linux/rcupdate.h> +#include <linux/rtnetlink.h> #include <net/mac80211.h> #include "ieee80211_i.h" #include "debugfs_key.h" #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, @@ -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 }; @@ -68,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, @@ -84,16 +98,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 +131,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) @@ -137,10 +159,7 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, key->conf.keyidx = idx; key->conf.keylen = key_len; memcpy(key->conf.key, key_data, key_len); - - key->local = sdata->local; - key->sdata = sdata; - key->sta = sta; + INIT_LIST_HEAD(&key->list); if (alg == ALG_CCMP) { /* @@ -154,13 +173,68 @@ 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 (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; + 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); @@ -175,61 +249,76 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata, 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(); } } - /* 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]; - list_add(&key->list, &sdata->key_list); + __ieee80211_key_replace(sdata, sta, old_key, key); - return key; + if (old_key) { + synchronize_rcu(); + ieee80211_key_free(old_key); + } + + if (netif_running(sdata->dev)) + 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. + * 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); - /* wait for all key users to complete */ - synchronize_rcu(); + /* + * Do NOT remove this without looking at sta_info_destroy() + */ + 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 +342,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 +355,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 +369,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/mesh.c b/net/mac80211/mesh.c new file mode 100644 index 000000000000..b10f1e543a94 --- /dev/null +++ b/net/mac80211/mesh.c @@ -0,0 +1,445 @@ +/* + * Copyright (c) 2008 open80211s Ltd. + * Authors: Luis Carlos Cobo <luisca@cozybit.com> + * Javier Cardona <javier@cozybit.com> + * + * 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 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; + + /* + * 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 + */ + 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; +} + +/** + * 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 + * + * @sdata: mesh interface in which mesh beacons are going to be updated + */ +void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata) +{ + 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 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); + + 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; +} + +/** + * 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 new file mode 100644 index 000000000000..8ff46ea0f1d7 --- /dev/null +++ b/net/mac80211/mesh.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2008 open80211s Ltd. + * Authors: Luis Carlos Cobo <luisca@cozybit.com> + * Javier Cardona <javier@cozybit.com> + * + * 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 <linux/types.h> +#include <linux/jhash.h> +#include "ieee80211_i.h" + + +/* 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_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), +}; + +/** + * 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. 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]; + 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 + +/* + * 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 +#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); +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); +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 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); +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); + +#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 - + atomic_read(&sdata->u.sta.mshstats.estab_plinks); +} + +static inline bool mesh_plink_availables(struct ieee80211_sub_if_data *sdata) +{ + return (min_t(long, 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) + +#else +#define mesh_allocated 0 +#endif + +#define MESH_PREQ(skb) (skb->cb + 30) + +#endif /* IEEE80211S_H */ diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c new file mode 100644 index 000000000000..576a6e55323e --- /dev/null +++ b/net/mac80211/mesh_hwmp.c @@ -0,0 +1,857 @@ +/* + * Copyright (c) 2008 open80211s Ltd. + * Author: Luis Carlos Cobo <luisca@cozybit.com> + * + * 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 <asm/unaligned.h> +#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 + +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) 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) +#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) { + rcu_read_unlock(); + 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: + rcu_read_unlock(); + 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(); + 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(); + 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); + } + + 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, cpu_to_le32(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; + + 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_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(); +} diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c new file mode 100644 index 000000000000..5845dc21ce85 --- /dev/null +++ b/net/mac80211/mesh_pathtbl.c @@ -0,0 +1,516 @@ +/* + * Copyright (c) 2008 open80211s Ltd. + * Author: Luis Carlos Cobo <luisca@cozybit.com> + * + * 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 <linux/etherdevice.h> +#include <linux/list.h> +#include <linux/netdevice.h> +#include <linux/random.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <net/mac80211.h> +#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) +{ + rcu_assign_pointer(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, or NULL for all entries + * + * 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 (dev && node->mpath->dev != dev) + continue; + 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->sdata->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(); +} +EXPORT_SYMBOL(mesh_plink_broken); + +/** + * 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 + * 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. + */ +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); + + del_timer_sync(&node->mpath->timer); + 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 + */ +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); + 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); +} diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c new file mode 100644 index 000000000000..56c54e321b38 --- /dev/null +++ b/net/mac80211/mesh_plink.c @@ -0,0 +1,763 @@ +/* + * Copyright (c) 2008 open80211s Ltd. + * Author: Luis Carlos Cobo <luisca@cozybit.com> + * + * 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 <linux/kernel.h> +#include <linux/random.h> +#include "ieee80211_i.h" +#include "ieee80211_rate.h" +#include "mesh.h" + +#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); +} + +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); +} + +/** + * 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 = PLINK_LISTEN; + sta->llid = sta->plid = sta->reason = 0; + 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) +{ + struct ieee80211_local *local = sdata->local; + struct sta_info *sta; + + if (local->num_sta >= MESH_MAX_PLINKS) + return NULL; + + sta = sta_info_alloc(sdata, hw_addr, GFP_ATOMIC); + if (!sta) + return NULL; + + sta->flags |= WLAN_STA_AUTHORIZED; + sta->supp_rates[local->hw.conf.channel->band] = rates; + + 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 + */ +static void __mesh_plink_deactivate(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + + if (sta->plink_state == PLINK_ESTAB) + mesh_plink_dec_estab_count(sdata); + sta->plink_state = PLINK_BLOCKED; + 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) { + 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; + + rcu_read_lock(); + + sta = sta_info_get(local, hw_addr); + if (!sta) { + sta = mesh_plink_alloc(sdata, hw_addr, rates); + if (!sta) { + rcu_read_unlock(); + return; + } + if (sta_info_insert(sta)) { + rcu_read_unlock(); + return; + } + } + + sta->last_rx = jiffies; + sta->supp_rates[local->hw.conf.channel->band] = rates; + 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); + + rcu_read_unlock(); +} + +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 + + /* + * 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); + 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; + sdata = sta->sdata; + dev = sdata->dev; + + switch (sta->plink_state) { + case PLINK_OPN_RCVD: + case PLINK_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; + 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); + break; + } + reason = cpu_to_le16(MESH_MAX_RETRIES); + /* fall through on else */ + case PLINK_CNF_RCVD: + /* confirm timer */ + if (!reason) + reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT); + 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 PLINK_HOLDING: + /* holding timer */ + del_timer(&sta->plink_timer); + mesh_plink_fsm_restart(sta); + spin_unlock_bh(&sta->plink_lock); + break; + default: + spin_unlock_bh(&sta->plink_lock); + break; + } +} + +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; + add_timer(&sta->plink_timer); +} + +int mesh_plink_open(struct sta_info *sta) +{ + __le16 llid; + struct ieee80211_sub_if_data *sdata = sta->sdata; +#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 != PLINK_LISTEN) { + spin_unlock_bh(&sta->plink_lock); + return -EBUSY; + } + 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", + print_mac(mac, sta->addr)); + + return mesh_plink_frame_tx(sdata->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 = PLINK_BLOCKED; + spin_unlock_bh(&sta->plink_lock); +} + +int mesh_plink_close(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + __le16 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 == 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 == 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 = PLINK_HOLDING; + llid = sta->llid; + plid = sta->plid; + spin_unlock_bh(&sta->plink_lock); + 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_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; + 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 + + 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); + + 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 == PLINK_BLOCKED) { + rcu_read_unlock(); + 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"); + rcu_read_unlock(); + return; + } + + rates = ieee80211_sta_get_rates(local, &elems, rx_status->band); + sta = mesh_plink_alloc(sdata, mgmt->sa, rates); + if (!sta) { + mpl_dbg("Mesh plink error: plink table full\n"); + rcu_read_unlock(); + return; + } + if (sta_info_insert(sta)) { + rcu_read_unlock(); + 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 == 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 + * 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); + rcu_read_unlock(); + 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 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 = PLINK_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 PLINK_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 = PLINK_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 = PLINK_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 = PLINK_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 PLINK_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 = PLINK_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: + del_timer(&sta->plink_timer); + 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", + print_mac(mac, sta->addr)); + break; + default: + spin_unlock_bh(&sta->plink_lock); + break; + } + break; + + case PLINK_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 = PLINK_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: + del_timer(&sta->plink_timer); + 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", + 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 PLINK_ESTAB: + switch (event) { + case CLS_ACPT: + reason = cpu_to_le16(MESH_CLOSE_RCVD); + sta->reason = reason; + __mesh_plink_deactivate(sta); + sta->plink_state = PLINK_HOLDING; + llid = sta->llid; + 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 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 PLINK_HOLDING: + switch (event) { + case CLS_ACPT: + if (del_timer(&sta->plink_timer)) + sta->ignore_plink_timer = 1; + 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, PLINK_BLOCKED is dealt with at the + * beggining of the function + */ + spin_unlock_bh(&sta->plink_lock); + break; + } + + rcu_read_unlock(); +} diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 3b77410588e7..a1993161de99 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -15,7 +15,7 @@ #include <linux/debugfs.h> #include <net/mac80211.h> #include "ieee80211_rate.h" - +#include "mesh.h" #include "rc80211_pid.h" @@ -63,6 +63,7 @@ * RC_PID_ARITH_SHIFT. */ + /* 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 @@ -72,14 +73,14 @@ 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; - int cur_sorted, new_sorted, probe, tmp, n_bitrates; - int cur = sta->txrate; - - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + struct ieee80211_supported_band *sband; + int cur_sorted, new_sorted, probe, tmp, n_bitrates, band; + int cur = sta->txrate_idx; - mode = local->oper_hw_mode; - n_bitrates = mode->num_rates; + sdata = sta->sdata; + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + band = sband->band; + n_bitrates = sband->n_bitrates; /* Map passed arguments to sorted values. */ cur_sorted = rinfo[cur].rev_index; @@ -97,20 +98,20 @@ static void rate_control_pid_adjust_rate(struct ieee80211_local *local, /* 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, mode, rinfo[probe].index)) + 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, mode, rinfo[probe].index)) + rate_supported(sta, band, rinfo[probe].index)) tmp = probe; } /* Fit the rate found to the nearest supported rate. */ do { - if (rate_supported(sta, mode, rinfo[tmp].index)) { - sta->txrate = rinfo[tmp].index; + if (rate_supported(sta, band, rinfo[tmp].index)) { + sta->txrate_idx = rinfo[tmp].index; break; } if (adj < 0) @@ -122,7 +123,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, - cur, mode->rates[cur].rate); + sta->txrate_idx, sband->bitrates[sta->txrate_idx].bitrate); #endif } @@ -147,9 +148,12 @@ 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 = sta->sdata; +#endif 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; @@ -158,7 +162,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 @@ -177,25 +181,32 @@ 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; 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; @@ -236,23 +247,27 @@ 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; + + 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 = sdata->bss->max_ratectrl_rateidx; - return; + sta->txrate_idx = sdata->bss->max_ratectrl_rateidx; + goto unlock; } /* 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]) - goto ignore; + if (status->control.tx_rate != &sband->bitrates[sta->txrate_idx]) + goto unlock; spinfo = sta->rate_ctrl_priv; spinfo->tx_num_xmit++; @@ -277,9 +292,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++; } @@ -293,12 +305,12 @@ 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, - struct ieee80211_hw_mode *mode, + struct ieee80211_supported_band *sband, struct sk_buff *skb, struct rate_selection *sel) { @@ -309,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 @@ -316,32 +330,31 @@ 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); - if (sta) - sta_info_put(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 = 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); + rcu_read_unlock(); - 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 } @@ -353,28 +366,33 @@ 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); + sta->fail_avg = 0; } 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; @@ -383,7 +401,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) @@ -391,11 +409,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 deleted file mode 100644 index 9a78b116acff..000000000000 --- a/net/mac80211/rc80211_simple.c +++ /dev/null @@ -1,400 +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 <linux/init.h> -#include <linux/netdevice.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/compiler.h> -#include <linux/module.h> - -#include <net/mac80211.h> -#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_hw_mode *mode; - int i = sta->txrate; - int maxrate; - - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); - if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { - /* forced unicast rate - do not change STA rate */ - return; - } - - mode = local->oper_hw_mode; - maxrate = sdata->bss ? sdata->bss->max_ratectrl_rateidx : -1; - - if (i > mode->num_rates) - i = mode->num_rates - 2; - - while (i + 1 < mode->num_rates) { - i++; - if (sta->supp_rates & BIT(i) && - mode->rates[i].flags & IEEE80211_RATE_SUPPORTED && - (maxrate < 0 || i <= maxrate)) { - sta->txrate = i; - break; - } - } -} - - -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; - - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); - if (sdata->bss && sdata->bss->force_unicast_rateidx > -1) { - /* forced unicast rate - do not change STA rate */ - return; - } - - mode = local->oper_hw_mode; - if (i > mode->num_rates) - i = mode->num_rates; - - while (i > 0) { - i--; - if (sta->supp_rates & BIT(i) && - mode->rates[i].flags & IEEE80211_RATE_SUPPORTED) { - sta->txrate = 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; - - sta = sta_info_get(local, hdr->addr1); - - if (!sta) - return; - - 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->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++; - } - 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.rate->rate; - 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 (srctrl->avg_rate_update + 60 * HZ < jiffies) { - 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; - } - } - - sta_info_put(sta); -} - - -static void -rate_control_simple_get_rate(void *priv, struct net_device *dev, - struct ieee80211_hw_mode *mode, - 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; - - 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, mode, sta); - if (sta) - sta_info_put(sta); - 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 = sdata->bss->force_unicast_rateidx; - - rateidx = sta->txrate; - - if (rateidx >= mode->num_rates) - rateidx = mode->num_rates - 1; - - sta->last_txrate = rateidx; - - sta_info_put(sta); - - sel->rate = &mode->rates[rateidx]; -} - - -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; - /* 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; - } - } -} - - -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 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 <linux/module.h> -#include <linux/netdevice.h> -#include <net/mac80211.h> -#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 535407d07fa4..0ac6db5c09ea 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -9,6 +9,7 @@ * published by the Free Software Foundation. */ +#include <linux/jiffies.h> #include <linux/kernel.h> #include <linux/skbuff.h> #include <linux/netdevice.h> @@ -19,6 +20,7 @@ #include "ieee80211_i.h" #include "ieee80211_led.h" +#include "mesh.h" #include "wep.h" #include "wpa.h" #include "tkip.h" @@ -82,10 +84,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 +196,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); @@ -226,6 +225,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) { @@ -249,15 +251,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_rx_data *rx) { u8 *data = rx->skb->data; int tid; @@ -268,9 +262,9 @@ ieee80211_rx_h_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 */ @@ -286,68 +280,19 @@ ieee80211_rx_h_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; - - return TXRX_CONTINUE; } - -static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, - struct sk_buff *skb, - struct ieee80211_rx_status *status) +static void ieee80211_verify_ip_alignment(struct ieee80211_rx_data *rx) { - 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)) - hdrtime = CHAN_UTIL_HDR_SHORT; - else - hdrtime = CHAN_UTIL_HDR_LONG; - - load = hdrtime; - if (!is_multicast_ether_addr(hdr->addr1)) - load += hdrtime; - - load += skb->len * rate->rate_inv; - - /* Divide channel_use by 8 to avoid wrapping around the counter */ - load >>= CHAN_UTIL_SHIFT; - - 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; + return; /* * Drivers are required to align the payload data in a way that @@ -369,83 +314,158 @@ ieee80211_rx_h_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); - - return TXRX_CONTINUE; -} #endif +} -ieee80211_rx_handler ieee80211_rx_pre_handlers[] = + +static u32 ieee80211_rx_load_stats(struct ieee80211_local *local, + struct sk_buff *skb, + struct ieee80211_rx_status *status, + struct ieee80211_rate *rate) { - ieee80211_rx_h_parse_qos, -#ifdef CONFIG_MAC80211_DEBUG_PACKET_ALIGNMENT - ieee80211_rx_h_verify_ip_alignment, -#endif - NULL -}; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + u32 load = 0, hdrtime; + + /* Estimate total channel use caused by this frame */ + + /* 1 bit at 1 Mbit/s takes 1 usec; in channel_use values, + * 1 usec = 1/8 * (1080 / 10) = 13.5 */ + + 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; + + load = hdrtime; + if (!is_multicast_ether_addr(hdr->addr1)) + load += hdrtime; + + /* 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; + + return load; +} /* rx handlers */ -static ieee80211_txrx_result -ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx) +static ieee80211_rx_result +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; - return TXRX_CONTINUE; + rx->sta->channel_use_raw += rx->load; + rx->sdata->channel_use_raw += rx->load; + return RX_CONTINUE; } -static ieee80211_txrx_result -ieee80211_rx_h_passive_scan(struct ieee80211_txrx_data *rx) +static ieee80211_rx_result +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) - != TXRX_QUEUED) + if (ieee80211_sta_rx_scan(rx->dev, skb, rx->status) + != RX_QUEUED) dev_kfree_skb(skb); - return TXRX_QUEUED; + 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 TXRX_DROP; + return RX_DROP_UNUSABLE; } - return TXRX_CONTINUE; + return RX_CONTINUE; +} + +static ieee80211_rx_result +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; + +#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))) + 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 || sta_plink_state(rx->sta) != PLINK_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_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 + + return RX_CONTINUE; } -static ieee80211_txrx_result -ieee80211_rx_h_check(struct ieee80211_txrx_data *rx) + +static ieee80211_rx_result +ieee80211_rx_h_check(struct ieee80211_rx_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) */ 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 TXRX_DROP; + 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)) { I802_DEBUG_INC(rx->local->rx_handlers_drop_short); - return TXRX_DROP; + return RX_DROP_MONITOR; } /* Drop disallowed frame classes based on STA auth/assoc state; @@ -456,6 +476,10 @@ 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. */ + + if (ieee80211_vif_is_mesh(&rx->sdata->vif)) + return ieee80211_rx_mesh_check(rx); + 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)) && @@ -464,26 +488,26 @@ 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 TXRX_DROP; + return RX_DROP_MONITOR; } - return TXRX_DROP; + return RX_DROP_MONITOR; } - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result -ieee80211_rx_h_decrypt(struct ieee80211_txrx_data *rx) +static ieee80211_rx_result +ieee80211_rx_h_decrypt(struct ieee80211_rx_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_UNUSABLE; struct ieee80211_key *stakey = NULL; /* @@ -513,14 +537,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; + if (!(rx->flags & IEEE80211_RX_RA_MATCH)) + return RX_CONTINUE; if (rx->sta) stakey = rcu_dereference(rx->sta->key); @@ -537,14 +561,14 @@ 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)) - return TXRX_CONTINUE; + if ((rx->status->flag & RX_FLAG_DECRYPTED) && + (rx->status->flag & RX_FLAG_IV_STRIPPED)) + return RX_CONTINUE; hdrlen = ieee80211_get_hdrlen(rx->fc); if (rx->skb->len < 8 + hdrlen) - return TXRX_DROP; /* TODO: count this? */ + return RX_DROP_UNUSABLE; /* TODO: count this? */ /* * no need to call ieee80211_wep_get_keyidx, @@ -573,14 +597,14 @@ 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_MONITOR; } /* 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++; @@ -597,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; } @@ -607,12 +631,12 @@ 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); 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); @@ -628,21 +652,21 @@ 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); - sta->flags &= ~(WLAN_STA_PS | WLAN_STA_TIM); - sta->pspoll = 0; - 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); - } + + sta->flags &= ~(WLAN_STA_PS | WLAN_STA_PSPOLL); + + 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; @@ -666,15 +690,15 @@ static int ap_sta_ps_end(struct net_device *dev, struct sta_info *sta) return sent; } -static ieee80211_txrx_result -ieee80211_rx_h_sta_process(struct ieee80211_txrx_data *rx) +static ieee80211_rx_result +ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) { struct sta_info *sta = rx->sta; struct net_device *dev = rx->dev; 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 @@ -690,24 +714,26 @@ 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; } - if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_CONTINUE; + 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); @@ -722,10 +748,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 * @@ -801,7 +827,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; } @@ -811,8 +837,8 @@ ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata, return NULL; } -static ieee80211_txrx_result -ieee80211_rx_h_defragment(struct ieee80211_txrx_data *rx) +static ieee80211_rx_result +ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr; u16 sc; @@ -838,27 +864,27 @@ 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 TXRX_QUEUED; + return RX_QUEUED; } /* This is a fragment for a frame that should already be pending in * 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 TXRX_DROP; + return RX_DROP_MONITOR; } /* Verify that MPDUs within one MSDU have sequential PN values. @@ -867,14 +893,14 @@ 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_UNUSABLE; memcpy(pn, entry->last_pn, CCMP_PN_LEN); for (i = CCMP_PN_LEN - 1; i >= 0; i--) { pn[i]++; 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 " @@ -885,7 +911,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_UNUSABLE; } memcpy(entry->last_pn, pn, CCMP_PN_LEN); } @@ -896,7 +922,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); @@ -906,7 +932,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_UNUSABLE; } } while ((skb = __skb_dequeue(&entry->skb_list))) { @@ -915,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) @@ -924,11 +950,11 @@ 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 -ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx) +static ieee80211_rx_result +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; @@ -938,12 +964,12 @@ 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))) - return TXRX_CONTINUE; + !(rx->flags & IEEE80211_RX_RA_MATCH))) + return RX_CONTINUE; if ((sdata->vif.type != IEEE80211_IF_TYPE_AP) && (sdata->vif.type != IEEE80211_IF_TYPE_VLAN)) - return TXRX_DROP; + return RX_DROP_UNUSABLE; skb = skb_dequeue(&rx->sta->tx_filtered); if (!skb) { @@ -958,9 +984,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", @@ -970,46 +998,45 @@ 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); - if (no_pending_pkts) { - 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); - } + 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. + * 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 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 -ieee80211_rx_h_remove_qos_control(struct ieee80211_txrx_data *rx) +static ieee80211_rx_result +ieee80211_rx_h_remove_qos_control(struct ieee80211_rx_data *rx) { u16 fc = rx->fc; u8 *data = rx->skb->data; 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); @@ -1018,17 +1045,17 @@ 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 -ieee80211_802_1x_port_control(struct ieee80211_txrx_data *rx) +ieee80211_802_1x_port_control(struct ieee80211_rx_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; } @@ -1037,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. */ @@ -1060,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; @@ -1082,6 +1109,21 @@ ieee80211_data_to_8023(struct ieee80211_txrx_data *rx) hdrlen = ieee80211_get_hdrlen(fc); + if (ieee80211_vif_is_mesh(&sdata->vif)) { + 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; + } + /* convert IEEE 802.11 header + possible LLC headers into Ethernet * header * IEEE 802.11 address fields: @@ -1115,9 +1157,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), @@ -1192,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 }; @@ -1218,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; @@ -1232,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 @@ -1244,7 +1287,7 @@ ieee80211_deliver_skb(struct ieee80211_txrx_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 @@ -1254,8 +1297,38 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) xmit_skb = skb; skb = NULL; } - if (dsta) - sta_info_put(dsta); + } + } + + /* Mesh forwarding */ + if (ieee80211_vif_is_mesh(&sdata->vif)) { + 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 + 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) { + IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.sta, + 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; + } } } @@ -1275,8 +1348,8 @@ ieee80211_deliver_skb(struct ieee80211_txrx_data *rx) } } -static ieee80211_txrx_result -ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) +static ieee80211_rx_result +ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->dev; struct ieee80211_local *local = rx->local; @@ -1291,17 +1364,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_MONITOR; - if (!(rx->flags & IEEE80211_TXRXD_RX_AMSDU)) - return TXRX_CONTINUE; + if (!(rx->flags & IEEE80211_RX_AMSDU)) + return RX_CONTINUE; err = ieee80211_data_to_8023(rx); if (unlikely(err)) - return TXRX_DROP; + return RX_DROP_UNUSABLE; skb->dev = dev; @@ -1311,7 +1384,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_UNUSABLE; while (skb != frame) { u8 padding; @@ -1326,7 +1399,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_UNUSABLE; } skb_pull(skb, sizeof(struct ethhdr)); @@ -1338,7 +1411,7 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) subframe_len); if (frame == NULL) - return TXRX_DROP; + return RX_DROP_UNUSABLE; skb_reserve(frame, local->hw.extra_tx_headroom + sizeof(struct ethhdr)); @@ -1351,7 +1424,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_UNUSABLE; } } @@ -1381,7 +1454,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_UNUSABLE; dev_kfree_skb(frame); continue; } @@ -1389,11 +1462,11 @@ ieee80211_rx_h_amsdu(struct ieee80211_txrx_data *rx) ieee80211_deliver_skb(rx); } - return TXRX_QUEUED; + return RX_QUEUED; } -static ieee80211_txrx_result -ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) +static ieee80211_rx_result +ieee80211_rx_h_data(struct ieee80211_rx_data *rx) { struct net_device *dev = rx->dev; u16 fc; @@ -1401,17 +1474,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_MONITOR; err = ieee80211_data_to_8023(rx); if (unlikely(err)) - return TXRX_DROP; + return RX_DROP_UNUSABLE; if (!ieee80211_frame_allowed(rx)) - return TXRX_DROP; + return RX_DROP_MONITOR; rx->skb->dev = dev; @@ -1420,11 +1493,11 @@ ieee80211_rx_h_data(struct ieee80211_txrx_data *rx) ieee80211_deliver_skb(rx); - return TXRX_QUEUED; + return RX_QUEUED; } -static ieee80211_txrx_result -ieee80211_rx_h_ctrl(struct ieee80211_txrx_data *rx) +static ieee80211_rx_result +ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) { struct ieee80211_local *local = rx->local; struct ieee80211_hw *hw = &local->hw; @@ -1435,15 +1508,16 @@ 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; + 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; @@ -1460,77 +1534,35 @@ 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_UNUSABLE; } - return TXRX_CONTINUE; + return RX_CONTINUE; } -static ieee80211_txrx_result -ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx) +static ieee80211_rx_result +ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) { struct ieee80211_sub_if_data *sdata; - if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) - return TXRX_DROP; + if (!(rx->flags & IEEE80211_RX_RA_MATCH)) + return RX_DROP_MONITOR; 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); + ieee80211_sta_rx_mgmt(rx->dev, rx->skb, rx->status); else - return TXRX_DROP; + return RX_DROP_MONITOR; - return TXRX_QUEUED; -} - -static inline ieee80211_txrx_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; - - for (handler = handlers; *handler != NULL; handler++) { - res = (*handler)(rx); - - switch (res) { - case TXRX_CONTINUE: - continue; - case TXRX_DROP: - I802_DEBUG_INC(local->rx_handlers_drop); - if (sta) - sta->rx_dropped++; - break; - case TXRX_QUEUED: - I802_DEBUG_INC(local->rx_handlers_queued); - break; - } - break; - } - - if (res == TXRX_DROP) - 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) == - TXRX_CONTINUE) - dev_kfree_skb(rx->skb); + return RX_QUEUED; } static void ieee80211_rx_michael_mic_report(struct net_device *dev, struct ieee80211_hdr *hdr, - struct sta_info *sta, - struct ieee80211_txrx_data *rx) + struct ieee80211_rx_data *rx) { int keyidx, hdrlen; DECLARE_MAC_BUF(mac); @@ -1548,7 +1580,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. @@ -1600,7 +1632,89 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, rx->skb = NULL; } -ieee80211_rx_handler ieee80211_rx_handlers[] = +/* 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; + 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->status; + + if (rx->flags & IEEE80211_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->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_RX_CMNTR_REPORTED; + return; + + out_free_skb: + dev_kfree_skb(skb); +} + +typedef ieee80211_rx_result (*ieee80211_rx_handler)(struct ieee80211_rx_data *); +static ieee80211_rx_handler ieee80211_rx_handlers[] = { ieee80211_rx_h_if_stats, ieee80211_rx_h_passive_scan, @@ -1622,10 +1736,51 @@ ieee80211_rx_handler ieee80211_rx_handlers[] = NULL }; +static void ieee80211_invoke_rx_handlers(struct ieee80211_sub_if_data *sdata, + struct ieee80211_rx_data *rx, + 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); + + switch (res) { + case RX_CONTINUE: + continue; + case RX_DROP_UNUSABLE: + case RX_DROP_MONITOR: + I802_DEBUG_INC(sdata->local->rx_handlers_drop); + if (rx->sta) + rx->sta->rx_dropped++; + break; + case RX_QUEUED: + I802_DEBUG_INC(sdata->local->rx_handlers_queued); + break; + } + break; + } + + switch (res) { + case RX_CONTINUE: + case RX_DROP_MONITOR: + ieee80211_rx_cooked_monitor(rx); + break; + case RX_DROP_UNUSABLE: + dev_kfree_skb(rx->skb); + break; + } +} + /* 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); @@ -1635,34 +1790,47 @@ 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: if (!bssid) return 0; - if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) { - if (!(rx->flags & IEEE80211_TXRXD_RXIN_SCAN)) + 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_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); 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_RX_RA_MATCH; + } + break; case IEEE80211_IF_TYPE_VLAN: case IEEE80211_IF_TYPE_AP: if (!bssid) { @@ -1671,12 +1839,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; @@ -1707,13 +1875,13 @@ 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; - struct sta_info *sta; 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; @@ -1725,42 +1893,33 @@ 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.status = status; + rx.load = load; + rx.rate = rate; rx.fc = le16_to_cpu(hdr->frame_control); type = rx.fc & IEEE80211_FCTL_FTYPE; if (type == IEEE80211_FTYPE_DATA || type == IEEE80211_FTYPE_MGMT) local->dot11ReceivedFragmentCount++; - sta = rx.sta = sta_info_get(local, hdr->addr2); - if (sta) { - rx.dev = rx.sta->dev; - rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev); + rx.sta = sta_info_get(local, hdr->addr2); + if (rx.sta) { + 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, sta, &rx); - goto end; + ieee80211_rx_michael_mic_report(local->mdev, hdr, &rx); + return; } if (unlikely(local->sta_sw_scanning || local->sta_hw_scanning)) - rx.flags |= IEEE80211_TXRXD_RXIN_SCAN; + rx.flags |= IEEE80211_RX_IN_SCAN; - if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx, - sta) != TXRX_CONTINUE) - goto end; - skb = rx.skb; + ieee80211_parse_qos(&rx); + ieee80211_verify_ip_alignment(&rx); - 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; - } + skb = rx.skb; list_for_each_entry_rcu(sdata, &local->interfaces, list) { if (!netif_running(sdata->dev)) @@ -1770,10 +1929,8 @@ 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); - /* prepare_for_handlers can change sta */ - sta = rx.sta; if (!prepares) continue; @@ -1804,26 +1961,14 @@ 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, local->rx_handlers, - &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, local->rx_handlers, - &rx, sta); + ieee80211_invoke_rx_handlers(prev, &rx, skb); } else dev_kfree_skb(skb); - - end: - if (sta) - sta_info_put(sta); } #define SEQ_MODULO 0x1000 @@ -1859,6 +2004,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; @@ -1889,12 +2036,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; } @@ -1934,11 +2083,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); @@ -1973,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; @@ -1994,7 +2146,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; @@ -2004,9 +2156,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; } @@ -2019,6 +2169,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 @@ -2033,17 +2202,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 1f74bd296357..7e1e87257647 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -15,21 +15,59 @@ #include <linux/skbuff.h> #include <linux/if_arp.h> #include <linux/timer.h> +#include <linux/rtnetlink.h> #include <net/mac80211.h> #include "ieee80211_i.h" #include "ieee80211_rate.h" #include "sta_info.h" #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. + * + * 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. 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, 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 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. + * + * 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, @@ -41,237 +79,464 @@ 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; } -struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) +/* protected by RCU */ +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)]; + sta = rcu_dereference(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; + sta = rcu_dereference(sta->hnext); } - read_unlock_bh(&local->sta_lock); - return sta; } + +struct sta_info *sta_info_get(struct ieee80211_local *local, u8 *addr) +{ + return __sta_info_find(local, addr); +} EXPORT_SYMBOL(sta_info_get); -int sta_info_min_txrate_get(struct ieee80211_local *local) +struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, + struct net_device *dev) { 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; + 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; } + return sta; } - read_unlock_bh(&local->sta_lock); - if (min_txrate == 9999999) - min_txrate = 0; - return mode->rates[min_txrate].rate; + 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 */ -static void sta_info_release(struct kref *kref) + kfree(sta); +} + +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 ieee80211_local *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(); + + if (!sta) + return; + + local = sta->local; + + 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 + + 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)) + 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++) { + 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); } - for (i = 0; i < STA_TID_NUM; i++) - del_timer_sync(&sta->ampdu_mlme.tid_rx[i].session_timer); - rate_control_free_sta(sta->rate_ctrl, sta->rate_ctrl_priv); - rate_control_put(sta->rate_ctrl); - kfree(sta); + + __sta_info_free(local, 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_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); + DECLARE_MAC_BUF(mbuf); sta = kzalloc(sizeof(*sta), gfp); if (!sta) return NULL; - 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); if (!sta->rate_ctrl_priv) { rate_control_put(sta->rate_ctrl); kfree(sta); return NULL; } - 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++) { /* 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; - /* 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); + /* tid to tx queue: initialize according to HW (0 is valid) */ + sta->tid_to_tx_q[i] = local->hw.queues; + /* 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); - __sta_info_get(sta); /* sta used by caller, decremented by - * sta_info_put() */ - write_lock_bh(&local->sta_lock); + +#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 */ + +#ifdef CONFIG_MAC80211_MESH + sta->plink_state = PLINK_LISTEN; + spin_lock_init(&sta->plink_lock); + init_timer(&sta->plink_timer); +#endif + + 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; + int err = 0; + DECLARE_MAC_BUF(mac); + + /* + * 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))) { + err = -ENETDOWN; + goto out_free; + } + + 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); + err = -EEXIST; + goto out_free; + } 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); + STA_NOTIFY_ADD, sta->addr); } - write_unlock_bh(&local->sta_lock); #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 + /* + * 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 - return sta; + if (ieee80211_vif_is_mesh(&sdata->vif)) + mesh_accept_plinks_update(sdata); + + return 0; + out_free: + BUG_ON(!err); + __sta_info_free(local, sta); + return err; } -/* Caller must hold local->sta_lock */ -void sta_info_remove(struct sta_info *sta) +static inline void __bss_tim_set(struct ieee80211_if_ap *bss, u16 aid) { - struct ieee80211_local *local = sta->local; - struct ieee80211_sub_if_data *sdata; + /* + * 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)); +} - /* don't do anything if we've been removed already */ - if (sta_info_hash_del(local, sta)) - return; +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)); +} - 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); +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->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; } - local->num_sta--; - sta_info_remove_aid_ptr(sta); +} +void sta_info_set_tim_bit(struct sta_info *sta) +{ + unsigned long flags; + + 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); } -void sta_info_free(struct sta_info *sta) +static void __sta_info_clear_tim_bit(struct ieee80211_if_ap *bss, + struct sta_info *sta) { - struct sk_buff *skb; - struct ieee80211_local *local = sta->local; - DECLARE_MAC_BUF(mac); + if (bss) + __bss_tim_clear(bss, sta->aid); + 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; + } +} - might_sleep(); +void sta_info_clear_tim_bit(struct sta_info *sta) +{ + unsigned long flags; - write_lock_bh(&local->sta_lock); - sta_info_remove(sta); - write_unlock_bh(&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); +} - 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); - } +/* + * 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; + struct ieee80211_sub_if_data *sdata = (*sta)->sdata; #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 */ + DECLARE_MAC_BUF(mbuf); +#endif + /* + * pull caller's reference if we're already gone. + */ + if (sta_info_hash_del(local, *sta)) { + *sta = NULL; + return; + } - ieee80211_key_free(sta->key); - sta->key = NULL; + /* + * 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 (local->ops->sta_notify) { - struct ieee80211_sub_if_data *sdata; + 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--; + + 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, @@ -299,6 +564,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)) @@ -307,21 +573,23 @@ 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 = sta->sdata; + 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)) + sta_info_clear_tim_bit(sta); } } @@ -331,13 +599,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); @@ -345,38 +610,75 @@ 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); + rtnl_lock(); + sta_info_destroy(sta); + rtnl_unlock(); } } #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) { - rwlock_init(&local->sta_lock); + 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); @@ -384,7 +686,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 } @@ -397,47 +699,80 @@ 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(); } -void sta_info_remove_aid_ptr(struct sta_info *sta) +/** + * 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 + */ +int sta_info_flush(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) { - struct ieee80211_sub_if_data *sdata; + struct sta_info *sta, *tmp; + LIST_HEAD(tmp_list); + int ret = 0; + unsigned long flags; - if (sta->aid <= 0) - return; + might_sleep(); + ASSERT_RTNL(); + + 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); + ret++; + } + } + } + spin_unlock_irqrestore(&local->sta_lock, flags); - sdata = IEEE80211_DEV_TO_SUB_IF(sta->dev); + list_for_each_entry_safe(sta, tmp, &tmp_list, list) + sta_info_destroy(sta); - 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); + return ret; } - /** - * 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 + * 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(struct ieee80211_local *local, struct net_device *dev) +void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata) { + struct ieee80211_local *local = sdata->local; struct sta_info *sta, *tmp; - LIST_HEAD(tmp_list); - - 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); + 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; + } } - write_unlock_bh(&local->sta_lock); - - list_for_each_entry_safe(sta, tmp, &tmp_list, list) { - sta_info_free(sta); - sta_info_put(sta); } + 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 96fe3ed95038..ebb7b2b4d0b9 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -12,160 +12,293 @@ #include <linux/list.h> #include <linux/types.h> #include <linux/if_ether.h> -#include <linux/kref.h> #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_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. + * @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, + WLAN_STA_ASSOC = 1<<1, + WLAN_STA_PS = 1<<2, + 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, + WLAN_STA_CLEAR_PS_FILT = 1<<9, +}; #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) +#define HT_AGG_STATE_DEBUGFS_CTL BIT(7) /** - * struct tid_ampdu_rx - TID aggregation information (Rx). + * struct tid_ampdu_tx - TID aggregation information (Tx). * - * @state: TID's state in session state machine. + * @addba_resp_timer: timer for peer's response to addba request + * @ssn: Starting Sequence Number expected to be aggregated. * @dialog_token: dialog token for aggregation session + */ +struct tid_ampdu_tx { + struct timer_list addba_resp_timer; + u16 ssn; + u8 dialog_token; +}; + +/** + * struct tid_ampdu_rx - TID aggregation information (Rx). + * + * @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. - * @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) + * @dialog_token: dialog token for aggregation session */ struct tid_ampdu_rx { - u8 state; - u8 dialog_token; + 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; - u16 head_seq_num; - u16 stored_mpdu_num; - struct sk_buff **reorder_buf; - struct timer_list session_timer; + u8 dialog_token; +}; + +/** + * 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 { + PLINK_LISTEN, + PLINK_OPN_SNT, + PLINK_OPN_RCVD, + PLINK_CNF_RCVD, + PLINK_ESTAB, + PLINK_HOLDING, + PLINK_BLOCKED }; /** * struct sta_ampdu_mlme - STA aggregation information. * - * @tid_agg_info_rx: aggregation info for Rx per TID + * @tid_state_rx: TID's state in Rx session state machine. + * @tid_rx: aggregation info for Rx 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]; + /* 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; }; + +/* 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 - 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 { - struct kref kref; + /* 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 */ - 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 */ - 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; - unsigned long tx_filtered_count; - - 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; - - struct net_device *dev; /* which net device is this station associated - * 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 last_ack_rssi[3]; /* RSSI of last received ACKs from this STA */ - unsigned long last_ack; - 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; - struct ieee80211_ht_info ht_info; /* 802.11n HT capabilities - of this STA */ + /* + * Aggregation information, comes with own locking. + */ 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 + * TODO: move to a sub-structure that is referenced with pointer? + */ + __le16 llid; /* Local link ID */ + __le16 plid; /* Peer link ID */ + __le16 reason; /* Cancel reason on PLINK_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; + 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 { 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 struct dentry *wme_rx_queue; struct dentry *wme_tx_queue; #endif + struct dentry *agg_status; } debugfs; #endif }; +static inline enum plink_state sta_plink_state(struct sta_info *sta) +{ +#ifdef CONFIG_MAC80211_MESH + return sta->plink_state; +#endif + return PLINK_LISTEN; +} + /* Maximum number of concurrently registered stations */ #define MAX_STA_COUNT 2007 @@ -185,22 +318,47 @@ struct sta_info { */ #define STA_INFO_CLEANUP_INTERVAL (10 * HZ) -static inline void __sta_info_get(struct sta_info *sta) -{ - kref_get(&sta->kref); -} +/* + * 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); +/* + * Create a new STA info, caller owns returned structure + * until sta_info_insert(). + */ +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 + * 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); +void sta_info_clear_tim_bit(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); -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_remove_aid_ptr(struct sta_info *sta); -void sta_info_flush(struct ieee80211_local *local, struct net_device *dev); +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 */ diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 3abe194e4d55..45d59f19c29f 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 @@ -238,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; @@ -315,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/tx.c b/net/mac80211/tx.c index 67b509edd431..80f4343a3007 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -26,6 +26,7 @@ #include "ieee80211_i.h" #include "ieee80211_led.h" +#include "mesh.h" #include "wep.h" #include "wpa.h" #include "wme.h" @@ -86,15 +87,19 @@ 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_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 +155,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 +205,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); } @@ -212,8 +233,8 @@ static int inline is_ieee80211_device(struct net_device *dev, /* tx handlers */ -static ieee80211_txrx_result -ieee80211_tx_h_check_assoc(struct ieee80211_txrx_data *tx) +static ieee80211_tx_result +ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG struct sk_buff *skb = tx->skb; @@ -221,20 +242,23 @@ 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)) - return TXRX_CONTINUE; + if (unlikely(tx->flags & IEEE80211_TX_INJECTED)) + 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; + if (tx->sdata->vif.type == IEEE80211_IF_TYPE_MESH_POINT) + return TX_CONTINUE; + + 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)) { @@ -245,7 +269,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 && @@ -255,23 +279,23 @@ 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 -ieee80211_tx_h_sequence(struct ieee80211_txrx_data *tx) +static ieee80211_tx_result +ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; 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 @@ -303,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++; @@ -314,15 +336,16 @@ 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", wiphy_name(local->hw.wiphy), purged); } -static ieee80211_txrx_result -ieee80211_tx_h_multicast_ps_buf(struct ieee80211_txrx_data *tx) +static ieee80211_tx_result +ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) { /* * broadcast/multicast frame @@ -334,11 +357,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) { @@ -355,17 +378,17 @@ 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; + tx->control->flags |= IEEE80211_TXCTL_SEND_AFTER_DTIM; - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result -ieee80211_tx_h_unicast_ps_buf(struct ieee80211_txrx_data *tx) +static ieee80211_tx_result +ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) { struct sta_info *sta = tx->sta; DECLARE_MAC_BUF(mac); @@ -373,9 +396,10 @@ 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)) { + 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 " @@ -383,7 +407,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) { @@ -396,18 +419,15 @@ 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->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); - } + 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); - return TXRX_QUEUED; + return TX_QUEUED; } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG else if (unlikely(sta->flags & WLAN_STA_PS)) { @@ -416,40 +436,40 @@ 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 TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result -ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx) +static ieee80211_tx_result +ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx) { - if (unlikely(tx->flags & IEEE80211_TXRXD_TXPS_BUFFERED)) - return TXRX_CONTINUE; + 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_txrx_result -ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) +static ieee80211_tx_result +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 TXRX_DROP; + return TX_DROP; } else tx->key = NULL; @@ -476,13 +496,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 TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result -ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) +static ieee80211_tx_result +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; @@ -492,8 +512,8 @@ ieee80211_tx_h_fragment(struct ieee80211_txrx_data *tx) u8 *pos; int frag_threshold = tx->local->fragmentation_threshold; - if (!(tx->flags & IEEE80211_TXRXD_FRAGMENTED)) - return TXRX_CONTINUE; + if (!(tx->flags & IEEE80211_TX_FRAGMENTED)) + return TX_CONTINUE; first = tx->skb; @@ -544,10 +564,10 @@ 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 TXRX_CONTINUE; + return TX_CONTINUE; fail: printk(KERN_DEBUG "%s: failed to fragment frame\n", tx->dev->name); @@ -558,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 -ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) +static ieee80211_tx_result +ieee80211_tx_h_encrypt(struct ieee80211_tx_data *tx) { if (!tx->key) - return TXRX_CONTINUE; + return TX_CONTINUE; switch (tx->key->conf.alg) { case ALG_WEP: @@ -578,59 +598,60 @@ ieee80211_tx_h_encrypt(struct ieee80211_txrx_data *tx) /* not reached */ WARN_ON(1); - return TXRX_DROP; + return TX_DROP; } -static ieee80211_txrx_result -ieee80211_tx_h_rate_ctrl(struct ieee80211_txrx_data *tx) +static ieee80211_tx_result +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)) { - rate_control_get_rate(tx->dev, tx->u.tx.mode, tx->skb, &rsel); - tx->u.tx.rate = rsel.rate; - if (unlikely(rsel.probe != NULL)) { - tx->u.tx.control->flags |= + if (likely(!tx->rate)) { + rate_control_get_rate(tx->dev, sband, tx->skb, &rsel); + tx->rate = rsel.rate; + if (unlikely(rsel.probe)) { + 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.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 = -1; + tx->control->alt_retry_rate = NULL; - if (!tx->u.tx.rate) - return TXRX_DROP; + if (!tx->rate) + return TX_DROP; } else - tx->u.tx.control->alt_retry_rate = -1; + tx->control->alt_retry_rate = NULL; - if (tx->u.tx.mode->mode == MODE_IEEE80211G && - 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 (tx->sdata->bss_conf.use_cts_prot && + (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->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->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->val; + tx->control->tx_rate = tx->rate; - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result -ieee80211_tx_h_misc(struct ieee80211_txrx_data *tx) +static ieee80211_tx_result +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_hw_mode *mode = tx->u.tx.mode; + struct ieee80211_tx_control *control = tx->control; if (!control->retry_limit) { if (!is_multicast_ether_addr(hdr->addr1)) { @@ -652,20 +673,20 @@ 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 * 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) && - (tx->flags & IEEE80211_TXRXD_TXUNICAST) && + if ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && + (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; @@ -674,62 +695,76 @@ 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->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->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) || (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--; + rate = tx->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) { 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; } } } - return TXRX_CONTINUE; + return TX_CONTINUE; } -static ieee80211_txrx_result -ieee80211_tx_h_load_stats(struct ieee80211_txrx_data *tx) +static ieee80211_tx_result +ieee80211_tx_h_load_stats(struct ieee80211_tx_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->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->channel->band == IEEE80211_BAND_5GHZ || + (tx->channel->band == IEEE80211_BAND_2GHZ && + rate->flags & IEEE80211_RATE_ERP_G)) hdrtime = CHAN_UTIL_HDR_SHORT; else hdrtime = CHAN_UTIL_HDR_LONG; @@ -751,19 +786,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; - 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) { + 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->rate; + load += tx->extra_frag[i]->len * + tx->rate->bitrate; } } @@ -774,13 +810,12 @@ 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 - * into ordered list */ -ieee80211_tx_handler ieee80211_tx_handlers[] = +typedef ieee80211_tx_result (*ieee80211_tx_handler)(struct ieee80211_tx_data *); +static ieee80211_tx_handler ieee80211_tx_handlers[] = { ieee80211_tx_h_check_assoc, ieee80211_tx_h_sequence, @@ -801,8 +836,8 @@ 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 -__ieee80211_parse_tx_radiotap(struct ieee80211_txrx_data *tx, +static ieee80211_tx_result +__ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, struct sk_buff *skb) { /* @@ -816,13 +851,15 @@ __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; + 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 @@ -852,11 +889,13 @@ __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; + + r = &sband->bitrates[i]; - if (r->rate == target_rate) { - tx->u.tx.rate = r; + if (r->bitrate == target_rate) { + tx->rate = r; break; } } @@ -870,9 +909,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) { @@ -884,7 +925,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); } @@ -892,7 +933,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; /* @@ -907,7 +948,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 @@ -916,14 +957,14 @@ __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 -__ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, +static ieee80211_tx_result +__ieee80211_tx_prepare(struct ieee80211_tx_data *tx, struct sk_buff *skb, struct net_device *dev, struct ieee80211_tx_control *control) @@ -939,18 +980,18 @@ __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); 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 @@ -965,27 +1006,27 @@ __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) - 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); @@ -995,13 +1036,13 @@ __ieee80211_tx_prepare(struct ieee80211_txrx_data *tx, } control->flags |= IEEE80211_TXCTL_FIRST_FRAGMENT; - return TXRX_CONTINUE; + return TX_CONTINUE; } /* * 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) @@ -1024,9 +1065,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) && @@ -1043,20 +1084,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_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]) + 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_hwrate; - control->rate = tx->u.tx.last_frag_rate; - if (tx->flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG) + if (i == tx->num_extra_frag) { + control->tx_rate = tx->last_frag_rate; + + if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG) control->flags |= IEEE80211_TXCTL_RATE_CTRL_PROBE; else @@ -1066,18 +1107,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; } @@ -1088,8 +1129,8 @@ 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; - ieee80211_txrx_result res = TXRX_DROP, res_prepare; + struct ieee80211_tx_data tx; + ieee80211_tx_result res = TX_DROP, res_prepare; int ret, i; WARN_ON(__ieee80211_queue_pending(local, control->queue)); @@ -1099,59 +1140,52 @@ 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 == TXRX_DROP) { + 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.u.tx.mode = local->hw.conf.mode; + 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 != TXRX_CONTINUE) + if (res != TX_CONTINUE) break; } skb = tx.skb; /* handlers are allowed to change 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; } - 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.u.tx.last_frag_hwrate = tx.u.tx.rate->val; + tx.rate = tx.last_frag_rate; } dur = ieee80211_duration(&tx, 0, next_len); hdr->duration_id = cpu_to_le16(dur); @@ -1186,12 +1220,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_hwrate = tx.u.tx.last_frag_hwrate; - 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; @@ -1199,10 +1232,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; } @@ -1260,6 +1293,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); @@ -1346,8 +1381,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; @@ -1389,6 +1425,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 */ @@ -1409,10 +1476,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)) { + rcu_read_lock(); + sta = sta_info_get(local, hdr.addr1); + if (sta) + sta_flags = sta->flags; + rcu_read_unlock(); } /* receiver is QoS enabled, use a QoS type frame */ @@ -1422,12 +1496,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. + * Drop unicast frames to unauthorised stations unless they are + * EAPOL frames from the local station. */ - if (unlikely(sdata->ieee802_1x_pac && - !(sta_flags & WLAN_STA_AUTHORIZED) && - !(ethertype == ETH_P_PAE && + if (unlikely(!is_multicast_ether_addr(hdr.addr1) && + !(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 @@ -1480,7 +1554,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 @@ -1514,6 +1588,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; @@ -1583,7 +1663,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); @@ -1595,14 +1675,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_hwrate = store->last_frag_hwrate; - 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) @@ -1636,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 */ @@ -1687,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, @@ -1701,16 +1778,96 @@ 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; + struct ieee80211_mgmt *mgmt; + int *num_beacons; + bool err = true; + u8 *pos; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; rcu_read_lock(); sdata = vif_to_sdata(vif); bdev = sdata->dev; - ap = &sdata->u.ap; - beacon = rcu_dereference(ap->beacon); + if (sdata->vif.type == IEEE80211_IF_TYPE_AP) { + ap = &sdata->u.ap; + beacon = rcu_dereference(ap->beacon); + 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; + + 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); + + /* + * 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), + beacon->tail, beacon->tail_len); - if (!ap || sdata->vif.type != IEEE80211_IF_TYPE_AP || !beacon) { + num_beacons = &ap->num_beacons; + + 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); + + num_beacons = &sdata->u.sta.num_beacons; + + err = false; + } + + if (err) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "no beacon data avail for %s\n", @@ -1720,27 +1877,8 @@ 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, 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: " @@ -1753,20 +1891,17 @@ 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; + control->flags |= IEEE80211_TXCTL_CLEAR_PS_FILT; } - - ap->num_beacons++; - - out: + (*num_beacons)++; +out: rcu_read_unlock(); return skb; } @@ -1814,8 +1949,8 @@ 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; - ieee80211_txrx_result res = TXRX_DROP; + struct ieee80211_tx_data tx; + ieee80211_tx_result res = TX_DROP; struct net_device *bdev; struct ieee80211_sub_if_data *sdata; struct ieee80211_if_ap *bss = NULL; @@ -1836,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 */ @@ -1862,27 +1996,26 @@ 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.mode = local->hw.conf.mode; + tx.flags |= IEEE80211_TX_PS_BUFFERED; + 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 == 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; } - if (sta) - sta_info_put(sta); + rcu_read_unlock(); return skb; } diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 5e631ce98d7e..57c404f3f6d0 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -26,6 +26,7 @@ #include "ieee80211_i.h" #include "ieee80211_rate.h" +#include "mesh.h" #include "wme.h" /* privid for wiphys to determine whether they belong to us or not */ @@ -41,92 +42,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) { @@ -232,17 +147,35 @@ int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb) } EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb); -void ieee80211_tx_set_iswep(struct ieee80211_txrx_data *tx) +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; + } +} + +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); } } @@ -262,7 +195,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 +237,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 +269,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 +303,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 +321,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); @@ -480,6 +401,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) diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index a0cff72a580b..affcecd78c10 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -305,39 +305,39 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) return NULL; } -ieee80211_txrx_result -ieee80211_crypto_wep_decrypt(struct ieee80211_txrx_data *rx) +ieee80211_rx_result +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 TXRX_CONTINUE; + 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()) printk(KERN_DEBUG "%s: RX WEP frame, decrypt " "failed\n", rx->dev->name); #endif /* CONFIG_MAC80211_DEBUG */ - return TXRX_DROP; + 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); } - return TXRX_CONTINUE; + 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; @@ -346,28 +346,28 @@ static int wep_encrypt_skb(struct ieee80211_txrx_data *tx, struct sk_buff *skb) return 0; } -ieee80211_txrx_result -ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx) +ieee80211_tx_result +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 TXRX_DROP; + 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 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..9f723938b63f 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_crypto_wep_decrypt(struct ieee80211_txrx_data *rx); -ieee80211_txrx_result -ieee80211_crypto_wep_encrypt(struct ieee80211_txrx_data *tx); +ieee80211_rx_result +ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx); +ieee80211_tx_result +ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx); #endif /* WEP_H */ diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 4e236599dd31..4e94e4026e78 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[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]; @@ -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,26 @@ 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; + rcu_read_lock(); + 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; + } + } + rcu_read_unlock(); + skb_queue_tail(&q->requeued[queue], skb); qd->q.qlen++; return 0; } @@ -159,14 +178,31 @@ 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; + + rcu_read_lock(); + + 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; + } + } + + rcu_read_unlock(); } if (unlikely(queue >= local->hw.queues)) { @@ -184,6 +220,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 +272,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 +398,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 +647,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", + i, tid, print_mac(mac, sta->addr), + q->qdisc_pool[0]); +#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; diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 6f04311cf0a0..45709ada8fee 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -70,8 +70,8 @@ static int ieee80211_get_hdr_info(const struct sk_buff *skb, u8 **sa, u8 **da, } -ieee80211_txrx_result -ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx) +ieee80211_tx_result +ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) { u8 *data, *sa, *da, *key, *mic, qos_tid; size_t data_len; @@ -84,18 +84,18 @@ 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) && + !(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 */ - 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,12 +119,12 @@ 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_h_michael_mic_verify(struct ieee80211_txrx_data *rx) +ieee80211_rx_result +ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) { u8 *data, *sa, *da, *key = NULL, qos_tid; size_t data_len; @@ -139,16 +139,16 @@ 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; + if (rx->status->flag & RX_FLAG_MMIC_STRIPPED) + 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_UNUSABLE; data_len -= MICHAEL_MIC_LEN; @@ -161,29 +161,29 @@ 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)) - return TXRX_DROP; + if (!(rx->flags & IEEE80211_RX_RA_MATCH)) + 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 TXRX_DROP; + return RX_DROP_UNUSABLE; } /* remove Michael MIC from payload */ 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 TXRX_CONTINUE; + 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; } @@ -242,42 +242,42 @@ static int tkip_encrypt_skb(struct ieee80211_txrx_data *tx, } -ieee80211_txrx_result -ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx) +ieee80211_tx_result +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; - return TXRX_CONTINUE; + tx->control->key_idx = tx->key->conf.hw_key_idx; + return TX_CONTINUE; } if (tkip_encrypt_skb(tx, skb, test) < 0) - return TXRX_DROP; + 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 TXRX_DROP; + return TX_DROP; } } - return TXRX_CONTINUE; + return TX_CONTINUE; } -ieee80211_txrx_result -ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx) +ieee80211_rx_result +ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; u16 fc; @@ -290,19 +290,19 @@ 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_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 * we cannot do any checks here. */ - return TXRX_CONTINUE; + return RX_CONTINUE; } /* let TKIP code verify IV, but skip decryption */ @@ -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); + hdr->addr1, hwaccel, rx->queue, + &rx->tkip_iv32, + &rx->tkip_iv16); if (res != TKIP_DECRYPT_OK || wpa_test) { #ifdef CONFIG_MAC80211_DEBUG if (net_ratelimit()) @@ -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_UNUSABLE; } /* 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; } @@ -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; } @@ -491,42 +491,42 @@ static int ccmp_encrypt_skb(struct ieee80211_txrx_data *tx, } -ieee80211_txrx_result -ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx) +ieee80211_tx_result +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; - return TXRX_CONTINUE; + tx->control->key_idx = tx->key->conf.hw_key_idx; + return TX_CONTINUE; } if (ccmp_encrypt_skb(tx, skb, test) < 0) - return TXRX_DROP; + 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 TXRX_DROP; + return TX_DROP; } } - return TXRX_CONTINUE; + return TX_CONTINUE; } -ieee80211_txrx_result -ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx) +ieee80211_rx_result +ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; u16 fc; @@ -541,21 +541,21 @@ 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_UNUSABLE; - if ((rx->u.rx.status->flag & RX_FLAG_DECRYPTED) && - (rx->u.rx.status->flag & RX_FLAG_IV_STRIPPED)) - return TXRX_CONTINUE; + 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 " @@ -565,10 +565,10 @@ 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_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; @@ -589,16 +589,16 @@ 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_UNUSABLE; } } - 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); 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..d42d221d8a1d 100644 --- a/net/mac80211/wpa.h +++ b/net/mac80211/wpa.h @@ -13,19 +13,19 @@ #include <linux/types.h> #include "ieee80211_i.h" -ieee80211_txrx_result -ieee80211_tx_h_michael_mic_add(struct ieee80211_txrx_data *tx); -ieee80211_txrx_result -ieee80211_rx_h_michael_mic_verify(struct ieee80211_txrx_data *rx); +ieee80211_tx_result +ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx); +ieee80211_rx_result +ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx); -ieee80211_txrx_result -ieee80211_crypto_tkip_encrypt(struct ieee80211_txrx_data *tx); -ieee80211_txrx_result -ieee80211_crypto_tkip_decrypt(struct ieee80211_txrx_data *rx); +ieee80211_tx_result +ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx); +ieee80211_rx_result +ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx); -ieee80211_txrx_result -ieee80211_crypto_ccmp_encrypt(struct ieee80211_txrx_data *tx); -ieee80211_txrx_result -ieee80211_crypto_ccmp_decrypt(struct ieee80211_txrx_data *rx); +ieee80211_tx_result +ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx); +ieee80211_rx_result +ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx); #endif /* WPA_H */ diff --git a/net/netfilter/core.c b/net/netfilter/core.c index c4065b8f9a95..292fa28146fb 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 ? dev_net(outdev) : dev_net(indev); + if (net != &init_net) + return 1; +#endif + /* We may already have this, but read-locks nest anyway */ rcu_read_lock(); 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 684ec9c1ad38..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); @@ -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; @@ -159,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) { @@ -193,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); } @@ -228,10 +240,11 @@ 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) +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) { int len; @@ -241,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; @@ -297,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); @@ -317,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); @@ -374,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()) @@ -460,6 +488,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); @@ -475,6 +504,14 @@ 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"); + delim = ","; + } + if (expect->flags & NF_CT_EXPECT_INACTIVE) + seq_printf(s, "%sINACTIVE", delim); + return seq_putc(s, '\n'); } 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 9810d81e2a06..08404e6755fb 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; @@ -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..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 <chentschel@arnet.com.ar> * based on RR's ip_conntrack_ftp.c and other modules. + * (C) 2007 United Security Providers + * (C) 2007, 2008 Patrick McHardy <kaber@trash.net> * * 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 @@ -17,6 +19,7 @@ #include <linux/netfilter.h> #include <net/netfilter/nf_conntrack.h> +#include <net/netfilter/nf_conntrack_core.h> #include <net/netfilter/nf_conntrack_expect.h> #include <net/netfilter/nf_conntrack_helper.h> #include <linux/netfilter/nf_conntrack_sip.h> @@ -36,214 +39,102 @@ 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)"); + +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, - 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; -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 *); -}; +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); -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, - .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 - }, - [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 - } -}; +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); -/* get line length until first CR or LF seen. */ -int ct_sip_lnlen(const char *line, const char *limit) -{ - const char *k = line; +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); - while ((line <= limit) && (*line == '\r' || *line == '\n')) - line++; +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); - while (line <= limit) { - if (*line == '\r' || *line == '\n') - break; - line++; - } - return line - k; -} -EXPORT_SYMBOL_GPL(ct_sip_lnlen); +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); -/* 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) +static int string_len(const struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) { - const char *limit = haystack + (haystack_len - needle_len); + int len = 0; - 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++; + while (dptr < limit && isalpha(*dptr)) { + dptr++; + len++; } - return NULL; + return len; } -EXPORT_SYMBOL_GPL(ct_sip_search); 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++; } 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) +/* get media type + port length */ +static int media_len(const struct nf_conn *ct, const char *dptr, + const char *limit, int *shift) { - for (; dptr <= limit && *dptr == ' '; dptr++) - (*shift)++; + int len = string_len(ct, dptr, limit, shift); + + dptr += len; + if (dptr >= limit || *dptr != ' ') + return 0; + len++; + dptr++; - return digits_len(ct, dptr, limit, shift); + return len + digits_len(ct, dptr, limit, shift); } static int parse_addr(const struct nf_conn *ct, const char *cp, @@ -302,13 +193,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 { @@ -319,74 +210,894 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, return epaddr_len(ct, dptr, limit, shift); } -/* 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) +/* 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, + union nf_inet_addr *addr, __be16 *port) { - const struct sip_header_nfo *hnfo = &ct_sip_hdrs[pos]; - const char *limit, *aux, *k = dptr; + const char *start = dptr, *limit = dptr + datalen, *end; + unsigned int mlen; + unsigned int p; int shift = 0; - limit = dptr + (dlen - hnfo->lnlen); + /* 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; + } + if (!skp_epaddr_len(ct, dptr, limit, &shift)) + return 0; + 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); + +/* 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. + * + * 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_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), + [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), +}; + +static const char *sip_follow_continuation(const char *dptr, const char *limit) +{ + /* 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; +} + +/* 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; + } + + 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; - while (dptr <= limit) { - if ((strncmp(dptr, hnfo->lname, hnfo->lnlen) != 0) && - (hnfo->sname == NULL || - strncmp(dptr, hnfo->sname, hnfo->snlen) != 0)) { - dptr++; + 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 = dptr - start + shift; + return 1; + } + return 0; +} +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); + +/* 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. + * + * 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=", NULL, media_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; + } - *matchoff = (aux - k) + shift; + 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; - pr_debug("%s match succeeded! - len: %u\n", hnfo->lname, - *matchlen); + *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; } - pr_debug("%s header not found.\n", hnfo->lname); return 0; } -EXPORT_SYMBOL_GPL(ct_sip_get_info); +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, + 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 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) +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); +} + +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; + 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 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; + 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. + * + * 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) + 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(); + do { + exp = __nf_ct_expect_find(&tuple); + + 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; + 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, class, family, saddr, daddr, + 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 && !direct_rtp) + 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) + nf_ct_unexpect_related(rtp_exp); + else + ret = NF_ACCEPT; + } + } + nf_ct_expect_put(rtcp_exp); +err2: + nf_ct_expect_put(rtp_exp); +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) +{ + 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; + 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; + 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; + + /* Find beginning of session description */ + if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, + SDP_HDR_VERSION, SDP_HDR_UNSPEC, + &matchoff, &matchlen) <= 0) + return NF_ACCEPT; + 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; + + 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; + + /* 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; + + port = simple_strtoul(*dptr + mediaoff, NULL, 10); + if (port == 0) + continue; + if (port < 1024 || port > 65535) + return NF_DROP; + + /* 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 && 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 */ + 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, + 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, true); + 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); + else { + flush_expectations(ct, true); + 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, true); + 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, 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_sdp_hook) nf_nat_sdp; + 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 == NULL) + if (!exp) return NF_DROP; - nf_ct_expect_init(exp, family, - &ct->tuplehash[!dir].tuple.src.u3, addr, + + 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_sdp = rcu_dereference(nf_nat_sdp_hook); - if (nf_nat_sdp && ct->status & IPS_NAT_MASK) - ret = nf_nat_sdp(skb, ctinfo, exp, dptr); + 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; @@ -395,22 +1106,160 @@ static int set_expected_rtp(struct sk_buff *skb, } 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; +} + +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), + 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, + 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, 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 sip_header_pos pos; + int ret; typeof(nf_nat_sip_hook) nf_nat_sip; /* No Data ? */ @@ -424,58 +1273,45 @@ static int sip_help(struct sk_buff *skb, dptr = skb->data + dataoff; else { pr_debug("Copy of skbuff not supported yet.\n"); - goto out; - } - - 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)) { - ret = NF_DROP; - goto out; - } + return NF_ACCEPT; } datalen = skb->len - dataoff; - if (datalen < sizeof("SIP/2.0 200") - 1) - 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) { - 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) { - - /* 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_info(ct, dptr, datalen, &matchoff, &matchlen, - POS_MEDIA) > 0) { + if (datalen < strlen("SIP/2.0 200")) + return NF_ACCEPT; - port = simple_strtoul(dptr + matchoff, NULL, 10); - if (port < 1024) { - ret = NF_DROP; - goto out; - } - ret = set_expected_rtp(skb, ct, ctinfo, &addr, - htons(port), dptr); - } + if (strnicmp(dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) + ret = process_sip_request(skb, &dptr, &datalen); + else + 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; } -out: + return ret; } 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[SIP_EXPECT_MAX + 1] = { + [SIP_EXPECT_SIGNALLING] = { + .max_expected = 1, + .timeout = 3 * 60, + }, + [SIP_EXPECT_AUDIO] = { + .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) { int i, j; @@ -505,8 +1341,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].max_expected = 2; - sip[i][j].timeout = 3 * 60; /* 3 minutes */ + 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; diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 8599068050ec..9d0b8bb4113c 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/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; 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/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 10522c04ed24..2c9fe5c12894 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/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/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/netlink/af_netlink.c b/net/netlink/af_netlink.c index 1ab0da2632e1..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 ((sk->sk_net == 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 ((osk->sk_net == net) && (nlk_sk(osk)->pid == pid)) + if (net_eq(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 (!net_eq(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); @@ -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; @@ -955,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 (!net_eq(sock_net(sk), p->net)) goto out; if (p->failure) { @@ -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 { @@ -996,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; @@ -1054,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 || @@ -1344,22 +1354,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), @@ -1388,8 +1382,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; @@ -1424,7 +1417,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 +1430,7 @@ EXPORT_SYMBOL(netlink_kernel_create); void netlink_kernel_release(struct sock *sk) { - if (sk == NULL || sk->sk_socket == NULL) - return; - - __netlink_release(sk); + sk_release_kernel(sk); } EXPORT_SYMBOL(netlink_kernel_release); @@ -1553,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; } @@ -1564,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); @@ -1602,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; @@ -1644,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) { @@ -1759,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) != seq_file_net(seq)) continue; if (off == pos) { iter->link = i; @@ -1795,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) != seq_file_net(seq)); if (s) return s; @@ -1807,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) != seq_file_net(seq)) s = sk_next(s); if (s) { iter->link = i; diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c index 972250c974f1..4bae8b998cab 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) @@ -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 b8b827c7062d..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->nd_net != 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->nd_net != 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->nd_net != 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); } @@ -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) { @@ -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 @@ -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; diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c index 063cbc5c26b1..d1ff3f885c5d 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) @@ -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/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/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, }; 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/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/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/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..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) { @@ -189,7 +175,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; @@ -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/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/input.c b/net/sctp/input.c index 812ff1756c3e..c1d7e3b5c4b4 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 b1e05d719f9b..036bfcc8d15b 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -225,7 +225,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); @@ -250,7 +250,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); @@ -259,7 +259,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; @@ -312,10 +312,13 @@ 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_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, + 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; @@ -350,7 +353,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(); @@ -633,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/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 1bb3c5c35d2a..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, @@ -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(); @@ -1203,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. @@ -1441,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; @@ -1558,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; } @@ -1623,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); } } @@ -1646,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/proc.c b/net/sctp/proc.c index 973f1dbc2ec3..ddca90e5e3a5 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -279,8 +279,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; } @@ -319,15 +321,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 " + "%8lu %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/protocol.c b/net/sctp/protocol.c index f90091a1b9ce..5aea91137fbb 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; @@ -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)) { @@ -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? */ @@ -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) @@ -630,6 +630,9 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, struct sctp_sockaddr_entry *temp; int found = 0; + if (dev_net(ifa->ifa_dev->dev) != &init_net) + return NOTIFY_DONE; + switch (ev) { case NETDEV_UP: addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC); @@ -826,9 +829,9 @@ 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)); + __func__, skb, skb->len, + NIPQUAD(skb->rtable->rt_src), + NIPQUAD(skb->rtable->rt_dst)); SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS); return ip_queue_xmit(skb, ipfragok); 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_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 f2ed6473feef..b534dbef864f 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; } @@ -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)); } @@ -3668,7 +3664,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 +3724,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. @@ -4219,7 +4215,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 +4232,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 +4251,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 +4270,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); @@ -5312,6 +5308,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)); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d994d822900d..00ebd0610be2 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; @@ -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 @@ -3302,7 +3302,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); @@ -3823,7 +3823,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) @@ -3837,7 +3837,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; @@ -6233,7 +6233,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. */ @@ -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) */ 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/socket.c b/net/socket.c index 9d3fbfbc8535..9b5c917f8a6b 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)->core.sysctl_somaxconn; if ((unsigned)backlog > somaxconn) backlog = somaxconn; 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/tipc/core.c b/net/tipc/core.c index d2d7d32c02c7..740aac5cdfb6 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -48,16 +48,8 @@ #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" +#define TIPC_MOD_VER "1.6.3" #ifndef CONFIG_TIPC_ZONES #define CONFIG_TIPC_ZONES 3 @@ -277,7 +269,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/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) { 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/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 e9ef6df26562..6ad070d87702 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 /* @@ -72,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; } /* @@ -87,7 +87,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) @@ -97,7 +97,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) @@ -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 @@ -388,7 +365,6 @@ static inline void msg_expand(struct tipc_msg *m, u32 destnode) #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 f508614ca59b..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); @@ -413,13 +414,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); @@ -632,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, diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 22909036b9bc..1b5fb6103ded 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -43,7 +43,7 @@ #include <linux/slab.h> #include <linux/poll.h> #include <linux/fcntl.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> #include <asm/string.h> #include <asm/atomic.h> #include <net/sock.h> @@ -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) @@ -102,44 +102,6 @@ static void sock_unlock(struct tipc_sock* tsock) } /** - * 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 */ @@ -217,7 +179,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 +215,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 +250,7 @@ static int release(struct socket *sock) atomic_dec(&tipc_queue_size); } - up(&tsock->sem); + mutex_unlock(&tsock->lock); sock_put(sk); @@ -315,7 +277,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 +308,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 +329,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 +342,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; } @@ -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; } /** @@ -477,7 +471,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 +517,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 +556,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 +572,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 +840,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 +924,7 @@ restart: advance_queue(tsock); } exit: - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } @@ -981,7 +975,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 +1071,7 @@ restart: goto restart; exit: - up(&tsock->sem); + mutex_unlock(&tsock->lock); return sz_copied ? sz_copied : res; } @@ -1293,7 +1287,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 +1311,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 +1359,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, @@ -1375,7 +1369,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; @@ -1412,14 +1406,14 @@ static int accept(struct socket *sock, struct socket *newsock, int flags) } } exit: - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } /** * 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,9 +1426,10 @@ 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 (down_interruptible(&tsock->sem)) + if (mutex_lock_interruptible(&tsock->lock)) return -ERESTARTSYS; sock_lock(tsock); @@ -1484,7 +1479,7 @@ restart: sock_unlock(tsock); - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } @@ -1518,7 +1513,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 +1536,7 @@ static int setsockopt(struct socket *sock, res = -EINVAL; } - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } @@ -1574,7 +1569,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 +1602,7 @@ static int getsockopt(struct socket *sock, res = put_user(sizeof(value), ol); } - up(&tsock->sem); + mutex_unlock(&tsock->lock); return res; } diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index b8788fd5e3c6..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 (s->sk_net != 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 (s->sk_net != net) + if (!net_eq(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; @@ -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 (s->sk_net != 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 && (sk->sk_net != iter->p.net)) + while (sk && (sock_net(sk) != seq_file_net(seq))) sk = next_unix_socket(&iter->i, sk); return sk; } @@ -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; } 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/nl80211.c b/net/wireless/nl80211.c index e3a214f63f91..64a7460af734 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -81,7 +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 */ @@ -98,6 +103,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 +117,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: @@ -262,12 +341,45 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) return -ENOBUFS; } +static const struct nla_policy mntr_flags_policy[NL80211_MNTR_FLAG_MAX + 1] = { + [NL80211_MNTR_FLAG_FCSFAIL] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_PLCPFAIL] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_CONTROL] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_OTHER_BSS] = { .type = NLA_FLAG }, + [NL80211_MNTR_FLAG_COOK_FRAMES] = { .type = NLA_FLAG }, +}; + +static int parse_monitor_flags(struct nlattr *nla, u32 *mntrflags) +{ + struct nlattr *flags[NL80211_MNTR_FLAG_MAX + 1]; + int flag; + + *mntrflags = 0; + + if (!nla) + return -EINVAL; + + if (nla_parse_nested(flags, NL80211_MNTR_FLAG_MAX, + nla, mntr_flags_policy)) + return -EINVAL; + + for (flag = 1; flag <= NL80211_MNTR_FLAG_MAX; flag++) + if (flags[flag]) + *mntrflags |= (1<<flag); + + return 0; +} + 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]); @@ -287,8 +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 = 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, ¶ms); rtnl_unlock(); unlock: @@ -299,8 +421,12 @@ 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; @@ -320,11 +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); + nla_data(info->attrs[NL80211_ATTR_IFNAME]), + type, err ? NULL : &flags, ¶ms); rtnl_unlock(); + unlock: cfg80211_put_dev(drv); return err; @@ -752,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) @@ -764,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); @@ -785,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; @@ -812,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); @@ -891,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; @@ -1005,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, @@ -1089,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, }, @@ -1111,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 */ diff --git a/net/wireless/reg.c b/net/wireless/reg.c new file mode 100644 index 000000000000..8cc6037eb2ae --- /dev/null +++ b/net/wireless/reg.c @@ -0,0 +1,159 @@ +/* + * Copyright 2002-2005, Instant802 Networks, Inc. + * Copyright 2005-2006, Devicescape Software, Inc. + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + * + * 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 <linux/kernel.h> +#include <net/wireless.h> +#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, 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), +}; + +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..f54424693a38 --- /dev/null +++ b/net/wireless/util.c @@ -0,0 +1,121 @@ +/* + * Wireless utility functions + * + * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> + */ +#include <net/wireless.h> +#include <asm/bitops.h> +#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); + +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) +{ + 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 != 3 && 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); +} 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..6ba67c523c16 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 @@ -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); 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 9fc4c315f6cd..15d73e47cc2c 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); @@ -96,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; } @@ -208,6 +236,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 +259,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 +617,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 +856,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); @@ -1344,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; @@ -1374,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; @@ -2038,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); } @@ -2309,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) { @@ -2365,6 +2406,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 58f1f9347b54..5dcc10b93c86 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; @@ -512,6 +513,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); @@ -537,6 +539,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); @@ -913,6 +919,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); @@ -1522,36 +1530,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 5d96f2728dc6..5578c909fcf6 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -529,8 +529,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) @@ -597,9 +595,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) @@ -612,8 +607,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: @@ -621,18 +614,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; } @@ -651,7 +658,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); @@ -1229,9 +1235,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) @@ -1247,8 +1250,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: @@ -1256,21 +1257,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; } @@ -1290,7 +1303,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); @@ -1888,15 +1900,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 }, @@ -1935,7 +1950,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, |